Skip to content

maxjustships/mcpgate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mcpgate

mcpgate is a companion runtime for mcp2cli-style, CLI-first MCP use. It keeps persistent stdio MCP sessions behind a small local daemon, avoiding the roughly 1.7 seconds of cold per-process startup paid for each discovery, help, or call; repeated warm operations typically take about 2–10 ms. It also adds the guardrails missing when agents invoke MCP through a shell: read-only mutation-name rejection, optional exact tool allowlists, and metadata-only audit trails. In a Codex CLI benchmark with a 150-tool catalog, CLI-first discovery used 31% fewer tokens than naive MCP catalog injection while retaining 100% task success. mcpgate is not an MCP replacement and is not an mcp2cli clone.

Install

Python 3.11 or newer and uv are required:

uv tool install .

For development from a checkout:

uv sync
uv run mcpgate --help

Quickstart

Create ~/.config/mcpgate/targets.toml:

[targets.local_docs]
command = "uv"
args = ["run", "--directory", "/absolute/path/to/server", "python", "-m", "docs_server"]
read_only = true
allow_tools = ["search_documents", "read_document", "server_info"]
idle_timeout_minutes = 15

The command must start an MCP server using stdio. Then use the compact workflow:

mcpgate list local_docs
mcpgate describe local_docs search_documents
mcpgate call local_docs search_documents --args '{"query":"safety"}'
mcpgate audit --lines 10

list, describe, and call start the daemon automatically. Explicit lifecycle commands are also available:

mcpgate daemon start
mcpgate daemon status
mcpgate daemon stop

Set MCPGATE_CONFIG, MCPGATE_STATE_DIR, or MCPGATE_SOCKET to override the config file, state directory, or Unix socket. MCPGATE_BRIDGE_DIR enables the filesystem bridge described below.

Sandboxed agents

Some agent shells cannot reach the Unix socket. In measured Codex CLI workspace-write sandboxing, filesystem access is the only usable host IPC:

Channel from the sandbox Measured result
Nested stdio MCP server spawn Blocked
Unix-domain socket connect Blocked with PermissionError: Operation not permitted
Internet socket creation (AF_INET socket()) Blocked with the same error
Files in the shared workspace Read/write allowed

The last row is what the file bridge uses. The host daemon still owns the stdio MCP processes and also keeps serving its Unix socket. A sandbox client publishes a complete JSON request by atomic rename under requests/; the daemon polls it, runs it through the same session, policy, and audit path as a socket request, then atomically publishes the response under responses/.

Start the daemon in a normal host shell. Put the bridge inside the workspace shared with the agent:

export MCPGATE_CONFIG=/absolute/path/to/targets.toml
export MCPGATE_STATE_DIR=/absolute/path/to/mcpgate-state
export MCPGATE_SOCKET=/absolute/path/to/mcpgate-state/daemon.sock
export MCPGATE_BRIDGE_DIR=/absolute/path/to/agent-workspace/.mcpgate-bridge
mcpgate daemon start
mcpgate daemon status

Then, in a Codex or Claude Code sandboxed shell, only the bridge variable and a visible mcpgate binary path are needed. The client must not be given the target configuration, state directory, or socket:

export MCPGATE_BRIDGE_DIR=/workspace/.mcpgate-bridge
/absolute/path/to/mcpgate list local_docs
/absolute/path/to/mcpgate describe local_docs search_documents
/absolute/path/to/mcpgate call local_docs search_documents \
  --args '{"query":"safety"}'

If no bridge daemon is reachable and the sandbox has no config, the client instructs you to start it on the host. Stop it from either environment with mcpgate daemon stop; daemon status lists the active unix and file_bridge transports.

Bridge requests temporarily contain the raw call arguments because they are the IPC message, so use a dedicated bridge directory inside a workspace trusted by the same user. Its requests, responses, and dead subdirectories are mode 0700, and a normal client deletes request and response artifacts after completion. The bridge is not an authorization boundary and does not expand mcpgate's single-user scope. An agent that forges a request file gains no operation beyond what the CLI already exposes: every request still reaches the daemon's existing target session, pre-call policy enforcement, safe error mapping, and metadata-only audit writer. Raw arguments and results are never written to the audit log.

Policy

read_only defaults to false, including under an optional [defaults] table. When it is true, mcpgate rejects tokenized mutation-shaped tool names such as create_issue, run_query, or delete-record. Names such as server_info are not false positives. If allow_tools is present, every call must also match that exact allowlist, regardless of read_only. Rejections happen in the daemon before the MCP request is sent and return an explicit policy error.

This is a fail-closed name and allowlist gate, not semantic verification of server behavior. A deceptively named tool or a compromised server can still mutate data. For meaningful read-only safety, use a narrow allowlist, trusted local commands, and read-only credentials or OS permissions at the server.

Audit

The append-only audit log is ~/.local/state/mcpgate/audit.jsonl, or $MCPGATE_STATE_DIR/audit.jsonl. It records exactly one entry for each list, describe, and call: timestamp, operation, target, tool name, duration, serialized result byte count and SHA-256 digest, status, and error class. It never records raw arguments, results, environment variables, secrets, or config contents.

Generated agent skill

mcpgate skill local_docs > SKILL.md

The generated short skill teaches agents to discover with list, inspect only the selected tool with describe, and then invoke it with call.

Non-goals

  • mcpgate is not an MCP replacement or an mcp2cli clone.
  • v0.1 supports local stdio MCP servers only—no HTTP or SSE.
  • The file bridge is client-to-daemon IPC; MCP targets remain stdio-only.
  • v0.1 is a single-user local daemon with no authentication.
  • It does not adapt OpenAPI or GraphQL services.

Development

Tests are local and offline:

uv sync
uv run pytest -q

See AGENTS.md for invariants and docs/test-plan.md for the full quality gate.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages