Codex Can Reach Internal MCP Servers Through OpenAI Secure Tunnels
OpenAI Secure MCP Tunnel gives ChatGPT, Codex, Responses API, and AgentKit an outbound-only path to private MCP servers without public endpoints.
- What happened: OpenAI published
Secure MCP Tunnelsdocumentation and theopenai/tunnel-clientrepository.- ChatGPT, Codex, Responses API, and AgentKit can call the same private MCP server through this tunnel model.
- How it works: A customer-run
tunnel-clientkeeps an outbound HTTPS long-poll connection to OpenAI's tunnel service.- The MCP server stays on an internal URL without a public listener or inbound firewall rule.
- Operational impact: MCP reviews now move from model capability to runtime keys, OAuth reachability, logs, and tunnel lifecycle.
- Watch: The authorization server is not tunneled, and raw HTTP logging should stay disabled by default.
OpenAI has added Secure MCP Tunnels to its developer documentation and published the openai/tunnel-client repository on GitHub. The target is broader than a single ChatGPT connector. OpenAI describes the tunnel as a shared path for ChatGPT, Codex, Responses API, and AgentKit to call private MCP servers. When an internal tool is attached to an AI product, the review question is no longer just "where do we expose the MCP server?" It becomes "which OpenAI product is using which tunnel id, runtime key, and internal tool surface?"
Once MCP moves inside engineering teams, the first bottleneck is often networking rather than JSON-RPC schema design. Jira, GitHub Enterprise, code search, deployment approvals, data warehouses, and internal document search are rarely safe to place directly on the public internet. Before this pattern, teams mixed VPNs, reverse proxies, Cloudflare Tunnel, Tailscale, ngrok, and hand-written allowlists. OpenAI's new path narrows MCP calls from OpenAI products into an outbound-only tunnel operated from the customer network.
The architecture document is unusually explicit about the request path. A small agent called tunnel-client runs inside the customer network and keeps an outbound HTTPS connection to the OpenAI tunnel service. OpenAI products do not learn the customer's internal MCP URL directly. They call an OpenAI-hosted MCP tunnel URL, while the private MCP server address remains inside the tunnel-client configuration.
OpenAI Secure MCP Tunnel Request Flow
Receives /v1/mcp/{tunnel_id} requests
Source: request lifecycle and trust boundaries in openai/tunnel-client architecture.md.
The request lifecycle compresses into four steps. First, tunnel-client waits for work through GET /v1/tunnel/{tunnel_id}/poll. When an OpenAI product sends an MCP JSON-RPC request to POST /v1/mcp/{tunnel_id}, the tunnel service delivers that work to the client. The client forwards the request to the internal MCP server and returns the result through POST /v1/tunnel/{tunnel_id}/response. For streaming requests, intermediate JSON-RPC notifications can continue over SSE until the final JSON-RPC response closes the stream.
The first operational change is that the internal MCP server is not published. OpenAI's documentation says the MCP server does not need an inbound firewall rule or public listener. The internal URL remains in the client configuration, and the externally visible endpoint is the tunnel URL on OpenAI's tunnel service. That reduces exposure compared with directly placing an internal API on the internet, but it also makes OpenAI's tunnel service part of the control plane.
The default security posture is worth reading as product news. The architecture document says the tunnel path requires the client's control-plane API key, while the admin UI and log endpoint are loopback-only by default. Remote UI access requires --allow-remote-ui, and raw HTTP logging is disabled by default. MCP tool arguments and responses can contain tokens, customer data, internal URLs, and code references. In that context, raw logs are less a convenient debugging feature than a potential data leak path.
OpenAI's onboarding document also pushes teams toward key separation. CONTROL_PLANE_TUNNEL_ID comes from Tunnels management or admin commands, and CONTROL_PLANE_API_KEY is a runtime API key. OPENAI_ADMIN_KEY is reserved for management operations such as tunnel creation, updates, and deletion. A runtime key subject needs Tunnels Read and Use permissions, while a person or automation that creates and edits tunnels needs Read and Manage. Teams that drop one sk-... key into every step will need to revise their deployment process.
| Review area | Documented default | Operations question |
|---|---|---|
| Network | Client opens outbound HTTPS to OpenAI | Who owns proxies, CA bundles, and egress allowlists? |
| Permissions | Runtime key uses Read/Use, admin key manages tunnels | Are daemon keys separated from creation keys? |
| MCP server | HTTP, stdio, and in-memory bindings are supported | Which internal resources can each tool read or write? |
| Logs | Raw HTTP logging is disabled by default | Who can enable payload logs during incident response? |
| OAuth | Authorization headers and discovery pass through the tunnel | Can the authorization server be reached from both required sides? |
The Codex connection is especially sensitive. If a coding agent can call an internal MCP server, code search, build logs, issues, CI controls, and deployment workflows can all enter the same work loop. An outbound-only tunnel does not make tool permissions safe by itself. The risk level changes depending on whether the MCP server exposes read-only code search, PR creation, CI reruns, or deployment approval actions.
OpenAI's decision to place ChatGPT and Codex in the same documentation matters. If consumer-facing chat and developer agents use the same private MCP connection method, internal tools become organization-level resources rather than product-specific plugins. One team can attach document search to a ChatGPT connector, another can attach codebase tools to Codex, and a backend team can call the same MCP server from Responses API. At that point, tunnel ids, runtime keys, connector settings, and MCP routing become operational assets that need ownership.
OAuth-protected MCP shows both the advantage and the boundary of the approach. The onboarding document says the Authorization header passes through OpenAI's tunnel service to the MCP server, and OAuth discovery GET requests are executed by the client from the customer network. Protected Resource Metadata resource URLs and WWW-Authenticate values are rewritten to OpenAI tunnel-service endpoints. That allows the private MCP server to remain hidden while the OAuth flow keeps standard MCP semantics.
The authorization server itself is not tunneled. OpenAI's documentation warns that the OAuth flow can fail if the authorization server is not reachable from both the public internet and the tunnel-client host. If an internal identity provider is only available inside a VPN and the OpenAI product's OAuth redirect cannot reach it, the network design still needs work. Secure MCP Tunnel hides the MCP server; it does not relocate the entire authentication stack.
OpenAI describes three deployment patterns. The first is a Kubernetes sidecar in the same pod as the MCP server. The second is a dedicated Kubernetes Deployment that reaches the MCP Service through cluster DNS. The third is a VM or host service managed by systemd. A sidecar has good locality and a simple shape, but it ties MCP server upgrades to tunnel-client upgrades. A dedicated Deployment allows independent rollout, while service discovery and network policy need separate review. A VM or systemd service fits existing internal server operations, but secret delivery and process monitoring must be handled by the surrounding platform.
There are also performance and reliability hints in the architecture notes. Request and response traffic uses backpressure, and the client only takes as much queued work as it can handle. The runtime component description mentions a bounded in-memory queue, control-plane.max-inflight, and mcp.max-concurrent-requests. If an internal MCP server performs slow work such as database search or code-index queries, those values are not cosmetic tuning knobs. They determine both waiting time in OpenAI products and load on the internal system.
The first developer-facing commands are intentionally direct. OpenAI's onboarding path starts with tunnel-client help quickstart and tunnel-client help samples, then shows an embedded MCP stub that can bring up a daemon and readiness check immediately. For local environments with Codex installed, the documentation includes commands such as tunnel-client codex plugin install, tunnel-client runtimes list, and tunnel-client codex status.
tunnel-client help quickstart
tunnel-client run \
--embedded-mcp-stub \
--control-plane.tunnel-id tunnel_0123456789abcdef0123456789abcdef \
--health.listen-addr 127.0.0.1:0 \
--health.url-file /tmp/tunnel-client-health.url
curl -fsS "$(cat /tmp/tunnel-client-health.url)/readyz"
That example says a lot about the product direction. OpenAI is not treating MCP tunnels only as a networking primitive. It is wrapping the path in a local daemon, admin UI, Codex plugin, runtime listing, samples, and doctor-style commands. For platform teams, "we built an MCP server" is no longer the endpoint. They need to know which developer used which profile, which tunnel was attached, and which runtime key kept that path alive.
The comparison with Anthropic is hard to avoid. Anthropic has disclosed self-hosted sandboxes and MCP tunnels for Claude Managed Agents, also using an outbound-only path for internal tools. OpenAI's version focuses on tying the OpenAI product family into one tunnel-client model. Anthropic's story centers on the execution boundary for Managed Agents and the Messages API. OpenAI's front-and-center claim is that ChatGPT, Codex, Responses API, and AgentKit can share access to the same private MCP server.
The competitive set also includes network tools rather than only AI labs. Cloudflare Tunnel, Tailscale, and ngrok already give teams ways to connect private services to a public edge or identity-aware proxy. OpenAI Secure MCP Tunnel differs because it is specialized for MCP JSON-RPC and the call path from OpenAI products. That specialization can reduce setup work, but it also pulls the organization deeper into OpenAI's control plane.
Organizations evaluating this now have three concrete checks. First, split private MCP servers by write capability. If "search" and "deploy" sit behind the same tunnel, ChatGPT connector use and Codex agent work inherit a mixed risk profile. Second, separate runtime keys from admin keys and document which subject has Read, Use, and Manage permissions. Third, place raw payload logging in the incident response process, including who can enable it, when, and how it is turned off again.
Product teams get a different set of questions. Internal knowledge search in ChatGPT, code search in Codex, and business automation in an API agent can all converge on one MCP standard. That can make tool reuse easier. It can also make the user experience inconsistent if tool descriptions, permission prompts, audit events, rate limits, and failure responses diverge by product surface. Secure MCP Tunnel reduces the connection problem, but it does not automatically align approval copy or tool UX.
This is not a flashy model launch. For AI engineering teams, it may be more durable. Once a model can call internal tools, the adoption review shifts from "which model are we using?" to "which tunnel reaches which MCP server, which key keeps it alive, and which logs record the path?" OpenAI Secure MCP Tunnel turns that question into an official deployment unit inside the OpenAI platform.