Skip to content

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.

You sawPage
authentication failed (CLI exits)CLI: authentication failed
session_limit — too many concurrent sessionssession_limit
401 with a WWW-Authenticate challenge401 invalid_token
403ip_forbidden, tool_denied, tool_pin_violation, suspended403 forbidden
404no tunnel found / no tunnel registered404 no tunnel found
429ip_rate_limited, rate_limited, or plan quota429 rate limited
402 when creating a tunnel402 plan limit

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.

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.

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 --json for 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.

When you use --stdio, the CLI spawns the command as a subprocess.

  • Command not found — on Windows, npx/pnpm/yarn are .cmd shims; the CLI resolves those automatically. For other tools, make sure the program is on your PATH.
  • The server crashes — the CLI auto-restarts it with backoff. Repeated crashes within 2s escalate the delay. The server’s stderr is logged at warn level; run with -v to 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.

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-check if egress is locked down.

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:

  1. Per-IP rate limit429 ip_rate_limited. Service-wide, not yours to configure.
  2. Routing404 if no tunnel answers for that host.
  3. Suspension403, plain text.
  4. IP allowlist403 ip_forbidden. Runs before auth and quota, so a blocked address never spends your auth budget or moves your counters.
  5. OAuth401 invalid_token, with an RFC 9728 pointer to where a token comes from. Only on tunnels in OAuth auth mode.
  6. Quota429 with plan and upgrade_url.
  7. Tool policy, pinning, per-tool rate limits403/429 as a JSON-RPC -32000 envelope with a policy_code.

Each has a page with the exact response body and every cause: 401 · 403 · 404 · 429

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.

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 pending and 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.

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_error is surfaced there.
  • If you would rather not use ACME, upload your own PEM (cert + key); an uploaded certificate is stored as active immediately. See Custom domains & TLS.

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.