svnscha - Profile Picture

Version 1.1.0 of mcp-windbg is out. It's the first release since 1.0.0, which was broken on fresh installs for some time.

What Happened: 1.0.1

The dependency was mcp>=1.28.1 with no upper bound. When the MCP Python SDK shipped 2.0.0 - renaming McpError to MCPError and dropping the @server.list_tools() decorator - every fresh install broke at import:

ImportError: cannot import name 'McpError' from 'mcp.shared.exceptions'

Existing installs worked fine; only new ones broke. That's the worst kind of bug: invisible to anyone who could report it. 1.0.1 capped the requirement at <2.0.0. Thanks to @aphroteus for the fix and @arjunarjun07 for finding the cause.

If you're still on 1.0.0, run pip install --upgrade mcp-windbg. Any pip install "mcp<2" workaround can go.

Support for the 2.x SDK

A cap is a stopgap, not a fix. 1.1.0 runs on mcp>=2.0.0: handlers are passed straight to Server(...) instead of registered via decorators, and they return the SDK's result types (ListToolsResult, CallToolResult).

Nothing changes for clients - same tools, same schemas, stdio and streamable-http both work as before. Python support is unchanged (the 2.x SDK wants 3.10+, like this project already did).

Two changes so the next SDK release is boring instead of another five silent weeks:

  • All runtime dependencies are capped at the next major version. Without a ceiling, moving to 2.x would have left the same trap for 3.0.0. Since mcp-windbg is an application, not a library, upper bounds can't conflict with anything downstream - a breaking SDK release just becomes a failing CI run.
  • A weekly canary tests what users actually get. CI installed from uv.lock, so it only tested pinned versions, while real installs resolve whatever the ranges allow. The canary ignores the lock, installs the newest allowed versions, and runs the test suite every Monday. It's scheduled rather than tied to pull requests on purpose: an upstream break should page me, not block someone's unrelated PR.

wait_for_break

The one new tool. Resume a target with g, go do something else, then call wait_for_break to block until it stops again - breakpoint, bugcheck, or CTRL+BREAK. It returns everything the debugger printed along the way.

If the wait expires, the target keeps running. Waiting never halts your machine behind your back.

Fixing g Freezing the Target

This was bad and hid for a while, so let me be honest about it.

Go-class commands (g, gh, gn, gN, gc, gu) hand control back to the target, after which the debugger stops reading stdin. The server queued an .echo marker behind the g, which never got answered - so the command sat until timeout, and the timeout's CTRL+BREAK halted the target again. Ask the machine to run, get it frozen a minute later. The opposite of what you asked for.

Go-class commands are now sent bare and return immediately. Step commands (p, t, pa, ta, ...) are unaffected.

Fixing that exposed several related problems:

  • A command right after g breaks in cleanly. No manual send_ctrl_break, and the target's output isn't thrown away.
  • A break-in sent immediately after g no longer gets lost. Resuming used to return before the debugger read the g, leaving a window where a CTRL+BREAK hit the prompt instead of the target. Against a live KDNET target, a break sent with no gap was lost every single time. The resume is now confirmed consumed before reporting success.
  • Break-in checks before signaling. A CTRL+BREAK aimed at an already-stopped target would queue and re-halt it later. The session now probes for a prompt first and only signals if there's no answer, making speculative send_ctrl_break calls safe.
  • bp nt!X; g reports whether the breakpoint was set. A typo'd symbol now shows up as Couldn't resolve error instead of an endless wait.
  • One operation per session at a time. wait_for_break parks on a worker thread while the server keeps answering other requests; a second call on the same session is refused immediately. Closing a session also ends any wait parked on it.
  • Kernel sessions over named pipe or serial connect. kd announces those links with a different message than KDNET, and only the latter was matched - so sessions that were actually attached timed out.

Getting Started

Still one line:

pip install mcp-windbg

Release notes: v1.1.0 - Docs: svnscha.github.io/mcp-windbg - Source: github.com/svnscha/mcp-windbg

Wrapping Up

No headline features here. Just a dependency cap, a canary, one new tool, and a long list of places where the debugger and the server disagreed about who was talking. That's what a .1 release should be - especially after a 1.0.0 nobody could install.


If mcp-windbg has helped you, I'd love to hear about it. Open an issue, reach out, or star the repository. Thank you.