Connect MCP to Claude.ai and ChatGPT
Publish a private endpoint, check its OAuth flow, then connect your tools.
Install tunn and Python 3. Save the echo example as echo.py in your working directory; it returns your message without file or network access.
Experimental: connections to Claude.ai and ChatGPT have not yet been verified end to end. You need an account that supports custom MCP connectors.
1. Publish
tunn logintunn mcp --tools echo -- python3 ./echo.pyKeep this terminal running. Copy its exact Connector URL, including /mcp. MCP is private by default. Use --name work-tools to request a stable name and --allow colleague@example.com to let that verified user approve access. Name protection and quotas depend on your plan; see current pricing and tunn usage.
Alternative to the echo command: for your own stdio server, list its exact tool names:
tunn mcp --tools status,search -- ./my-mcp-serverAlternative to the echo command: for an existing Streamable HTTP server:
tunn mcp http://127.0.0.1:3000/custom-mcp-pathtunn remaps public /mcp to the supplied HTTP path. --tools filters stdio tools only; HTTP upstreams enforce their own tool permissions.
2. Check
Open a second terminal on the same machine. Leave the publishing command running in the first terminal.
Replace https://your-name.tunn.to/mcp in both checks with the printed Connector URL, including /mcp. The default check verifies HTTPS, the private challenge, the exact resource, OAuth metadata and public-client S256 PKCE without registering a client.
tunn connector-check https://your-name.tunn.to/mcpFor the echo example, verify consent, initialization, the exact tool list, an allowed call and a denied call:
tunn connector-check --oauth --expect-tools echo --call-tool echo --arguments '{"message":"hello"}' --deny-tool hidden_echo https://your-name.tunn.to/mcpOpen the printed browser link on this machine. Sign in as the owner or an allowed user and approve tunn connector-check for the named tunnel. Expect PASS for discovery, OAuth, tools and both probes. Tokens stay in memory. --json produces a final structured report; the consent link goes to stderr. The default overall deadline is three minutes; --timeout permits up to ten minutes.
No tool is called unless explicitly chosen. Both probes must be harmless even if your policy is broken. The denied probe requires tunn's -32001 stdio policy error; an arbitrary upstream error does not prove filtering.
3. Connect
Claude.ai
Open Customize → Connectors and add a custom connector with the printed URL. Organization setup may need an owner. Choose OAuth and Register automatically if prompted; tunn supports dynamic registration (DCR), not published-client identity. Sign in to tunn, review the client and tunnel, and approve access. Enable the connector for a conversation and ask it to call echo with message=hello; inspect the tool result.
Official Claude connector instructions, accessed October 12, 2026.
ChatGPT
Go to Plugins → Add custom MCP server. Enter the printed HTTPS /mcp URL and choose OAuth with dynamic registration when available. Review the risk warning, create the plugin, install it and select it with @ in a new chat. Complete tunn consent and request the same echo call. This endpoint requires authentication for initialization and listing too; choose OAuth for the entire connection.
Official OpenAI connection instructions and OAuth and DCR requirements, accessed October 12, 2026. If the account cannot select DCR, record that failure; tunn does not implement CIMD or static OAuth client provisioning.
4. Revoke
Open Connected MCP clients on your relay as the owner. Disconnect tunn connector-check after diagnosing. Disconnect Claude or ChatGPT to revoke that client's current tokens and pending consent/codes for this tunnel. Try another hosted call: it must fail or require fresh approval. Remove the connector in the hosted client when finished.
Access tokens expire after one hour. Clients with refresh enabled receive a single-use refresh token; each refresh issues a new one, up to 30 days after consent. After that, sign in and approve access again. Clients without refresh must sign in again when their access token expires. Rotating a manual endpoint token does not revoke OAuth grants.
Diagnose failures
| Signal | Next action |
|---|---|
url, local_url | Copy the public printed HTTPS /mcp URL. Hosted clients cannot reach localhost or private addresses. |
dns, tls, network | Check DNS, trusted relay certificates, your clock and proxy/firewall connectivity. |
public, metadata_challenge, redirect | Publish privately at the exact /mcp URL. Its initial 401 Bearer resource_metadata challenge is expected. |
resource, issuer, origin, endpoint, pkce | Self-hosters: correct the relay public origins and OAuth metadata. The exact resource must match throughout; public clients need S256. |
401/403, state, denied | Restart consent with automatic registration; sign in as owner or an allowed verified email and approve the named tunnel. |
| 429 | Respect Retry-After. Check tunn usage for owner request/byte budgets; registration throttling requires waiting. |
| 404/405/502 | Keep the publisher and child running. Check the executable, stderr, port and MCP path. Upstreams must support POST; standalone GET/SSE is optional. |
| 503 | Retry with the publisher connected. Self-hosters: verify authenticated login-node, durable SQLite, JWT signing and shared grant authority configuration. |
504, timeout | Finish consent before the check deadline. Keep stdio calls below 25 seconds; forwarding expires at 27 seconds. Long work should return a job ID. |
tools_mismatch, tool_exposed, denial_unproven | Correct exact stdio --tools names; HTTP upstreams enforce their own policy. Unknown-tool errors do not prove denial. |
protocol, json, rpc, tool_schema, tool_error, pagination | Check upstream MCP version, framing, metadata, arguments and stderr. Reinitialize after a lost session. |
Protocol limits
The stdio bridge serializes calls through one child shared across clients. It supports current MCP versions, JSON and finite SSE POST responses. Standalone GET/SSE, stream resumption, sampling/elicitation and separate child processes per client are unavailable. Browser consent forms expire after ten minutes. Diagnostic responses are capped at 1 MiB and tool listing at 16 pages; large lists should be reduced.
Self-hosted OAuth requires an authenticated owner account, JWT signing, durable login-node SQLite and a shared grant ledger. Keep normal TLS and authorization checks enabled. For the endpoint contract, see protocol reference.
For HTTP MCP upstreams, tunn sends the upstream host as Host and the public host as X-Forwarded-Host; use --keep-original-host to preserve the public Host.