please consider temporary back-compat or clearer error; rmcp stdio client: handshake fails on legacy `notifications/message` ({level,message})
What feature would you like to see?
Improve interoperability for notifications/message during the MCP 2025-06-18 transition:
- Temporary backwards-compatibility: accept both payload shapes for
notifications/message— legacy{ level, message }and current{ level, data, logger? }— behind a short deprecation window or a config flag. - Or, at minimum, clearer diagnostics: when a server sends
{ level, message }, surface a precise error like<br>“MCP schema mismatch:notifications/messageexpecteddata, gotmessage”<br>so server authors can fix quickly.
Either approach would make Codex CLI more forgiving or at least more actionable while servers across the ecosystem finish migrating.
Additional information
Summary<br>After Codex CLI switched STDIO to the Rust-based rmcp client (e.g., v0.49.0), it strictly validates MCP messages and closes the connection if a server still emits notifications/message with { level, message }. The current MCP spec (2025-06-18) uses { level, data, logger? }. Some popular servers in the ecosystem haven’t migrated yet, which causes immediate handshake failures in Codex.
- Codex releases: [https://github.com/openai/codex/releases](<https://github.com/openai/codex/releases>)
- MCP spec (Logging, 2025-06-18): [https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging](<https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging>)
Environment
- Codex CLI: v0.49.0
- OS: Ubuntu 24.04
- Example server:
nx-mcp(latest), STDIO transport
Minimal repro<br>Start any MCP server that emits notifications/message with { level, message } (legacy). Connect with Codex CLI (STDIO). Codex fails the handshake.
Observed error (Codex CLI excerpt)
Failed to parse message decode: {"method":"notifications/message","params":{"level":"info","message":"..."},"jsonrpc":"2.0"}
Error: data did not match any variant of untagged enum JsonRpcMessage
input stream terminated
Concrete example of the legacy notification (from server STDIO)
{ "jsonrpc": "2.0", "method": "notifications/message", "params": { "level": "info", "message": "..." } }
Why this matters
- The ecosystem contains multiple MCP servers that still send
{message}. Codex currently fails fast and the error doesn’t point to the exact schema mismatch, making it harder for users to diagnose and server authors to fix. - MCP Inspector (JS) tends to be more tolerant, so users see a server “works in Inspector” but “fails in Codex,” which feels like a client-side regression.
Workaround I use today<br>A tiny STDIO shim that rewrites params.message → params.data on the fly restores interop immediately:
#!/usr/bin/env node
const { spawn } = require('node:child_process');
const readline = require('node:readline');
const workspace = process.argv[2] || process.cwd();
const child = spawn('npx', ['-y','nx-mcp@latest', workspace, '--transport','stdio','--disableTelemetry'],
{ stdio: ['pipe','pipe','pipe'] });
child.stderr.on('data', c => process.stderr.write(c));
const out = readline.createInterface({ input: child.stdout });
out.on('line', line => {
let s = line;
try {
const msg = JSON.parse(line);
if (msg?.method === 'notifications/message' && msg.params) {
const p = msg.params;
if (Object.prototype.hasOwnProperty.call(p,'message') && !('data' in p)) {
msg.params = { ...p, data: p.message };
delete msg.params.message;
s = JSON.stringify(msg);
}
}
} catch {}
process.stdout.write(s + '\n');
});
const inp = readline.createInterface({ input: process.stdin });
inp.on('line', line => child.stdin.write(line + '\n'));
['SIGINT','SIGTERM','SIGHUP'].forEach(sig => process.on(sig, () => child.kill(sig)));
child.on('exit', code => process.exit(code ?? 0));
Ask
- Please consider a temporary alias for
{message}→{data}(guarded by a deprecation plan or a config toggle), or provide a highly specific error message pointing to the exact field mismatch. Either would reduce friction while servers upgrade to the 2025-06-18 schema.
10 Comments
Do you mind sharing the MCP spec that has "message" instead of "data"? The 2024-11-05 spec is the same as today. I'm not saying you're wrong but I'd like to refer to a spec for reference and complete understanding here.
https://modelcontextprotocol.io/specification/2024-11-05/server/utilities/logging#log-message-notifications
Thanks for the clarification, you’re right. I wasn’t claiming there was a spec version that used
message. This is about interoperability: some servers (e.g.,nx-mcpover STDIO) still emitnotifications/messagewith{level, message}, and the Codex (rmcp stdio client) closes the connection during the handshake.Example of what I receive from the server (STDIO) and what Codex logs:
My suggestion: surface a more precise diagnostic, because I currently just see “transport closed” on startup. A message like
notifications/message: expected params.data, got params.messagewould make it much easier for users and server authors while the ecosystem fully converges on the spec.Got it. I'll leave this open to improve the error message rather than to update any actual compatibility. Sound good?
It sounds incredible.
mcp now can connect and discover tool in 0.52 version however the actual tool call still failed
mcp now can't connect exact same issue https://github.com/openai/codex/issues/6020, https://github.com/openai/codex/issues/5619
99% of these issues can be resolved with the solution I attached in the issue itself. Check the codex-tui logs and try to adapt the answer to something suitable for rust-sdk. I just don't think this is a problem that the codex-cli developers should be solving; it's more likely that the creators of mcp are writing the contracts incorrectly. I can't speak with certainty, but rather express my perspective. That's how I solve problems like these.
so, after create a shim just configure it in
.codex/config.tomllike this:So... is anyone working on this issue?
I also can’t use the latest VS Code extension because of this problem, so I’ve been stuck on 0.4.26.
(If I update to 0.4.30 or later, MCP servers fails to initialize and/or calls sometimes get “Transport closed” mid-call, making it far too unstable to use.)
Because the rmcp client even reacts to ordinary node's
console.logoutputs and causes a “transport closed”, I don’t think this is a problem that everyone should have to work around by writing shims.I found the real issue. I use third party library and it log to stdout while I run the mcp server.
call ensureMcpStdoutIsQuiet() before you start your mcp server will fix the issue.
This feature request has received few upvotes in the past three months, so I'm going to close it.