Skip to main content
Glama

mcp-mux

A stdio-to-stdio MCP multiplexer that presents itself to Claude Code as a single MCP server while sharing backend server processes across sessions via a background broker.

Problem

Claude Code spawns every configured stdio MCP server as a child process per session. With 9 servers and 12 concurrent sessions, that's 108+ long-lived Node processes.

mcp-mux reduces this to N shim processes + 9 shared servers, regardless of session count.

Claude Code Session A                Claude Code Session B
        │                                    │
    stdin/stdout                         stdin/stdout
        │                                    │
   ┌────▼─────┐                        ┌─────▼────┐
   │  Shim A  │                        │  Shim B  │
   │ (stdio)  │                        │ (stdio)  │
   └────┬─────┘                        └─────┬────┘
        │            local socket            │
        └──────────────┬─────────────────────┘
                       │
              ┌────────▼────────┐
              │     Broker      │
              │  (background)   │
              └───┬────┬────┬───┘
                  │    │    │
            ┌─────▼┐ ┌▼────▼──┐  ┌────────┐
            │Server│ │Server  │  │ etc... │
            │  A   │ │  B     │  │        │
            │stdio │ │stdio   │  │ stdio  │
            └──────┘ └────────┘  └────────┘

Related MCP server: mcp-ondemand

How it works

  1. Shim — Lightweight stdio process spawned by Claude Code (one per session). Speaks MCP over stdin/stdout to Claude Code, connects to the broker over a local socket.

  2. Broker — Long-lived background process managing all backend MCP servers. Auto-started by the first shim, auto-exits after 5 minutes of inactivity.

The shim aggregates tools from all backend servers into a single namespace, routes tools/call requests to the correct backend, and handles request ID remapping so multiple sessions can share servers without conflicts.

Install

# Install from GitHub
npm install -g github:jasonwarta/mcp-mux

# Or use npx directly from GitHub (no install)
npx github:jasonwarta/mcp-mux

Setup

1. Create .mcp-mux.json in your project root

{
  "servers": {
    "pare-git": {
      "command": "npx",
      "args": ["-y", "@paretools/git"]
    },
    "pare-test": {
      "command": "npx",
      "args": ["-y", "@paretools/test"]
    },
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest"],
      "mode": "per-session",
      "lazy": true
    }
  }
}

2. Point Claude Code at the mux

In your .mcp.json:

{
  "mcpServers": {
    "mcp-mux": {
      "type": "stdio",
      "command": "npx",
      "args": ["github:jasonwarta/mcp-mux"]
    }
  }
}

Or if you cloned the repo locally:

{
  "mcpServers": {
    "mcp-mux": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/mcp-mux/src/shim.mjs"]
    }
  }
}

That's it. The shim auto-starts the broker on first use. No daemon management required.

Configuration

Server options

Field

Type

Default

Description

command

string

required

Executable to spawn

args

string[]

[]

Arguments to the command

env

object

{}

Additional environment variables

cwd

string

project root

Working directory for the server

mode

"shared" | "per-session"

"shared"

Shared: one process for all sessions. Per-session: one per shim (for stateful servers like Playwright)

lazy

boolean

false

If true, don't spawn until first tools/call. Tools are probed at startup then the process is killed.

maxRestarts

integer

5

Max consecutive restart attempts before marking as failed

restartBackoffMs

integer

1000

Initial backoff (doubles each failure, capped at 30s)

Global options

Field

Type

Default

Description

idleTimeoutMs

integer

300000

Broker shuts down after this many ms with no connected shims

requestTimeoutMs

integer

60000

Timeout for individual tool call requests

Server modes

Shared (default) — One server process handles all sessions. Good for stateless tools (git, test runners, linters). The backend servers must accept explicit path/cwd parameters per request rather than relying on process.cwd().

Per-session — One server process per Claude Code session. Required for stateful servers that maintain session context (e.g., Playwright browser sessions, code-graph indexes). The process is spawned on first tool call and killed when the session disconnects.

Lazy — The server is probed for capabilities at broker startup (so its tools appear in the tool list), then the process is killed. A real instance is spawned on the first tools/call. Works with both shared and per-session modes. Good for heavy, rarely-used servers.

Tool naming

Tools are namespaced to avoid collisions. A tool named status from server pare-git appears in Claude Code as:

mcp__mcp-mux__pare-git__status

The format is mcp__<mcp-server-name>__<backend-server>__<tool>.

CLI

The shim doubles as a CLI for broker management:

# Check broker status (server states, connected shims, uptime)
npx github:jasonwarta/mcp-mux status

# Stop the broker
npx github:jasonwarta/mcp-mux stop

# Restart the broker
npx github:jasonwarta/mcp-mux restart

If installed globally or cloned locally, replace npx github:jasonwarta/mcp-mux with mcp-mux or node src/shim.mjs.

All commands accept --config <path> to specify an alternate config file.

How request routing works

  1. Claude Code sends tools/call with a namespaced tool name

  2. Shim looks up the routing table to find the backend server

  3. Shim remaps the tool name back to the original and forwards to the broker

  4. Broker remaps the request ID to a unique internal ID (so multiple shims can share a server without ID collisions)

  5. Backend server processes the request and responds

  6. Broker remaps the ID back and routes the response to the correct shim

  7. Shim returns the response to Claude Code on stdout

Crash recovery

  • Backend servers that crash are automatically restarted with exponential backoff

  • After maxRestarts consecutive failures, the server is marked as failed

  • In-flight requests to a crashed server get an error response (not a hang)

  • If the broker itself crashes, the next shim connection auto-starts a new one

Socket paths

The broker listens on a local socket derived from the config file path:

  • Linux/macOS: $XDG_RUNTIME_DIR/mcp-mux-<hash>.sock (or /tmp/)

  • Windows: \\.\pipe\mcp-mux-<hash>

Where <hash> is the first 8 chars of SHA-256 of the absolute config path. Different projects get different sockets.

Requirements

  • Node.js >= 20

  • Any stdio MCP server as a backend

Zero npm dependencies. Uses only Node.js built-in modules.

License

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Runs every configured MCP server once in a shared background engine and exposes them over a single HTTP endpoint, so Claude Code, Codex, Cursor, VS Code, Gemini CLI and SSH-connected remote machines all connect through one entry and pick up added, removed, or disabled servers and tools immediately. Also provides per-tool hiding, runtime supervision with logs and auto-restart, and secret storage isolated from the API.
    20 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables MCP clients to list and call tools from multiple configured servers while each backend starts only on first use, is shared across sessions, and stops when idle. This reduces memory and process overhead without changing tool names or permissions.
    37 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables connecting to and managing multiple backend MCP resource servers while routing tool and resource requests to the appropriate server and exposing their combined capabilities through a unified SSE, Streamable HTTP, or Stdio interface.
    52 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Connects to and aggregates multiple backend MCP servers (Stdio, SSE, and Streamable HTTP), exposing their combined tools and resources through a single unified SSE or Streamable HTTP endpoint, or as a standalone Stdio server. Handles request routing to the correct backend, supports optional API key/bearer token authentication, concurrent client connections, and a web admin UI for managing servers and individually enabling or renaming tools.
    52 npm
    MIT