mcpmu

mcpmu (μ)

One secure, context-efficient MCP gateway for all your agents.

mcpmu lets you configure MCP servers once and expose them through a single stdio or Streamable HTTP endpoint. Claude Code, Codex, Cursor, Windsurf, and other MCP clients can share the same servers without duplicating configuration. Lets you compress large tool lists behind discovery calls to prevent excess context usage in your agent harness. - **Control tools at the gateway** — Allowlist tools by namespace and globally block dangerous operations, regardless of which agent connects. - **Reduce tool-schema context costs** — Replace a large `tools/list` response with three discovery and invocation tools, configurable per namespace. - **Create focused namespaces** — Give work, personal, and project agents only the servers and tools they need. - **Connect any upstream** — Manage local stdio processes and remote Streamable HTTP/SSE servers. - **Serve any client** — Use local stdio shims or one persistent Streamable HTTP endpoint with a URL for each namespace. - **Manage everything visually** — Use the terminal UI or browser UI to add, test, monitor, and configure servers. - **Keep MCP metadata intact** — Tool annotations, output schemas, icons, and structured results survive the proxy hop. ### Terminal UI
Terminal UI server list Terminal UI server detail
Terminal UI namespace view Terminal UI permissions editor
### Web UI
Web UI servers Web UI server detail
Web UI namespaces Web UI registry
[Website](https://mcpmu.bigsy.uk) · Free and open source under the MIT license. ## Installation ### Homebrew (macOS/Linux) ```bash brew tap Bigsy/tap brew install mcpmu ``` ### From source ```bash go install github.com/Bigsy/mcpmu/cmd/mcpmu@latest ``` ## Quick start Add an MCP server: ```bash # Local stdio server mcpmu add context7 -- npx -y @upstash/context7-mcp # Remote HTTP server with OAuth mcpmu add atlassian https://mcp.atlassian.com/mcp --scopes read,write ``` Then register mcpmu with a local agent: ```bash claude mcp add mcpmu -- mcpmu serve --stdio # or codex mcp add mcpmu -- mcpmu serve --stdio ``` The equivalent MCP configuration is: ```json { "mcpmu": { "command": "mcpmu", "args": ["serve", "--stdio"] } } ``` Run `mcpmu` for the terminal UI or `mcpmu web` for the browser UI. Alternatively, let your coding agent perform the setup. Install the bundled agent skill, then ask it to import your existing MCP configuration: ```bash mcpmu skill install ``` ## Give each agent the right tools Namespaces create separate tool profiles from the same server configuration: ```bash mcpmu namespace add work --description "Work tools" mcpmu namespace assign work atlassian mcpmu namespace assign work context7 claude mcp add work -- mcpmu serve --stdio --namespace work ``` Permissions are enforced inside mcpmu, not delegated to the connecting client. You can deny dangerous tools everywhere, create an allowlist for a namespace, or choose defaults for one particularly broad server: ```bash # This cannot be overridden by a namespace mcpmu server deny-tool filesystem delete_file # Expose only selected tools in this namespace mcpmu namespace set-deny-default work true mcpmu permission set work context7 resolve allow ``` The precedence is: **server global deny > explicit tool rule > server default > namespace default > allow**. See [Tool permissions](docs/permissions.md) for recipes, the full resolution model, and the interaction with compression. Permission edits submitted together in the TUI save as one batch. If a referenced server or namespace was removed while the editor was open, the save fails and reports the error without saving any of the batch. ## Reduce tool-schema context costs Large MCP setups can send thousands of tokens of tool schemas when a session starts. Compression replaces that surface with `list_tools`, `get_tool_schema`, and `invoke_tool`, allowing an agent to fetch full schemas only when it needs them: ```bash # Recommended starting point for a large namespace mcpmu namespace set-compression work medium ``` Compression is opt-in and works with stdio and HTTP. Denied tools stay out of the compact listing, and calls through `invoke_tool` still use the real target tool for mcpmu permissions and metrics. See [Tool-surface compression](docs/compression.md) for level selection, flag overrides, client-side permission caveats, and operational details. ## Choose a client transport | Transport | Best fit | Namespace | Process model | |---|---|---|---| | stdio | Local agents and editor integrations | `--namespace work` | Per-client shim; shared daemon by default on Unix | | Streamable HTTP | Persistent or networked endpoints | `/mcp/work` | One long-running HTTP process | For HTTP clients, start the endpoint and point the client at the namespace URL: ```bash mcpmu serve --http ``` ```json { "mcpmu": { "url": "http://127.0.0.1:8081/mcp/work" } } ``` `/mcp` selects the default namespace; `/mcp/{namespace}` selects a named one. A non-loopback bind requires a bearer token: ```bash mcpmu serve --http --addr 0.0.0.0:8081 --token "$MCPMU_TOKEN" ``` Servers are shared by default. For stateful servers such as browser automation or REPLs, turn off **Share between agent connections** in the TUI or web server form, add with `mcpmu add browser --shared=false -- browser-command`, or set `"shared": false` in the config to give each client session a private instance. Changing sharing takes effect when serving processes reload the config. The [CLI reference](docs/CLI.md) covers daemon controls, HTTP security, OAuth, custom headers, and all serve flags. ## Runtime status and diagnostics TUI and web statuses describe **this management session**. Their start/stop controls use a separate supervisor from the daemon serving agent connections. A stopped server in a manager may still be running for an agent. ```bash mcpmu status # resolved config, daemon availability and running instances mcpmu status --json mcpmu doctor # config, executable, working-directory and env checks mcpmu doctor --json ``` Both commands are read-only and support `--config`. They never start upstreams, perform OAuth login, or start a daemon. Doctor checks the current CLI environment plus server overrides; a running daemon may have inherited a different environment. Missing configs use empty defaults. Status succeeds for a determined absent daemon; doctor exits 1 for invalid config or failed local prerequisite checks. Environment checks show variable names and outcomes, never values. Serve reloads keep unaffected upstreams running. Permission/compression edits retain instances; runtime edits restart affected servers. Invalid external edits retain the previous valid config, and the web UI shows a warning until recovery. Global settings such as metrics and OAuth still use a full reload. ## More features - Search and install servers from the official MCP registry. - Authenticate remote servers with OAuth 2.1, PKCE, dynamic client registration, bearer tokens, or custom headers. - Hot-reload configuration without restarting serve mode. - Start servers lazily or pre-start them with `--eager`. - Pass through upstream resources and prompts. - Track per-tool call counts, error rates, latency, and unused tools. Click a tool’s error count to inspect failed responses, including structured MCP errors and transport diagnostics, filtered by namespace and time window. Error responses are stored locally in `metrics.json` for 60 days, independently of counter retention, and flushed every ~30 seconds while metrics are enabled. Successful calls do not store inputs or responses. To retain inputs for failed calls, enable **Record inputs for failed tool calls** in the server edit form (or set `recordErrorInputs: true` on that server in the config). This defaults to off per server. Inputs share the error history’s 60-day retention and redact common secret fields recursively; free text and other data remain unchanged. Error responses retain whatever diagnostic content the upstream returned. Older counts have no response history. Expired responses are hidden on read and pruned while serve mode is running. - Share upstream processes across concurrent stdio clients while allowing private instances per server. - Negotiate MCP protocol revisions through 2025-11-25 and relay cancellation and progress in both directions. Upstream pings are answered, and the `instructions` of running upstreams are surfaced in the initialize result. - Relay an upstream's elicitation requests (forms and sign-in URLs) to the client that caused them, for servers that opt in (`--elicitation`). Routing is certain for `"shared": false` servers and strong for HTTP upstreams that send the request on the call's own response stream; an opt-in single-caller heuristic covers the rest. Anything that cannot be routed is answered `cancel`, and a tool's timeout pauses while it waits on the user. Upstream JSON-RPC errors such as `URLElicitationRequiredError` pass through intact. See [Client features](docs/CLI.md#client-features-elicitation). - Relay sampling requests for servers that opt in (`--sampling`), only where the request is certainly or strongly tied to one client. See [Sampling](docs/CLI.md#sampling). - Tell servers their roots (`--root`, `mcpmu server set-roots`): mcpmu answers `roots/list` itself and announces edits with `roots/list_changed`. See [Roots](docs/CLI.md#roots). ## Documentation - [Tool permissions](docs/permissions.md) — access rules, precedence, and practical allowlist and denylist patterns - [Tool-surface compression](docs/compression.md) — reduce tool-schema context while preserving gateway enforcement - [CLI reference](docs/CLI.md) — commands, flags, configuration fields, HTTP, and shared-daemon operation - [Shell completions](docs/completions.md) — zsh, bash, fish, and PowerShell - [Architecture](ARCHITECTURE.md) — implementation and protocol details ## Building and testing ```bash git clone https://github.com/Bigsy/mcpmu.git cd mcpmu go build -o mcpmu ./cmd/mcpmu ./mcpmu ``` ```bash go test ./... make check make test-integration ``` Local linting and CI use [golangci-lint v2.12.2](https://github.com/golangci/golangci-lint/releases/tag/v2.12.2), built with Go 1.26. Run `make check` and `make test-integration` sequentially: a legacy OAuth callback fixture uses a fixed port. Self-contained reload and diagnostic smoke coverage: `./scripts/smoke.sh smoke_selective_reload`. Performance fixtures and measured baselines are in [docs/performance.md](docs/performance.md).