Initial Release
A runnable example of how to give AI agents controlled access to InterSystems IRIS data through the Model Context Protocol (MCP). Built with AI Hub and ObjectScript, it includes tools for searching synthetic patient records, reading a selected global, and checking namespace health.
For implementation details, credentials, role configuration, and client examples, see the Developer Guide.
I created this project for the InterSystems Community Bounty Program “Idea to Application” — Round 2, in response to the MCP Data Exposure Toolkit idea (DPI-I-985).
The idea asked for examples of exposing IRIS data through MCP using AI Hub, with particular attention to sensitive data and access control.
I chose a healthcare example using synthetic patient records, alongside a few tools for inspecting the local IRIS namespace. That gave me a way to show both SQL and global access without including real patient data.
I obtained the IRIS Docker image through the instructions in the InterSystems AI Hub Early Access Program repository, which also provides the AI Hub documentation and samples used as a starting point.
An agent can discover the available tools and data sources, then use them through one MCP endpoint. It can filter patient records, read the ^ERRORS global, or request a short error summary. It cannot send its own SQL or choose another global or namespace.
The access rules live in IRIS: a dedicated user and role, limits on each tool, and shared authorization and audit policies. Docker Compose and client examples let you try the setup locally, then adapt the tools to your own data.
The examples cover SQL, globals, and operational data. There is no DocDB template yet.
The tools are methods in an ObjectScript class that extends %AI.Tool. A %AI.ToolSet groups them and attaches the authorization and audit policies; %AI.MCP.Service registers the service inside IRIS.
External clients connect through the EAP’s iris-mcp-server binary, which provides the Streamable HTTP transport and forwards requests to IRIS over port 1972. It runs in the separate mcp container so its startup and logs stay separate from the database. That container runs only the bridge, not a second IRIS instance.
MCP client
-> http://localhost:8280/mcp/health-example
-> iris-mcp-server in the mcp container (port 8080)
-> IRIS service iris:1972
-> MCPData.Service.HealthExample
-> MCPData.ToolSet.HealthExample
Sensitive access is controlled at several layers:
MCPDataReader role.SELECT only on MCPData_Data.Patient; database-resource access alone does not bypass IRIS SQL privileges.MCP_EXAMPLE namespace and cannot inspect the full IRIS instance.Audit records can be inspected in the IRIS Management Portal. This example queries MCPData_Data.Audit and shows a recorded ListResources call with its timestamp.

APP_USER and APP_PASS authenticate the MCP client. Setup creates this dedicated user (default mcp_reader) with the MCPDataReader role.WG_USER and WG_PASS authenticate the bridge’s internal connection to IRIS. This demo uses the privileged CSPSystem account. Never give these credentials to an MCP client or reuse them for the endpoint user.RecentApplicationErrors omits stack frames, variables, usernames, and object data from its response, but error text can still contain sensitive values. ReadGlobalData returns raw values within its allowed depth and is not a redaction layer. Review both outputs before adapting these examples to real logs or enterprise data.
This is a local development example built on pre-release software. The AI Hub EAP documentation states that the software is not intended for production. The demo uses HTTP Basic authentication over local HTTP and development credentials; do not expose it to an untrusted network. A deployment with real data would require a separate review of TLS, credentials, network exposure, data minimization, and privileges.
Compose also publishes the native IRIS port on host port 9291 for development. MCP clients do not need that port, and the bridge does not isolate it.
2026.3.0AI.136.0; make sure its base-image reference matches the image and architecture you downloaded..env file copied from .env.example. Review WG_USER, WG_PASS, APP_USER, and APP_PASS before starting; keep gateway and endpoint identities separate.VS Code users: Open this project folder and run the MCP - Docker: Build and Start task from Tasks: Run Task.
Command line users: Run from the project directory:
docker compose up -d --build --wait --wait-timeout 180 iris
docker compose exec iris iris session IRIS -U MCP_EXAMPLE '##class(MCPData.Setup).ConfigureUsers()'
docker compose up -d mcp
This sequence starts IRIS, configures the dedicated endpoint user and SQL grant from .env, and then starts the MCP bridge. Use a dedicated demo account for APP_USER: setup recreates that user if it already exists.
_SYSTEM, password SYS).The MCP URL is a protocol endpoint, not a browser user interface. Test it with VS Code or another MCP client using the configurations in https://github.com/pietrodileo/iris-mcp-data-exposure-toolkit/blob/main/dev.md.
After running the build task, verify the IRIS container is running and the user defined in the APP_USER variable of .env has the MCPDataReader role.
A correct connection discovers these five public MCP tool names:
mcp_health-example_ListResources
mcp_health-example_SearchPatients
mcp_health-example_ReadGlobalData
mcp_health-example_LargestGlobals
mcp_health-example_RecentApplicationErrors
Here is the same set of five tools discovered in Mistral Vibe:

An optional Python smoke test verifies authentication, checks that all five tools are discoverable, invokes every tool with small bounded inputs, and prints each structured response:
uv venv --python 3.12
source .venv/bin/activate
uv pip install -r requirements.txt
set -a
source .env
set +a
python test_mcp.py
The test checks the exact public names above and prints results from all five tools. It exits with status 1 when authentication, discovery, or invocation fails.
VS Code users can also run MCP - Docker: Cleanup Everything or MCP - Open: IRIS Management Portal from Tasks: Run Task. Cleanup removes the project’s containers, networks, volumes, and service images; treat it as destructive cleanup of the local demo.
ListResources: describes the approved data sources, read-only operations, and result limits.SearchPatients: searches imported patient records by diagnosis, diabetic status, smoker status, and age range. It accepts scalar filters only and returns at most 50 rows.ReadGlobalData: reads the ^ERRORS global with bounded depth and result count.LargestGlobals: top 1-20 globals visible in MCP_EXAMPLE, using native %SYS.GlobalQuery; system globals and mapped subscript ranges are excluded.RecentApplicationErrors: latest 1-20 MCP_EXAMPLE application errors from ^ERRORS; returns only ID, timestamp, and error text. Stack, variables, usernames, and object data stay hidden.Ask your agent to use this MCP server rather than local files or other data sources. These prompts show what it can do and where the limits apply. The server enforces those limits in code and permissions, not through prompt instructions.
| Capability | Example Prompt | Result |
|---|---|---|
| List available tools | “List all available resources and tools from the MCP server.” | MCP discovery exposes five tools; ListResources describes their data sources and limits |
| Query patient data | “Find diabetic patients aged 60 or older with a Diabetes diagnosis. Return at most 10 records. Use the tools exposed by the MCP server.” | Returns filtered patient results (max 50 rows) |
| Read error log | “Get the 10 most recent application errors from MCP_EXAMPLE. Use the tools exposed by the MCP server.” | Returns redacted errors (ID, timestamp, text only) |
| Read ^ERRORS global | “Read the ERRORS global at path ^ERRORS with depth 2 and limit 20. Use the MCP server tools.” | Returns bounded global traversal |
| Monitor namespace | “Show me the 5 largest globals in the MCP_EXAMPLE namespace. Use the MCP server.” | Returns top globals by size |
Examples from an agent session:
ListResources describes the available data sources and their limits.

SearchPatients returns synthetic patient records matching the requested diagnosis and age filters.

LargestGlobals reports estimated global sizes within MCP_EXAMPLE.

| Attempt | Example Prompt | Result |
|---|---|---|
| Arbitrary SQL | “Run SELECT * FROM MCPData_Data.Patient. Use the MCP server.” | Unsupported: No tool accepts SQL; patient access uses the fixed SearchPatients query |
| Non-allowlisted global | “Read the ^MCPData.Care global. Use the MCP server tools.” | Denied: Only ^ERRORS global is allowed |
| Cross-namespace access | “Show me the 5 largest globals in the USER namespace. Use the MCP server.” | Unsupported: Monitoring has no namespace selector and stays inside MCP_EXAMPLE |
| Unbounded results | “Find all patients without a limit. Use the MCP server.” | Bounded: The default limit applies when omitted; requested limits above 50 are clamped |
| Arbitrary table access | “List all tables in the database. Use the MCP server.” | Unsupported: No general schema-discovery tool is exposed |
An agent may explain that a request is unsupported or use a supported tool instead. Data-retrieval tools do not modify data; the audit policy writes execution metadata separately.
For an arbitrary SQL request, the agent explains that no SQL execution tool is available and points to SearchPatients instead.

Reading a non-allowlisted global produces an access-denied error. The same session also shows the agent explaining why monitoring cannot target the USER namespace.

The project imports all 500 records from https://github.com/pietrodileo/iris-mcp-data-exposure-toolkit/blob/main/data/synthetic_healthcare_data.csv during container installation. The source is Synthetic Healthcare Patient Records Dataset by dnation on Kaggle.
Each record contains a patient code, age, gender, BMI, blood pressure, cholesterol level, smoker and diabetic status, diagnosis, treatment cost, admission and discharge dates, and outcome. There are no real patient records or names.
MCPData.Data.Patient is the only patient class and patient table. Its importer separates blood pressure into systolic and diastolic columns and converts dates and yes/no fields to native IRIS types.
Start with the example closest to your data source:
SearchPatients with a fixed query, typed scalar filters, and only the output fields the agent needs.ReadGlobalData with an explicit allowlist and bounded traversal. Use a purpose-built response when raw values could disclose sensitive information.ListResources, tool descriptions, authorization rules, and IRIS grants so discovery and execution describe the same approved surface.See the Developer Guide for the class layout and configuration details. If you are using the surrounding AI Hub Studio workspace, the sibling ../my-first-agent project also includes a client configuration for this endpoint.