Skip to content

mcp-stdio-bridge

A generic, professional-grade gateway that bridges Model Context Protocol (MCP) servers between SSE (Server-Sent Events) and Stdio transports. It also ships a command-wrapper mode that turns any CLI tool directly into an MCP server without writing extra code.

Python · Unlicense · GitHub · PyPI

Why

MCP clients and servers do not always agree on transport: a remote client that only speaks SSE over HTTP still needs to talk to a local process that only speaks stdio, and vice versa. mcp-stdio-bridge sits in between and translates. Its command-wrapper mode goes a step further -- instead of proxying an existing MCP server, it hosts one internally and exposes individual CLI invocations as MCP tools, with argument allowlisting, environment scrubbing, and path traversal protection so the wrapped command can't be turned into a shell.

Features

  • Generic bridge -- works with any executable that speaks MCP over stdio.
  • Command wrapper mode -- directly wrap any CLI utility (wp-cli, git, custom scripts) into a restricted MCP server without external glue code.
  • Dual transport -- SSE (HTTP/HTTPS) for remote access or stdio for local use by MCP clients.
  • 100% test coverage -- exhaustive suite across all transports, operational modes, and failure paths.
  • YAML configuration -- central config file, layered with CLI flags and MCP_* environment variables.
  • Dynamic config reload -- opt-in live-reload from config.yaml via --watch-config or SIGHUP on POSIX systems.
  • Daemon mode -- --daemonize performs a POSIX double-fork to detach from the terminal; pairs with --pid-file for supervisor integration.
  • Idle session timeouts -- automatically terminates stalled proxy and wrapper sessions to prevent resource leaks.
  • Security -- API key authentication (header or query param), restricted argument prefixing and regex filtering for wrapped commands, directory traversal protection, environment allowlist/denylist scrubbing, secret masking in logs, connection limiting and message size throttling, and SSL/TLS with client certificate and CRL support.

Quick start

pip install mcp-stdio-bridge

# Proxy mode -- bridge an existing MCP stdio server over SSE
mcp-stdio-bridge --command "python my_mcp_server.py" --transport sse --port 8000

# Command-wrapper mode -- wrap a CLI tool as an MCP server
mcp-stdio-bridge --mode command-wrapper --config config.yaml

Minimal config.yaml:

host: "127.0.0.1"
port: 8000
command: "python your_mcp_server.py"
api_key: "your-secret-key"

Architecture

Two independent axes -- transport and mode -- combine orthogonally:

  • Transport layer (transport/sse.py, transport/stdio.py) -- SSE runs on Starlette + Uvicorn with API key auth, connection limits, and SSL/TLS; stdio uses raw stdin/stdout with logging forced to stderr to keep the JSON-RPC stream clean.
  • Mode layer (mode/proxy.py, mode/wrapper.py) -- proxy mode spawns one subprocess per connection and bridges streams bidirectionally, with an ActivityMonitor handling idle-timeout termination; wrapper mode runs an internal MCP server where each wrapped_commands entry becomes an MCP tool, enforcing argument allowlist/denylist rules via shlex parsing (no shell=True anywhere).

main.py loads configuration, initializes logging, optionally starts a config file watcher, then dispatches to the selected transport.

Security

  • API key authentication -- timing-safe comparison via APIKeyMiddleware.
  • Security headers -- CSP, HSTS, and X-Frame-Options via SecurityHeadersMiddleware.
  • Argument sandboxing -- per-tool allowed_args, allowed_patterns, forbidden_args, forbidden_patterns; allowlist and denylist rules are mutually exclusive.
  • Path traversal protection -- blocks .. segments and absolute paths outside the configured working directory.
  • Environment scrubbing -- sensitive variables stripped by default; env_allowlist allows explicit pass-through.
  • No shell injection -- shlex.split plus list-form anyio.run_process; shell=True is never used.

Deployment

Supports local execution, Docker, and Docker Compose:

docker build -t mcp-stdio-bridge .
docker run -p 8000:8000 -v $(pwd)/config.yaml:/app/config.yaml mcp-stdio-bridge

Examples

Ready-to-use configuration templates ship in the examples/ directory:

File Description
wp-cli-wrapper.yaml Manage WordPress via MCP using a mix of allowlist and denylist rules
git-wrapper.yaml Expose Git operations to local clients (allowlist-only)
sqlite-proxy.yaml Bridge an existing SQLite MCP server to SSE
security-patterns.yaml Advanced regex-based security filtering
docker-tool-wrapper.yaml Per-tool custom environment variables with Docker