Summary
codedb currently writes human-readable status/error text to stdout on at least one mcp startup failure path. For stdio MCP, that is a protocol violation: stdout must be reserved for JSON-RPC messages only.
This can cause hosts to fail parsing startup output with errors like:
invalid character 'â' looking for beginning of value
The â is the leading UTF-8 byte from symbols like ✗ / ✓ when those bytes hit the JSON-RPC stream.
Reproduction
On current main (33b11ab when verified locally):
./zig-out/bin/codedb /tmp mcp
Observed stdout output:
✗ refusing to index temporary root: /private/tmp
That line is currently emitted from src/main.zig on the mcp root-policy failure path.
What I verified
-
A normal launch on current main:
./zig-out/bin/codedb --mcp > /tmp/out 2> /tmp/err < /dev/null
produced:
stdout: 0 bytes
stderr: the normal codedb mcp: root=... info log
-
So this is not evidence that all mcp startup paths are dirty on current main.
-
It is evidence that at least one real mcp failure path contaminates stdout and can break stdio hosts.
Relevant code
Current verified offending path:
src/main.zig:145
✗ refusing to index temporary root: ...
Potentially related out.p(...) call sites in src/main.zig should also be audited for mcp safety.
Why this is out of spec
For stdio MCP servers, human-readable logs/status text should go to stderr, not stdout.
The official TypeScript SDK docs state this explicitly in the stdio server quickstart:
https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/server-quickstart.md
Always use console.error() instead of console.log() in stdio-based MCP servers. Standard output is reserved for JSON-RPC protocol messages, and writing to it with console.log() will corrupt the communication channel.
Expected fix
- Keep
stdout clean for JSON-RPC only when running codedb mcp
- Send all human-readable startup/status/error output to
stderr on the mcp path
- Audit
main.zig for any other out.p(...) paths reachable under cmd == "mcp"
Related
This was split out from the broader long-session transport-close discussion in #278, since this stdout-corruption bug is concrete and independently actionable.
Summary
codedbcurrently writes human-readable status/error text tostdouton at least onemcpstartup failure path. For stdio MCP, that is a protocol violation:stdoutmust be reserved for JSON-RPC messages only.This can cause hosts to fail parsing startup output with errors like:
The
âis the leading UTF-8 byte from symbols like✗/✓when those bytes hit the JSON-RPC stream.Reproduction
On current
main(33b11abwhen verified locally):Observed
stdoutoutput:That line is currently emitted from
src/main.zigon themcproot-policy failure path.What I verified
A normal launch on current
main:produced:
stdout:0bytesstderr: the normalcodedb mcp: root=...info logSo this is not evidence that all
mcpstartup paths are dirty on currentmain.It is evidence that at least one real
mcpfailure path contaminatesstdoutand can break stdio hosts.Relevant code
Current verified offending path:
src/main.zig:145✗ refusing to index temporary root: ...Potentially related
out.p(...)call sites insrc/main.zigshould also be audited formcpsafety.Why this is out of spec
For stdio MCP servers, human-readable logs/status text should go to
stderr, notstdout.The official TypeScript SDK docs state this explicitly in the stdio server quickstart:
https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/server-quickstart.md
Expected fix
stdoutclean for JSON-RPC only when runningcodedb mcpstderron themcppathmain.zigfor any otherout.p(...)paths reachable undercmd == "mcp"Related
This was split out from the broader long-session transport-close discussion in #278, since this stdout-corruption bug is concrete and independently actionable.