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

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.
This commit is contained in:
alonehobo
2026-04-21 12:33:58 +05:00
parent 1b00f93b37
commit 35b033d77f
+10
View File
@@ -1689,6 +1689,16 @@ def _restore_stdout():
def main(): def main():
_restore_stdout() _restore_stdout()
# Force UTF-8 on stdio. MCP JSON-RPC is UTF-8, but Python on Windows
# defaults stdin/stdout to the system codepage (e.g. cp1251), which
# corrupts non-ASCII payloads and surfaces as generic -32000 errors on
# Cyrillic/CJK content. See PEP 540.
for stream in (sys.stdin, sys.stdout):
if hasattr(stream, "reconfigure"):
try:
stream.reconfigure(encoding="utf-8", errors="replace")
except (AttributeError, OSError):
pass
logger.info("MemPalace MCP Server starting...") logger.info("MemPalace MCP Server starting...")
while True: while True:
try: try: