CLI reference
The CLI ships as a single self-contained binary, mcppipe, with two
subcommands: up and detect.
mcppipe [GLOBAL OPTIONS] <up|detect> [OPTIONS]See Install for how to get the binary, and the Quickstart for an end-to-end walkthrough.
Global options
Section titled “Global options”These apply to every subcommand.
| Flag | Environment variable | Default | Description |
|---|---|---|---|
--broker <URL> | MCPPIPE_BROKER | ws://127.0.0.1:7100 | WebSocket URL of the mcppipe service. |
--api-key <KEY> | MCPPIPE_API_KEY | — | The tunnel’s CLI key (mtk_…), created in the dashboard. |
-v, -vv, -vvv | RUST_LOG | info | Increase log verbosity. Default logs at info; -v adds debug logging for the CLI itself; -vv enables debug globally; -vvv enables trace. An explicit RUST_LOG takes precedence. |
--no-update-check | MCPPIPE_NO_UPDATE_CHECK | off | Disable the background “newer release available” check. |
--no-telemetry | MCPPIPE_NO_TELEMETRY | off | Disable crash/error reporting (Sentry). Nothing is sent off-machine. |
--version | — | — | Print the version and exit. |
--help | — | — | Print help and exit. |
Telemetry banner
Section titled “Telemetry banner”mcppipe up prints its telemetry posture as the very first line, before any
other output:
- Default:
· crash reports enabled (opt out: --no-telemetry or MCPPIPE_NO_TELEMETRY=1) - With
--no-telemetry:· crash reports disabled
Crash reporting only sends panic/error reports; it never streams MCP traffic.
mcppipe up
Section titled “mcppipe up”Start a tunnel that forwards to one or more local MCP servers.
mcppipe up [--upstream <URL>]... [--stdio "<CMD>"]... [--upstreams-file <PATH>] \ [--name <NAME>] [--config <PATH>]... [--metrics-addr <ADDR>] \ [--inspect] [--inspect-addr <ADDR>] [--inspect-admin]| Flag | Environment variable | Description |
|---|---|---|
--upstream <URL> | — | Forward to a local HTTP (Streamable HTTP) MCP server. Repeatable for multi-upstream layouts (see below). |
--stdio "<CMD>" | — | Spawn a stdio MCP server and bridge it. Shell-style, supports quotes, e.g. --stdio "npx -y @modelcontextprotocol/server-filesystem .". Repeatable. |
--upstreams-file <PATH> | — | Load a multi-upstream layout from a TOML file. Conflicts with --upstream / --stdio. |
--name <NAME> | — | Friendly name for the tunnel, shown in the dashboard and used as the config-snippet entry name. |
--config <PATH> | — | Force auto-detect to read this config file. Repeatable; bypasses the well-known-paths scan. |
--metrics-addr <ADDR> | MCPPIPE_METRICS_ADDR | Bind a Prometheus listener at HOST:PORT serving /metrics and /healthz. Off by default. |
--inspect | — | Start the local web inspector on 127.0.0.1:4040 (falls back to a free port if taken). Shows live MCP JSON-RPC traffic and lets you replay a call. Off by default; the URL (with a one-time token) is printed at startup. |
--inspect-addr <ADDR> | MCPPIPE_INSPECT_ADDR | Override the inspector bind address (implies --inspect). Bind loopback-only unless you know what you’re doing. |
--inspect-admin | MCPPIPE_INSPECT_ADMIN | Enable the inspector’s Config tab — edit, apply (reconnect), and save your upstreams live. Implies --inspect. Off by default; the mutation routes don’t exist without it. |
| — | MCPPIPE_INSPECT_TOKEN | Use a fixed inspector token instead of a fresh random one — handy for a stable bookmarkable URL. |
Choosing an upstream
Section titled “Choosing an upstream”The CLI works out where to send traffic from the flags you pass:
- No
--upstream/--stdio/--upstreams-file— the CLI auto-detects MCP servers configured in local clients (Claude Desktop, Cursor, Windsurf, VS Code, Cline, Continue.dev, Zed). In an interactive terminal it prompts you to pick; see auto-detection below. - Exactly one
--upstreamor one--stdio— single-upstream mode. These two are mutually exclusive in the one-upstream case; the bare value (noname=prefix) is forwarded directly. - Two or more
--upstream/--stdioflags (mixed is fine) — multi-upstream aggregator mode. Each flag must usename=valuesyntax, e.g.--upstream brave=http://127.0.0.1:3001 --stdio fs="npx ... server-filesystem .". Names must be unique and match^[a-z][a-z0-9_-]{0,31}$. See the aggregator guide for how tools/prompts get prefixed.
A one-entry --upstreams-file collapses to the single-upstream fast path
automatically.
Multi-upstream TOML layout
Section titled “Multi-upstream TOML layout”--upstreams-file <PATH> loads a TOML file with one section per upstream, each
setting http xor stdio:
[upstreams.filesystem]stdio = "npx -y @modelcontextprotocol/server-filesystem ."
[upstreams.brave]http = "http://127.0.0.1:3001"The CLI rejects the file if a section sets both transports, sets neither, has no
[upstreams.*] sections, uses an invalid name, or repeats a name.
What up prints
Section titled “What up prints”On a fresh connection the CLI prints the public URL, the upstream it forwards to, and a paste-ready JSON snippet for your remote MCP client:
{ "mcpServers": { "mcppipe": { "url": "https://<subdomain>--<account-slug>.<zone>/mcp" } }}The entry name defaults to mcppipe; if you pass --name, the key becomes
<name>-via-tunnel (with any unsafe characters replaced by -). VS Code wraps
the same block under "mcp": { "servers": { ... } }. The endpoint path is
always /mcp over Streamable HTTP, with no interstitial page on any tier. After
a reconnect that resumes the prior session, the snippet is not reprinted.
Behavior on an invalid key
Section titled “Behavior on an invalid key”If mcppipe rejects the API key, the CLI prints authentication failed with a
hint to check --api-key / MCPPIPE_API_KEY, and exits with a non-zero
status. It does not retry — an invalid key never becomes valid. Any other
transient failure (network blip, service restart) reconnects with exponential
backoff (1s up to 30s).
Graceful shutdown
Section titled “Graceful shutdown”On SIGTERM (Unix; sent by docker stop and Kubernetes pod termination) or
Ctrl-C, the CLI says goodbye, drains in-flight requests, and exits cleanly so
rolling updates don’t drop calls. A signal during reconnect backoff exits
promptly. The in-flight drain is bounded by MCPPIPE_DRAIN_GRACE_SECS
(default 10 seconds); after it elapses the connection closes even if a handler
is still running, so set it at or below your orchestrator’s termination grace
(for example Kubernetes terminationGracePeriodSeconds). See
Reliability for the session resume and shutdown details.
Prometheus metrics
Section titled “Prometheus metrics”With --metrics-addr 127.0.0.1:9090, the CLI binds a tiny HTTP/1.1 listener
serving GET /metrics (text exposition) and GET /healthz (ok). The counters
describe aggregator behavior — upstream recoveries/failures, fan-out, */list
snapshot hits, unknown-prefix errors, and id-rewriter evictions. If the bind
fails, traffic forwarding keeps running and a warning is logged.
mcppipe detect
Section titled “mcppipe detect”List MCP servers configured in local clients without exposing anything. Useful for sanity-checking what the auto-detect prompt would offer, or for piping into scripts.
mcppipe detect [--config <PATH>]... [--json]| Flag | Description |
|---|---|
--config <PATH> | Read this config file instead of scanning well-known paths. Repeatable. |
--json | Print machine-readable JSON instead of a formatted list. |
The JSON entries include each server’s name, the source client it was found
in, and the transport (stdio with command/args/env, or http with
url).
Auto-detection
Section titled “Auto-detection”Both up (with no upstream flags) and detect scan the well-known config
locations for Claude Desktop, Cursor, Windsurf, VS Code, Cline, Continue.dev and
Zed (plus workspace-local .cursor/mcp.json and .vscode/mcp.json). Files that
don’t exist are skipped; files that exist but fail to parse log a warning and
are skipped — detection never aborts the binary.
When up auto-detects:
- One server found — exposed directly.
- Several found, interactive terminal — you’re asked whether to expose one (single-upstream) or aggregate several (multi-upstream), then pick.
- Several found, no TTY (CI/Docker) — all of them are aggregated and a
warning is logged so you can switch to explicit
--upstream name=urlflags if the auto-picked set is wrong.
Detected names are sanitized into valid aggregator names (lowercased,
non-[a-z0-9_-] replaced with -, __ collapsed, prefixed srv- if needed,
truncated to 32 chars).
stdio bridge supervision
Section titled “stdio bridge supervision”--stdio spawns the MCP server as a child process and supervises it:
- If the child exits, it’s restarted with exponential backoff (500ms up to 10s). A child that survives 2s is treated as healthy and the backoff resets.
- If the child crashes (or fails to spawn) 3 times in a row within the
stable-runtime window, the CLI prints a one-time crash hint showing the
command and the last captured stderr line (usually the real cause — a missing
env var,
command not found, etc.). - On Windows, bare names like
npx/pnpm/yarnare resolved viaPATH+PATHEXT;.cmd/.batshims are launched throughcmd /C.
If an HTTP upstream is unreachable, the remote MCP client gets a synthetic 502
whose body names the URL and the underlying cause.
Examples
Section titled “Examples”# Expose a local HTTP MCP servermcppipe up --api-key mtk_xxx --upstream http://127.0.0.1:3000
# Bridge a stdio MCP servermcppipe up --api-key mtk_xxx --stdio "python my_server.py"
# Aggregate several upstreams behind one tunnel (name=value required)mcppipe up --api-key mtk_xxx \ --upstream brave=http://127.0.0.1:3001 \ --stdio fs="npx -y @modelcontextprotocol/server-filesystem ."
# Load a multi-upstream layout from a filemcppipe up --api-key mtk_xxx --upstreams-file tunnel.toml
# Auto-detect and pick interactivelymcppipe up --api-key mtk_xxx
# Expose with Prometheus metrics on :9090mcppipe up --api-key mtk_xxx --upstream http://127.0.0.1:3000 \ --metrics-addr 127.0.0.1:9090
# Just list what is configured locallymcppipe detect --json
# Verbose logs, update + crash reporting offmcppipe -vv --no-update-check --no-telemetry \ up --api-key mtk_xxx --upstream http://127.0.0.1:3000