Skip to main content

Loopback-only broker for explicitly approved stdio MCP servers

Project description

Irigate — an Iris flower opening into a gateway

GitHub PyPI

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 workspace input with type: directory, a non-empty allowed_roots list, and exactly one standalone placeholder. {workspace} remains valid; ordered forms such as {filesystem.workspace|github.workspace|workspace} choose the first supplied source.
  • Each allowed_roots entry 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.
  • uv for the recommended isolated installation and repository execution.
  • Node.js with npx for the Context7 upstream in profiles/mvp.yaml.
  • An installed code-review-graph executable 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

irigate-0.4.2.tar.gz (273.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

irigate-0.4.2-py3-none-any.whl (63.5 kB view details)

Uploaded Python 3

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

Hashes for irigate-0.4.2.tar.gz
Algorithm Hash digest
SHA256 4b4723d11513022b85e8274fc0b072be90d9d233cf182a57274f1233a4d7ced7
MD5 548a8bb8b6cf39b0466a1e9c9c1f9969
BLAKE2b-256 fc8e9b4d70b9a5354785856dfccf55701d18aa8a99ad73739e42a5992bcfa97e

See more details on using hashes here.

Provenance

The following attestation bundles were made for irigate-0.4.2.tar.gz:

Publisher: publish.yml on irigate/irigate-mcp-proxy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for irigate-0.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 8a602a162b23a677de301ace63d3eee394c0bae52c213cd6936cc004a36a1eaa
MD5 fb7d38f1749ee49db4d75118795e7ff9
BLAKE2b-256 081a8672221435ee753e9d728327197d51927dc785939276ad7c75b5af27db06

See more details on using hashes here.

Provenance

The following attestation bundles were made for irigate-0.4.2-py3-none-any.whl:

Publisher: publish.yml on irigate/irigate-mcp-proxy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page