1c0ba03ce6
Adding a full-suite CI job (prior commit) exposed two latent bugs that only
surface when the whole suite runs under pytest's DEFAULT fd-level capture —
which had never happened, because collection aborted early and most runs used
--capture=no.
1. Import-time stdio seizure (4 MCP servers). codex-image2, llm-chat,
minimax-chat, and gemini-review each ran, at MODULE TOP LEVEL,
`sys.stdout = os.fdopen(sys.stdout.fileno(), "wb")`. os.fdopen defaults to
closefd=True, so importing the module SEIZES ownership of the current stdout
fd — under pytest that is the capture tmpfile fd, and when the wrapper is GC'd
it closes it, corrupting capture for every subsequent test ("OSError: Bad
file descriptor" cascade; 395 spurious errors). Fixed by deferring the rebind
into an idempotent `_init_stdio()` called at the top of each `main()` — the
exact pattern manual-review already used. Real server launch
(`python server.py`) is unchanged (main() runs it first); only import is now
side-effect-free. test_codex_image2_server.py reverts to a plain import.
2. Module-name collision in tests (test_manual_review.py). It loaded the server
via bare `import server as srv` (x9). Every mcp-server is named server.py, and
test_minimax_chat_server does `sys.path.insert(0, <minimax dir>)` at
collection time, so by run time a bare `import server` resolved to minimax's
server → `AttributeError: module 'server' has no attribute 'create_thread'`
(passed in isolation, failed in the full suite). Fixed to load by explicit
path under a unique module name via spec_from_file_location, matching every
other server test in the suite.
Full suite now: 406 passed, 16 skipped under default fd-capture (was: aborted /
395 errors / 9 failures).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>