tunnel-client: the customer-run Go agent that lets ChatGPT and Codex reach an MCP server you never expose to the internet
Customer-run client for Secure MCP Tunnel: connect private or localhost MCP servers to ChatGPT, Codex, the Responses API, and AgentKit without exposing them to the public internet.
At a glance
- What is it?
- openai/tunnel-client is the Apache-2.0 Go client behind Secure MCP Tunnel. It runs next to a private or localhost MCP server and relays requests from an OpenAI-hosted tunnel endpoint, with a CLI, a Go SDK, and health and metrics endpoints.
- Who is it for?
- Use tunnel-client if you already have an MCP server on a laptop, VM or private network and need ChatGPT, Codex, the Responses API or AgentKit to call it without opening an inbound port. Do not treat it as a general tunneling tool, because it depends on an OpenAI-hosted endpoint, a runtime API key and a tunnel ID.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- openai/tunnel-client636 ★ · +250
| Repository | 2026-09-14 | 2026-11-13 |
|---|---|---|
| openai/tunnel-client | 386 | 636 |
250 Stars in the last 60 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
It only works with an OpenAI-hosted tunnel endpoint, not as a general tunnel
tunnel-client is the customer-run side of Secure MCP Tunnel. Applications call an OpenAI-hosted /v1/mcp/{tunnel_id} endpoint through their MCP transport, and the client running beside your private server receives those requests and returns the responses. The poll and response endpoints are described as the runtime's queue protocol for client implementers.
This means the tool has one purpose: it connects a private or localhost MCP server to ChatGPT, Codex, the Responses API and AgentKit. It cannot forward arbitrary TCP traffic or reach an MCP server on behalf of a client that is not one of those products. To run it you need a runtime API key and a tunnel ID issued by the service, so without an OpenAI account set up for tunnels there is nothing for the client to connect to.
The pitch is no inbound firewall rule, and the operator endpoints are healthz, readyz, metrics and ui
The README gives three reasons to use it. You have an MCP server on a laptop, VM, Kubernetes cluster or private network and need an OpenAI-hosted product to reach it. Security will not approve a new inbound firewall rule or public endpoint. And you want an operator-visible daemon with /healthz, /readyz, /metrics and /ui before a connector or API call depends on it.
The consequence of the second point is that the MCP server stays off the public internet and the only new exposure is the client process itself. The health endpoints exist so you can check readiness before anything depends on the connector. The docs folder has separate files for architecture, permissions, deployment and troubleshooting, so the trust-boundary story is meant to be shared with a security reviewer.
The embedded demo needs a real runtime API key and tunnel ID
You can try the client without your own MCP server. With a runtime API key and tunnel ID, the built-in server_info, echo and uppercase tools run from the client itself:
export CONTROL_PLANE_API_KEY="sk-..."
export CONTROL_PLANE_TUNNEL_ID="tunnel_0123456789abcdef0123456789abcdef"
tunnel-client run --embedded-stateless-mcp-stub --health.listen-addr 127.0.0.1:0The stateless stub issues no MCP session ID and its demo tools do not require session affinity between processes. The other flag, --embedded-mcp-stub, keeps its compatibility behavior: legacy initialization and session requests use stateful handling, and self-contained modern requests use stateless handling. Choose one embedded mode per run. OAuth and application state have separate requirements, so a passing demo does not prove your own server will behave the same way.
Tracing and request ID forwarding are opt-in or tunable, with caveats about the service side
Trace forwarding is disabled by default. Passing --mcp.forward-trace-context carries W3C trace context in MCP params._meta over stdio and Streamable HTTP, and local span export is switched on with --tracing.enabled and --tracing.file. The README adds that complete traces require compatible service queue handoff and caller parent propagation first, so enabling the flags on your side does not by itself give you an end-to-end trace.
Request ID forwarding for MCP HTTP is enabled by default. The setting --forward-request-id accepts mcp,harpoon to include Harpoon REST requests, mcp,oauth to include eligible queued OAuth discovery requests, and none to turn automatic forwarding off. The same setting is available as FORWARD_REQUEST_ID or as top-level YAML forward_request_id.
The Go SDK runs the tunnel inside your server process through an in-memory MCP transport
If your MCP server is written in Go, you do not need it to bind a port or use stdio. The module can run in the same process: one side of an in-memory MCP transport pair goes to your server and the other goes to tunnelclient.New. Install the module with:
go get github.com/openai/tunnel-clientThe example in the repository registers an echo tool and connects it to the OpenAI Tunnel control plane, and it lives in examples/go-sdk-inmemory. The repository also has proxy examples for Python and TypeScript. The Go route keeps the MCP server and the tunnel client in one process, so you deploy and restart them as a single unit.
Every release is 0.0.x and they land within days of each other
The recent releases are v0.0.19 on 2026-10-30, v0.0.18 on 2026-10-23 and v0.0.17 on 2026-10-21. The last push was on 2026-11-02. A zero major version with three releases in under two weeks is a reason to read the release notes before each upgrade, and to pin the version you deploy.
The README itself gives a sense of the churn. Server-directed polling placement is described in routing correction notes, where supporting clients work with existing services immediately and corrections are enabled separately after a client release. Response timing has its own release and rollback guidance in the configuration documentation. Treat these as moving parts you should check at upgrade time.
Building it yourself pulls in Go 1.27, a pnpm-built admin UI and a pinned Node version
go.mod declares Go 1.27 with toolchain go1.27.3, and the dependency list includes the MCP Go SDK, the OpenAI Go SDK, cobra, the AWS SDK v2 and OpenTelemetry packages. The Makefile builds three targets: tunnel-client, tunnel-client-runtime and tunnel-client-runtime-cloudflared. The admin UI in the adminui directory is built with pnpm, and package.json pins Node 22.23.3 and a pnpm version.
So a source build needs more than a Go toolchain. A Dockerfile and a Dockerfile.runtime are in the repository for container builds, and the Dockerfile builds the UI in a separate Node stage. If you only want to run the client, use a release rather than compiling it, and keep the build route for when you need to change the code.
Editorial conclusion
Use tunnel-client if you already have an MCP server on a laptop, VM or private network and need ChatGPT, Codex, the Responses API or AgentKit to call it without opening an inbound port. Do not treat it as a general tunneling tool, because it depends on an OpenAI-hosted endpoint, a runtime API key and a tunnel ID. Before you adopt it, remember that every release is still 0.0.x and that its Go 1.27 requirement affects building it yourself.
Frequently asked questions
What is tunnel-client?
tunnel-client is the customer-run agent behind Secure MCP Tunnel. It connects a private or localhost MCP server to ChatGPT, Codex, the Responses API and AgentKit through an OpenAI-hosted tunnel endpoint.
Does tunnel-client need an inbound firewall rule?
The README lists the case where security will not approve a new inbound firewall rule or public endpoint as a reason to use it. The MCP server stays off the public internet.
How do I embed tunnel-client in a Go MCP server?
Run go get github.com/openai/tunnel-client, then give one side of an in-memory MCP transport pair to your server and the other to tunnelclient.New. A runnable example is in examples/go-sdk-inmemory.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/openai-tunnel-client)Star history chart for your README
[](https://hysenlabs.com/projects/openai-tunnel-client)Was this useful?