Troubleshooting
Most problems fall into two buckets: the CLI cannot connect, or mcppipe refuses a request with a 401/402/403/404/429. This page is the map; each error has its own page with the exact message, every cause, and the fix.
Most refusals carry a machine-readable JSON body, and tool-call refusals arrive as a JSON-RPC error envelope. Two do not — an operator suspension and a routing 404 answer as plain text — so error handling should branch on the status code before it tries to parse a body.
Error reference
Section titled “Error reference”| You saw | Page |
|---|---|
authentication failed (CLI exits) | CLI: authentication failed |
session_limit — too many concurrent sessions | session_limit |
401 with a WWW-Authenticate challenge | 401 invalid_token |
403 — ip_forbidden, tool_denied, tool_pin_violation, suspended | 403 forbidden |
404 — no tunnel found / no tunnel registered | 404 no tunnel found |
429 — ip_rate_limited, rate_limited, or plan quota | 429 rate limited |
402 when creating a tunnel | 402 plan limit |
The tunnel will not connect
Section titled “The tunnel will not connect””authentication failed”
Section titled “”authentication failed””mcppipe rejected your API key. The CLI prints authentication failed and exits — it does not retry, because an invalid key never becomes valid. Check the --api-key value (or MCPPIPE_API_KEY); it starts with mtk_, and rotating a key invalidates the old one immediately.
Full causes and fixes: CLI: authentication failed.
”session_limit” — concurrent session cap reached
Section titled “”session_limit” — concurrent session cap reached”Your key was accepted, but the tunnel is already at its plan’s concurrent-session cap (Free 3 / Pro 10 / Scale 25). The arriving connection is refused and the running sessions are left alone — never a silent displacement. A resume does not count against the cap.
Full causes and fixes: session_limit.
It hangs without printing a subdomain
Section titled “It hangs without printing a subdomain”The CLI connected but never received mcppipe’s Welcome. Re-run with -v (or -vv) to see the handshake, and confirm the control-plane endpoint your --broker / MCPPIPE_BROKER value points at is reachable. The ws://127.0.0.1:7100 default is local-dev only; against the hosted service this must be the mcppipe broker’s wss:// URL. See CLI reference.
Dropped sessions and reconnects
Section titled “Dropped sessions and reconnects”A flaky network is expected, not an error. The CLI keeps a session alive across short outages:
- It sends an application-level heartbeat every 25s; mcppipe drops the session only after 35s of silence.
- On a drop the CLI reconnects with exponential backoff (1s → 30s) and resumes the same session — mcppipe replays buffered frames that were in flight, so a tool call is not silently lost.
- A dropped session can be resumed for up to 60s before it is cleaned up.
If reconnects are constant, the link itself is the problem — see Network restrictions below.
Auto-detect found nothing, or the wrong server
Section titled “Auto-detect found nothing, or the wrong server”mcppipe up with no --upstream/--stdio scans the configs of Claude Desktop, Cursor, Windsurf, VS Code, Cline, Continue.dev, and Zed.
- See exactly what it finds:
mcppipe detect(add--jsonfor raw output). - Nothing detected? Point at a config file explicitly with
--config <path>, or skip detection entirely with--upstream <url>/--stdio "<cmd>". - In a non-interactive shell (CI, containers) with several servers detected, the CLI aggregates them headlessly instead of prompting. Pass
--upstream/--stdio(repeatable) or--upstreams-file <path>to be explicit. See Multi-upstream aggregation.
stdio bridge problems
Section titled “stdio bridge problems”When you use --stdio, the CLI spawns the command as a subprocess.
- Command not found — on Windows,
npx/pnpm/yarnare.cmdshims; the CLI resolves those automatically. For other tools, make sure the program is on yourPATH. - The server crashes — the CLI auto-restarts it with backoff. Repeated crashes within 2s escalate the delay. The server’s stderr is logged at
warnlevel; run with-vto see it. - Garbled output — anything the server writes to stdout that is not a single line of JSON is logged and discarded; it does not corrupt the protocol.
Network restrictions
Section titled “Network restrictions”The CLI only ever makes one outbound connection — a WebSocket to mcppipe. It never listens for inbound connections, so you do not need to open a port or touch your router.
- If outbound WebSocket traffic is blocked by a corporate proxy or firewall, the tunnel cannot connect. WebSocket runs over HTTPS (port 443) in production.
- The update check makes one extra outbound request to the GitHub API. Disable it with
--no-update-checkif egress is locked down.
The agent gets a 401, 403, 404, or 429
Section titled “The agent gets a 401, 403, 404, or 429”These come from mcppipe, not the CLI — the tunnel is up but the service refused the request before (or instead of) forwarding it. Which gate fired, in the order they run:
- Per-IP rate limit →
429ip_rate_limited. Service-wide, not yours to configure. - Routing →
404if no tunnel answers for that host. - Suspension →
403, plain text. - IP allowlist →
403ip_forbidden. Runs before auth and quota, so a blocked address never spends your auth budget or moves your counters. - OAuth →
401invalid_token, with an RFC 9728 pointer to where a token comes from. Only on tunnels in OAuth auth mode. - Quota →
429withplanandupgrade_url. - Tool policy, pinning, per-tool rate limits →
403/429as a JSON-RPC-32000envelope with apolicy_code.
Each has a page with the exact response body and every cause: 401 · 403 · 404 · 429
Creating a tunnel fails with 402
Section titled “Creating a tunnel fails with 402”Creating a tunnel over your plan’s tunnel cap returns 402 Payment Required. Caps are Free 2 / Pro 5 / Scale 20, and a deleted tunnel keeps its slot during its 7-day recovery window — which is usually why deleting one does not free space immediately. See 402 plan limit.
Custom domain not verified yet
Section titled “Custom domain not verified yet”Before mcppipe routes a custom domain (or requests an ACME certificate), you must prove ownership with a DNS TXT record:
- Publish a TXT record at
_mcppipe-challenge.<your-domain>with the token shown in Settings → Custom domain, then click Verify. - While the record is missing or not yet propagated, verification stays
pendingand the domain does not route. - A
503“DNS lookup failed; try again” means the resolver could not be reached — retry; it is not a record problem.
Also confirm the domain’s CNAME points at the target zone: <subdomain>--<slug>.cname.<zone>. See Custom domains & TLS.
Certificate stuck on “pending”
Section titled “Certificate stuck on “pending””After ownership is verified, an ACME (Let’s Encrypt) certificate is requested and its status moves from pending to active. If it stays pending:
- ACME uses an HTTP-01 challenge — make sure the custom domain’s CNAME is in place and resolves to the service so the challenge can be served.
- Check the cert status widget in Settings; a
last_erroris surfaced there. - If you would rather not use ACME, upload your own PEM (cert + key); an uploaded certificate is stored as
activeimmediately. See Custom domains & TLS.
Getting more detail
Section titled “Getting more detail”Raise CLI log verbosity with -v (info), -vv (debug), or -vvv (trace), or set RUST_LOG directly. Logs go to stderr, so they never corrupt protocol output. For server-side gates, the JSON error/error_description (or JSON-RPC data.policy_code) on the response tells you which check fired.
Still stuck? Email support@mcppipe.dev with the -vv output and the response body.