{"record":{"id":"12f1238aa837f168","repo":"vercel/ai","slug":"stdio-mcp-commands-and-arguments-must-not-contain","errorCode":null,"errorMessage":"Stdio MCP commands and arguments must not contain line breaks on Windows.","messagePattern":"Stdio MCP commands and arguments must not contain line breaks on Windows\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/mcp/src/tool/mcp-stdio/create-child-process.ts","lineNumber":14,"sourceCode":"import type { ChildProcess } from 'node:child_process';\nimport spawn from 'cross-spawn';\nimport { getEnvironment } from './get-environment';\nimport type { StdioConfig } from './mcp-stdio-transport';\n\nexport function createChildProcess(\n  config: StdioConfig,\n  signal: AbortSignal,\n): ChildProcess {\n  if (\n    globalThis.process.platform === 'win32' &&\n    [config.command, ...(config.args ?? [])].some(value => /[\\r\\n]/.test(value))\n  ) {\n    throw new TypeError(\n      'Stdio MCP commands and arguments must not contain line breaks on Windows.',\n    );\n  }\n\n  return spawn(config.command, config.args ?? [], {\n    env: getEnvironment(config.env),\n    stdio: ['pipe', 'pipe', config.stderr ?? 'inherit'],\n    shell: false,\n    signal,\n    windowsHide: globalThis.process.platform === 'win32' && isElectron(),\n    cwd: config.cwd,\n  });\n}\n\nfunction isElectron() {\n  return 'type' in globalThis.process;\n}\n","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/mcp/src/tool/mcp-stdio/create-child-process.ts#L1-L32","documentation":"On Windows, spawn treats newlines in a command or argument as argument separators, enabling command/argument injection into stdio MCP servers. createChildProcess proactively throws a TypeError if the command or any arg contains \\r or \\n when process.platform is 'win32'.","triggerScenarios":"Creating a StdioMCPTransport whose config.command or config.args contains a line break (from shell-interpolated strings, copied multi-line commands, or user/LLM-supplied config) while running on Windows.","commonSituations":"Building the command from template strings that include newlines; passing user-controlled config into stdio transport on Windows; splitting commands incorrectly instead of using separate args entries.","solutions":["Remove line breaks: split multi-line commands into separate args entries or trim/replace [\\r\\n] before constructing the transport","Validate command/args with a regex like /[\\r\\n]/ before creating StdioMCPTransport, especially for dynamic or user-provided config","Run the same config through validation on all platforms, or normalize config per-OS before spawn"],"exampleFix":"// before\nnew StdioMCPTransport({ command: `npx\\n-y mcp-server` });\n// after\nnew StdioMCPTransport({ command: 'npx', args: ['-y', 'mcp-server'] });","handlingStrategy":"validation","validationCode":"function assertNoLineBreaks(config) {\n  if (process.platform === 'win32' &&\n      [config.command, ...(config.args ?? [])].some(v => /[\\r\\n]/.test(v))) {\n    throw new TypeError('Stdio MCP command/args must not contain line breaks on Windows');\n  }\n}\nassertNoLineBreaks(config);","typeGuard":"function isSafeStdioConfig(config: { command: string; args?: string[] }): boolean {\n  return ![config.command, ...(config.args ?? [])].some(v => /[\\r\\n]/.test(v));\n}","tryCatchPattern":"try {\n  const client = await createMCPClient({ transport: new StdioMCPTransport(config) });\n} catch (error) {\n  if (error instanceof TypeError && error.message.includes('line breaks')) {\n    // sanitize config.command/args and retry\n  } else throw error;\n}","preventionTips":["Sanitize or split any dynamic/user-provided command strings before building the transport","Always pass multi-token commands as separate args entries, never as one newline-containing string","Run this validation on every platform to catch config issues early"],"tags":["security","windows","stdio","injection"],"backgroundTag":"command-injection","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}