Skip to content

fix(mcp): force UTF-8 on stdio to fix -32000 on non-ASCII payloads (Windows)#1060

Merged
igorls merged 1 commit into
MemPalace:developfrom
alonehobo:fix/stdio-utf8
May 6, 2026
Merged

fix(mcp): force UTF-8 on stdio to fix -32000 on non-ASCII payloads (Windows)#1060
igorls merged 1 commit into
MemPalace:developfrom
alonehobo:fix/stdio-utf8

Conversation

@alonehobo

Copy link
Copy Markdown
Contributor

Summary

On Windows, the MCP server misdecodes non-ASCII JSON-RPC payloads because Python defaults sys.stdin/sys.stdout to the system codepage (e.g. cp1251 on Russian locales, cp1252 on Western European) while MCP is always UTF-8. Any tool call with Cyrillic, CJK, or accented European characters in a string field returns a generic MCP error -32000: Internal tool error.

Root cause

main() in mempalace/mcp_server.py reads requests with sys.stdin.readline() and writes responses with sys.stdout.write(...) without forcing the encoding. On Windows those streams are opened with the system ANSI codepage. UTF-8 bytes for non-ASCII characters are mis-decoded before json.loads runs, so the parse fails (or the handler receives garbled strings).

Calling handlers like tool_add_drawer(content='тест кириллица') directly in Python works fine — the bug is purely in the stdio transport.

Fix

Reconfigure stdin/stdout to UTF-8 at the start of main(), right after _restore_stdout(). errors="replace" is defensive so a single bad byte cannot take down the server. Guarded by hasattr(stream, "reconfigure") for exotic stream replacements (embedded interpreters, test harnesses).

This gives the same behaviour as running under PYTHONUTF8=1 / python -X utf8 without requiring users to set an env var.

Repro

  1. On Windows with a non-Latin locale (confirmed on Windows 10 Pro, Russian, Python 3.14):
    from mempalace.mcp_server import tool_add_drawer
    tool_add_drawer(wing='wing_test', room='test', content='тест кириллица')
    # -> {'success': True, ...}   (works: no transport involved)
  2. Same call via the MCP client (Claude Code) with Cyrillic in contentMCP error -32000.
  3. With this patch, or with PYTHONUTF8=1 set, the MCP call succeeds.

Test plan

  • On Windows (non-UTF-8 locale): call mempalace_add_drawer / mempalace_kg_add with Cyrillic content via Claude Code → succeeds
  • On macOS/Linux (UTF-8 locale): existing behaviour unchanged — reconfigure(encoding="utf-8") is a no-op there
  • Existing test suite: no regressions

🤖 Generated with Claude Code

On Windows, Python defaults sys.stdin/sys.stdout to the system codepage
(e.g. cp1251 on Russian locales, cp1252 on Western European), while MCP
JSON-RPC is always UTF-8. Non-ASCII payloads (Cyrillic, CJK, accented
European) get mis-decoded before reaching handlers, causing json.loads
to fail or tool handlers to receive garbled strings. Both surface to
the client as a generic MCP error -32000.

Reproduction:
  1. On Windows with a non-Latin locale, call mempalace_add_drawer or
     mempalace_kg_add with Cyrillic/CJK in content or KG object.
  2. Server returns: MCP error -32000: Internal tool error.
  3. Calling the handler directly from Python works fine -- the bug is
     purely in the stdio transport.

Fix:
  Reconfigure stdin/stdout to UTF-8 at the start of main(), after
  _restore_stdout(). Uses errors="replace" defensively so a lone bad
  byte cannot take down the server. Guarded by hasattr(reconfigure)
  for exotic stream replacements.

This matches the behaviour of PYTHONUTF8=1 / python -X utf8 without
requiring users to set an env var.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/mcp MCP server and tools area/windows Windows-specific bugs and compatibility bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants