Model or dataset
openai/tunnel-client avatar
openai/tunnel-client

openai/tunnel-client: connect a private MCP server to ChatGPT and Codex

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.

512 stars99 forksGoApache-2.0

At a glance

What is it?
A Go daemon plus SDK that keeps your MCP server off the public internet while an OpenAI-hosted tunnel endpoint reaches it. The Homebrew path is the only supported install on macOS.
Who is it for?
Adopt tunnel-client if you run an MCP server on a laptop, VM or cluster and security will not approve an inbound firewall rule or a public endpoint, and you are already inside the OpenAI products listed in the README. Do not adopt it if your MCP server already has a reachable HTTPS endpoint, or if you want a protocol-neutral tunnel: this client speaks to an OpenAI-hosted tunnel endpoint, and its documentation set is written for that path.
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 September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The inbound firewall rule you cannot get approved

Most MCP servers start life on a laptop or inside a private network. The moment you want ChatGPT, Codex, the Responses API or AgentKit to call a tool on that server, the conventional answer is to give the server a public endpoint or open an inbound rule. That is exactly the change security teams reject, and it is the problem tunnel-client exists to solve.

The README frames the intended user narrowly. You have an MCP server on a laptop, a VM, a Kubernetes cluster or a private network, and you need an OpenAI-hosted product to reach it. Security will not approve a new inbound firewall rule or a public endpoint for the MCP server. You also want an operator-visible daemon with /healthz, /readyz, /metrics and /ui before a connector or API call depends on it. All three conditions describe the same operator: someone wiring an internal tool into an OpenAI product without changing the network posture of the machine that hosts it.

The client is customer-run by design. It is the agent behind Secure MCP Tunnel, and it dials out to an OpenAI-hosted MCP tunnel endpoint rather than waiting for inbound connections. The README states that the MCP server stays off the public internet. That single direction of travel is the whole point of the project, and it is why the README tells you to start with tunnel-client help quickstart rather than with a firewall diagram.

How the daemon, the control plane and the MCP server fit together

There are three moving parts. Your MCP server is the thing with the tools. The tunnel-client process is the customer-run agent. The OpenAI-hosted tunnel endpoint is the other side of the connection, and it is what ChatGPT, Codex, the Responses API and AgentKit talk to.

The client can run in two shapes. As a standalone process it is a foreground daemon started with tunnel-client run, or a long-lived managed runtime started with tunnel-client runtimes connect. As a library it runs inside the same Go process as your MCP server. The README describes the embedded case precisely: the MCP server does not need to bind a port or use stdio, because you hand the server side of an in-memory MCP transport pair to your server and the client side to tunnelclient.New. The MCP SDK's in-memory transport carries the traffic, and tunnelclient.Config takes a TunnelID and an APIKey.

The Go module is github.com/openai/tunnel-client and it depends on github.com/modelcontextprotocol/go-sdk v1.7.0, so the embedded path uses the same SDK the server side does. The repository also ships a bundled Cloudflare companion, documented in docs/deployment/cloudflared.md, which suggests the network path can be composed with cloudflared rather than replaced by it. The README does not spell out the full data flow at the byte level; for that it points to docs/protocol.md and docs/openapi.json for anyone building a compatible client in another language. If you need to know what crosses the wire, those two files are the source, not the README.

Installing on macOS with Homebrew and running the first check

On macOS, Homebrew is the supported installation path. The README is explicit that directly downloaded release ZIPs are not currently notarized and can be blocked by Gatekeeper, and it warns against using xattr, spctl or Open Anyway to bypass the check. Install from the official OpenAI tap instead:

bash
brew install openai/tools/tunnel-client

The Formula installs the matching tunnel-client, a bundled cloudflared, and a companion manifest together, while exposing only the tunnel-client command. That last detail matters if you expected to call cloudflared directly after installing.

Verify the installed version, then start the guided setup:

bash
tunnel-client --version
tunnel-client help quickstart

The README says to start with the quickstart output if you searched for phrases like "secure MCP tunnel" or "connect local MCP server to Codex". It then points at docs/onboarding.md for the shortest working path from a localhost or private MCP server to ChatGPT or Codex.

For a long-lived local runtime, the README prefers the managed runtime over a backgrounded shell process:

bash
tunnel-client runtimes connect ...
tunnel-client runtimes status <alias>

Do not use nohup or disown as the supervision path. After runtimes connect, check status before reporting success, and only report success when status shows the managed runtime running with health reported. Add --json when you need the explicit process_running, healthy and ready fields. For Docker, Kubernetes or VM deployments, the README defers to docs/deployment/overview.md.

Embedding the client in a Go process instead of running a daemon

The embedded path is the most interesting design choice in the repository, and the README gives a complete example. Fetch the module first:

bash
go get github.com/openai/tunnel-client

Then construct an MCP server, create an in-memory transport pair, run the server on one side and hand the other side to tunnelclient.New:

go
ctx := context.Background()
server := mcp.NewServer(&mcp.Implementation{Name: "my-server", Version: "1.0.0"}, nil)
serverTransport, tunnelTransport := mcp.NewInMemoryTransports()
go server.Run(ctx, serverTransport)

client, err := tunnelclient.New(tunnelclient.Config{
    TunnelID: "tunnel_0123456789abcdef0123456789abcdef",
    APIKey:   apiKey,
}, tunnelTransport)
if err != nil {
    return err
}
return client.Run(ctx)

The runnable example lives at examples/go-sdk-inmemory and registers an echo tool connected to the OpenAI Tunnel control plane. Note what disappears in this mode: no listening port, no stdio plumbing, no separate process to supervise. If your MCP server is already a Go program, this removes an entire deployment artifact.

If it is not a Go program, the repository also carries examples/python-mcp-tunnel-client-proxy and examples/typescript-mcp-tunnel-client-proxy, which the README does not describe in detail. Treat those two directories as the starting point for reading rather than as documented products. The README says nothing about their supported status.

Where tunnel-client is the wrong tool

The first limitation is scope. tunnel-client connects to an OpenAI-hosted MCP tunnel endpoint. It is not a general-purpose tunnel, and the README does not present it as one. If your MCP server already has a reachable HTTPS endpoint, or if the consumer of your tools is not ChatGPT, Codex, the Responses API or AgentKit, this client adds a daemon and a control plane for nothing.

The second is the macOS install story. Homebrew is the supported path, and the README explicitly says directly downloaded release ZIPs are not currently notarized. That is a real constraint for air-gapped or locked-down Mac fleets where adding a Homebrew tap is itself a review item. The README does not describe a notarized manual install, so do not assume one exists.

The third is supervision. The README warns against nohup and disown and directs you to tunnel-client runtimes connect for a long-lived runtime managed by Codex. If your environment already has its own process supervisor and you intended to wrap tunnel-client in it, the documentation does not cover that arrangement, and docs/deployment/overview.md is where you would have to check whether it is supported.

Finally, the release history is early. The most recent release in the repository is v0.0.14, published on 2026-09-01, preceded by v0.0.13 on 2026-08-26 and v0.0.13-dev on 2026-08-20. A 0.0.x version line means interfaces can move. The last push to the repository was on 2026-09-14, so the project is being worked on, but the version number is the honest signal about API stability.

How this differs from a Cloudflare tunnel or an SSH tunnel

The related searches around this project include "cloudflare tunnel client download" and "ssh tunnel client", which is a reasonable place to draw the comparison, because both alternatives move traffic without opening an inbound port, and both stop short of what tunnel-client does.

An SSH tunnel gives you a port forward. You still need something on the far end that speaks the MCP protocol to your server, and you still need to manage keys, host configuration and the lifetime of the forwarding process. It is a transport, not an integration.

Cloudflare Tunnel is closer, and the relationship here is not purely competitive: the Homebrew Formula installs a bundled cloudflared alongside tunnel-client, and docs/deployment/cloudflared.md documents a bundled Cloudflare companion. The difference is what sits on top. Cloudflare's client publishes a service to the network. tunnel-client carries MCP semantics, registers with an OpenAI Tunnel control plane, and exposes an operator surface with /healthz, /readyz, /metrics and /ui. It also has the embedded Go SDK path, where no network hop exists at all between the server and the client library.

If you want a general ingress layer for many services, Cloudflare Tunnel is the broader tool. If you want an MCP server reachable by ChatGPT or Codex with health, readiness and metrics built in, tunnel-client is the narrower and more direct one. The README does not claim feature parity with either alternative, and it does not benchmark against them.

Maintenance cost, licensing and what to check before you commit

The licence is Apache-2.0, and the repository carries both a LICENSE and a NOTICE file, which is the normal pairing for that licence. Apache-2.0 permits commercial use and modification and includes a patent grant. The NOTICE file may carry attribution obligations you need to pass along if you redistribute the binary. That is a description of the files present, not legal advice; your own counsel should read the NOTICE before you ship a modified build.

Upgrade cost depends on how you consume it. The Homebrew Formula installs tunnel-client, cloudflared and the companion manifest as a matched set, so brew upgrade keeps those three in step and you do not have to reconcile versions yourself. The Go SDK path is a normal module dependency: go get github.com/openai/tunnel-client and your build picks up the new version, which also means a breaking change in tunnelclient.Config or the client's Run behaviour lands at your next dependency bump. Pin the version if you embed it.

The operator surface is the part that costs ongoing attention. The README positions /healthz, /readyz, /metrics and /ui as things to have before a connector or API call depends on the daemon, so whatever monitoring you already run should be pointed at those endpoints. The README does not document rollback, and it does not describe a downgrade procedure, so plan your upgrade window accordingly.

One practical note on the repository layout: there is a package.json at the top level pinning Node 22.23.2 and [email protected], and the Makefile builds an admin UI from adminui/ into pkg/adminui/assets. That is build machinery for the /ui surface, not something an operator installs. If you build from source rather than from Homebrew, expect a Go 1.27.0 toolchain, a Node 22 toolchain and pnpm to be present.

Editorial conclusion

Adopt tunnel-client if you run an MCP server on a laptop, VM or cluster and security will not approve an inbound firewall rule or a public endpoint, and you are already inside the OpenAI products listed in the README. Do not adopt it if your MCP server already has a reachable HTTPS endpoint, or if you want a protocol-neutral tunnel: this client speaks to an OpenAI-hosted tunnel endpoint, and its documentation set is written for that path. Before rollout, verify three things on your own infrastructure: that tunnel-client runtimes status <alias> reports a managed runtime running with health reported, that the /healthz, /readyz, /metrics and /ui endpoints answer on the operator port you configured, and that your organisation has the tunnel ID, runtime API key and admin API key that docs/permissions.md requires.

Frequently asked questions

How do I install openai/tunnel-client on macOS?

Homebrew is the supported installation path. Run brew install openai/tools/tunnel-client, then check the version with tunnel-client --version. The README warns that directly downloaded release ZIPs are not currently notarized and can be blocked by Gatekeeper.

Can tunnel-client connect a localhost MCP server to ChatGPT?

Yes. The README describes tunnel-client as connecting a private or localhost MCP server to ChatGPT, Codex, the Responses API and AgentKit through an OpenAI-hosted MCP tunnel endpoint, while keeping the MCP server off the public internet. It points to docs/onboarding.md for the shortest working path.

Can I embed tunnel-client in a Go program instead of running a daemon?

Yes. The module runs in the same process as a Go MCP server using the MCP SDK's in-memory transport, with the server side given to your server and the client side to tunnelclient.New. The runnable example is at examples/go-sdk-inmemory.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. openai/tunnel-client on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/openai-tunnel-client.svg)](https://hysenlabs.com/projects/openai-tunnel-client)