Most tools work over the Atelier REST API and connect to any IRIS instance — no Docker
required unless noted. Tools marked ✦ require IRIS_CONTAINER. Tools marked 🔒 are
write-gated (suppressed on Live instances unless IRIS_ALLOW_PROD=1). Tools marked ☠
are destructive-gated — they require destructive_tools_enabled = true in addition to
write_tools_enabled = true.
namespace defaults to "USER" on every tool. It is omitted from parameter tables below
unless there is something non-obvious to say about it.
| Tool | Section |
|---|---|
iris_servers |
Server Management |
iris_add_server |
Server Management |
iris_remove_server ☠ |
Server Management |
iris_reload_pool |
Server Management |
iris_test_server |
Server Management |
iris_import_servers |
Server Management |
iris_doc |
Code |
iris_compile |
Code |
iris_execute |
Code |
iris_execute_method |
Code |
iris_query |
Code |
iris_test |
Code |
iris_coverage |
Code |
iris_global 🔒 |
Code |
iris_source_control ✦ |
Code |
iris_symbols |
Search and introspection |
iris_symbols_local |
Search and introspection |
docs_introspect |
Search and introspection |
iris_search |
Search and introspection |
iris_info |
Search and introspection |
iris_macro |
Search and introspection |
iris_table_info |
Search and introspection |
resolve_dynamic_dispatch |
Search and introspection |
extract_message_map_routing |
Search and introspection |
find_subclass_implementations |
Search and introspection |
iris_debug |
Debugging |
iris_get_log |
Debugging |
check_config |
Debugging |
iris_generate |
Generation |
iris_generate_class |
Generation |
iris_generate_test |
Generation |
iris_production ✦ |
Interoperability |
iris_interop_query ✦ |
Interoperability |
iris_production_item 🔒 |
Interoperability |
iris_production_diff |
Interoperability |
iris_message_body |
Interoperability |
iris_business_rule_info |
Interoperability |
iris_credential_list |
Interoperability |
iris_credential_manage 🔒 ☠ |
Interoperability |
iris_lookup_manage ☠ |
Interoperability |
iris_lookup_transfer |
Interoperability |
iris_ws_open |
WebSocket sessions |
iris_ws_exec |
WebSocket sessions |
iris_ws_close |
WebSocket sessions |
global_preview |
Administration |
global_kill 🔒 ☠ |
Administration |
iris_namespace_list |
Administration |
iris_namespace_create 🔒 ☠ |
Administration |
iris_database_list |
Administration |
iris_mirror_status |
Administration |
iris_system_performance |
Administration |
iris_database_stats |
Administration |
journal_search |
Administration |
query_audit_log |
Administration |
stream_inspect |
Administration |
my_access |
Administration |
capability_matrix |
Administration |
hl7_schema_list |
Administration |
hl7_schema_inspect |
Administration |
mermaid_class |
Administration |
mermaid_production |
Administration |
resolve_storage |
Administration |
compare_document |
Administration |
compare_namespace |
Administration |
iris_admin ☠ |
Administration |
iris_containers ✦ |
Administration |
skill |
Skills and knowledge base |
skill_community |
Skills and knowledge base |
kb / kb_index / kb_recall |
Skills and knowledge base |
agent_history / agent_stats |
Skills and knowledge base |
telemetry_query |
Skills and knowledge base |
telemetry_export_trace |
Skills and knowledge base |
Every tool advertises its parameters in its inputSchema: names, JSON types, and — where
the handler branches on a fixed set of values — an enum. 28 parameters across 24 tools
carry one, iris_admin.action (25 values) being the largest. The parameter tables in this
file describe the same contract in prose; the schema is what a client can read without
parsing English.
Every declared enum is the set the handler branches on, checked against the source rather
than against these tables — a test extracts the string literals each dispatcher matches on
and compares them with the schema. Two parameters have no branch literal behind them and
say so in the test with a reason: iris_add_server.scheme, which is interpolated into a
URL, and iris_admin.type, which filters the webapp list case-insensitively against a name
derived from IRIS. Declaring an enum changes nothing at runtime: a value outside the set
still reaches the handler and still comes back with the handler's own message naming the
values it accepts.
Every tool also sets additionalProperties: false. A parameter the tool does not declare
is rejected with UNKNOWN_PARAMETER and the error lists the names it does accept. Through
1.3.2, 31 tools advertised an open object with no properties at all, so a misspelled or
invented parameter was dropped in silence — stream_inspect was documented with a
character cap that no code read, and a caller asking for 10,000 characters got the whole
stream and no warning. The name of that parameter is deliberately absent from this file:
a guard in the test suite fails if it comes back, because the docs row is what created the
bug in the first place.
Six tools take no parameters at all and declare an empty property set: agent_stats,
check_config, iris_import_servers, iris_reload_pool, skill_community_list,
skill_list.
This server exposes 80 to 84 tools depending on toolset (IRIS_TOOLSET=baseline|nostub|merged),
with full schemas and descriptions: 94 KB to 107 KB of JSON, roughly 26K to 30K tokens, if a
client loads the whole catalog on every connection. Two independent ways to avoid paying that
cost, and you don't have to pick just one:
- Client-side, zero server changes needed: Anthropic's Tool Search
Tool
(
tool_search_tool_bm25_20251119/_regex_20251119) lets a model discover tools on demand instead of front-loading the full catalog. It already works against this server's MCP surface unmodified — enabling it on the client is the whole change. - Server-side:
list_toolssupports real cursor-based pagination. A plain, unconfiguredtools/listcall still returns the entire effective toolset in one response (the default page size is set above every toolset's real tool count, so nothing changes for existing clients). SetIRIS_LIST_TOOLS_PAGE_SIZEto a smaller value to page the catalog across multipletools/listcalls instead — each response includes anextCursorwhen more tools remain; omitcursoron the first call and pass back whatevernextCursoryou last received to get the next page, until a response with nonextCursorsignals the end.
tool --list prints one line per tool — name and a one-sentence summary. tool <name> --schema prints one tool's full description and inputSchema. Both read the same router
tools/list reads, so the schema you get from the CLI is byte-identical to the schema an MCP
client receives, and a test compares all 81 for every build.
Neither path connects to IRIS. Discovery works with no container running, no credentials, and a closed port:
iris-agentic-dev tool --list # 81 names + summaries
iris-agentic-dev tool --list --json # same, as {"count": 81, "tools": [...]}
iris-agentic-dev tool iris_query --schema # one tool's contract
iris-agentic-dev tool iris_query --schema --json # same, as one JSON document--json works on both paths. --list with a tool name is an error rather than a silent
preference for one or the other.
Why it exists — measured against this tree:
| Reading the surface via | Bytes |
|---|---|
MCP tools/list (81 tools, compact) |
106,658 |
tool --list |
7,648 |
tool <name> --schema, smallest |
231 |
tool <name> --schema, median |
1,357 |
tool <name> --schema, largest |
10,134 |
An agent with only a shell reads the whole surface for 7.6 KB and then pays for the one or two
schemas it actually needs, instead of 107 KB up front. A wrong name is refused with the nearest
accepted name, the same suggestion UNKNOWN_PARAMETER uses for misspelled parameters.
IRIS_TOOLSET applies to --list, so the CLI lists the tier the server would serve.
Tools for registering, testing, and managing IRIS server connections. All other tools
accept an optional server parameter that routes to a named instance — see iris_servers
to list what's registered.
List all registered IRIS instances from all configuration sources (iad-native config, VS Code Server Manager settings, workspace fleet config, environment variables). Shows name, host, port, namespace, source, and reachability status.
Default (probe omitted or false): fast path — reachable is null per entry, no HTTP
requests made.
Pass probe: true to fan out a parallel Atelier REST probe to every server in the pool
(5-second timeout each). Each entry then includes reachable, auth, latency_ms,
iris_version, atelier_version, and error.
Register a new IRIS instance. Writes server details to
~/.config/iris-agentic-dev/servers.json and stores the password in the OS keychain —
the password never appears in any config file. Uses the same keychain format as VS Code
Server Manager, so credentials are shared automatically if both tools are installed.
Parameters: name, host, port, namespace, username, password, description
(optional), scheme (optional, default "http").
After adding a server, restart iad for the new connection to appear in the pool.
Remove a server from the iad-native config and its keychain entry. Requires
destructive_tools_enabled = true. Cannot remove servers sourced from VS Code settings —
edit settings.json directly for those.
Hot-reload the connection pool from disk without restarting iad. Re-reads the workspace
TOML config and the iad-native servers list, then atomically replaces the in-memory pool.
Returns {success, servers_loaded, servers, note}. Parse errors preserve the existing pool
and return {success: false, error_code: "TOML_PARSE_ERROR", ...}.
Background reload: iad also reloads the pool automatically when the workspace TOML
changes on disk. The change is detected via file mtime on each call to iris_servers,
iris_compile, iris_execute, and similar tools. A parse error during background reload
is silently swallowed — the existing pool is kept.
Probe an IRIS server for reachability. Returns reachable, auth, iris_version,
atelier_version, and latency_ms.
Two modes:
- Named server (
name): looks up the server in the connection pool and probes it. - Ad-hoc (
host, optionalweb_port,username,password): probes a server that is not in the pool. Useful for discovery before callingiris_add_server. Default port is 52773; default credentials are_SYSTEM/"". Returnsreachable: true, auth: falsewhen the server responds with HTTP 401 (reachable but credentials wrong).
One-time import of IRIS server definitions from VS Code or Cursor settings into the iad-native config. Reads passwords from the existing OS keychain — no re-entry required. Reports servers imported, skipped (already present), and those with no keychain entry.
Read, write, delete, insert lines, or list IRIS documents.
| Parameter | Type | Default | Notes |
|---|---|---|---|
mode (alias: action) |
string | "get" |
See modes below |
name (alias: document) |
string | — | Document name, e.g. "MyApp.MyClass.cls" |
names |
string[] | [] |
Batch get/delete |
content |
string | — | Document content for put/insert |
compile |
bool | false |
Compile after put |
start |
int | — | Start line for get (fragment) or delete_lines |
end |
int | — | End line for get (fragment) or delete_lines |
line |
int | — | Insert-before line for insert |
expected |
string | — | CAS guard: current content at start–end; fails with STALE_CONTENT if mismatch |
pattern |
string | — | Glob filter for list, e.g. "MyApp.*.cls" |
category |
string | — | "CLS" | "MAC" | "INT" | "INC" | "ALL" |
max_results |
int | 200 |
Max 1000; for list |
compiled_type |
string | "INT" |
"INT" is the only value; for compiled mode. OBJ returns INVALID_PARAMS |
allow_storage_regeneration |
bool | false |
Required to proceed when IRIS strips Storage blocks on PUT |
elicitation_id |
string | — | SCM checkout dialog resume ID |
elicitation_answer |
string | — | SCM checkout dialog answer |
namespace |
string | "USER" |
Modes:
| Mode | What it does |
|---|---|
get |
Read document content |
put |
Write document content (SCM-gated, strips Storage blocks on IRIS 2025.1+) |
delete |
Delete document |
head |
Return metadata only (size, timestamp) without content |
fragment |
Read lines start–end |
compiled |
Read compiled INT or OBJ source |
list |
List documents matching pattern/category |
insert |
Insert content before line (use expected for a CAS check) |
delete_lines |
Delete lines start–end (use expected for a CAS check) |
Examples:
# Read a class
iris_doc(mode="get", name="MyApp.MyClass.cls")
# Write and compile
iris_doc(mode="put", name="MyApp.MyClass.cls", content="...", compile=true)
# Patch line 42 — fail if content changed since last read
iris_doc(mode="insert", name="MyApp.MyClass.cls", line=42,
content=" Set x = 1\n", expected=" // placeholder\n")
# List all classes in a package
iris_doc(mode="list", pattern="MyApp.*.cls")
Storage block guard. IRIS 2025.1+ rejects Storage XML in a PUT request (upstream
bug). iris_doc strips it before writing and refuses by default with
STORAGE_RESET_REQUIRES_CONFIRMATION. Pass allow_storage_regeneration: true to proceed — but
understand that recompiling without Storage forces IRIS to regenerate global layout,
which can change the extent for %Persistent classes. Use mode=insert or
mode=delete_lines when the edit does not touch the Storage block.
SCM checkout. On source-controlled instances, iris_doc runs the SCM pre-write
check before writing. If checkout is required, the tool returns an elicitation dialog
rather than writing. Resume it with elicitation_id + elicitation_answer.
Compile a class, routine, or wildcard pattern.
| Parameter | Type | Default | Notes |
|---|---|---|---|
target |
string | — | Required. Class name, routine, or glob like "MyApp.*.cls" |
flags |
string | "cuk" |
Compile flags |
namespace |
string | "USER" |
|
force_writable |
bool | false |
Override read-only check |
inline |
bool | false |
Return all errors inline (bypass log store) |
Returns errors with line numbers.
iris_compile(target="MyApp.MyClass.cls")
iris_compile(target="MyApp.*.cls", flags="cukd")
Run arbitrary ObjectScript and return the output.
| Parameter | Type | Default | Notes |
|---|---|---|---|
code |
string | — | Required. ObjectScript to execute |
namespace |
string | "USER" |
|
timeout |
int | 120 |
Seconds; overridden by OBJECTSCRIPT_TEST_TIMEOUT env var |
translate_sql |
bool | true |
Rewrite &sql(...) macros to %SQL.Statement |
use_session |
bool | false |
Enable %ctx session carrier (see below) |
session_state |
string | — | Token from a prior call; restores %ctx |
iris_execute(code="Write $ZVersion")
iris_execute(code="Set sc = ##class(MyApp.Util).Run() Write sc", namespace="MYAPP")
Code-edit guard — see Code-edit guard below.
Destructive-tier gate — iris_execute requires write_tools_enabled = true (it is
write-gated). Additionally, if the literal code string contains a Kill ^<global> pattern
(any case variant), destructive_tools_enabled = true is also required. This check catches
direct global kills written literally in the code. Indirect operations — Kill @variable,
Xecute-dispatched code, or class method calls that internally kill a global — are not
detected; IRIS-side credentials and the mcpTemplate env gate are the appropriate controls
for those.
Set use_session: true to get a %ctx variable (%DynamicObject) injected before your code
and serialized into a session_state token in the response. Pass that token back as
session_state on the next call to restore %ctx. Nothing is written to IRIS — the token
lives entirely in the client.
# Call 1 — compute something and stash it
iris_execute(
use_session=true,
code="Set %ctx.count = 1247 Set %ctx.label = \"patients\""
)
# → response includes session_state: "eyJjb3VudCI6MTI0N..."
# Call 2 — pick up where you left off
iris_execute(
use_session=true,
session_state="eyJjb3VudCI6MTI0N...",
code="Write %ctx.count * 0.05"
)
# → output: 62.35
%Persistent objects are automatically stubbed on save ({"_cls": "...", "_id": "..."})
and re-opened on restore. %DynamicObject and scalar values survive round-trips unchanged.
Values that cannot serialize (open file handles, result sets, device references) must be
removed from %ctx before the epilogue runs.
Session error codes:
| Code | Meaning |
|---|---|
SESSION_INVALID |
Token is malformed or %FromJSON failed |
SESSION_RESTORE_FAILED |
A stubbed %Persistent object could not be re-opened (class missing or bad ID) |
SESSION_SERIALIZE_FAILED |
%ctx could not be serialized at end of call |
server (optional): route this call to a named registered IRIS instance. If omitted,
uses the default connection. Use iris_servers to list available instances.
iris_execute has two execution paths:
-
HTTP (primary) — wraps code in a temporary class method body, compiles it via Atelier REST, runs it, deletes the class. Block syntax (
{}) works here because class method bodies support it. -
docker exec (fallback) — used when
IRIS_CONTAINERis set and HTTP fails, or whendocker_only = truein config. This path pipes code intoiris sessionstdin, which is a line-by-line terminal interpreter. Block syntax is not supported in terminal mode.If cond { Write x }causes<SYNTAX>with no explanation.
Use classic terminal-compatible form for the docker exec path:
// Terminal-compatible: classic form
If cond Write x
// Terminal-compatible: dotted-DO
If cond Do
. Write x
// NOT terminal-compatible: block syntax
If cond {
Write x // causes <SYNTAX> on docker exec path
}
Escape hatch for complex scripts on the docker exec path: write a .mac routine with
iris_doc, compile it with iris_compile, then call iris_execute Do entry^RoutineName.
Block syntax works inside compiled routines.
// Step 1: write the routine
iris_doc(mode="put", name="MyScript.mac", content="ROUTINE MyScript\nentry()\n If x=1 {\n Write \"yes\"\n }\n Quit")
// Step 2: compile it
iris_compile(target="MyScript.mac")
// Step 3: run it
iris_execute(code="Do entry^MyScript")
Error code TERMINAL_SYNTAX_UNSUPPORTED is returned when block syntax is detected before
the docker exec round-trip, with an actionable message pointing to this pattern.
Invoke a ClassMethod directly by class, method name, and arguments.
| Parameter | Type | Default | Notes |
|---|---|---|---|
class |
string | — | Required. e.g. "%Library.Integer" |
method |
string | — | Required. e.g. "IsValid" |
args |
string[] | [] |
Positional string arguments |
namespace |
string | "USER" |
String-returning methods only (v1).
iris_execute_method(class="MyApp.Util", method="GetVersion")
iris_execute_method(class="%Library.Integer", method="IsValid", args=["42"])
Execute SQL and return rows as JSON.
| Parameter | Type | Default | Notes |
|---|---|---|---|
query |
string | "" |
SQL statement; required for read/explain/write |
parameters |
string[] | [] |
Bind parameters (positional ?) |
mode |
string | "read" |
"read" | "explain" | "count" | "write" |
table |
string | — | For mode=count without a query |
max_rows_affected |
int | 1000 |
Write mode only; clamped to [1, 10000] |
namespace |
string | "USER" |
|
force |
bool | false |
Bypass SQL safety validation |
# Read
iris_query(query="SELECT ID, Name FROM MyApp.Patient WHERE Status = ?", parameters=["Active"])
# Query plan
iris_query(query="SELECT * FROM MyApp.Patient", mode="explain")
# Row count without fetching data
iris_query(table="MyApp.Patient", mode="count")
# DML (gated)
iris_query(query="UPDATE MyApp.Patient SET Status = 'Archived' WHERE ID = ?",
parameters=["123"], mode="write")
server (optional): route this call to a named registered IRIS instance. If omitted,
uses the default connection. Use iris_servers to list available instances.
Run %UnitTest tests and return structured pass/fail results.
| Parameter | Type | Default | Notes |
|---|---|---|---|
pattern |
string | — | Required. Package name, e.g. "App.Tests" |
namespace |
string | "USER" |
|
timeout |
int | 60 |
Seconds |
coverage |
bool | — | Also measure line coverage inline |
coverage_classes |
string[] | — | Explicit class list for coverage; defaults to all classes in pattern |
coverage_target_pct |
float | — | Fail if coverage falls below this threshold |
iris_test(pattern="MyApp.Tests")
iris_test(pattern="MyApp.Tests", coverage=true, coverage_target_pct=80)
Standalone line coverage via %Monitor.System.LineByLine.
| Parameter | Type | Default | Notes |
|---|---|---|---|
mode |
string | — | Required. See modes below |
classes |
string[] | — | Classes to monitor; used with start/run |
package |
string | — | Package prefix — alternative to explicit classes |
test_path |
string | — | %UnitTest package to run; required for run |
target_pct |
float | — | Fail threshold % |
cobertura_path |
string | — | Write Cobertura XML here (requires TestCoverage IPM) |
namespace |
string | "USER" |
| Mode | What it does |
|---|---|
check |
Pre-flight: verify gmheap ≥ 256 MB; returns testcoverage_available |
run |
All-in-one: start → RunTest → stop → report |
start |
Start monitoring the given classes |
stop |
Stop monitoring |
report |
Collect results from a previously stopped run |
iris_coverage(mode="check")
iris_coverage(mode="run", package="MyApp", test_path="MyApp.Tests", target_pct=80)
iris_coverage(mode="run", classes=["MyApp.Service", "MyApp.Util"], test_path="MyApp.Tests")
Requires gmheap ≥ 256 MB. Run mode=check first. If BBSIZ_NOT_CONFIGURED is
returned, increase gmheap in Management Portal → System Administration →
Configuration → Additional Settings → Advanced Memory, then restart IRIS.
Read, write, kill, or list IRIS global nodes. Gated — see Data safety gates.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "get" | "set" | "kill" | "list" |
global_name |
string | — | Required. With or without leading ^ |
subscripts |
string[] | — | Subscript path; values validated [a-zA-Z0-9 _.:\-]+ |
value |
string | — | Required for action=set |
subtree |
bool | — | get only: include all descendants |
max_nodes |
int | 100 |
get + subtree; max 1000 |
max_subscripts |
int | 50 |
list action; max 500 |
acknowledgePhi |
bool | — | Required when global name matches a PHI pattern |
namespace |
string | — |
iris_global(action="get", global_name="^MyApp.Config", subscripts=["timeout"])
iris_global(action="list", global_name="^MyApp.Config")
iris_global(action="set", global_name="^MyApp.Config", subscripts=["timeout"], value="30")
Check lock status, checkout, or execute SCM actions.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "status" | "menu" | "checkout" | "execute" |
document |
string | — | Document name |
action_id |
string | — | For action=execute: the menu action ID |
elicitation_id |
string | — | Elicitation dialog resume ID |
answer |
string | — | Elicitation dialog answer |
namespace |
string | "USER" |
CheckIn is opt-in via IRIS_SCM_ALLOW_CHECKIN=1.
iris_source_control(action="status", document="MyApp.MyClass.cls")
iris_source_control(action="checkout", document="MyApp.MyClass.cls")
iris_source_control(action="menu") # list available actions
iris_execute rejects any code matching class- or routine-editing patterns. The check
runs before execution — a compound line mixing innocent data work with one blocked token
is rejected entirely; nothing executes.
Blocked patterns: %Dictionary.*Definition, $system.OBJ (Load, Compile, Delete, and
variants), %RoutineMgr, and direct writes to code-storage globals (^rOBJ, ^rINDEX,
^%occRoutine, etc.).
The error response includes a matched field naming the specific token and a
remediation field pointing to the correct tools:
- To write or delete a class/routine:
iris_docwithmode=putormode=delete. - To compile:
iris_compile.
The guard is non-configurable and applies to all connections. Error code:
CODE_EDIT_BLOCKED.
Search classes and methods via %Dictionary.
| Parameter | Type | Default | Notes |
|---|---|---|---|
query |
string | — | Required. Search term |
limit |
int | 20 |
|
namespace |
string | "USER" |
iris_symbols(query="IRISDemo.*")
iris_symbols(query="Patient", limit=50)
Search .cls/.mac/.inc files on disk by glob pattern. No IRIS connection required.
| Parameter | Type | Default | Notes |
|---|---|---|---|
query |
string | — | Required. Search string |
workspace_path |
string | — | Root path to search; defaults to current workspace |
limit |
int | 50 |
|
kinds |
string[] | — | Filter by symbol kind |
iris_symbols_local(query="Patient")
iris_symbols_local(query="GetStatus", workspace_path="/home/user/myapp")
Deep class inspection: methods, properties, parameters, XData blocks, superclasses.
Returns xdata_flow for BPL and DTL classes showing the step tree.
| Parameter | Type | Default | Notes |
|---|---|---|---|
class_name |
string | — | Required. |
namespace |
string | "USER" |
docs_introspect(class_name="MyApp.BP.PatientProcess")
docs_introspect(class_name="Ens.BusinessProcess")
Full-text search across the namespace. Supports regex and category filters.
| Parameter | Type | Default | Notes |
|---|---|---|---|
query |
string | — | Required. Search string |
documents |
string[] | — | Required. Scope, e.g. ["MyApp.*.cls"]; empty triggers SCOPE_REQUIRED |
regex |
bool | false |
|
case_sensitive |
bool | false |
|
category |
string | — | "CLS" | "MAC" | "INT" | "INC" | "ALL" |
namespace |
string | "USER" |
|
inline |
bool | false |
Bypass log store |
Namespace-wide grep times out — always provide a documents scope.
iris_search(query="GetPatient", documents=["MyApp.*.cls"])
iris_search(query="##class\(.*Patient", documents=["MyApp.*.cls"], regex=true)
Namespace discovery: documents, jobs, CSP apps, metadata.
| Parameter | Type | Default | Notes |
|---|---|---|---|
what |
string | — | Required. "documents" | "modified" | "namespace" | "metadata" | "jobs" | "csp_apps" | "csp_debug" | "sa_schema" |
doc_type |
string | — | "CLS" | "MAC" | "INT" | "INC" | "CSP" | "ALL" |
name |
string | — | For what=sa_schema |
namespace |
string | "USER" |
|
inline |
bool | false |
iris_info(what="namespace")
iris_info(what="documents", doc_type="CLS")
iris_info(what="jobs")
Inspect $$$ macros: list, signature, location, definition, expand.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "list" | "signature" | "location" | "definition" | "expand" |
name |
string | — | Macro name |
args |
string[] | [] |
Arguments for expand |
namespace |
string | "USER" |
iris_macro(action="list")
iris_macro(action="signature", name="ThrowOnError")
iris_macro(action="expand", name="ThrowOnError", args=["sc"])
Inspect a SQL table: storage type, backing globals, optional row count.
| Parameter | Type | Default | Notes |
|---|---|---|---|
table |
string | — | Required. "Schema.Table" format |
include_row_count |
bool | false |
|
namespace |
string | "USER" |
iris_table_info(table="MyApp.Patient")
iris_table_info(table="MyApp.Patient", include_row_count=true)
Resolve $classmethod/##class({var}) polymorphic dispatch to concrete candidate
classes, with confidence scores.
| Parameter | Type | Default | Notes |
|---|---|---|---|
method_name |
string | — | Required. |
package_prefix |
string | — | Restrict candidates to a package, e.g. "MyApp" |
limit |
int | 50 |
|
namespace |
string | "USER" |
resolve_dynamic_dispatch(method_name="ProcessRequest", package_prefix="MyApp")
Extract a compiled Ensemble MessageMap routing table from a BusinessProcess or Router.
| Parameter | Type | Default | Notes |
|---|---|---|---|
class_name |
string | — | Required. |
namespace |
string | "USER" |
extract_message_map_routing(class_name="MyApp.BP.PatientProcess")
Find all concrete subclass implementations of a method across the inheritance hierarchy.
| Parameter | Type | Default | Notes |
|---|---|---|---|
method_name |
string | — | Required. |
base_classes |
string[] | — | Required. Non-empty list |
limit |
int | 100 |
|
namespace |
string | "USER" |
find_subclass_implementations(method_name="OnProcessInput",
base_classes=["Ens.BusinessProcess"])
Map INT offsets to source lines, fetch error logs, capture error state.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "map_int" | "error_logs" | "capture" | "source_map" |
error_string |
string | — | For action=map_int, e.g. "^MyApp.Patient.1+42" |
class_name |
string | — | For action=source_map |
limit |
int | 20 |
|
namespace |
string | "USER" |
ObjectScript errors report INT line numbers. map_int resolves them to source
locations.
iris_debug(action="map_int", error_string="^MyApp.Patient.1+42^MyApp.Patient")
iris_debug(action="error_logs", limit=50)
iris_debug(action="capture")
Retrieve a full result when a tool returns truncated: true.
| Parameter | Type | Default | Notes |
|---|---|---|---|
id |
string | — | Log entry UUID; omit to list all stored entries |
limit |
int | — | Max entries; must be > 0 if provided |
offset |
int | 0 |
Start index into stored results |
iris_get_log(id="a1b2c3d4-...")
iris_get_log() # list all stored entries
Show active connection state. No parameters.
Returns host, port, namespace, discovery source, container name, config file path, and write tool status. Run this first if anything seems misconfigured.
Build a context-rich prompt for generating ObjectScript. Pulls relevant class definitions and coding conventions into a structured prompt. No API key required.
| Parameter | Type | Default | Notes |
|---|---|---|---|
description |
string | — | Required. What to generate |
gen_type |
string | "class" |
"class" | "test" |
class_name |
string | — | Source class for context |
namespace |
string | "USER" |
iris_generate(description="A REST API handler that validates patient demographics",
class_name="MyApp.Patient")
Generate and compile a class from a description. Requires an LLM API key in the connection config.
| Parameter | Type | Default | Notes |
|---|---|---|---|
description |
string | — | Required. |
overwrite |
bool | false |
Overwrite if class already exists |
namespace |
string | "USER" |
iris_generate_class(description="A %Persistent class storing patient visit records with indexes on PatientID and VisitDate")
Generate %UnitTest scaffolding for an existing class.
| Parameter | Type | Default | Notes |
|---|---|---|---|
class_name |
string | — | Required. |
namespace |
string | "USER" |
iris_generate_test(class_name="MyApp.Service")
Start, stop, update, check, or recover a production.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "status" | "start" | "stop" | "update" | "check" | "recover" | "get_autostart" | "set_autostart" |
production_name |
string | — | Production class name for start and stop; defaults to the currently running production |
production |
string | — | set_autostart only — the class name to autostart. No other action reads this key |
timeout |
int | 30 |
Seconds; stop only |
force |
bool | false |
stop only |
full |
bool | false |
status only: include per-item state |
enabled |
bool | — | set_autostart only |
namespace |
string | "USER" |
production_name and production are two distinct keys, and each action reads exactly
one of them. Passing production to start is silently ignored — the production name
comes out empty and the call starts nothing.
Actions that modify production state require IRIS_CONTAINER.
iris_production(action="status")
iris_production(action="stop", timeout=60, force=true)
iris_production(action="start", production_name="MyApp.Production")
iris_production(action="set_autostart", production="MyApp.Production", enabled=true)
Query production logs, queue depths, or message archive.
| Parameter | Type | Default | Notes |
|---|---|---|---|
what |
string | "logs" |
Enum: "logs" | "queues" | "messages" |
component |
string | — | logs: filter by business host name |
log_type |
string | "error,warning" |
logs only; comma-separated, see below |
limit |
int | 50 |
Applies to logs and messages |
source |
string | — | messages: filter by source |
target |
string | — | messages: filter by target |
message_class |
string | — | messages: filter by message class |
session_id |
int | string | — | messages: one session's messages; decimal string accepted |
since_id |
int | string | — | messages: tail after this header ID |
body_class |
string | — | messages: body class to join, e.g. Ens.StringContainer |
body_where |
string | — | messages: SQL predicate on the joined body table |
body_select |
array<string> | — | messages: body-table columns to add to each row |
search_table |
object | — | messages: indexed Search Table search — see below |
namespace |
string | "USER" |
|
server |
string | — | Named server; omit for default |
log_type takes any comma-separated subset of assert, error, warning, info, trace,
alert — the six values of Ens.Util.Log.Type, matched case-insensitively. A name that is not one
of those six contributes no filter, and the response reports it under unknown_log_types rather
than quietly widening the query to every severity.
search_table takes prop (required), one of value or value_like, and optional
class and extent (default EnsLib.HL7.SearchTable).
iris_interop_query(what="logs", log_type="error", limit=50)
iris_interop_query(what="queues")
iris_interop_query(what="messages", source="MyApp.BS.HL7Listener", limit=20)
Enable, disable, or get/set settings on an individual production config item.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "enable" | "disable" | "get_settings" | "set_settings" |
item |
string | — | Required. Production item name |
settings |
map<string,string> | {} |
For set_settings |
namespace |
string | "USER" |
|
server |
string | — | Named server; omit for default |
Works via Atelier HTTP — no Docker required.
iris_production_item(action="get_settings", item="MyApp.BO.LabResults")
iris_production_item(action="set_settings", item="MyApp.BO.LabResults",
settings={"ReplyCodeActions": "E=R,D=C,~=C"})
iris_production_item(action="disable", item="MyApp.BS.HL7Listener")
Diff the running production config against the last source-controlled version.
| Parameter | Type | Default | Notes |
|---|---|---|---|
production |
string | — | Defaults to currently running production |
namespace |
string | "USER" |
|
server |
string | — | Named server; omit for default |
iris_production_diff()
iris_production_diff(production="MyApp.Production")
Read a message body by ID. Gated — see Data safety gates.
| Parameter | Type | Default | Notes |
|---|---|---|---|
message_id |
string | — | Required. |
max_bytes |
int | 65536 |
Max 1 MB (1048576) |
acknowledgePhi |
bool | false |
Required when dataPolicy = "allow" |
dataPolicy |
string | block |
block | allow | redact |
namespace |
string | "USER" |
|
server |
string | — | Named server; omit for default |
The connection's dataPolicy is applied before the call's, so passing allow here
cannot widen what [policy.<server>] restricted.
iris_message_body(message_id="123456")
iris_message_body(message_id="123456", acknowledgePhi=true)
List or inspect Ensemble business rules.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "list" | "get" |
rule_name |
string | — | |
namespace |
string | "USER" |
|
server |
string | — | Named server; omit for default |
iris_business_rule_info(action="list")
iris_business_rule_info(action="get", rule_name="MyApp.RoutingRule")
List Ensemble credentials. Passwords are never returned.
| Parameter | Type | Default |
|---|---|---|
namespace |
string | "USER" |
No other parameters.
Create, update, or delete an Ensemble credential.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "create" | "update" | "delete" |
id |
string | — | Required. Credential ID |
username |
string | — | |
password |
string | — | |
namespace |
string | "USER" |
Read, write, delete, or list Ensemble lookup table entries. Write and delete actions are
🔒 ☠ gated. Read actions (get, list_keys, list_tables) are unrestricted.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "get" | "set" | "delete" | "list_keys" | "list_tables" |
table |
string | — | Table name |
key |
string | — | |
value |
string | — | For action=set |
namespace |
string | "USER" |
iris_lookup_manage(action="list_tables")
iris_lookup_manage(action="list_keys", table="FacilityMap")
iris_lookup_manage(action="get", table="FacilityMap", key="MGH")
Export or import an Ensemble lookup table as XML. Import is 🔒 gated.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "export" | "import" |
table |
string | — | Required. |
xml |
string | — | For action=import |
namespace |
string | "USER" |
Most tools in this section are ported from Pierre Abdelsayed's Server Manager MCP work.
The global confirmation pattern, namespace/database admin, observability tools, HL7
schema tools, Mermaid diagrams, and resolve_storage all originate from his design.
Preview the top N subscripts of an IRIS global and mint a confirmation token for a
subsequent global_kill. Returns up to 100 entries, the total subscript count, and a
confirm_token that expires in 5 minutes.
| Parameter | Type | Default | Notes |
|---|---|---|---|
global |
string | — | Required. Global name, with or without ^ |
count |
number | 20 |
Max entries to preview (1–100) |
server |
string | — | Named server; omit for default |
Kill an IRIS global after confirming with a token from global_preview. The token
validates the global name and server — a token issued for ^Foo cannot be used to kill
^Bar. Tokens expire after 5 minutes. Write-gated.
| Parameter | Type | Default | Notes |
|---|---|---|---|
global |
string | — | Required. Must match the global in the token |
confirm_token |
string | — | Required. Token from global_preview |
server |
string | — | Named server; omit for default |
List all namespaces on the connected IRIS instance.
| Parameter | Type | Default | Notes |
|---|---|---|---|
server |
string | — | Named server; omit for default |
Create a new namespace and its backing database. Write-gated and destructive-gated.
| Parameter | Type | Default | Notes |
|---|---|---|---|
name |
string | — | Required. Namespace name (A–Z, 0–9, -) |
db_path |
string | — | Database directory path; defaults to name |
server |
string | — | Named server; omit for default |
List databases, their directory paths, and free space. Each entry includes
size_mb, free_space_mb, free_pct, and max_size_mb (null when unlimited).
| Parameter | Type | Default | Notes |
|---|---|---|---|
server |
string | — | Named server; omit for default |
Report mirror membership and role for the connected IRIS instance. Non-mirror
instances return {is_member: false}. Useful as a pre-flight check before
operations that require a primary.
| Parameter | Type | Default | Notes |
|---|---|---|---|
server |
string | — | Named server; omit for default |
Response fields: is_member (bool), mirror_name (string or null),
member_type (string or null — primary/backup/async), is_primary (bool).
Manage IRIS SystemPerformance (pbuttons) profiles, start and poll runs, and locate the report a finished run wrote.
| Parameter | Type | Default | Notes |
|---|---|---|---|
mode |
string | — | Required. start / status / last_runid / list_profiles / add_profile / delete_profile / list_runs / report |
profile |
string | test |
mode=start: which profile to run. mode=add_profile / delete_profile: which profile to create or remove |
run_id |
string | — | Required for mode=status. Optional for mode=report — omit for the newest completed run |
description |
string | — | Required for mode=add_profile |
interval_seconds |
integer | — | Required for mode=add_profile. Seconds between samples; the shipped profiles use 1 to 60 |
sample_count |
integer | — | Required for mode=add_profile. interval_seconds × sample_count is the run length |
server |
string | — | Named server; omit for default |
Response fields: success (bool), mode (string).
mode=startreturnsprofileandrun_id. The run ID comes straight from$$run^SystemPerformance(profile).mode=last_runidreturnsrun_idandin_progress(bool). It reads^IRIS.SystemPerformance("run")before("history"), so a run that is still collecting is reported within_progress: true— a run gets no history node until it finishes.mode=statusreturnswait_time(string from$$waittime^SystemPerformance, e.g."7 minutes").mode=list_profilesreturnsprofilesandcount. Each profile hasname,interval_seconds,sample_count,duration_minutes, anddescription.mode=add_profilereturns the storedprofile,interval_seconds,sample_count, andduration_minutes. A duplicate name comes back assuccess: falsewith IRIS's ownprofile name exists already.mode=delete_profilereturns the deletedprofile. A deleted profile is oneadd_profileaway from being back, so this is a write, not a destructive operation.mode=list_runsreturnsruns(newest first, capped at 100) andcount. Each run hasrun_id,completed_at,output_dir, andprofile.mode=reportreturnsrun_id,completed_at,output_dir,report_path,size_bytes, andexists. A run still collecting has no report yet and comes back withexists: falseand anotesaying so.
Profile names accept letters, digits and underscore only. That is stricter than IRIS itself:
addprofile accepts "bad name", returns success, and stores the profile as badname — so the
name you asked for does not exist and nothing tells you. Names outside the safe set are rejected
before the call.
The completed report lands in the instance's mgr directory as
<host>_<instance>_<run_id>.html; mode=report resolves that path and falls back to scanning
the run's output directory if the host name has changed since. There is no cancel entry point —
a started profile runs to completion, so prefer test unless you need a longer window.
Show size, free space, and block stats for a specific database directory.
| Parameter | Type | Default | Notes |
|---|---|---|---|
db |
string | — | Required. Database directory path |
server |
string | — | Named server; omit for default |
Search the IRIS journal for global set/kill records in a time range. Bulk-PHI gated —
requires dataPolicy = "allow" on the connection.
| Parameter | Type | Default | Notes |
|---|---|---|---|
start |
string | — | ISO 8601 start timestamp (inclusive) |
end |
string | — | ISO 8601 end timestamp (inclusive) |
global_pattern |
string | — | Substring to filter global names |
max_entries |
number | 100 |
Cap results (1–500) |
server |
string | — | Named server; omit for default |
Query the %SYS.Audit table for recent events.
Both filters are equality comparisons (EventType = ?, Username = ?), not substring
matches — event_type="Login" will not find LoginFailure.
| Parameter | Type | Default | Notes |
|---|---|---|---|
event_type |
string | — | Exact match on the EventType column |
user |
string | — | Exact match on the Username column |
start |
string | — | Lower bound on UTCTimeStamp, inclusive; ISO 8601 |
end |
string | — | Upper bound on UTCTimeStamp, inclusive; ISO 8601 |
limit |
number | 100 |
Max rows; clamped to 1–500 |
server |
string | — | Named server; omit for default |
Inspect a %Stream.GlobalBinary or %Stream.GlobalCharacter object by OID.
Returns the whole stream and its size — there is no length cap, so a large stream
produces a large response.
| Parameter | Type | Default | Notes |
|---|---|---|---|
oid |
string | — | Required. Stream OID |
namespace |
string | "USER" |
Namespace that contains the stream |
server |
string | — | Named server; omit for default |
Show current user, roles, and privileges for the connected session.
| Parameter | Type | Default | Notes |
|---|---|---|---|
server |
string | — | Named server; omit for default |
Show the roles assigned to one user. Returns {user, full_name, roles} from
Security.Users — one user, not a namespace-by-privilege matrix.
| Parameter | Type | Default | Notes |
|---|---|---|---|
user |
string | $USERNAME |
Username to look up |
server |
string | — | Named server; omit for default |
List available HL7 2.x schema versions. Returns HL7_NOT_AVAILABLE if
EnsLib.HL7.Schema is absent. Requires HealthShare or IRIS for Health — not present on
plain IRIS regardless of edition.
| Parameter | Type | Default | Notes |
|---|---|---|---|
namespace |
string | — | Namespace to list from |
server |
string | — | Named server; omit for default |
Show segment definitions, field names, and data types for a specific HL7 schema version and optional segment filter.
| Parameter | Type | Default | Notes |
|---|---|---|---|
schema |
string | — | Required. e.g. "2.6" |
segment |
string | — | Segment name filter, e.g. "PID" (optional) |
namespace |
string | — | Namespace to read the schema from |
server |
string | — | Named server; omit for default |
Generate a Mermaid class diagram showing inheritance for one class. Walks the Super
hierarchy and strips %-prefixed system class names.
| Parameter | Type | Default | Notes |
|---|---|---|---|
class |
string | — | Required. Starting class |
depth |
number | 3 |
Levels of Super to walk |
namespace |
string | "USER" |
Namespace to query |
server |
string | — | Named server; omit for default |
Generate a Mermaid flowchart of an Ensemble/IRIS Interoperability production — hosts, connections, and enabled/disabled state.
| Parameter | Type | Default | Notes |
|---|---|---|---|
production |
string | — | Required. Production class name |
namespace |
string | "USER" |
Namespace that hosts the production |
server |
string | — | Named server; omit for default |
Show the storage definition (^oddDEF structure) for a persistent class. Helps diagnose
global layout, extents, and index locations.
| Parameter | Type | Default | Notes |
|---|---|---|---|
class |
string | — | Required. Class name |
namespace |
string | "USER" |
Namespace to query |
server |
string | — | Named server; omit for default |
Compare a single document (class, routine, or include file) between two IRIS servers.
Returns same: true/false and a unified diff when different.
| Parameter | Type | Default | Notes |
|---|---|---|---|
document |
string | — | Required. Document name, e.g. MyApp.cls |
server_a |
string | — | Required. First server name |
server_b |
string | — | Required. Second server name |
namespace |
string | "USER" |
Namespace on both servers |
Compare all classes in a namespace between two IRIS servers. Lists classes only in A,
only in B, and classes present in both that differ. Caps comparison at 200 classes to
avoid overload — unchecked_count reports how many were skipped.
| Parameter | Type | Default | Notes |
|---|---|---|---|
namespace |
string | "USER" |
Namespace to compare |
server_a |
string | — | Required. First server name |
server_b |
string | — | Required. Second server name |
Five read-only iris_admin actions give a real-time view into IRIS internals. All run
against %SYS directly — no external monitoring stack required.
view_locks — lists all active IRIS locks. Each row shows the lock name, lock type
(shared/exclusive), the owning process ID, and the caller's job ID. Useful for debugging
contention during long-running transactions or BPL routes that hold locks across
Await calls.
iris_admin(action="view_locks")
view_processes — shows running IRIS processes. Columns include process ID,
namespace, routine+label (i.e. where the process is executing), CPU time, and whether
the process is suspended. The namespace parameter narrows results to a single
namespace. Process user names are redacted in the response (PHI precaution) unless the
call passes dataPolicy = "allow"; the default is block, which refuses the call
outright.
iris_admin(action="view_processes", dataPolicy="redact")
iris_admin(action="view_processes", dataPolicy="redact", namespace="MYAPP")
namespace_mappings — returns the global, package, and routine mappings for a
namespace: which packages and globals resolve to which databases. Equivalent to the
Namespace Mappings page in Management Portal, useful when debugging <CLASS DOES NOT EXIST> errors that turn out to be mapping gaps.
iris_admin(action="namespace_mappings", namespace="MYAPP")
database_status — calls SYS.Database:FreeSpace and returns size, free space, and
journal state for every database. Pass name to narrow to a substring match on
the database path.
iris_admin(action="database_status")
iris_admin(action="database_status", name="MYAPP")
journal_search — scans the IRIS journal for global set/kill records in a time
window. Gated: requires dataPolicy = "allow" because journal records can contain PHI.
The global_pattern substring filter keeps results manageable; max_records caps at 1000.
iris_admin(action="journal_search",
global_pattern="^MyApp.Order",
time_range={"from": "2026-01-15T00:00:00Z",
"to": "2026-01-15T23:59:59Z"})
For standalone journal access there is also a journal_search tool (Administration
section below) that does not require iris_admin. It is not an alias — the two take
different parameter names for the same concepts, and passing one tool's names to the
other is rejected with UNKNOWN_PARAMETER:
| Concept | iris_admin(action="journal_search") |
standalone journal_search |
|---|---|---|
| Time window | time_range={"from": …, "to": …} |
start / end |
| Result cap | max_records (default 100, max 1000) |
max_entries (1–500) |
| PHI gate | connection dataPolicy |
connection dataPolicy |
| Global filter | global_pattern |
global_pattern |
global_pattern is the only name they share.
List namespaces, databases, users, roles, and web apps. Read actions have no gate.
Write actions require IRIS_WRITE_TOOLS_ENABLED=1.
Read actions (no env gate):
| Action | Parameters |
|---|---|
list_namespaces |
— |
list_databases |
— |
list_users |
— |
list_roles |
— |
list_webapps |
type (string, optional) |
get_webapp |
path (string, required) |
check_permission |
resource (string, required), permission (string, required) |
view_locks |
— |
view_processes |
namespace (string, optional) |
namespace_mappings |
namespace (string, optional) |
database_status |
name (string, optional) |
list_user_roles |
username (string, required) |
journal_search |
global_pattern (string), time_range ({from, to} ISO8601), max_records (int, default 100, max 1000) |
action is the only required parameter, and its 25 values are advertised as an enum, so a
client can complete them and a value outside the list comes back as INVALID_ACTION.
server routes the call to a named registered instance. Every other parameter is optional
at the schema level and required by the action that reads it, per the tables here.
The parameter set is closed: a filter typed as type_filter or name_filter is rejected
with UNKNOWN_PARAMETER naming what the tool does accept. It used to be dropped silently,
and the unfiltered result set came back looking like an answer.
view_processes and journal_search redact PHI according to dataPolicy in
[policy.<server>], which defaults to block. It used to be a call parameter, which meant
a caller could authorize its own bulk journal read by passing dataPolicy: "allow". That
key is no longer part of the schema, so passing it is now an UNKNOWN_PARAMETER error
rather than a no-op. journal_search needs dataPolicy = "allow" on the connection.
Write actions (require IRIS_WRITE_TOOLS_ENABLED=1):
| Action | Parameters |
|---|---|
create_user |
username, password (required); full_name, roles (optional) |
update_user |
username (required); password, enabled, roles (optional) |
delete_user |
username (required) |
create_namespace |
name, code_database, data_database (all required) |
delete_namespace |
name (required) |
create_webapp |
path, namespace, enabled (required); dispatch_class (optional) |
delete_webapp |
path (required) |
clear_password_change_flag |
username (default _SYSTEM), password (default SYS), new_password (optional, default same as password) |
unlock_user |
username (required) |
fresh_container_setup |
username (default _SYSTEM), password (default SYS), new_password (optional) |
mirror_add_async |
mirror_name, primary_host (required); primary_port (default 2188), instance_name (default IRIS), async_member_type (0=DR, 1=ReadOnly, 2=ReadWrite; default 0) |
Destructive actions (require IRIS_DESTRUCTIVE_TOOLS_ENABLED=1):
| Action | Parameters |
|---|---|
mirror_failover |
confirm (bool, required — must be true; prevents accidental promotion) |
Fresh container setup actions clear the first-boot blockers on a newly-started IRIS community container:
clear_password_change_flag— clears the forced-password-change flag on an account by calling%SYSTEM.Security.ChangePassword. Whennew_passwordis omitted, the same password is used for both old and new — clears the flag without changing the credential.unlock_user— resetsInvalidLoginAttemptsto 0 viaSecurity.Users.Modify, unblocking a locked account. Idempotent — safe to call on an account that is not locked.fresh_container_setup— runsclear_password_change_flagthenunlock_userin sequence. Returns{success, ready, steps[]}. Continues on per-step errors so callers see which steps succeeded. Call this once on a fresh container before any other iad tool.
Mirror management:
mirror_add_async— joins this IRIS instance to an existing mirror set as an async disaster-recovery member by callingSYS.Mirror.JoinMirrorAsAsyncMemberin%SYS. Performs a pre-flightIsMember()check; returnsALREADY_MEMBERif already in a mirror. Version mismatches between primary and candidate surface asMIRROR_VERSION_MISMATCH.mirror_failover— promotes this backup member to primary viaSYS.Mirror.BecomePrimary. Irreversible without manual recovery. Requiresconfirm: trueto prevent accidental promotion. Pre-flights: returnsNOT_MIRROR_MEMBERif not in a mirror,ALREADY_PRIMARYif this instance is already the primary.
iris_admin(action="list_namespaces")
iris_admin(action="list_users")
iris_admin(action="journal_search", global_pattern="^MyApp.*",
time_range={"from": "2025-01-01T00:00:00Z", "to": "2025-01-02T00:00:00Z"})
iris_admin(action="fresh_container_setup")
iris_admin(action="clear_password_change_flag", username="_SYSTEM", password="SYS")
iris_admin(action="unlock_user", username="_SYSTEM")
iris_admin(action="mirror_add_async", mirror_name="DR_SET", primary_host="10.0.1.5")
iris_admin(action="mirror_failover", confirm=true)
List, select, or start IRIS Docker containers.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "list" | "select" | "start" |
name |
string | "" |
Container name; required for select, optional for start |
Those two are the only parameters this tool reads. list scans
$OBJECTSCRIPT_WORKSPACE (falling back to the process working directory) — there is no
workspace_root override. select and start connect as _SYSTEM/SYS on the
community edition and take the namespace from the container, so passing namespace,
username, password, or edition has no effect.
iris_containers(action="list")
iris_containers(action="select", name="my-iris-container")
Persistent IRIS terminal sessions over WebSocket. Requires IRIS 2023.2+ (Atelier V7 API).
Each session keeps a live ObjectScript context between calls — variables set in one
iris_ws_exec call are visible in the next.
Session tokens have the form ws:{server}:{NAMESPACE}:{uuid}.
Open a new WebSocket terminal session. Returns a session token to pass to subsequent
calls.
| Parameter | Type | Default | Notes |
|---|---|---|---|
namespace |
string | "USER" |
Namespace for the session |
server |
string | — | Named server; omit for default |
Execute ObjectScript in an existing session. The session context (variables, open devices) persists across calls.
| Parameter | Type | Default | Notes |
|---|---|---|---|
session |
string | — | Required. Token from iris_ws_open |
code |
string | — | Required. ObjectScript to run |
The per-frame timeout is a fixed 30 seconds, not a parameter. On timeout the session
stays open; call iris_ws_close to release it.
Close a WebSocket session and free its resources. Passing an already-closed or expired
token returns already_closed: true rather than an error.
| Parameter | Type | Default | Notes |
|---|---|---|---|
session |
string | — | Required. Token from iris_ws_open |
Manage the learning agent skill registry.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "list" | "describe" | "search" | "forget" | "propose" |
name |
string | — | For describe/forget |
query |
string | — | For search |
action=forget is ☠ destructive-gated — requires destructive_tools_enabled = true.
skill(action="list")
skill(action="describe", name="objectscript-review")
skill(action="search", query="status handling")
skill(action="propose") # mine recent tool calls into a new skill
skill(action="forget", name="outdated-skill")
Browse or install community skills from subscribed GitHub repos.
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "list" | "install" |
package |
string | — | For action=install |
Index markdown/text into the IRIS knowledge base, or recall content by keyword.
kb (unified):
| Parameter | Type | Default | Notes |
|---|---|---|---|
action |
string | — | Required. "index" | "recall" |
path |
string | — | For action=index |
query |
string | — | For action=recall |
top_k |
int | 5 |
kb_index:
| Parameter | Type | Default |
|---|---|---|
workspace_path |
string | — |
kb_recall:
| Parameter | Type | Default | Notes |
|---|---|---|---|
query |
string | — | Required. |
top_k |
int | 20 |
kb(action="index", path="/home/user/myapp/docs")
kb(action="recall", query="how to handle %Status errors", top_k=5)
Recent tool-call history and learning agent status.
| Parameter | Type | Default |
|---|---|---|
limit |
int | 20 |
agent_history(limit=50)
agent_stats()
Query the durable telemetry record.
| Parameter | Type | Default | Notes |
|---|---|---|---|
tool_name |
string | — | Filter by tool |
session_id |
string | — | |
since |
string | — | ISO8601 |
until |
string | — | ISO8601 |
limit |
int | 500 |
telemetry_query(tool_name="iris_doc", since="2025-01-01T00:00:00Z")
Export tool calls as {from, to, via, count, ts} dispatch-trace records.
| Parameter | Type | Default | Notes |
|---|---|---|---|
session_id |
string | — | |
since |
string | — | ISO8601 |
See iris_coverage and iris_test above for the full
parameter reference.
Quick reference:
iris_coverage(mode="check")
iris_coverage(mode="run", package="MyApp", test_path="MyApp.Tests", target_pct=80)
iris_test(pattern="MyApp.Tests", coverage=true, coverage_target_pct=80)
Every response includes testcoverage_available. When the
TestCoverage IPM package is installed,
cobertura_path writes Cobertura XML output.
VS Code: The InterSystems Testing Manager
extension surfaces the same %UnitTest classes in the Test Explorer view. Use
iris_test to run and fix tests from Copilot or Claude; use Testing Manager to browse
results in the IDE. They share the same server connection.
Every tool in iad exposes MCP ToolAnnotations — machine-readable hints that MCP clients
can act on before calling the tool.
| Annotation | Set on | What it means |
|---|---|---|
read_only_hint |
53 tools — all query, inspect, list, history, and comparison tools | The tool makes no changes to IRIS state |
destructive_hint |
7 tools — global_kill, iris_admin, iris_credential_manage, iris_lookup_manage, iris_namespace_create, iris_remove_server, skill_forget |
The tool can irreversibly delete or overwrite data |
MCP clients that respect read_only_hint can run read-only tools in parallel or in
background without approval prompts. Clients that respect destructive_hint can surface
an extra confirmation step before calling the destructive tools.
These are hints, not enforcement. Enforcement comes from the config gates described below.
Two config keys control which tools can write. They form a stack — the destructive tier can only further restrict the write tier, never expand it.
Every write-capable tool returns WRITE_TOOLS_DISABLED when this is false. Set it in
.iris-agentic-dev.toml:
write_tools_enabled = trueEditing the file changes the gate on the next tool call, in both directions — no restart.
Environment variable: IRIS_WRITE_TOOLS_ENABLED=1. An operator who exported it before
starting iad outranks the file; the file wins over everything else. With neither declared,
IRIS SystemMode decides, then the namespace. check_config reports which of those decided
in write_tools_source, so an unexpected answer names its own cause.
The 7 tools marked ☠ require an additional opt-in. Even with write_tools_enabled = true,
they return DESTRUCTIVE_TOOLS_DISABLED unless you also set:
destructive_tools_enabled = trueDefault: false, and never inferred — the destructive tier stays off until you declare it.
Declaring destructive_tools_enabled = true with write_tools_enabled = false is a
contradiction, so iad logs DESTRUCTIVE_REQUIRES_WRITES and exits 2 rather than serving
requests with one of the two answers silently discarded.
Why a separate flag? A compile-test workflow needs write_tools_enabled = true, but
there's no reason for that same session to be able to kill globals or delete namespaces.
Enabling the two tiers independently means an agent that can compile can't accidentally wipe
data even if it constructs a destructive call.
Environment variable: IRIS_DESTRUCTIVE_TOOLS_ENABLED=1
There is no per-server write allowlist. Restricting writes to particular named servers is
designed in specs/074-write-server-allowlist/ and not implemented; until it ships, a write
allowed on this instance is allowed against every server in the pool. Use separate
workspaces with their own .iris-agentic-dev.toml if you need different answers per server.
1. write_tools_enabled — if false, WRITE_TOOLS_DISABLED
2. destructive_tools_enabled — if false and tool is ☠, DESTRUCTIVE_TOOLS_DISABLED
3. policy.<server>.allow — category gate (POLICY_GATE)
4. data safety gates — PHI, system globals, env template
5. Execute
Steps 1 and 2 run once, in call_tool, before the request reaches the tool — so a tool
cannot be added without passing through them. Read-only tools skip steps 1 and 2.
Gate design by Pierre Abdelsayed (InterSystems Server Manager MCP), ported to Rust.
PHI is Protected Health Information — the patient-identifying data HIPAA governs.
Some tools can reach PHI, and some can reach the globals IRIS uses to store its own code and configuration. Those calls are checked before they run and refused by default. Four checks run in order; the first one that refuses wins.
1. Environment template. A connection declares what kind of instance it points at via
mcpTemplate in .iris-agentic-dev.toml — dev (the default) permits everything,
test blocks code execution and compiles, and live blocks those plus source control.
Writes count as execution here: iris_global with action=set or kill, and
iris_query with mode=write, are treated as execution even though reads from the same
tools are not. Error code: ENV_GATE_BLOCKED.
2. Bulk-PHI tools. journal_search and iris_message_body return whole records, so
there is no field to inspect and no safe subset to return. They are refused outright
unless the connection sets dataPolicy = "allow", with no per-call override. Error code:
DATA_POLICY_BLOCKED.
3. System globals. IRIS keeps compiled classes, routines, roles, users, and
interoperability config in globals such as ^oddDEF, ^ROUTINE, ^%Dictionary*,
^ROLE, and ^Ens.Config*. Writing to them can leave the instance unable to compile or
start. This blocklist is hardcoded and cannot be switched off — globalBlocklist in your
config adds to it, never replaces it. The one exception is dataPolicyKillAllowlist,
which exempts named patterns from this check on kill operations only. Error code:
SYSTEM_BLOCKLIST.
4. Globals whose names suggest PHI. Reading ^PAPMI*, ^PAADM*, ^MRADM*,
^ORDER*, and similar requires acknowledgePhi: true on the call. This is a speed bump,
not a lock — it exists so nobody pulls a patient record into a chat transcript by
accident. Error code: PHI_GATE_BLOCKED.
iris_message_body is gated separately by dataPolicy alone: block refuses the call
(PHI_POLICY_BLOCKED), allow requires acknowledgePhi: true (PHI_ACK_REQUIRED), and
redact returns the body with the standard HL7 v2 patient fields replaced by [REDACTED]
(PID-3, 5, 7, 8, 11, 18 and MSH-3). Redaction only recognizes HL7 v2 — anything else
comes back as-is, so redact is not a safe default for XML or custom message bodies.
| Code | Meaning |
|---|---|
POLICY_GATE |
Call blocked by per-connection policy — see allow in .iris-agentic-dev.toml |
ENV_GATE_BLOCKED |
Tool not permitted by this connection's mcpTemplate — see gates |
DATA_POLICY_BLOCKED |
Bulk-PHI tool called without dataPolicy = "allow" |
SYSTEM_BLOCKLIST |
Global is on the system blocklist — not bypassable |
PHI_GATE_BLOCKED |
Global name matches a PHI pattern — pass acknowledgePhi: true |
SCOPE_REQUIRED |
iris_search called without a document scope — pass a documents wildcard list |
STALE_CONTENT |
iris_doc insert/delete_lines expected field didn't match stored content |
STORAGE_RESET_REQUIRES_CONFIRMATION |
iris_doc mode=put would reset an existing Storage block — pass allow_storage_regeneration: true to proceed |
CODE_EDIT_BLOCKED |
iris_execute call matched a code-editing pattern — use iris_doc + iris_compile |
CHECKIN_BLOCKED |
SCM CheckIn called without IRIS_SCM_ALLOW_CHECKIN=1 |
HTTP_EXECUTION_FAILED |
Atelier HTTP call failed — check host, port, credentials |
CONTAINER_UNREACHABLE |
docker exec never reached IRIS — the container is missing or stopped; the message names which |
IRIS_UNREACHABLE |
No IRIS connection discoverable — run check_config |
INTEROP_ERROR |
Ensemble/interop HTTP call failed — check production state and container access |
SESSION_WS_UNAVAILABLE |
The instance does not serve the WebSocket terminal endpoint — requires IRIS 2023.2+ |
SESSION_WS_DISCONNECTED |
Session token is invalid or already closed — call iris_ws_open to get a new token |
SESSION_STALE |
Session outlived its idle window and was reaped — open a new one |
SESSION_TIMEOUT |
IRIS sent no frame within 30 seconds — the statement is still running on the server |
CONFIRM_REQUIRED |
global_kill requires a confirm_token from global_preview |
CONFIRM_EXPIRED |
Confirmation token is older than 5 minutes — call global_preview again |
CONFIRM_MISMATCH |
Token was issued for a different global or server |
WRITE_TOOLS_DISABLED |
Write tool called without write_tools_enabled = true in .iris-agentic-dev.toml |
DESTRUCTIVE_TOOLS_DISABLED |
Destructive tool (☠) called without destructive_tools_enabled = true |
DESTRUCTIVE_REQUIRES_WRITES |
destructive_tools_enabled = true set while write_tools_enabled = false — invalid config |
FETCH_FAILED |
compare_document could not fetch source from one or both servers |
HL7_NOT_AVAILABLE |
EnsLib.HL7.Schema not installed on this instance |