MCP Server
The Model Context Protocol (MCP) is a method for giving LLMs access to external systems and data. In the context of InterSystems IRIS, the MCP lets you expose tools and data in your InterSystems IRIS instance to your preferred models. Implementing this protocol is the iris-mcp-server binary, an MCP gateway that bridges LLM clients to InterSystems IRIS MCP server endpoints. These endpoints provide the tools to your agent.
The AI Hub is a new capability of InterSystems IRIS, and an Early Access Program is available to assist early adopters. After signing up to the EAP, you'll get advance notice of updates to the software and a channel to report feedback and issues directly to the product team.
Configuring an MCP Endpoint (Quick Start)
The following procedure shows how to set up an MCP endpoint with some simple tools in InterSystems IRIS and how to link it to iris-mcp-server. The iris-mcp-server exposes this endpoint to your MCP client so that it can use your tools. The example uses Claude Desktop, but any LLM client that implements the MCP will work:
-
Create a %AI.Tool or %AI.ToolSet:
Class Sample.GetTime Extends %AI.Tool { Property Name As %String [ InitialExpression = "GetTime" ]; Property Description As %String(MAXLEN = "") [ InitialExpression = "Gets the current system time." ]; /// Get the current server time. ClassMethod GetTime() As %String { Return $ZTIME($PIECE($HOROLOG,",",2),1) } } -
Create an MCP service class, specifying the name of your tool:
Class MyApp.MCP.MyService Extends %AI.MCP.Service { Comma-delimited list of %AI.Tools or %AI.ToolSets Parameter SPECIFICATION As STRING = "Sample.GetTime"; } -
Add an MCP server to your InterSystems IRIS and specify your service class:
-
In the Management Portal, go to System Administration > Security > Applications > MCP Servers.
-
Select Create New MCP server, specifying the following:
-
Name — /mcp/myservice
-
Namespace — USER
-
Dispatch Class — MyApp.MCP.MyService
-
Enable Service — Select this option.
-
Allowed Authentication Methods — For demonstration purposes, you can select Unauthenticated. Do not use this setting in for a real endpoint in a production environment (unless you use the stdio transport mode).
For details on authenticating MCP endpoints in production, see MCP Server Endpoint Authentication.
-
-
-
Configure iris-mcp-server to point to your InterSystems IRIS instance and its MCP server. The example below contains the contents of config.toml, a configuration file that specifies the InterSystems IRIS instance with server and the MCP server with endpoints:
[mcp] transport = "stdio" [[iris]] name = "local" server = { host = "localhost", port = 1972, username = "CSPSystem", password = "SYS" } pool = { min = 2, max = 5 } endpoints = [ { path = "/mcp/myservice" }, ] [logging] level = "info" output = "file" file = "iris-mcp.log" -
Configure your MCP client to point to the iris-mcp-server binary. This example uses Claude Desktop, so it adds the entry to mcpServers in claude_desktop_config.json:
"mcpServers": { "iris": { "command": "C:\\InterSystems\\IRIS\\bin\\iris-mcp-server.exe", "args": [ "--config=C:\\InterSystems\\IRIS\\bin\\config.toml", "run" ] } }, -
Restart your MCP client and try to ask it a question that requires the use of one of the tools that you defined. Your MCP client might prompt you to allow the use of the tool before answering your question.
In this example, Claude Desktop uses the GetTime method to get the time on the current instance:
What's the current server time? The current InterSystems IRIS instance time is 1:35:56 PM.
Configuring iris-mcp-server
The behavior and features of iris-mcp-server are determined by a combination of CLI flags, a config.toml, and its default settings. When the same value is specified in multiple locations, the setting with the highest priority applies:
-
CLI flag (highest)
-
config.toml
-
Default settings (lowest)
Credential Fields
The iris-mcp-server configuration file accepts several formats for credential fields:
-
Literal — A string, such as "CSPSystem".
-
Environment variable — A string in the form "@{env:CRED}", where CRED is an environment variable.
-
Vault KV2 — A string in the form "@{vault:path/#field}", where path/ is the path relative to the vault_mountOpens in a new tab and field is the Vault field.
This option is only available for HashiCorp Vault users and requires you to enable the vault feature in your configuration file. For details, see HashiCorp Vault Integration.
As a best practice, you should prefer using either environment variables or references to HashiCorp Vault credentials over using literals.
Configuration File Reference
# ── MCP Transport ─────────────────────────────────────────────────────────────
[mcp]
transport = "stdio" # stdio | http | https
host = "127.0.0.1" # bind address for HTTP/HTTPS transports (default: 127.0.0.1)
# IPv6 literals are also accepted, e.g. "::1" or "::".
port = 8080 # bind port
base_route = "/mcp" # HTTP route prefix (default: /mcp)
# Allowed Host header values for inbound HTTP/HTTPS requests (optional).
# Localhost variants are always permitted. Default behaviour:
# loopback bind (127.0.0.1): only localhost variants accepted.
# public bind (0.0.0.0): all Host values accepted (a warning is logged).
# Set to enforce a strict allowlist on a public server:
# allowed_hosts = ["mcp.example.com", "mcp.example.com:8080"]
# An IPv6 entry must be bracketed, e.g. "[2001:db8::1]:8443".
# Peer IP allow/deny lists, in CIDR notation (optional, IPv4 and IPv6 may be
# mixed freely). Enforced at TCP-accept time, before any HTTP/TLS handshake.
# Empty allowed_networks (the default) means all peers are allowed, subject
# to denied_networks; denied_networks always takes precedence.
# allowed_networks = ["10.0.0.0/8", "2001:db8::/32"]
# denied_networks = ["10.0.5.0/24"]
# Require a bearer token from remote (non-loopback) callers before falling
# back to a configured endpoint credential (default: false, i.e. required).
# Only set to true if you specifically want an anonymous remote caller to
# execute tools as the operator-configured [iris.user_auth] identity -- see
# "Remote MCP — OAuth Passthrough" below.
# allow_anonymous = false
# Maximum concurrently accepted TCP connections on this listener (HTTP/HTTPS
# only; default: 1024). Bounds file-descriptor/memory exhaustion from a
# connection flood (including Slowloris-style attacks).
# max_connections = 1024
# Maximum number of tools/call and initialize-triggered discovery requests
# this listener processes concurrently across all sessions (default: 128).
# Additional requests are rejected immediately rather than queuing, so a
# burst of concurrent requests can't drive unbounded load onto IRIS.
# max_concurrent_requests = 128
# TLS for the MCP HTTP transport (required when transport = "https")
# [mcp.tls]
# cert = "/etc/certs/server.crt" # path to PEM certificate
# key = "/etc/certs/server.key" # path to PEM private key
# Secret references are also accepted:
# cert = "@{vault:tls/iris-mcp#certificate}"
# key = "@{vault:tls/iris-mcp#private_key}"
# ── IRIS Servers ──────────────────────────────────────────────────────────────
# Use [[iris]] (double brackets) — one entry per IRIS instance.
# Multiple instances can be declared in the same file.
[[iris]]
name = "production"
# Super-server connection credentials.
# Credential fields accept a literal value, @{env:VAR}, or @{vault:path#field}.
server = { host = "iris.example.com", port = 52773, username = "@{env:WG_USER}", password = "@{env:WG_PASS}" }
# WebSocket session pool for this instance.
pool = { min = 2, max = 10 }
# MCP endpoint paths on this InterSystems IRIS instance.
# Each entry is a CSP web application path, with optional application-layer auth.
# Auth options per endpoint:
# username + password -> HTTP Basic (Authorization: Basic ...)
# bearer -> Bearer token (Authorization: Bearer ...)
# (no auth fields) -> unauthenticated endpoint
endpoints = [
{ path = "/mcp/myapp" },
{ path = "/mcp/secure", username = "@{env:APP_USER}", password = "@{env:APP_PASS}" },
{ path = "/mcp/api", bearer = "@{vault:iris/prod#api_token}" },
]
# How often to retry a lost connection (default: "30s"). Accepts "30s", "1m", "500ms" etc.
reconnect_interval = "30s"
# How often to re-fetch the tool list (default: "5m").
tool_refresh_interval = "5m"
# Maximum bytes to accumulate from InterSystems IRIS for a single tool response (default: 10 MiB).
# Increase for tools that return very large payloads; decrease if your LLM has a
# small context window and is being overwhelmed by large results.
max_response_bytes = 10485760
# Maximum time to wait for a WebSocket session to open (default: "30s").
connect_timeout = "30s"
# Maximum time to wait for a tool call to complete once the connection is
# established -- covers both the REST tool-call round trip and the WebSocket
# response wait (default: "60s"). A hung/silent backend fails and releases
# the pooled connection instead of holding it indefinitely.
request_timeout = "60s"
# How long a pooled WebSocket session may sit idle before it is closed (default: "5m").
# Closing an idle session causes the InterSystems IRIS job to Halt, freeing its license slot.
# Lower values free licenses faster; higher values reduce reconnection overhead.
idle_timeout = "5m"
# Maximum number of concurrent pooled sessions per (endpoint, auth_context) pair.
# Each OAuth user or opaque token gets its own pool up to this limit.
# Prevents runaway license consumption when many distinct identities are active.
# Default: same as pool.max.
max_sessions_per_auth_context = 10
# Hard cap on total session lifetime, regardless of activity.
# When set, a session older than this is dropped the next time it becomes idle
# (InterSystems IRIS job Halts, license freed). Off by default — only idle_timeout applies.
# Useful in high-churn environments to guarantee periodic license recycling.
# max_age = "1h"
# TLS for the connection to this instance (optional).
# Presence of the tls field enables TLS; absence means plaintext.
# tls = {} # system CA roots
# tls = { ca_cert = "/etc/certs/iris-ca.crt" } # custom CA
# tls = { ca_cert = "/etc/certs/iris-ca.crt", # mutual TLS
# cert = "/etc/certs/client.crt",
# key = "/etc/certs/client.key" }
# ── OAuth 2.1 Authorization Server Proxy ─────────────────────────────────────
# Optional. When present, iris-mcp-server serves:
# GET /.well-known/oauth-authorization-server (RFC 8414 — AS metadata discovery)
# GET /.well-known/oauth-protected-resource (RFC 9728 — resource metadata, MCP 2025-11-25)
# and proxies OAuth flows (authorize, token, JWKS, register) to InterSystems IRIS.
# [oauth]
# iris = "production" # [[iris]] section that is the AS
# host = "https://mcp.example.com" # public base URL (optional)
# well_known_path = "/.well-known/oauth-authorization-server" # override if non-standard
# allowed_paths = ["/csp/sys/auth"] # extra paths to proxy (e.g. login pages)
# metadata_cache_ttl = "5m" # how long to cache AS metadata
# ── Secret Provider ──────────────────────────────────────────────────────────
[secrets]
provider = "env" # env | vault (default: env)
# Required only when provider = "vault":
# vault_addr = "http://127.0.0.1:8200"
# vault_token = "s.xxxx" # literal token
# vault_token_file = "/var/run/vault/token" # or path to token file
# vault_mount = "secret" # KV v2 mount (default: secret)
# ── Logging ──────────────────────────────────────────────────────────────────
[logging]
level = "info" # error | warn | info | debug
output = "stderr" # stderr | file
# file = "/var/log/iris-mcp.log" # required when output = "file"
# ── Optional Feature Toggles ─────────────────────────────────────────────────
[features]
smart_discovery = false # enable RAG tool search (requires smart-discovery feature)
telemetry = false # enable OpenTelemetry tracing
vault = false # enable Vault secret provider
monitor_ipc = true # run the IPC metrics server `iris-mcp-server monitor` connects to
# (default: true); override per-invocation with --monitor-ipc/--no-monitor-ipc
CLI Flags
The following is a list of supported CLI flags and their respective effects.
| Flag | Description and Example |
| --log-level level | Where level is the minimum severity level of event to log, one of the following:
|
| --log-output out | Where out is the location where logs are written, one of the following:
|
| --log-file path | The location to output the log file, where path is a file path. This option is required if you set --log-output file. |
| --config path | Where path is the path to a TOML configuration file. |
| --transport mode | The method with which iris-mcp-server communicates with InterSystems IRIS, where mode is one of the following:
|
| --http-tls-cert path | A TLS certificate in PEM format, where path is a path to the file. This option is required if you use --transport https. |
| --http-tls-key path | A TLS key in PEM format, where path is a path to the file. This option is required if you use --transport https. |
| --http-base-route path | The HTTP route prefix, where path is the prefix (default: /mcp). |
| --help | Prints command information. |
| --version | Prints version information. |
The following are the CLI flags for the run subcommand:
| Flag | Description and Example |
| --status-tool boolean | Whether to expose the iris_status diagnostic tool (default: true). |
| --iris-host host | The host for the InterSystems IRIS instance, where host is a hostname or IP address. |
| --iris-port port | The port for the InterSystems IRIS instance, where port is the superserver port. |
| --iris-endpoint path for each endpoint | Where path is the name of an MCP server endpoint configured in InterSystems IRIS. To specify more than one endpoint, use the --iris-endpoint flag for each one. For example: --iris-endpoint /mcp/myservice --iris-endpoint /mcp/myotherservice |
| --monitor-ipc boolean | Whether to enable the IPC metrics server used by iris-mcp-server monitor (default: true). |
| --help | Prints command information. |
The following are the CLI flags for the monitor subcommand (see Monitoring and Telemetry for details):
| Flag | Description and Example |
| --pid pid | The process to monitor, where pid is the process ID. |
| --socket path | The IPC socket to connect to, where path is the IPC path. |
Transport Modes
The transport mode is the protocol the iris-mcp-server uses to communicate with an MCP client.
This transport mode is incompatible with the stderr logging output location.
All of the following examples set up a configuration file with the relevant settings. After setting up this configuration file, you can start the iris-mcp-server with:
iris-mcp-server --config config.toml run
stdio
The stdio transport mode communicates with a local MCP client through standard I/O.
The following example configures iris-mcp-server to use stdio. It also includes a section for logging directly to a file because the default logging output mode, stderr, is not compatible with stdio:
[mcp]
transport = "stdio"
[logging]
output = "file"
file = "C:\\logs\\iris-mcp.log"
http
The http transport mode communicates with a remote MCP client through HTTP. This is an unencrypted connection, so you should only use it if your network is secured in some other way.
The following example configures iris-mcp-server to use http:
[mcp]
transport = "http"
host = "127.0.0.1"
port = 8080
https
The https transport mode communicates with a remote MCP client through HTTPS, such as ChatGPT. This transport mode encrypts the connection with TLS, so you need to provide a server TLS certificate and key in PEM format:
The following example configures iris-mcp-server to use https:
[mcp]
transport = "https"
host = "127.0.0.1"
port = 8443
[mcp.tls]
cert = "/etc/certs/server.crt"
key = "/etc/certs/server.key"
Alternatively, if you use HashiCorp Vault and have enabled vault integration, then you specify the cert and key from your Vault:
[mcp.tls]
cert = "@{vault:tls/iris-mcp#certificate}"
key = "@{vault:tls/iris-mcp#private_key}"
Allowed Hosts and Networks
When using http or https transport and binding to 0.0.0.0, you can configure iris-mcp-server to validate the Host header on incoming requests to prevent DNS rebinding attacks.
To validate incoming requests, you can provide a list of allowed hosts in mcp.allowed_hosts:
[mcp]
transport = "http"
host = "0.0.0.0"
port = 8080
allowed_hosts = ["mcp.example.com", "mcp.example.com:8080", "[2001:db8::1]:8443"]
This can be useful in cases where for example, your InterSystems IRIS instance and iris-mcp-server are in a container in AWS and are behind a load balancer hosted on mcp.example.com. MCP clients would therefore send requests to mcp.example.com, which would then forward those requests to iris-mcp-server. If you set allowed_hosts, it will validate that the requests are coming from the hosts you expect (the load balancer, mcp.example.com, in this case).
You can also specifically allow or deny particular networks by IP address. If the same IP address is specified in both lists, it is denied:
# Peer IP allow/deny lists, in CIDR notation (optional, IPv4 and IPv6 may be
# mixed freely). Enforced at TCP-accept time, before any HTTP/TLS handshake.
# Empty allowed_networks (the default) means all peers are allowed, subject
# to denied_networks; denied_networks always takes precedence.
# allowed_networks = ["10.0.0.0/8", "2001:db8::/32"]
# denied_networks = ["10.0.5.0/24"]
Connection Pools
Each InterSystems IRIS instance has its own WebSocket session pool, the size of which is determined by pool = { min, max }, where:
-
min — The number of connections that should be kept in the pool when idle.
-
max — The maximum number of connections in the pool. As a general rule, this value should be at least as large as the number of simultaneous tool calls you expect to have.
Each pool slot is one WebSocket connection to InterSystems IRIS (one concurrent, in-flight tool call per slot).
The following example shows how to use the pool field:
[[iris]]
name = "production"
server = { host = "iris.example.com", port = 1972, username = "CSPSystem", password = "SYS" }
pool = { min = 5, max = 20 } # up to 20 concurrent tool calls
endpoints = [{ path = "/mcp/prod" }]
Session Lifetime
Each pooled session corresponds to one InterSystems IRIS license slot (job). Three settings control how long sessions live:
-
idle_timeout — (Default: "5m") How long, a session can be idle before it is closed, which halts the InterSystems IRIS job and frees its license. This parameter is a string and accepts values with units such as "70ms" (70 milliseconds), "1m" (one minute), "2h" (two hours), and so on.
For OAuth sessions, InterSystems IRIS validates a Bearer token once when the WebSocket session is opened. It does not re-validate the token while the session is running; a session stays alive even after the token expires. idle_timeout is therefore the primary mechanism for cleaning up stale-token sessions; you should set idle_timeout to a value less than or equal to your OAuth token lifetime so that expired sessions are recycled before the next token rotation.
-
max_sessions_per_auth_context — (Default: pool.max) The maximum number of sessions per token identity (OAuth or otherwise).
-
max_age — (Default: None; only idle_timeout applies) The maximum length of a session. If a session's length exceeds this, it is closed the next time it's idle. This parameter is a string and accepts values with units such as "70ms" (70 miliseconds), "1m" (one minute), "2h" (two hours), and so on.
In deployments with many OAuth users (each user gets their own session pool), lower idle_timeout and set max_sessions_per_auth_context to prevent license exhaustion:
[[iris]]
name = "production"
server = { host = "iris.example.com", port = 1972, username = "CSPSystem", password = "SYS" }
pool = { min = 2, max = 10 }
idle_timeout = "5m" # free licenses after 5 minutes idle
max_sessions_per_auth_context = 3 # each user may have at most 3 concurrent sessions
max_age = "1h" # recycle sessions after 1 hour regardless of activity
endpoints = [{ path = "/mcp/prod" }]
In deployments with multiple InterSystems IRIS instances, each instance gets its own pool:
[[iris]]
name = "primary"
server = { host = "iris1.example.com", port = 1972, username = "CSPSystem", password = "SYS" }
pool = { min = 5, max = 20 }
endpoints = [{ path = "/mcp/prod" }]
[[iris]]
name = "analytics"
server = { host = "iris2.example.com", port = 1972, username = "CSPSystem", password = "SYS" }
pool = { min = 2, max = 10 }
endpoints = [{ path = "/mcp/analytics" }]
Authentication
A connection between iris-mcp-server and InterSystems IRIS consists of two different authentication layers. For the purposes of the iris-mcp-server, you must authenticate to both layers:
-
Layer 1 — Authentication to the InterSystems IRIS superserver
-
Layer 2 — User authentication to an MCP server endpoint.
Superserver Authentication (Layer 1)
To authenticate to InterSystems IRIS with the iris-mcp-server, provide the credentials of a privileged gateway user (such as CSPSystemOpens in a new tab) in the server inline table:
server = { host = "iris.example.com", port = 1972, username = "CSPSystem", password = "SYS" }
User Authentication to an MCP Server Endpoint (Layer 2)
To authenticate to an MCP server endpoint with the iris-mcp-server, provide the credentials in the endpoints array, where each entry consists of an inline table of a path and credentials. The following example shows how to provide credentials depending on their Allowed Authentication Methods:
endpoints = [
# Unauthenticated (should only be used with stdio, if at all) or OAuth2.
# For OAuth2, the credentials are provided to your authorization server and the token is used to validate
# to the resource server (the resource being the MCP server endpoint); it is not stored in the configuration file.
{ path = "/mcp/myservice" },
# Password or LDAP
{ path = "/mcp/myotherservice", username = "myUser", password = "myPassword" },
]
OAuth Integration
You can configure InterSystems IRIS to be your OAuth resource server and have it protect MCP server endpoint through a resource mapping.
If you want to use InterSystems IRIS as a resource server (where the MCP server endpoint is the protected resource):
-
In System Administration > Security > System Security > Authentication/Web Session Options, verify that Allow OAuth2 authentication is selected.
-
In System Administration > Security > Applications > MCP Servers, select your MCP server endpoint.
-
In Allowed Authentication Methods, select OAuth2.
-
Configure InterSystems IRIS as an OAuth resource serverOpens in a new tab.
-
Verify that the resource server is responsible for the MCP Server endpoint. This is specified in the resource mapping (System Administration > Security > OAuth 2.0 > Resource Server > Mappings) and its associated Key, which should either contain the name of the name of your MCP server endpoint (for example, /mcp/myservice) or a * (asterisk) which matches all web application and MCP server endpoint names.
OAuth Passthrough (Remote MCP)
When iris-mcp-server uses an HTTP-based transfer mode (that is, http or https), each MCP client session contains an Authorization header (commonly an OAuth 2.0 Bearer token). iris-mcp-server forwards this header value, unchanged, to the InterSystems IRIS MCP endpoint in every request within that session. This is called OAuth Passthrough. Any valid scheme works without server-side changes.
OAuth Passthrough is always active for the HTTP-based transfer modes; the credentials provided for each endpoint acts as a fallback only when no Authorization header arrives from the MCP client.
For InterSystems IRIS to validate incoming Bearer tokens automatically, OAuth authentication must be enabled on the MCP server endpoint. When enabled, InterSystems IRIS validates the token when the WebSocket session is opened; by the time a tool call runs, the MCP client would have already authenticated to the endpoint using their token.
For JWT tokens, expired Bearer tokens (indicated by its exp claim) are rejected by iris-mcp-server before they reach InterSystems IRIS; this optimization is not available for opaque tokens.
iris-mcp-server as an OAuth Proxy
If you use InterSystems IRIS as your OAuth resource server, you can configure iris-mcp-server to act as its proxy for all OAuth flows sent to InterSystems IRIS. It does this by providing its own OpenID Connect Discovery endpoint, rewriting the endpoints to point to iris-mcp-server instead of your InterSystems IRIS instance, keeping the InterSystems IRIS instance hidden.
With iris-mcp-server as a proxy for your resource server, the authentication process is as follows:
-
The MCP client sends a request to the OpenID Connect Discovery endpoint (RFC 8414Opens in a new tab) exposed by the iris-mcp-server (GET /.well-known/oauth-authorization-server).
-
iris-mcp-server retrieves the authorization server metadata from InterSystems IRIS, rewrites all endpoint URLs to point to iris-mcp-server (replacing the InterSystems IRIS host), and returns this rewritten version to the MCP client.
-
The client uses the discovered endpoints to obtain a token. All requests go to the iris-mcp-server proxy, which sends them to InterSystems IRIS.
-
The client uses the resulting Bearer token for MCP calls: iris-mcp-server forwards the token to InterSystems IRIS using OAuth Passthrough.
To enable this behavior:
-
Configure InterSystems IRIS as a resource serverOpens in a new tab.
-
Add an [oauth] section to your configuration file. In the example below, production refers to the name of the InterSystems IRIS instance specified in the [[iris]] section of the configuration file (iris[0].name); this instance acts as the authorization server for all MCP endpoints:
[oauth] iris = "production" # name of the [[iris]] section whose InterSystems IRIS instance is the authorization server # Optional: public base URL for URL rewriting in the AS metadata response. # If omitted, derived from the incoming Host header. # Set explicitly when running behind a reverse proxy that does not forward Host accurately. host = "https://mcp.example.com" # Optional: path to fetch AS metadata from InterSystems IRIS. # Defaults to /.well-known/oauth-authorization-server (RFC 8414 standard). # Override when the AS metadata is served at a non-standard path. # well_known_path = "/custom/as-metadata" # Optional: additional URL prefixes to allow through the proxy beyond those # listed in the AS metadata. Use for IRIS login pages served outside the # standard OAuth prefix when supporting the Authorization Code flow interactively. # allowed_paths = ["/csp/sys/auth"]
InterSystems IRIS must be configured with its public issuer URL (the value of host, which is the URL that MCP clients use to reach the iris-mcp-server) so that the issuer field in the authorization server metadata matches the iss claim in issued tokens; while iris-mcp-server is capable of rewriting endpoint URLs, it cannot rewrite iss claims. A mismatch in the issuer and the iss claim will cause clients that validate the iss to reject otherwise valid tokens.
HashiCorp Vault Integration
You can integrate iris-mcp-server with HashiCorp Vault by enabling the vault feature and pointing iris-mcp-server to your Vault.
All secret references are resolved once at startup before any connections are established. If any secret fails to resolve, the iris-mcp-server exits with an error.
The following example configures iris-mcp-server to use secrets from a local Vault and shows how to reference secrets in various credential fields:
-
Add information about your Vault to the secrets section of your configuration file:
[secrets] provider = "vault" vault_addr = "http://127.0.0.1:8200" vault_token = "@{env:VAULT_TOKEN}" # token as env var reference # vault_token_file = "/var/run/vault/token" # or path to a token file vault_mount = "secret" # KV v2 mount name (default: "secret") [features] vault = trueNote:For Kubernetes, use vault_token_file with a projected service account tokenOpens in a new tab volume rather than storing a static token in a secret. To do this, mount the projected token at a path like /var/run/secrets/vault/token and set vault_token_file to that path. This token is automatically rotated by Kubernetes and reread by iris-mcp-server on the next startup.
-
Reference your secrets in credential fields using the format @{vault:path#field}, where the path is relative to vault_mount.
For example, with vault_mount = secret, the reference @{vault:iris/gateway#password} reads the field password from the Vault KV2 secret at secret/data/iris/gateway:
[[iris]] name = "production" server = { host = "iris.example.com", port = 52773, username = "@{vault:iris/gateway#username}", password = "@{vault:iris/gateway#password}" } pool = { min = 10, max = 50 } endpoints = [ { path = "/mcp/prod", bearer = "@{vault:iris/prod#app_token}" }, ] -
Set up the Vault secrets:
# Enable KV v2 secrets engine (if not already enabled) vault secrets enable -path=secret kv-v2 # Store InterSystems IRIS gateway credentials vault kv put secret/iris/gateway \ username=CSPSystem \ password=SYS # Store InterSystems IRIS application token vault kv put secret/iris/prod \ app_token=eyJ... -
Run iris-mcp-server with the token in the environment:
export VAULT_TOKEN="s.xxxx" iris-mcp-server --config config.toml run
Using TLS
iris-mcp-server is associated with two connections:
-
Superserver-side — The connection from iris-mcp-server to InterSystems IRIS.
-
Server-side — The connection from LLM clients to iris-mcp-server
The sections below detail how to encrypt each connection.
Superserver-Side TLS
You can encrypt the superserver-side connection between iris-mcp-server and InterSystems IRIS by adding the tls field to the [[iris]] entry of your configuration file. The presence of the tls field enables TLS and its value determines which certificates and keys to use for the connection:
-
tls = {} — Use the system's default CA certificates to verify the identity of the InterSystems IRIS server.
-
tls = { ca_cert = path/to/ca.crt } - Use the CA certificate ca.crt to verify the identity of the InterSystems IRIS server.
-
tls = { ca_cert = path/to/ca.crt, cert = path/to/client.crt, key = /path/to/client.key } — (Mutual TLS only) Use the CA certificate ca.crt to verify the identity of the InterSystems IRIS server and present the certificate client.crt to InterSystems IRIS.
All certificates and keys must be in PEM format.
If you've integrated iris-mcp-server with HashiCorp Vault, you can reference your secrets instead:
tls = { ca_cert = "@{vault:tls/iris#ca_cert}" }
Server-Side TLS (Remote MCP endpoint)
You can encrypt the connection between LLM clients and iris-mcp-server the MCP server endpoints by adding the cert and key fields to [mcp.tls]:
# Both from files
[mcp.tls]
cert = "/etc/certs/server.crt"
key = "/etc/certs/server.key"
# HashiCorp Vault integration
[mcp.tls]
cert = "@{vault:tls/iris-mcp#certificate}"
key = "@{vault:tls/iris-mcp#private_key}"
Discovery
Before iris-mcp-server can make tools available to MCP clients, it has to fetch the list from each InterSystems IRIS MCP endpoint. This process of fetching tools is called discovery.
Discovery is deferred until the first MCP client connects to iris-mcp-server. When it does, iris-mcp-server discovers the tools from each MCP server endpoint in InterSystems IRIS.
If discovery fails (for example, if the InterSystems IRIS instance is unreachable), existing tool registrations are used as a fallback; iris-mcp-server makes a new discovery attempt on the next tool call.
Smart Discovery (RAG)
iris-mcp-server supports RAG-based (Retrieval-Augmented Generation) smart tool discovery, to perform a semantic search across all registered tool descriptions. When an LLM asks for tools with a natural-language query, the relevant tools are returned automatically.
The embedding model is automatically downloaded from HuggingFace on first use (~25 MB).
To enable this feature in your configuration file:
[features]
smart_discovery = true
Tool Refresh
The background tool-refresh loop fetches tool lists in the interval defined by tool_refresh_interval (default: "5m"). This parameter is a string and accepts values with units such as "70ms" (70 milliseconds), "1m" (one minute), "2h" (two hours), and so on.
A 304 Not Modified response means no change and tools are not reregistered. On a 200 response, iris-mcp-server only reregisters and sends notifications to MCP clients for tools that have changed.
The following example shows how to configure tool_refresh_interval:
[[iris]]
name = "dev"
server = { host = "localhost", port = 1972, username = "CSPSystem", password = "SYS" }
pool = { min = 2, max = 5 }
tool_refresh_interval = "1m" # poll every minute
endpoints = [{ path = "/mcp/myapp" }]
Endpoint Auto-Discovery
If don't specify any MCP server endpoints in [[iris]], iris-mcp-server queries the InterSystems IRIS CSP application registry for all applications whose names start with /mcp and connects to each one automatically.
[[iris]]
name = "local"
server = { host = "localhost", port = 1972, username = "CSPSystem", password = "SYS" }
pool = { min = 2, max = 5 }
# endpoints omitted, so auto-discover /mcp* apps
Tool Name Prefixing
When iris-mcp-server is connected to an MCP server endpoint, the tools provided by that endpoint are prefixed with a service ID derived from the MCP server's path. These prefixes prevent name collisions and tell the LLM which service each tool belongs to.
Tool name prefixes are applied even if iris-mcp-server is only connected to a single endpoint.
The service ID is the endpoint path of the MCP Server with the leading slash stripped and remaining slashes replaced with underscores. For example:
| MCP server endpoint name | Service ID prefix | Example tool name |
| /mcp | mcp | mcp_ExecuteQuery |
| /mcp/database | mcp_database | mcp_database_ExecuteQuery |
| /mcp/myapp | mcp_myapp | mcp_myapp_GetCustomer |
Reconnection
If iris-mcp-server loses its connection to InterSystems IRIS, iris-mcp-server automatically attempts to reconnect in the background in the interval defined by reconnect_interval (default: "30s"). You do not need to restart iris-mcp-server.
This parameter is a string and accepts values with units such as "70ms" (70 milliseconds), "1m" (one minute), "2h" (two hours), and so on.
The example below configures iris-mcp-server to attempt to reconnect every 10 seconds:
[[iris]]
name = "dev"
server = { host = "localhost", port = 1972, username = "CSPSystem", password = "SYS" }
pool = { min = 2, max = 5 }
reconnect_interval = "10s" # attempt to reconnect every 10 seconds
endpoints = [{ path = "/mcp/myapp" }]
Monitoring and Telemetry
iris-mcp-server provides several features for monitoring and telemetry.
Real-Time Monitoring
iris-mcp-server includes a live terminal dashboard that shows connection pool status, active sessions, tool call throughput, and a live log feed. These are updated every 500 milliseconds.
To use this monitoring tool:
-
Start iris-mcp-server. This outputs the IPC socket path in the form /tmp/iris-mcp-PID.sock:
./iris-mcp-server run ... 2026-06-05 20:20:56.521 INFO IPC server listening on /tmp/iris-mcp-15108.sock (mode 0600, owner-only) 2026-06-05 20:20:56.522 INFO IPC metrics socket: /tmp/iris-mcp-15108.sock (iris-mcp-server monitor --socket /tmp/iris-mcp-15108.sock) ... -
Start the monitoring tool, specifying either the socket path or PID to connect to the iris-mcp-server:
Linux:
# Unix, connect by PID iris-mcp-server monitor --pid 15108 # Unix, connect by explicit socket path iris-mcp-server monitor --socket /run/user/1000/iris-mcp-15108.sockWindows:
# Windows, connect by PID iris-mcp-server.exe monitor --pid 15108 # Windows, connect by explicit socket path iris-mcp-server.exe monitor --socket \\.\pipe\iris-mcp-15108 -
To exit the monitoring tool, press q. This does not interrupt the iris-mcp-server process.
The monitoring tool provides the following dashboard panels:
-
GATEWAY — Active MCP sessions, authenticated contexts (distinct OAuth identities), WebSocket sessions, error counts, and discovery cache hit rates
-
CONNECTIONS — Per-endpoint WebSocket pool state (active, queued, idle, total), P50/P99 latency per tool, session eviction counts by reason, InterSystems IRIS connection failure breakdown by reason, HTTP pool self-heal counters (stale/healed/failed), and WebSocket session error breakdown (send, receive, stale-session)
-
TOOLS — Per-tool call counts, success/error rates, P50/P99 execution latency, and input/output byte totals
-
LOG — Live stream of recent INFO/WARN/ERROR log lines, color-coded by severity
The monitoring tool communicates with the iris-mcp-server through a local IPC channel (a named pipe on Windows and a Unix domain socket on Unix). The channel is strictly one-way; the monitor receives periodic read-only metrics and cannot send commands to the server. This local IPC channel also cannot be accessed over the network.
-
Windows — Access to the monitoring tool is restricted to the user who started iris-mcp-server, the SYSTEM account, and members of the local Administrators group. No other local user account can connect to the monitor.
-
Unix — The socket file is created with mode 0600. Only the user who started iris-mcp-server and root can connect to the monitor.
Logging
iris-mcp-server has robust logging capabilities. It collects and outputs the following information:
-
Connection events (connect, disconnect, reconnect)
-
Tool discovery requests and ETag comparisons
-
STP request/response JSON
-
Smart discovery indexing
Logging is configured by specifying, in the [logging section of the configuration file, a log level and an output location.
The log level expresses the minimum level of severity that you want to record. This means that if you set the log level to info, the log will contain messages of severity info and above, which includes info, warn, and error. These are ordered by the most to least severe:
-
error (most severe)
-
warn
-
info (default)
-
debug
The output location expresses where the logs should be written:
-
stderr (default) — Logs are written to stderr. This logging method is incompatible with the stdio transport mode.
-
output — Logs are written to the file specified by logging.file.
-
file — (Required only if output = "file"; ignored otherwise) A file path to write logs to.
The following examples show how to set these options with CLI flags and a configuration file.
To write logs of severity debug and higher to stderr:
iris-mcp-server --log-level debug --log-output stderr --config config.toml run
To write logs of severity debug and higher to /example/iris-mcp.log:
[logging]
level = "debug"
output = "file"
file = "/example/iris-mcp.log"
OpenTelemetry Tracing
To enable OpenTelemetry tracing:
-
Enable the telemetry feature in your configuration file:
-
Set up the OpenTelemetry Protocol (OTLP) endpoint with the OTEL_EXPORTER_OTLP_ENDPOINT environment variable.
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317" -
Run Jaeger for local trace visualization:
docker run -d --name jaeger \ -p 16686:16686 \ -p 4317:4317 \ jaegertracing/all-in-one:latest # View traces at http://localhost:16686
Troubleshooting
The iris_status Diagnostic Tool
If you use the --status-tool flag, iris-mcp-server exposes a special MCP tool called iris_status that the LLM can call to report connection errors or startup failures. This tool only appears in the tool list when there are active errors.
If the LLM sees that the iris_status tool is available, it means that something went wrong. Calling it returns a structured report of all current errors:
iris_status result:
- mcp_database: connection failed — refused at localhost:1972
- mcp_analytics: authentication error — 403 Forbidden (check endpoint credentials)
This allows the LLM to proactively report issues rather than silently failing when tools are called.
iris_status should only be used in a development environment.
Connection Failures
-
Verify that the InterSystems IRIS superserver is running on the configured port.
-
Verify that the MCP server endpoint in InterSystems IRIS (System Administration > Security > Applications > MCP Servers) exists and is enabled.
-
Verify that the Dispatch Class is set in the MCP server endpoint and that the class is compiled in InterSystems IRIS.
-
Verify that the credentials specified for server.username and server.password in [[iris]] are correct. These are gateway-level credentials for a privileged gateway user (for example, CSPSystem), not InterSystems IRIS application user credentials.
-
Verify that your firewall allows TCP connections to the InterSystems IRIS superserver port.
Authentication Failures (403)
The Tool call error: 403 Forbidden error means that you successfully authenticated with InterSystems IRIS, but not with the MCP server endpoint.
-
Verify that the MCP server endpoint entry in [[iris]] has the correct credentials (username and password or bearer).
-
For HTTP Basic authentication: verify that the username and password are valid InterSystems IRIS credentials for a user with the required resource for that endpoint.
-
OAuth passthrough: Verify that the MCP client is sending a valid Authorization header with its requests.
-
Verify that the MCP server's Allowed Authentication Methods are what you expect.
Connected, But Tools Do Not Appear
iris-mcp-server establishes the connection between your LLM and InterSystems IRIS, but you do not see any tools (or your LLM only sees the special iris_status tool).
First, verify whether the issue is on the InterSystems IRIS side or the LLM side:
-
View the output of iris_status to see if it reported the source of the error. If it does not report any issues, then the error is on the InterSystems IRIS side.
-
Run iris-mcp-server with the log level set to debug and look for the tool count logged during discovery. If this shows 0 tools, then the issue is on the InterSystems IRIS side.
If the issue is on the InterSystems IRIS side, then your tools aren't appearing because of a misconfigured MCP server:
-
Verify that the SPECIFICATION parameter of the MCP service class is not empty and references the correct class names.
-
Verify that all listed tool/toolset classes are compiled in the correct namespace.
-
Verify that the Namespace setting of all MCP servers match where the service classes are compiled.
Verifying Tool Discovery
To confirm whether iris-mcp-server is discovering tools, verify that the startup logs contain entries in the form:
registered N tools from /mcp/database
Where N refers is the number of tools registered. If no tools are registered, set the logging level to debug and look for discovery errors.
If you have access to an InterSystems IRIS web gateway (not the superserver port), you can also send a request to the InterSystems IRIS health endpoint directly:
curl http://iris-web-gateway-host/mcp/database/v1/health
Particular Tool Not Shown
If a tool appears in discovery but the tool call fails or if a particular tool is not shown that particular tool might be misconfigured:
-
Verify that the SPECIFICATION parameter of the MCP service class includes the tool or toolset.
-
Verify that the method is public (that is, not set as Private or Internal).
-
Tool names are case-sensitive; verify the names logged during discovery by setting the log level to debug.
Secret and Credential Resolution Failures
If your iris-mcp-server exits at startup with a secret resolution error:
-
For environment variables (@{env:VAR}), verify that the environment variable is set.
-
For vault secrets (@{vault:path#field}), verify that the Vault specified by your configuration file is accessible. This includes:
-
Verify that vault_addr is reachable.
-
Verify that vault_token is valid.
-
Verify that you have permission for the specified secret: vault token lookupOpens in a new tab
-
Verify that the path in the secret reference exists.
-
Verify that the field in the secret reference exactly matches the one in the Vault.
-