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-devis the streamlined, interoperability-focused fork of the communityintersystems-community/iris-agentic-devMCP 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 theintersystems-ib/iris-interop-skillsplugin works with either server. It is the binary baked into the "De Prompt a Producción" workshop VM.
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-devOn 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 mcpOr 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.jsonregistration shown above.Connection settings from VS Code are read natively by this binary.
iris-interop-devparses.vscode/settings.json—objectscript.conn, including named servers resolved throughintersystems.servers— from all three VS Code scopes, narrower winning: your user-scope settings, the nearest*.code-workspaceabove 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-workspacetwo levels up — and win over whatever happens to answer on port 52773.Two things stay under your control, not the editor's.
IRIS_PASSWORDsupplies the password VS Code does not expose (it keeps secrets in an encrypted store this binary cannot read), andIRIS_NAMESPACEoverrides thensfrom 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 ofdiscovery.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 — seeintersystems-community/iris-agentic-dev— and it is bound to theiris-agentic-devbinary, so it will not register this one.This fork ships as the
iris-interop-devbinary; the workshop VM registers it for Claude Code.
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 execcancels 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.envsubtable header. TOML puts any bare key written after that header into the env table instead, silently.
Whatever the client:
- Verify with
check_configfirst. It reportsmcp_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_TOOLSETselects the tool surface (--toolsetalso works). This fork defaults tointerop— the tools listed under Tools.baselineexposes everything the binary carries. No count is written here on purpose: they have been wrong before, andtools/liston 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:routinesdid not exist before #531, and asking an older binary for it got you everything. IRIS_TOOLSET=routinesis for legacy ObjectScript (#531):.macroutines 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) andiris_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_configreports the active profile in itstoolsetfield.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'smcp_versiontells you which build is actually answering.
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 |
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:
- Open IIS Manager → expand your server → Sites → Default Web Site
- Right-click → Add Application. Alias:
api, physical path:C:\InterSystems\IRIS\CSP\bin(adjust to your install path) - Add a wildcard script handler mapping: executable =
CSPms.dll, no verb restriction - Verify
CSP.inicontains 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".
Run iris-interop-dev init in your project directory — it detects running IRIS containers and writes
.iris-agentic-dev.toml automatically:
iris-interop-dev initOr 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.
iris-interop-dev resolves the IRIS connection in this order — first match wins:
- CLI flags (
--host,--web-port,--scheme) .iris-agentic-dev.tomlin the workspace root- Environment variables (
IRIS_HOST, etc.) - Running Docker containers (scored by workspace name similarity)
- Localhost port scan (52773, 41773, 51773, 8080)
| 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 |
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
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).
| 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.
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 versionIssues 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.