Mixing up Streaming HTTP protocol versions results in connection failures
What version of Codex is running?
codex-cli 0.47.0
What subscription do you have?
Plus
Which model were you using?
n/a
What platform is your computer?
Ubuntu WSL1
What issue are you seeing?
codex is not authenticating with some non-stdio MCP servers.
Take the rest with a grain of salt (Claude analysis of the server logs, and your github code):-
The Codex client is sending 2025-06-18 but appears to be expecting 2024-11-05 behavior (immediate close after endpoint event).
Based on the documentation from Context7 about the official rmcp SDK, and examining the Codex code:
🎯 Root Cause Analysis: Client Bug Confirmed
What I Found:
- The Official
rmcpSDK Documentation shows that for Streamable HTTP transport, the server should:
- Send SSE headers
- Send the
endpointevent - Then continue processing the initialize request synchronously and send the response via SSE
- Your Server is Correct: The logs show you're doing exactly that:
````
18:58:39 Streaming HTTP response... (SSE headers + endpoint event)
18:58:39 Processing initial request for session...
18:58:39 JSONRPC Request... method=initialize
18:58:39 Session FIN detected: SSL client closed connection gracefully
- The Codex Client Bug: Looking at the client code structure:
auth_status.rsline 21 uses"2024-11-05"for OAuth discovery- But the logs show the client sent
"protocolVersion":"2025-06-18"in the initialize request - This is the problem! The client is mixing protocol versions and may be expecting immediate JSON response instead of SSE-based response
The Protocol Version Mismatch:
From the MCP spec documentation you showed me earlier and the Context7 docs:
2024-11-05: Original spec where initialize response could be synchronous2025-06-18: New spec where Streamable HTTP uses SSE for all messages including initialize response
The Codex client is sending 2025-06-18 but appears to be expecting 2024-11-05 behavior (immediate close after endpoint event).
✅ Conclusion: This is 100% a Client Bug
Your server implementation is completely correct. The Codex client (codex-mcp-client v0.47.0) has a bug where it:
- Sends protocol version
2025-06-18 - Receives the SSE
endpointevent - Immediately closes the connection without waiting for the
initializeresponse via SSE - This causes the "connection closed: initialize response" error
Recommended Action:
Report this as a bug to the Codex team at [https://github.com/openai/codex/issues](<https://github.com/openai/codex/issues>) with:
- Your server logs
- The fact that your server works perfectly with Cursor IDE
- Reference to the MCP
2025-06-18spec requirement that responses come via SSE
Your OAuth implementation and server are working perfectly. ✅
Logs:-
Discovery:-
18:58:39 Connect from ('127.0.0.1', 63924) <br>18:58:39 Request from 127.0.0.1:63924 < {'Method': 'GET', 'Path': '/.well-known/oauth-authorization-server/sse', 'Headers': {'mcp-protocol-version': '2024-11-05', 'accept': '/', 'host': '[127-0-0-1.local.aurafriday.com:31173](<http://127-0-0-1.local.aurafriday.com:31173>)'}, 'Body length': 0} Body: <br>18:58:39 RESponse to 127.0.0.1:63924 > 1174 bytes\\nb'HTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\nCache-Control: public, max-age=3600\\r\\nContent-Length: 1045\\r\\nConnection: close\\r\\n\\r\\n{\\n "issuer": "[https://127-0-0-1.local.aurafriday.com:31173](<https://127-0-0-1.local.aurafriday.com:31173>)",\\n "authorization_endpoint": "[https://127-0-0-1.local.aurafriday.com:31173/oauth2/authorize](<https://127-0-0-1.local.aurafriday.com:31173/oauth2/authorize>)",\\n "token_endpoint": "[https://127-0-0-1.local.aurafriday.com:31173/oauth2/token](<https://127-0-0-1.local.aurafriday.com:31173/oauth2/token>)",\\n "registration_endpoint": "[https://127-0-0-1.local.aurafriday.com:31173/oauth2/register](<https://127-0-0-1.local.aurafriday.com:31173/oauth2/register>)",\\n "introspection_endpoint": "[https://127-0-0-1.local.aurafriday.com:31173/oauth2/introspect](<https://127-0-0-1.local.aurafriday.com:31173/oauth2/introspect>)",\\n "revocation_endpoint": "[https://127-0-0-1.local.aurafriday.com:31173/oauth2/revoke](<https://127-0-0-1.local.aurafriday.com:31173/oauth2/revoke>)",\\n "grant_types_supported": \[\\n "authorization_code",\\n "refresh_token"\\n \],\\n "response_types_supported": \[\\n "code"\\n \],\\n "response_modes_supported": \[\\n "query",\\n "form_post"\\n \],\\n "code_challenge_methods_supported": \[\\n "S256"\\n \],\\n "token_endpoint_auth_methods_supported": \[\\n "client_secret_basic",\\n "client_secret_post",\\n "none"\\n \],\\n "scopes_supported": \[\\n "offline_access"\\n \],\\n "claims_parameter_supported": false,\\n "request_parameter_supported": false,\\n "request_uri_parameter_supported": false\\n}'<br>18:58:39 Session Initiated graceful socket shutdown (FIN sent)<br>18:58:39 Session Client socket closed<br>18:58:39 Connect from ('127.0.0.1', 63925)
Auth:-
18:58:39 Request from 127.0.0.1:63925 < {'Method': 'POST', 'Path': '/sse', 'Headers': {'accept': 'text/event-stream, application/json', 'authorization': 'Bearer ', 'content-type': 'application/json', 'host': '[127-0-0-1.local.aurafriday.com:31173](<http://127-0-0-1.local.aurafriday.com:31173>)', 'content-length': '198'}, 'Body length': 198} Body: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{"elicitation":{}},"clientInfo":{"name":"codex-mcp-client","title":"Codex","version":"0.47.0"}}} 18:58:39 Auth Attempting Bearer OAuth for OAuth client: Codex from 127.0.0.1:63925 18:58:39 Auth Successful Bearer OAuth authentication for OAuth client: Codex from 127.0.0.1:63925 18:58:39 Streaming HTTP Parsed initial request: {'jsonrpc': '2.0', 'id': 0, 'method': 'initialize', 'params': {'protocolVersion': '2025-06-18', 'capabilities': {'elicitation': {}}, 'clientInfo': {'name': 'codex-mcp-client', 'title': 'Codex', 'version': '0.47.0'}}} 18:58:39 New streaming HTTP connection from 127.0.0.1:63925, session_id=f9c5483294394a9ca75e32ea1870f67d 18:58:39 Streaming HTTP response to 127.0.0.1:63925 > b'HTTP/1.1 200 OK\\r\\nContent-Type: text/event-stream; charset=utf-8\\r\\nConnection: keep-alive\\r\\nCache-Control: no-store\\r\\nX-Accel-Buffering: no\\r\\nAccess-Control-Allow-Origin: null\\r\\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS\\r\\nAccess-Control-Allow-Headers: \*\\r\\nAccess-Control-Allow-Credentials: true\\r\\nAccess-Control-Max-Age: 86400\\r\\n\\r\\nevent: endpoint\\r\\ndata: /messages/?session_id=f9c5483294394a9ca75e32ea1870f67d\\r\\n\\r\\n' 18:58:39 Streaming HTTP Processing initial request for session f9c5483294394a9ca75e32ea1870f67d 18:58:39 JSONRPC Request session=f9c5483294394a9ca75e32ea1870f67d, method=initialize, id=0 18:58:39 Session FIN detected: SSL client 127.0.0.1:63925 closed connection gracefully 18:58:39 Session Disconnect detected for client 127.0.0.1:63925 before sending
What steps can reproduce the bug?
Maybe work out which protocol(s) you want to support, and check if the flow is correct?<br>Claude 4.5 (Above) is not always right.
What is the expected behavior?
OAuth should work.
Additional information
See also: 5588 <br> [Attempts OAuth even when the MCP SSE server does not support oauth](<https://github.com/openai/codex/issues/5588#top>)
7 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Is there a public MCP server I can test against? I don't totally trust the AI report attached but can take a look if there is a public repro.
@gpeal I see that it's a little bit different but might be related. You could test it with this server, for example, https://docs.z.ai/devpack/mcp/reader-mcp-server.
I see the error:
And feature
experimental_use_rmcp_client = trueis doesn't help.Confirming this with a fresh repro on 2026-03-15 against the Z.AI public MCP endpoints.
Setup:
web-search-prime:https://api.z.ai/api/mcp/web_search_prime/mcpweb-reader:https://api.z.ai/api/mcp/web_reader/mcpzread:https://api.z.ai/api/mcp/zread/mcpbearer_token_env_var = "ZAI_API_KEY"http_headers = { Accept = "application/json, text/event-stream" }Observed in Codex startup:
What I verified manually outside Codex:
initializesucceeds on all three endpoints when I send:Authorization: Bearer $ZAI_API_KEYAccept: application/json, text/event-streaminitialize200,content-type: text/event-stream, and anmcp-session-id.initializeresult advertisesprotocolVersion: "2024-11-05"even when the client asks for2025-03-26.notifications/initializedmanually with the returnedMcp-Session-Idsucceeds with200.tools/listmanually after that also succeeds.So this does not look like:
Accept: application/json, text/event-streamIt looks like a compatibility problem in the Codex streamable HTTP MCP client during/after the
initializedstep, likely related to protocol negotiation or how this older server implementation is handled.If useful, I can provide exact
curlrepro commands, but the short version is: the same session works manually and fails only in Codex withTransport channel closed, when send initialized notification.This looks closely related to #5208.
Why I think so:
Transport channel closed, when send initialized notificationThe difference is that this is still reproducible now with public Z.AI MCP servers, despite #5208 having been closed as fixed via the earlier rust-sdk work.
So this may be either:
initializebut advertiseprotocolVersion: "2024-11-05"while Codex is initiating with2025-03-26.If helpful, I can post exact
curlrepro commands for the full successful manual sequence (initialize->notifications/initialized->tools/list).Here is a minimal manual repro that succeeds outside Codex for
web_search_prime. The same pattern also works forweb_readerandzreadby swapping the URL.Expected successful manual behavior:
200,content-type: text/event-stream, and anmcp-session-id200200plus the tool listIn my environment, this full manual sequence succeeds, while Codex startup still fails earlier with:
I find a workaround for this
use mcp-proxy, you should install it first
here's the example config.toml