Loopback-only broker for explicitly approved stdio MCP servers
Project description
Shared local MCP infrastructure for developers running multiple AI coding agents.
Irigate is a loopback-only MCP broker. It lets local agent sessions share explicitly qualified stdio MCP servers—including Windows-native servers launched from WSL—while reducing duplicate processes and providing metadata-only runtime reports, one audit record for every completed or rejected tool call, and local start-scoped MCP request/response logs.
Feature overview
| Capability | Capability | ||
|---|---|---|---|
| ⌁ | One local MCP endpoint Connect Hermes, Claude Code, Codex, and other Streamable HTTP clients to the same loopback broker. |
⟲ | Connection-preserving reloads Apply profile changes in the background without disconnecting active AI-agent sessions. |
| ◈ | Selective process reuse Share qualified stdio servers across compatible sessions and restart only upstreams whose configuration changed. |
⛨ | Fail-closed sharing Keep upstreams isolated by default; sharing requires explicit opt-in and an upstream-specific qualifier. |
| ⎇ | Exact namespaced routing Expose deterministic <upstream>__<tool> names and reject ambiguous or unknown routes. |
◎ | Session isolation Scope non-shareable workers to downstream sessions so context-bound state never leaks across agents. |
| ⚡ | Explicit concurrency Choose serial or parallel execution per upstream, with independent queues and bounded call timeouts. |
◷ | Bounded lifecycle Shut down each idle upstream on its configured timeout, restart it on demand, and terminate children without leaving orphans. |
| ◇ | Layered observability Keep reports and audit output metadata-only; inspect full local tool requests and responses only through protected rotating logs. |
⚖ | Measured compatibility Run qualification, multi-client compatibility checks, and repeatable 1/5/20-client resource benchmarks. |
| ⌘ | Direct CLI tool calls Invoke one namespaced MCP tool from automation without starting the HTTP listener. |
▦ | Process and usage inspection Use irigate status for the broker process and irigate ps for upstream state and per-agent usage. |
| ⊞ | First-class WSL/Windows bridging Run Windows-native MCP servers from a long-lived WSL broker with fresh interop selection and explicit path conversion. |
⋯ | Progressive tool disclosure Inspect upstreams, brief tool metadata, and one exact schema before calling a tool without registering the full catalog. |
Development highlights
Per-session inputs let a client supply an approved value when starting an isolated upstream. The currently supported input is a required directory named workspace:
- Profiles can declare one reserved, required
workspaceinput withtype: directory, a non-emptyallowed_rootslist, and exactly one standalone placeholder.{workspace}remains valid; ordered forms such as{filesystem.workspace|github.workspace|workspace}choose the first supplied source. - Each
allowed_rootsentry authorizes that directory and all of its subdirectories. Profile-side leading~and${ENV_NAME}references are expanded under strict rules; environment-derived roots must be absolute. - Workspace authorization resolves the requested directory and each literal pattern prefix canonically before matching. Traversal, sibling-prefix confusion, nonexistent paths, files, and symlink escapes fail closed.
- A valid scoped or global input is fixed for the downstream MCP session, rendered into each selected worker's local argument list, and included in each isolated worker's non-raw context fingerprint. One
workspace=query value can therefore feed multiple upstreams that list it as a fallback.
Input values are accepted only when a positively selected upstream or exact tool references that source in its placeholder. Bare and reverse-only URLs cannot supply dynamic inputs, unused sources fail closed, and workspace values never enter audit records or runtime reports.
Problem hypothesis
MCP-capable coding agents commonly start stdio MCP servers as child processes. Several concurrent Hermes, Claude Code, Codex, or worker sessions can therefore start duplicate copies of the same expensive server.
A broker may improve this when:
- Several agent sessions run concurrently.
- An upstream has meaningful startup or memory cost.
- The upstream is safe to share between sessions.
- The sessions use compatible state, workspace, and credential contexts.
Sharing is not universally safe. Some MCP servers retain client-specific state, and distinct workspaces or credentials may still require separate instances. Irigate must prove the benefit per upstream rather than assuming every N×M process set can collapse to M.
Requirements
- Python 3.11 through 3.14.
uvfor the recommended isolated installation and repository execution.- Node.js with
npxfor the Context7 upstream inprofiles/mvp.yaml. - An installed
code-review-graphexecutable for the isolated code-review-graph upstream.
The default profile defines real MCP upstreams. An upstream starts only when an agent selects it; its first selected use may download pinned or current package artifacts and require network access.
Installation
Install the published PyPI release as an isolated user application with uv:
uv tool install irigate
irigate --version
Or install it with pip in a virtual environment:
python3 -m venv ~/.venvs/irigate
~/.venvs/irigate/bin/python -m pip install irigate
~/.venvs/irigate/bin/irigate --version
uv provides the irigate console script from its tool bin directory. Ensure that directory—normally ~/.local/bin—is on PATH; run uv tool update-shell if needed. See the changelog for release highlights and upgrade notes.
Development installation
When working from a repository checkout—either to develop Irigate itself or to test a local change—pick the mode that matches how you intend to use the checkout.
Live edit mode (--editable)
uv tool install --editable .
This installs a .pth shim that points back at src/ in the checkout. Source edits take effect the next time you invoke irigate; no reinstall is needed. Use this when developing or debugging Irigate.
Snapshot mode (--force --from .)
uv tool install --force --from . irigate
This builds a regular installation from the checkout and copies the package into uv's tool environment. The installed tool is frozen at the current source state; later edits are invisible until you reinstall. Use this to exercise the checkout as a release-like build without allowing local edits to affect the running tool.
When to choose which
| Goal | Mode |
|---|---|
| Install the official PyPI release | uv tool install irigate |
| Developing or debugging Irigate | Live edit (--editable .) |
| Trying the current checkout as a release-like build | Snapshot (--force --from . irigate) |
| Switching back to live edits after a snapshot install | uv tool install --editable . (overwrites the snapshot) |
| Returning to the official PyPI release after a checkout install | uv tool install --force irigate |
The --force flag in snapshot mode matters when Irigate is already installed in that tool environment: it forces replacement instead of skipping the existing installation. Omit it on a clean install. Remove either installation with uv tool uninstall irigate.
Project environment
Tool installation does not install test dependencies into the checkout. Create the locked project environment before running the test suite or repository commands:
uv sync --frozen
Run the checkout and confirm that the default profile loads without starting upstream processes:
uv run --frozen irigate --help
uv run --frozen irigate --config profiles/mvp.yaml --check
For source checkout setup, repository checks, and release-artifact verification, see DEVELOPMENT.md. Maintainers should use docs/RELEASING.md for PyPI trusted-publisher setup and tag-driven releases.
Website
The public website and documentation are maintained in the site/ git submodule, backed by irigate/irigate.github.io. The website repository owns Astro dependencies, content, verification, GitHub Pages deployment, and custom-domain operations. This source repository remains authoritative for broker behavior, architecture, benchmark evidence, and brand source assets.
Initialize the website after cloning this repository:
git submodule update --init site
Website changes require two commits: commit and push inside site/ first, then commit the updated site pointer in this repository.
Configuration
Irigate reads ~/.config/irigate/config.yaml by default. Set IRIGATE_CONFIG to use another file, or pass --config; the command-line argument takes precedence over the environment variable. Profiles are validated before any upstream process starts: unknown fields, duplicate YAML keys, unsupported transports, invalid routing keys, non-loopback listeners, and missing environment references are rejected.
name: local
host: 127.0.0.1
port: 8765
upstreams:
context7:
description: Resolve library identifiers and query current library documentation.
transport: stdio
command: npx
args: ["-y", "@upstash/context7-mcp"]
env:
CONTEXT7_API_KEY: ${CONTEXT7_API_KEY}
LOG_LEVEL: info
shareable: true
qualifier: context7-readonly-v3
concurrency: serial
call_timeout_seconds: 30
idle_timeout_seconds: 300
failure_threshold: 5
crash_threshold: 2
Broker fields
| Field | Required | Default | Contract |
|---|---|---|---|
name |
Yes | — | Profile identifier using lowercase letters, digits, and hyphens. It labels --check output and runtime reports so operators can distinguish configurations; it does not affect routing. |
host |
No | 127.0.0.1 |
Listener address. Only localhost or an IP loopback address is accepted. |
port |
No | 8765 |
Streamable HTTP listener port, from 1 through 65535. |
runtime_report_path |
No | ${XDG_STATE_HOME:-~/.local/state}/irigate/<name>/runtime-report.json |
Exact JSON report destination override. Relative paths are anchored to the profile directory. The file contains process statistics plus validated agent labels, never payloads or credentials. |
runtime_log_path |
No | ~/.local/log/irigate/<name>/ |
Exact directory for protected start-scoped MCP payload logs. Relative paths are anchored to the profile directory. Changing it requires a broker restart. |
upstreams |
Yes | — | Non-empty mapping of routing keys to stdio upstream definitions. |
Required broker-field example
name and upstreams belong in the selected broker profile. They are not HTTP query parameters, and Irigate does not accept --name or --upstreams CLI flags. The smallest useful profile includes both required broker fields and the two required fields for each upstream:
name: local-development
upstreams:
context7:
command: npx
args: ["-y", "@upstash/context7-mcp"]
idle_timeout_seconds: 300
Choose name as a stable identifier for where or why the profile runs, such as local-development, project-docs, or benchmark. It appears in validation output and runtime reports but does not change routing. Choose each upstream key, such as context7, as the stable tool namespace: the key becomes the prefix in <upstream-key>__<tool-name>. Add every MCP server Irigate should be able to expose under upstreams; at least one entry is required.
Save that profile as ~/.config/irigate/config.yaml to use it by default:
mkdir -p ~/.config/irigate
cp profiles/local.yaml ~/.config/irigate/config.yaml
uv run --frozen irigate --check
uv run --frozen irigate
The first command validates the required fields without starting upstreams. The second starts the broker with profile name local-development and the configured context7 upstream.
For a different profile, set its full path in the environment or override it for one invocation:
export IRIGATE_CONFIG="$HOME/.config/irigate/work.yaml"
uv run --frozen irigate --check
uv run --frozen irigate --config profiles/benchmark-heavy.yaml --check
If either broker field is absent, Irigate exits before starting the HTTP listener and writes an actionable configuration error to stderr with a minimal example.
An upstream key becomes the prefix in every exposed <upstream-key>__<tool-name> route. Keys must start with a lowercase letter and may contain lowercase letters, digits, and hyphens.
Upstream fields
| Field | Required | Default | Contract |
|---|---|---|---|
description |
No | — | Short operator-authored purpose used by the optional progressive-disclosure catalog. It never starts the upstream. |
transport |
No | stdio |
Only stdio is supported. |
command |
Yes | — | One executable token. Put command arguments in args. |
args |
No | [] |
Argument list. Environment references and credentials are not accepted. An upstream with inputs.workspace must contain exactly one standalone workspace placeholder. Pipe-separated sources are checked left to right and rendered from the canonical session input before process startup. |
execution |
No | native |
Process-launch environment. Use explicit wsl-windows for a Windows executable launched from WSL; Irigate refreshes the per-session WSL interop endpoint before every spawn. |
wsl_path_arguments |
No | {} |
Explicit tool-to-JSON-pointer map accepted only for wsl-windows. POSIX absolute strings at * and exact-tool pointers are converted with wslpath -w immediately before forwarding. |
cwd |
No | Inherit broker directory | Working directory for the stdio process. Migration resolves relative agent paths against the owning user or project directory. |
env |
No | {} |
Child environment mapping. Values may be literal strings or explicit ${BROKER_ENV_NAME} references. Use references for credentials so secret values stay out of the profile. |
inputs |
No | {} |
Per-session input declaration. Only a required workspace directory is supported. It needs non-empty allowed_roots, requires shareable: false, and is immutable after the MCP session is established. |
shareable |
No | false |
Requests one process shared across downstream sessions. Sharing is admitted only by a registered qualifier. |
qualifier |
Conditional | — | Required when shareable: true; rejected otherwise. Currently registered: context7-readonly-v3 for the context7 key. |
concurrency |
No | serial |
serial executes one call at a time; parallel permits concurrent calls within the worker. |
call_timeout_seconds |
No | 30 |
Per-call timeout greater than 0 and no more than 3600 seconds. It does not control process idleness. |
idle_timeout_seconds |
Yes | — | Per-process inactivity TTL greater than 0 and no more than 86400 seconds. |
failure_threshold |
No | 5 |
Error count from 1 through 100 that degrades a shared upstream. |
crash_threshold |
No | 2 |
Crash count from 1 through 100 that degrades a shared upstream. |
Each spawned worker tracks its own idle timeout. A worker shuts down only when its TTL expires with no queued or active calls. Shared and session-isolated workers expire independently, and the next routed call starts a fresh process in the same effective sharing mode. A long-running call remains governed by call_timeout_seconds, not by the idle timeout.
MCP application errors remain tool-level error results and count as call failures rather than process crashes. Connection-closed and session-terminated errors remain transport failures, so crash degradation still reflects lost upstream processes.
Long-running WSL brokers must mark Windows-native upstreams explicitly. WSL creates per-session interop sockets and removes them when their owning shell exits, so a broker that reuses its startup environment can later fail with Broken pipe. execution: wsl-windows selects the newest live /run/WSL/<pid>_interop socket for each process spawn. If no live endpoint exists, Irigate returns an actionable restart error without exposing the command or child environment.
upstreams:
pencil:
command: "/mnt/c/Users/<Windows-user>/AppData/Local/Programs/Pen/resources/app.asar.unpacked/out/mcp-server-windows-x64.exe"
args: ["--app", "desktop"]
execution: wsl-windows
wsl_path_arguments:
# filePath is the open .pen document path used across Pencil tools.
"*": ["/filePath"]
# These are exact Pencil MCP tool names and request fields.
export_html: ["/outputPath"]
export_nodes: ["/outputDir"]
env: {}
shareable: false
concurrency: serial
idle_timeout_seconds: 300
Replace <Windows-user> with the Windows account directory under /mnt/c/Users. wsl_path_arguments is opt-in and valid only with execution: wsl-windows. Its keys are exact upstream MCP tool names or *; its values are JSON Pointers into request objects, not filesystem directories. export_html and export_nodes are Pencil MCP tools, while outputPath and outputDir are fields in those tools' request schemas.
The actual paths arrive in MCP calls. For example, /home/<WSL-user>/designs/dashboard.pen converts to \\wsl.localhost\\<distribution>\\home\\<WSL-user>\\designs\\dashboard.pen. /mnt/c/Users/<Windows-user>/Documents/pencil-export/dashboard.html converts to C:\\Users\\<Windows-user>\\Documents\\pencil-export\\dashboard.html. These are caller-selected examples; Irigate neither creates nor selects those directories in the profile.
Missing pointers, empty strings, Windows drive paths, UNC paths, and other non-POSIX strings pass through unchanged. Slash-prefixed Windows drive paths such as /C:/Users/example/design.pen are normalized directly rather than sent through wslpath. A configured pointer that resolves to a non-string rejects the call. Irigate converts a rendered {workspace} process argument automatically for Windows-native upstreams. Protected MCP payload logs retain the original client-facing arguments; only the worker-boundary copy is transformed.
Literal strings are passed directly to the child process. ${ENV_NAME} values are resolved from the broker process without being written into the profile, audit log, runtime report, or validation output:
export CONTEXT7_API_KEY='...'
uv run --frozen irigate --config profiles/local.yaml --check
Migrate installed agent configurations
irigate migrate discovers user and current-project MCP configurations for Claude Code, Codex CLI, Cursor, Gemini CLI, and Hermes. It presents an interactive numbered selection, moves each selected stdio server into the Irigate profile, and replaces those direct server entries with one agent-specific Streamable HTTP connection to Irigate. Existing remote MCP entries and unrelated agent settings remain in place.
uv run --frozen irigate migrate --config ~/.config/irigate/config.yaml
uv run --frozen irigate migrate --all --config ~/.config/irigate/config.yaml
uv run --frozen irigate migrate ~/.cursor/mcp.json --config ~/.config/irigate/config.yaml
Providing a file bypasses discovery and migrates only that file. Non-interactive use requires either a file or --all. Existing files receive adjacent .irigate.bak backups before replacement; a pre-existing backup stops the migration rather than overwriting evidence. New upstreams default to isolated, serial execution with a 30-second call timeout and 300-second idle timeout. Existing remote MCP servers are not moved.
Agent-local environment values are never copied into the Irigate profile. Every migrated child environment variable becomes an explicit ${ENV_NAME} broker reference, and that variable must already be exported in the environment running the migration. The same environment must be available when Irigate runs. Conflicting normalized upstream names or unsupported configuration shapes fail before any file changes.
While serving, Irigate watches the selected profile. Changed active upstreams must initialize successfully before routing switches. Added and changed dormant upstreams remain stopped until selected. Invalid updates leave the last valid active configuration available. Changes to name, host, port, runtime_report_path, or runtime_log_path require restarting the broker.
Run
Start the broker in the foreground with strict sharing admission:
uv run --frozen irigate \
--config profiles/mvp.yaml \
--require-qualified-sharing
Inspect the installed version and all available commands:
uv run --frozen irigate --version
uv run --frozen irigate --help
The root help lists status, reload, and stop; the reload and stop help output also identifies the running Irigate version so a stale installed executable is visible immediately.
The broker listens at http://127.0.0.1:8765/mcp without starting upstreams. A client may use the bare URL to expose all configured upstreams, or add a selector to narrow the set. Qualification, schema discovery, and process startup happen on first use. Each upstream's idle_timeout_seconds shuts down that process independently after inactivity; the next routed call starts a fresh process without changing the downstream session.
Agent-side selection
The agent URL does not repeat the broker profile's required name and upstreams fields. It connects to an already-running profile. The examples below assume Irigate was started with --config profiles/mvp.yaml; that profile contains name: mvp and defines the context7 and code-review-graph upstream keys. Use exact tools for the narrowest and recommended agent configuration:
http://127.0.0.1:8765/mcp?tools=context7__resolve-library-id,context7__query-docs
Select complete upstreams by their keys from the active broker profile when the agent needs their full tool surfaces:
http://127.0.0.1:8765/mcp?upstreams=context7,code-review-graph
Prefix an upstream with ! when the agent starts that MCP server directly and wants every other configured Irigate upstream:
http://127.0.0.1:8765/mcp?upstreams=!code-review-graph
Positive and reverse selectors may be mixed. Positive names form the base set and exclusions are subtracted regardless of order:
http://127.0.0.1:8765/mcp?upstreams=context7,code-review-graph,!code-review-graph
This selects only context7. Omitting both selector parameters exposes all configured upstreams unchanged. Reverse-only selection also starts from all currently configured upstreams, so profile reloads can broaden it when a new upstream is added. Prefer tools= for least privilege. When selection is used, provide only one tools or upstreams parameter; repeated parameters, unknown names, malformed tokens, unrelated query parameters, and an empty result are rejected. Exact tool selection never supports ! because excluding one tool cannot avoid starting its upstream.
Per-session input
An upstream may declare one required directory input named workspace. This filesystem server is one example; the input contract is not specific to that server. The following profile permits the home directory and all of its subdirectories:
filesystem:
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "{workspace}"]
inputs:
workspace:
type: directory
required: true
allowed_roots: ["${HOME}"]
shareable: false
idle_timeout_seconds: 300
Select the upstream positively and URL-encode the absolute workspace value:
http://127.0.0.1:8766/mcp?upstreams=filesystem&filesystem.workspace=${HOME}
Here ${HOME} denotes the absolute value supplied by the client; Irigate does not expand shell syntax in query values.
An exact tool selector for the configured upstream may carry the same input. Inputs do not select upstreams by themselves: bare URLs, reverse-only selectors, excluded upstreams, missing or duplicate values, relative paths, and unknown input names are rejected before activation. The canonical mapping is bound to the first successful MCP session response; later requests for that session must present the identical mapping.
Each configured allowed_roots entry permits its canonical directory and all descendants. Profile-side leading ~ and braced ${ENV_NAME} references expand at load time under strict validation, but query values never expand shell syntax. Irigate strictly resolves the requested directory before authorization, so traversal and symlink paths are judged by their canonical destination.
Add an explicit agent= label to attribute calls in the runtime report:
http://127.0.0.1:8765/mcp?upstreams=code-review-graph&agent=codex
Agent labels are metadata, not authentication. They must be 1–64 letters, digits, dots, underscores, or hyphens and are recorded only after a valid tool call. Omitted labels are grouped as anonymous; Irigate does not guess identity from client headers.
CLI operations
Configure Windows tool paths automatically
When a profile contains one or more execution: wsl-windows upstreams, let Irigate inspect their live MCP tool schemas instead of writing wsl_path_arguments by hand:
# Diagnose only; exit 1 means the profile needs path mappings.
irigate doctor --config ~/.config/irigate/config.yaml
# Add the schema-derived mappings to the profile.
irigate doctor --config ~/.config/irigate/config.yaml --apply
doctor starts only the configured wsl-windows upstreams, reads their advertised input schemas, and recognizes string fields whose names denote file or directory paths, including filePath, outputPath, outputDir, requestFilePath, and responseFilePath. It ignores unrelated strings such as prompts, URLs, JSONPath expressions, and XPath expressions. Existing operator-authored mappings are preserved; discovered paths already covered by a * mapping are not duplicated.
Without --apply, the command does not modify the profile and returns 1 when repair is needed. With --apply, Irigate validates a temporary repaired profile, preserves the original as <profile>.irigate-doctor.bak on the first repair, then replaces the profile atomically. Comments and unrelated profile text remain intact. Re-run doctor after an upstream package upgrade because its tool schemas may have added path fields. Use --json for machine-readable findings.
Optional progressive-disclosure Agent Skill
Irigate bundles an AgentSkills-compatible integration for agents that have shell access and need only a few tools from a large catalog. Locate the installed skill and copy that directory into the explicit skill directory used by the agent:
irigate skill-path
cp -R "$(irigate skill-path)" <agent-skill-directory>/irigate-progressive
The skill uses four explicit layers:
# Layer 1: static profile metadata; no upstream startup or environment resolution
irigate upstreams --config profiles/mvp.yaml --json
# Layer 2: names and descriptions from one upstream; schemas are omitted
irigate tools --config profiles/mvp.yaml --upstream code-review-graph --json
# Layer 3: one exact namespaced schema
irigate schema --config profiles/mvp.yaml code-review-graph__get_minimal_context_tool
# Layer 4: one exact call
irigate call --config profiles/mvp.yaml \
code-review-graph__get_minimal_context_tool \
--arguments '{"repo_root":"/path/to/project","task":"review changes"}'
upstreams reads only validated metadata and does not require referenced environment values. tools, schema, and call initialize only the selected upstream and close it before returning. Separate commands therefore do not preserve an isolated upstream session; use the standard Streamable HTTP endpoint for stateful or multi-call workflows. The progressive integration deliberately keeps exact tool names visible instead of adding a generic dispatcher that would hide them from approval and audit surfaces.
Tool discovery and calls
List the exact namespaced tools available from a profile before configuring an agent:
uv run --frozen irigate tools --config profiles/mvp.yaml
The command prints one <upstream>__<tool> name per line so its output can be copied into tools=. Tool schemas are runtime metadata rather than static profile fields, so discovery temporarily starts and initializes every configured upstream, then closes all spawned processes. It may therefore download upstream packages, use the network, and require the profile's referenced environment variables. Use --check instead when only configuration validation without startup is needed.
Call a namespaced tool directly from a shell without starting the HTTP listener:
uv run --frozen irigate call --config profiles/mvp.yaml \
code-review-graph__build_or_update_graph_tool \
--arguments '{"repo_root":"/path/to/project","full_rebuild":false}'
--arguments accepts one JSON object and defaults to {}. The command prints the complete MCP CallToolResult as JSON, exits 0 for a successful tool result, 1 for an MCP or upstream error, and 2 for invalid configuration or arguments. The upstream starts only for this call and is closed before the command exits. A valid direct call creates its own MCP log file. Pass credentials through the profile's environment references, never through tool arguments.
Inspect the latest runtime snapshot in a ps/netstat-style table:
uv run --frozen irigate ps --config profiles/mvp.yaml
uv run --frozen irigate ps --config profiles/mvp.yaml --json
Each table row identifies an upstream/agent pair and shows effective mode, live process count, activity state (busy, idle, or stopped), elapsed idle time, configured idle timeout, calls, and failures. IDLE_FOR is - while busy or stopped; while idle it is calculated from the report's UTC idle_since timestamp, so it continues advancing between report writes. --json returns the complete schema-version-3 report, including activity_state, active_calls, idle_since, and idle_timeout_seconds, for automation. This command reads runtime_report_path without starting upstreams or resolving their environment references; a report left by a stopped broker retains cumulative usage from that run.
Inspect the serving process separately from its potentially stale runtime report:
uv run --frozen irigate status --config profiles/mvp.yaml
uv run --frozen irigate status --config profiles/mvp.yaml --json
For a verified running process, status reports the PID, effective host, port and MCP endpoint, canonical configuration path, runtime-report path, current start-scoped MCP log file, instance ID, package version, and UTC start time. If no live control document exists, it reports state=stopped and whether a stale runtime report or control document remains. It does not resolve upstream environment references or start upstreams.
Print the newest MCP call log for the selected profile, or follow appended JSON-line records live on stdout:
uv run --frozen irigate logs --config profiles/mvp.yaml
uv run --frozen irigate logs -f --config profiles/mvp.yaml
Every server start and valid direct call starts a new file under ~/.local/log/irigate/<profile>/ by default. Set the optional profile field runtime_log_path to use another exact directory; relative values are anchored to the profile directory. Irigate retains the newest 10 files per profile. The directory is mode 0700 and files are mode 0600. Each record contains the agent label, complete tools/call arguments, complete MCP result or raised error, and duration. These payload logs can contain sensitive tool input or output; unlike audit records and runtime reports, they are not metadata-only. logs reads no upstream environment references and starts no processes. -f follows the selected file; run it again after a new broker start to follow the new file.
Gracefully stop the server selected by the same profile:
uv run --frozen irigate stop --config profiles/mvp.yaml
Request an immediate connection-preserving profile reload:
uv run --frozen irigate reload --config profiles/mvp.yaml
Serving writes a credential-free <runtime_report_path>.control document containing the effective process, listener, configuration, report, and current log-file metadata used by status, reload, and stop. These commands treat that document as an untrusted claim: they check the selected profile and configuration path and verify that the PID is a live Irigate process. reload sends SIGHUP to wake the same atomic reload path used by profile watching; exit 0 confirms delivery, while validation or activation failures remain in the server log and leave the last valid configuration active. stop sends SIGTERM and waits for normal application and child-process cleanup. None resolves upstream environment references. A missing runtime_report_path, stale or mismatched control document, non-Irigate PID, or signal failure fails without signaling another process; stop also fails when cleanup is not observed.
An agent can combine Irigate with a directly managed MCP server:
mcp_servers:
irigate:
url: "http://127.0.0.1:8765/mcp?upstreams=!code-review-graph"
code-review-graph:
command: code-review-graph
args: [serve]
For a foreground broker, Ctrl+C remains equivalent operationally: shutdown drains active calls and closes child processes.
Strict mode rejects the first selected use of Context7 if it cannot be qualified. Omit --require-qualified-sharing to downgrade failed selected shared upstreams to isolated mode.
Run qualification without opening the client endpoint when diagnosing startup:
uv run --frozen irigate qualify --config profiles/mvp.yaml
Audit records are written as metadata-only JSON lines to stderr. Each profile atomically refreshes ${XDG_STATE_HOME:-~/.local/state}/irigate/<name>/runtime-report.json by default with metadata-only process, reuse, timing, failure, and per-agent usage counters. Tool arguments and results remain excluded from both surfaces and are retained only in the protected rotating MCP call logs.
Not part of the MVP
- Enterprise governance or compliance claims
- User identity, tenant isolation, RBAC, OAuth, or remote access
- Credentials in URLs or dynamic HTTP environment overrides
- Generic secret scanning or response rewriting
- A custom filesystem MCP server or path-guessing middleware
- SSE as the primary client transport
- OpenAI or Anthropic API proxying
- Kubernetes, a web portal, daemon management, or dynamic configuration APIs
Architecture direction
Hermes / Claude Code / Codex / test clients
│
│ MCP over Streamable HTTP on loopback
▼
┌──────────────┐
│ Irigate │
│ │
│watched config│
│ exact routing│
│ process reuse│
│ metadata log │
└──────┬───────┘
│ stdio MCP
┌─────────┼─────────┐
▼ ▼ ▼
upstream A upstream B upstream C
isolated shareable shareable
by default only after only after
testing testing
Different upstreams must progress independently. Shared instances are permitted only after transport, concurrency, and state-isolation tests pass.
Implementation
IMPLEMENTATION.md documents runtime architecture, module ownership, safety contracts, extension workflows, and verification commands.
Positioning
The current market hypothesis is documented in MARKET-RESEARCH.md.
Irigate is positioned as local AI developer infrastructure, not as a competitor to enterprise control planes such as Microsoft MCP Gateway. Microsoft focuses on Kubernetes deployment, management APIs, Entra authorization, session-aware routing, and a portal. Irigate's narrower hypothesis is workstation-local stdio process consolidation across several coding-agent products.
Repository contents
IMPLEMENTATION.md— Current architecture, contracts, extension workflows, and verification.MARKET-RESEARCH.md— Market hypothesis, measured evidence, positioning, and go/no-go criteria.assets/— Reproducible Iris-gate project mark, lockup, and raster exports.profiles/— Validated loopback-only runtime and benchmark profiles.src/irigate/— Installable package, configuration models, loader, and CLI.tests/— Executable package and runtime contracts.
License
Irigate is available under the MIT License.
Status
- Product scope: loopback-only local MCP broker.
- Validation: Context7 is qualified for shared mode; code-review-graph remains isolated.
- Evidence: process and resident-memory consolidation is established for identical Context7 contexts. Call-latency evidence remains invalid because Context7 throttled the benchmark.
- Market evidence: hypothesis only.
- Next action: rerun the latency benchmark with adequate Context7 quota and observe normal development sessions before making a release decision.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file irigate-0.4.2.tar.gz.
File metadata
- Download URL: irigate-0.4.2.tar.gz
- Upload date:
- Size: 273.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b4723d11513022b85e8274fc0b072be90d9d233cf182a57274f1233a4d7ced7
|
|
| MD5 |
548a8bb8b6cf39b0466a1e9c9c1f9969
|
|
| BLAKE2b-256 |
fc8e9b4d70b9a5354785856dfccf55701d18aa8a99ad73739e42a5992bcfa97e
|
Provenance
The following attestation bundles were made for irigate-0.4.2.tar.gz:
Publisher:
publish.yml on irigate/irigate-mcp-proxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
irigate-0.4.2.tar.gz -
Subject digest:
4b4723d11513022b85e8274fc0b072be90d9d233cf182a57274f1233a4d7ced7 - Sigstore transparency entry: 2256406227
- Sigstore integration time:
-
Permalink:
irigate/irigate-mcp-proxy@94fa49c36797db1830a01a00a41360d975eade9a -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/irigate
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94fa49c36797db1830a01a00a41360d975eade9a -
Trigger Event:
push
-
Statement type:
File details
Details for the file irigate-0.4.2-py3-none-any.whl.
File metadata
- Download URL: irigate-0.4.2-py3-none-any.whl
- Upload date:
- Size: 63.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a602a162b23a677de301ace63d3eee394c0bae52c213cd6936cc004a36a1eaa
|
|
| MD5 |
fb7d38f1749ee49db4d75118795e7ff9
|
|
| BLAKE2b-256 |
081a8672221435ee753e9d728327197d51927dc785939276ad7c75b5af27db06
|
Provenance
The following attestation bundles were made for irigate-0.4.2-py3-none-any.whl:
Publisher:
publish.yml on irigate/irigate-mcp-proxy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
irigate-0.4.2-py3-none-any.whl -
Subject digest:
8a602a162b23a677de301ace63d3eee394c0bae52c213cd6936cc004a36a1eaa - Sigstore transparency entry: 2256406236
- Sigstore integration time:
-
Permalink:
irigate/irigate-mcp-proxy@94fa49c36797db1830a01a00a41360d975eade9a -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/irigate
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94fa49c36797db1830a01a00a41360d975eade9a -
Trigger Event:
push
-
Statement type: