diff --git a/packages/agent-core/src/mcp/client-stdio.ts b/packages/agent-core/src/mcp/client-stdio.ts index adffda0ca..61d7094f8 100644 --- a/packages/agent-core/src/mcp/client-stdio.ts +++ b/packages/agent-core/src/mcp/client-stdio.ts @@ -236,5 +236,18 @@ export function mergeStdioEnv( if (configEnv !== undefined) Object.assign(merged, configEnv); Object.assign(merged, proxyEnvForChild(merged)); reconcileChildNoProxy(merged, configEnv); + // Ensure Python MCP servers use UTF-8 for stdio encoding. + // On Windows the default console code page (e.g. cp1252) cannot encode + // non-ASCII characters, causing UnicodeEncodeError when Python servers + // print Unicode to stdout/stderr. JSON-RPC over stdio is always UTF-8, + // so forcing the encoding is correct on every platform. + // See https://github.com/MoonshotAI/kimi-code/issues/886 + if (merged['PYTHONIOENCODING'] === undefined) { + merged['PYTHONIOENCODING'] = 'utf-8'; + } + if (merged['PYTHONUTF8'] === undefined) { + merged['PYTHONUTF8'] = '1'; + } + return merged; } diff --git a/packages/agent-core/test/mcp/client-stdio.test.ts b/packages/agent-core/test/mcp/client-stdio.test.ts index 2e18c5406..4ae5cb78b 100644 --- a/packages/agent-core/test/mcp/client-stdio.test.ts +++ b/packages/agent-core/test/mcp/client-stdio.test.ts @@ -266,4 +266,25 @@ describe('mergeStdioEnv', () => { const merged = mergeStdioEnv({ FOO: 'override' }, { FOO: 'parent', PATH: '/x' }); expect(merged['FOO']).toBe('override'); }); + + it('injects PYTHONIOENCODING=utf-8 and PYTHONUTF8=1 for Python MCP servers', () => { + const merged = mergeStdioEnv(undefined, { PATH: '/usr/bin' }); + expect(merged['PYTHONIOENCODING']).toBe('utf-8'); + expect(merged['PYTHONUTF8']).toBe('1'); + expect(merged['PATH']).toBe('/usr/bin'); + }); + + it('does not override user-provided PYTHONIOENCODING or PYTHONUTF8', () => { + const merged = mergeStdioEnv( + { PYTHONIOENCODING: 'latin-1', PYTHONUTF8: '0' }, + { PATH: '/usr/bin' }, + ); + expect(merged['PYTHONIOENCODING']).toBe('latin-1'); + expect(merged['PYTHONUTF8']).toBe('0'); + }); + + it('inherits parent PYTHONIOENCODING when present', () => { + const merged = mergeStdioEnv(undefined, { PATH: '/usr/bin', PYTHONIOENCODING: 'cp1252' }); + expect(merged['PYTHONIOENCODING']).toBe('cp1252'); + }); });