Skip to content

About

Streamlined interop-focused fork of iris-agentic-dev MCP server

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

iris-interop-dev

Connect Claude Code and other AI coding assistants directly to a live InterSystems IRIS instance. The AI can compile classes, run ObjectScript, execute SQL, run %UnitTest tests, drive Interoperability productions, and inspect class definitions — without leaving the chat.

Works with IRIS installed natively on Windows or Linux, and with Docker. Requires IRIS 2023.1 or later.

What this is. iris-interop-dev is the streamlined, interoperability-focused fork of the community intersystems-community/iris-agentic-dev MCP server. It exposes a locked interop profile, ships as a single binary (no Python), and uses a distinct MCP server name (iris-interop-dev) so it can be installed alongside the original. Tool names are identical, so the intersystems-ib/iris-interop-skills plugin works with either server. It is the binary baked into the "De Prompt a Producción" workshop VM.


Quick start: Claude Code

1. Install the binary from the latest release:

# macOS — picks arm64 or Intel from `uname -m`, so the same line works on either
arch=$([ "$(uname -m)" = "arm64" ] && echo arm64 || echo x64)
curl -fsSL "https://github.com/intersystems-ib/iris-interop-dev/releases/latest/download/iris-interop-dev-macos-$arch" \
  -o /usr/local/bin/iris-interop-dev && chmod +x /usr/local/bin/iris-interop-dev
xattr -d com.apple.quarantine /usr/local/bin/iris-interop-dev 2>/dev/null
# Linux — picks x64 or arm64 from `uname -m`, and REFUSES an architecture with no published
# asset instead of downloading one built for a different machine. That is deliberate: the
# wrong-architecture binary downloads, hash-verifies, and only then dies at exec, which reads
# as a broken release rather than a missing build (#543, and #423 before it on macOS).
case "$(uname -m)" in
  x86_64|amd64)  asset=iris-interop-dev-linux-x64 ;;
  aarch64|arm64) asset=iris-interop-dev-linux-arm64 ;;
  *) echo "iris-interop-dev: no Linux release asset for $(uname -m) — published: x86_64/amd64, aarch64/arm64" >&2
     exit 1 ;;
esac
curl -fsSL "https://github.com/intersystems-ib/iris-interop-dev/releases/latest/download/$asset" \
  -o /usr/local/bin/iris-interop-dev && chmod +x /usr/local/bin/iris-interop-dev

On a distribution with an older glibc — Amazon Linux 2023, RHEL 8-9, Debian 12 — append -musl to whichever asset the block above selected (iris-interop-dev-linux-x64-musl, iris-interop-dev-linux-arm64-musl). Those are statically linked, so they have no glibc floor; the two assets above are built on Ubuntu 24.04 and need GLIBC 2.39, which those distributions do not have. The symptom is a download that hash-verifies and then fails at exec.

scripts/select-release-asset.sh in this repo answers the same question for any host, including the refusal — bash scripts/select-release-asset.sh prints the asset name for the machine it runs on, --musl asks for the static flavour, and --list prints every published asset.

Windows: download iris-interop-dev-windows-x64.exe from the releases page, rename it to iris-interop-dev.exe, and put it somewhere on disk (e.g. C:\iris-interop-dev\iris-interop-dev.exe).

2. Register it as an MCP server. The one-line form (works from any directory, user scope):

claude mcp add --scope user iris-interop-dev \
  --env IRIS_HOST=localhost --env IRIS_WEB_PORT=80 --env IRIS_WEB_PREFIX=irishealth \
  --env IRIS_USERNAME=_SYSTEM --env IRIS_PASSWORD=SYS --env IRIS_NAMESPACE=USER \
  -- /usr/local/bin/iris-interop-dev mcp

Or add it by hand to ~/.claude/settings.json:

{
  "mcpServers": {
    "iris-interop-dev": {
      "command": "iris-interop-dev",
      "args": ["mcp"],
      "env": {
        "IRIS_HOST": "localhost",
        "IRIS_WEB_PORT": "52773",
        "IRIS_USERNAME": "_SYSTEM",
        "IRIS_PASSWORD": "SYS",
        "IRIS_NAMESPACE": "USER"
      }
    }
  }
}

Restart Claude and verify with the check_config tool that it connects and the tools appear.

VS Code? Three separate things get read as one here, so to be explicit about which is which:

  • Claude Code's own VS Code extension works today, with no extra setup. It is a front-end for Claude Code and reads the same user-scope ~/.claude.json registration shown above.

  • Connection settings from VS Code are read natively by this binary. iris-interop-dev parses .vscode/settings.json — objectscript.conn, including named servers resolved through intersystems.servers — from all three VS Code scopes, narrower winning: your user-scope settings, the nearest *.code-workspace above you, and this folder's .vscode/settings.json. That is what lets a folder which merely names a server ("server": "workshop-iris") resolve against the definition kept in the multi-root .code-workspace two levels up — and win over whatever happens to answer on port 52773.

    Two things stay under your control, not the editor's. IRIS_PASSWORD supplies the password VS Code does not expose (it keeps secrets in an encrypted store this binary cannot read), and IRIS_NAMESPACE overrides the ns from settings — so a deliberately read-only default namespace stays in force and a write that forgets to name its namespace still fails immediately. The full order, and the remaining limits, are at the top of discovery.rs (issue #187).

  • What this fork does not carry is the Marketplace extension that auto-registers the server, and skill install --agent copilot. That path belongs to the upstream community tool — see intersystems-community/iris-agentic-dev — and it is bound to the iris-agentic-dev binary, so it will not register this one.

This fork ships as the iris-interop-dev binary; the workshop VM registers it for Claude Code.


Other MCP clients (Cursor, Codex, …)

iris-interop-dev mcp is a plain stdio MCP server, so any client that can launch a command and pass environment variables can drive it. Only the registration file differs — the binary, the arguments and the environment are the same ones the Claude Code section uses above.

Cursor — ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one:

{
  "mcpServers": {
    "iris-interop-dev": {
      "command": "/usr/local/bin/iris-interop-dev",
      "args": ["mcp"],
      "env": {
        "IRIS_HOST": "localhost",
        "IRIS_WEB_PORT": "52773",
        "IRIS_USERNAME": "_SYSTEM",
        "IRIS_PASSWORD": "SYS",
        "IRIS_NAMESPACE": "USER"
      }
    }
  }
}

Codex CLI — ~/.codex/config.toml:

[mcp_servers.iris-interop-dev]
command = "/usr/local/bin/iris-interop-dev"
args = ["mcp"]
default_tools_approval_mode = "approve"

[mcp_servers.iris-interop-dev.env]
IRIS_HOST = "localhost"
IRIS_WEB_PORT = "52773"
IRIS_USERNAME = "_SYSTEM"
IRIS_PASSWORD = "SYS"
IRIS_NAMESPACE = "USER"

Two things that cost real time when we ran the skills eval corpus under Codex:

  • default_tools_approval_mode = "approve" is not optional for non-interactive runs. Without it, codex exec cancels every MCP tool call (user cancelled MCP tool call) — reproduced 5/5 on codex-cli 0.146.1. auto, writes, project trust settings and feature flags did not help.
  • It must sit inside [mcp_servers.<name>] and before the .env subtable header. TOML puts any bare key written after that header into the env table instead, silently.

Whatever the client:

  • Verify with check_config first. It reports mcp_version, connected, host/port/namespace and the active toolset from a cached snapshot — no IRIS round-trip — so it answers even when IRIS is down, which makes it the right first call to tell "MCP not registered" from "IRIS unreachable".
  • IRIS_TOOLSET selects the tool surface (--toolset also works). This fork defaults to interop — the tools listed under Tools. baseline exposes everything the binary carries. No count is written here on purpose: they have been wrong before, and tools/list on your own build is the only answer that cannot go stale.
  • A name this build does not recognise refuses to start (#541), naming the valid profiles. It used to fall back to baseline — the widest surface — so a typo bought more tools than any correct value would have, silently. If startup fails with that message, check the spelling against the table below rather than the release you remember: routines did not exist before #531, and asking an older binary for it got you everything.
  • IRIS_TOOLSET=routines is for legacy ObjectScript (#531): .mac routines with dot syntax, $PIECE-delimited records in globals, cross-reference globals, LOCK/TSTART. Use it when the code you are working on has no production — it drops the production, routing-rule, lookup, credential and HL7 tools, which otherwise invite an agent to look for interop structure that is not there, and it adds two read-only tools the interop profile excluded on scope: iris_search (which routine references this global — a name search cannot answer that) and iris_info (what did I just change). Execution, compilation, testing and introspection are the same in both profiles, and so are the write gate and the read-only modes. check_config reports the active profile in its toolset field.
  • IRIS_LOG_FILE=<path> is how a session's traces survive it. An MCP client keeps the server's stderr to itself, so without this there is nothing to read after a failed run.
  • A running client keeps the binary it started with. After installing a new release, restart the client — check_config's mcp_version tells you which build is actually answering.

Connecting to IRIS

Native IRIS on Windows or Linux (no Docker)

Add a .iris-agentic-dev.toml file to your project root (the config filename is unchanged from the upstream codebase):

host = "localhost"
web_port = 80        # IIS default for IRIS 2024.1+; use 52773 for pre-2024.1
namespace = "USER"
username = "_SYSTEM"
password = "SYS"

Port reference

IRIS version Web server Default port
2024.1+ on Windows IIS 80
2024.1+ on Linux Apache 80
Pre-2024.1 (any OS) Private Web Server (PWS) 52773

Windows IIS: /api web application required

This is the most common failure on Windows. IIS needs an explicit /api web application mapped to the IRIS Web Gateway module. Without it, /api/atelier returns 404 — even when the Management Portal loads.

To fix:

  1. Open IIS Manager → expand your server → Sites → Default Web Site
  2. Right-click → Add Application. Alias: api, physical path: C:\InterSystems\IRIS\CSP\bin (adjust to your install path)
  3. Add a wildcard script handler mapping: executable = CSPms.dll, no verb restriction
  4. Verify CSP.ini contains an [APP_PATH:/api] section

localhost vs 127.0.0.1: on some older Web Gateway builds, localhost causes a brief connection error before each request. If you see delays, set host = "127.0.0.1".

Docker

Run iris-interop-dev init in your project directory — it detects running IRIS containers and writes .iris-agentic-dev.toml automatically:

iris-interop-dev init

Or configure manually:

container = "myapp-iris"
namespace = "MYAPP"

Enterprise IRIS images (intersystems/iris, intersystems/irishealth) ship without a built-in web server — run the ISC Web Gateway container alongside IRIS and point web_port at it.

Connection discovery order

iris-interop-dev resolves the IRIS connection in this order — first match wins:

  1. CLI flags (--host, --web-port, --scheme)
  2. .iris-agentic-dev.toml in the workspace root
  3. Environment variables (IRIS_HOST, etc.)
  4. Running Docker containers (scored by workspace name similarity)
  5. Localhost port scan (52773, 41773, 51773, 8080)

Environment variables

Variable Default Description
IRIS_HOST localhost IRIS web gateway hostname
IRIS_WEB_PORT 52773 Web gateway port
IRIS_SCHEME http http or https
IRIS_WEB_PREFIX (empty) URL path prefix for non-root gateway installs (e.g. irishealth)
IRIS_USERNAME _SYSTEM IRIS username
IRIS_PASSWORD SYS IRIS password
IRIS_NAMESPACE USER Default namespace
IRIS_CONTAINER (empty) Docker container name — required for Docker-dependent tools
IRIS_TOOLSET interop Tool surface: interop (the locked profile), routines (legacy routines and globals, #531), baseline (full upstream surface), nostub or merged. An unrecognised name refuses to start (#541). Same as --toolset
IRIS_LOG_FILE (empty) Mirror server traces to this file — the only trace that outlives an MCP session
IRIS_DISCOVERY_TIMEOUT_MS 2000 How long startup waits for IRIS discovery before serving. Missing this window is not fatal — the connection is adopted whenever the probe finishes — so raise it only if you would rather initialize block than serve unconnected
IRIS_ALLOW_PROD (unset) Allow MUTATING calls on a connection that is not write-allowed (Live system mode, or a production-looking namespace). Reads are never blocked, so this is only needed to write. Set to 1 deliberately
IRIS_SOFT_READ_ONLY (unset) Ask for read-only: every MUTATING call is refused regardless of what the instance looks like. Beats IRIS_ALLOW_PROD — an explicit request is not a heuristic, so it cannot be overridden by one. The tools that answer by writing a temporary class still work (see IRIS_STRICT_READ_ONLY). Set to 1
IRIS_STRICT_READ_ONLY (unset) As above, and additionally refuses the tools that answer by PUT/compile/delete of a scratch class in IrisDevTmp — iris_table_info, iris_production_diff, iris_message_body, the hl7_schema_* pair and the rest of GENERATOR_WRITE_TOOLS. They are read-only in intent but the data they read has no SQL projection to reach it through, so strict is the level for an instance that must not be written at all. Those tools are also absent from the advertised list. Wins over IRIS_SOFT_READ_ONLY if both are set. Set to 1
IRIS_BLOCK_CODEGEN (unset) Refuse an iris_doc put whose class declares CodeMode = objectgenerator. Off by default: a generator grants no capability iris_execute does not already have on a write-allowed connection, and on a Live one IRIS_ALLOW_PROD already governs the write. Turn it on where a later compile, by another identity, is the thing you are protecting. The methods are named in compile_time_methods on every put either way
IRIS_DISCOVERY_RETRY_SECS 15 Minimum gap between lazy re-probes when a session has no connection. A session started before IRIS was ready heals on a later tool call instead of answering IRIS_UNREACHABLE for its lifetime
OBJECTSCRIPT_WORKSPACE $PWD Workspace root for .iris-agentic-dev.toml lookup
OBJECTSCRIPT_SKILLMCP_NAMESPACE (connection namespace) Namespace holding the ^SKILLS / ^KBCHUNKS registry (baseline toolset). Defaults to the connection namespace (IRIS_NAMESPACE / --namespace); set it only to centralise the registry in one namespace

The interop skills

This server is the runtime for the intersystems-ib/iris-interop-skills Claude Code plugin — 20 skills that steer Claude when building IRIS For Health Interoperability productions (messages, BS/BP/BO, BPL, DTL, HL7 schemas, SOAP/REST/FHIR/DICOM, alerting, security, lifecycle), plus governance hooks, subagents and a post-build conformance review. Install it with:

/plugin marketplace add intersystems-ib/iris-interop-skills
/plugin install iris-interop-skills@iris-interop-skills

Tools (interop profile)

Most tools work over the Atelier REST API against any IRIS instance; Docker-only tools accept an IRIS_CONTAINER but also run over HTTP/Atelier against native/remote IRIS.

Code & data — iris_doc (read/write/delete documents), iris_compile (compile, errors with line numbers), iris_execute (run ObjectScript), iris_query (SQL → JSON rows), iris_test (run %UnitTest, structured pass/fail), iris_get_log (fetch a truncated result by log_id), iris_execute_method (invoke a ClassMethod by name), iris_coverage (line coverage of a %UnitTest run, via %Monitor.System.LineByLine), stream_inspect (read a stream body by id — size plus the first max_chars as exact bytes; an id that does not exist is reported as such rather than as an empty stream, and a CR-separated HL7 body keeps its segments), compare_namespace / compare_document (diff two namespaces on the connected instance, or one document across them — in_sync is never claimed by a comparison that examined nothing), iris_source_control (drive the instance's own %Studio.SourceControl hooks — status, the action menu, checkout, and the SCM actions themselves; status and menu stay available on a read-only connection, while check-in, get-latest and disconnect go through the write gate).

Introspection — docs_introspect (methods/properties/XData/superclasses), iris_symbols (search classes/methods), iris_table_info (real projected table + columns), check_config (active connection state), find_subclass_implementations (who overrides a method), iris_debug (map a .INT offset back to source, error logs), iris_symbols_local (parse a .cls on disk — no IRIS round trip), iris_macro (expand a macro / read an include), iris_doc_search (full-text search of the class documentation on this instance).

Interoperability — iris_production (start/stop/update/status/recover/autostart), iris_production_item (item get/set settings), iris_interop_query (logs, queues, message archive/trace), iris_message_body (read a message body — string/stream containers and any EnsLib.EDI.Document: HL7 v2, X12, ASTM, EDIFACT, EDI XML — with a PHI gate), iris_business_rule_info (list/describe routing rules), iris_production_diff (running config vs committed source), extract_message_map_routing (message-map targets of a business process), iris_lookup_manage / iris_lookup_transfer (lookup tables), iris_credential_list / iris_credential_manage (SSL/credentials), hl7_schema_list / hl7_schema_inspect (the HL7 v2 schemas this instance actually carries, and their segments/fields — both refuse with HL7_NOT_AVAILABLE on a stock IRIS that has none).

External data — iris_gateway_query (read through a configured SQL Gateway connection to a foreign database), iris_gateway_manage (probe whether a JDBC gateway can run here at all, list the connections defined on the instance, test one end to end — and get back WHICH failure mode it is, each with its own remedy, instead of one opaque "connection failed"; create and delete a JDBC connection, write-gated, with the stored password never returned by any action).


Troubleshooting

Symptom Likely cause Fix
404 on /api/atelier (Windows) IIS missing /api web application See Windows IIS setup above
check_config works but compile/search fail Atelier web app Recurse=0 Management Portal → Security → Web Apps → /api/atelier → enable Recurse
iris_execute returns empty output HTTP CodeMode only returns what your code writes Use write <expr>,!, or wrap side effects as a [SqlProc] and read via iris_query
DOCKER_REQUIRED on native IRIS IRIS_CONTAINER set unnecessarily Retry without IRIS_CONTAINER — the interop tools run over HTTP
403 on write operations Insufficient permissions Use a user with %DB_USER or %All role
Connection delays on Windows localhost DNS issue Use host = "127.0.0.1" in .iris-agentic-dev.toml

Verbose HTTP logging: iris-interop-dev mcp --verbose 2>debug.log.


Commands

iris-interop-dev mcp                     # Start the MCP server
iris-interop-dev compile MyApp.Foo.cls   # Compile from the terminal
iris-interop-dev init                    # Generate .iris-agentic-dev.toml from running containers
iris-interop-dev --version               # Print version

Contributing

Issues and pull requests welcome — file bugs at the Issues tab.

Read CLAUDE.md first. It documents the one defect class this codebase produces more than any other — a failure answered with a fact that looks like an answer — the constructs that cause it, the repair that works, and how to run the gate without getting a false green from it.

This is an interop-focused fork of the community intersystems-community/iris-agentic-dev; upstream fixes to the shared codebase flow from there. The repositories in intersystems-ib are community utilities and examples — not covered by official InterSystems support.

About

Streamlined interop-focused fork of iris-agentic-dev MCP server

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages