Skip to content

Fix Windows MCP handshake crash under PYTHONUTF8 - #42

Open
Facetomyself wants to merge 1 commit into
MeroZemory:mainfrom
Facetomyself:fix/windows-utf8-tasklist-handshake
Open

Fix Windows MCP handshake crash under PYTHONUTF8#42
Facetomyself wants to merge 1 commit into
MeroZemory:mainfrom
Facetomyself:fix/windows-utf8-tasklist-handshake

Conversation

@Facetomyself

Copy link
Copy Markdown

Problem

On Chinese (and other non-English) Windows, MCP clients such as Grok start Python in UTF-8 mode (PYTHONUTF8=1). ida-multi-mcp scans for live IDA GUI processes with tasklist /FO CSV and netstat before answering MCP initialize.

Those utilities emit OEM/GBK. With subprocess.check_output(..., text=True) and no encoding=, CPython decodes as UTF-8. The stdout reader thread raises UnicodeDecodeError (often byte 0xb1), check_output returns None, and out.strip() crashes the process. The client reports:

handshake failed: connection closed: initialize response

This happens even when no IDA GUI is running. Headless idalib_* tools never get a chance to start.

Reproduced with Python 3.13 UTF-8 mode: text=True on tasklist returns None; the raw bytes decode with GBK/OEM.

Fix

  • Decode console utilities with encoding="oem" on Windows and UTF-8 elsewhere, always errors="replace".
  • Treat empty/None stdout as "no GUI instances" instead of crashing.
  • Accept localized listen states (LISTENING / 侦听) and IPv6 local addresses.
  • Catch unexpected rediscovery errors so they cannot prevent MCP initialize.

Tests

pytest tests/test_health.py: 18 passed, 3 skipped (Unix-only cases on Windows).

Live stdio initialize under PYTHONUTF8=1 now returns serverInfo.name=ida-multi-mcp with no UnicodeDecodeError.

tasklist/netstat emit OEM/GBK on non-English Windows. With UTF-8 mode,
subprocess text=True decodes as UTF-8, the reader thread raises
UnicodeDecodeError, check_output returns None, and out.strip() kills
the stdio server before initialize.

Decode console utilities with encoding=oem (UTF-8 elsewhere) and
errors=replace. Treat empty/None stdout as no GUI instances. Accept
localized LISTENING states. Never let rediscovery exceptions prevent
MCP initialize so headless idalib tools still start.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant