MCP stdio server: SyntaxError Unexpected token in deserializeMessage when using console.log
When I run an MCP server built with @modelcontextprotocol/typescript-sdk over stdio and start it with
npx @modelcontextprotocol/inspector node ./server.js, calling a tool throwsSyntaxError: Unexpected token 'g', "get_weathe"... is not valid JSONatdeserializeMessageinshared/stdio.js. The tool handler logsconsole.log("get_weather tool called with", city)before returning its result. Why is the plain log line being parsed as JSON?Originally asked on GitHub: https://github.com/modelcontextprotocol/typescript-sdk/issues/244
4 answers
Status: explained — a contributor identified the cause and proposed a fix, but no one in the thread reported testing it.
The error happens because the stdio transport treats stdout as the JSON-RPC message channel. A plain-text
console.log("get_weather tool called with", city)inside the tool handler is sent to stdout and therefore reaches the client as if it were a protocol message. The client'sdeserializeMessagethen callsJSON.parseon that line, producingSyntaxError: Unexpected token 'g'.A contributor stated that, per the MCP docs on logging in MCP servers, console logging should not be sent to stdio for stdio servers, and recommended using
console.error()instead in TypeScript. That applies to all logs in a stdio server, including the startup messages in the reporter's example (console.log("start demo MCP server...")), since those also go to stdout and corrupt the protocol stream.The reporter reproduced the issue with
npx @modelcontextprotocol/inspector node ./server.jsusingMcpServerandStdioServerTransportfrom the TypeScript SDK. The reporter's suggested alternative — makingdeserializeMessagecheck whether the input is JSON before parsing — was not tested or adopted in the thread. Note that whether switching toconsole.error()actually resolves the error is not confirmed anywhere in the thread, so treat it as a proposed fix rather than a verified one.Did this work for you?What @bhosmer-ant tried on GitHub (Outcome unclear)
A contributor stated that for stdio servers console logging should not be sent to stdout, pointed to the MCP docs on logging in servers, and suggested using
console.error()instead ofconsole.log()in TypeScript.Did this work for you?What @karmiy tried on GitHub (Outcome unclear)
Reproduced the error with the posted server code (a
get_weathertool with aconsole.login the handler) started vianpx @modelcontextprotocol/inspector node ./server.js.Did this work for you?What @karmiy tried on GitHub (Outcome unclear)
Reported the bug and proposed either making
deserializeMessagecheck whether the incoming line is JSON before parsing, or changing the tool-call notification format to valid JSON.Source: https://github.com/modelcontextprotocol/typescript-sdk/issues/244 (opens external site)
Did this work for you?
Related questions
- MCP TypeScript SDK StreamableHttp without sticky sessions in multi-replica deployments?
- MCP typescript-sdk: tool inputSchema/outputSchema reject JSON Schema type 'array'?
- Use Zod union/intersection as MCP tool paramsSchema in typescript-sdk?
- MCP Inspector: "Invalid transport type: undefined" when connecting to an SSE server
- MCP TypeScript SDK with Zod v4 fails: `w._parse is not a function` — how to fix?