Freezes the server into a single self-contained `mcp-windbg.exe` with
PyInstaller,
for users who want nothing to do with a Python toolchain. `cdb.exe`
stays a
prerequisite.
**What the build does.** `scripts/Build-Exe.ps1` builds it, `-Verify`
runs the
scenarios against it, and `MCP_WINDBG_SERVER_EXE` re-points the e2e
harness at a
built binary so the whole suite runs with the same assertions and a
different
launcher. A new `exe` job does both on every PR.
**Signed release asset.** The exe is signed and attached to each release
with a
`SHA256SUMS` taken from the signed binary, since signing rewrites the PE
and a
digest from before it would match nothing anyone can download. The
signature is
verified before the asset is attached.
**Identity.** Version resource generated from `pyproject.toml`, plus an
icon and a
`Comments` field stating the binary is signed by Liasoft GmbH, which
sponsors the
certificate. Windows shows the certificate subject as the verified
publisher, so
without that note the author and the signer read as two unrelated names.
**Why signing uses a self-hosted runner.** The signing service requires
one. Two
rules keep that safe on a public repository, and both must hold if the
job is ever
changed: it stays out of reach of `pull_request`, `pull_request_target`
and
`issue_comment`, which would run a fork's code on it, and it never
checks out the
repository. It declares `permissions: {}`, takes its endpoint from a
secret, and
waits for approval in a `signing` environment.
**Verified.** 29 scenarios pass against the binary (2 kernel skips, no
target).
Signing exercised end to end with a rehearsal run, which builds, signs
and
attaches while publishing nothing: `osslsigncode verify` reports
`Succeeded`,
signer `O=Liasoft GmbH`, RFC3161 countersigned.
**Not yet exercised.** Nothing launches the signed binary, so a
post-sign smoke
step is worth adding.
Out of scope: winget.
Release the separate server, skills, and agents plugins with updated installation and migration documentation. Align all package versions and publish the 1.3.0 changelog.
Installing mcp-windbg into Claude Code meant a `pip install` plus a
hand-written server registration with an env var. It becomes two lines:
```
/plugin marketplace add svnscha/mcp-windbg
/plugin install mcp-windbg@mcp-windbg
```
This repo hosts the marketplace itself, so there is no second repository
to keep in step.
## Why there is no install step at all
The plugin launches the server with `uvx`, pinned to the matching
release, so uv fetches it from PyPI on first use. That is what makes the
two lines *complete* rather than the last two of five. `server.json`
already declared `runtimeHint: uvx`, so this is how the package
presented itself anyway.
## What ships
- The ten tools, through the plugin's `.mcp.json`.
- **`/mcp-windbg:analyze-dump`** - crash-dump triage that separates fact
from inference and calls out missing symbols rather than reading meaning
into `module+0x1234`.
- **`/mcp-windbg:debug-remote`** - attaching to a user-mode debug
server, and the part that is easy to get wrong by hand: saying plainly
whether the target was left running or frozen.
- **`/mcp-windbg:kernel-debug`** - driving a live kernel target,
including the `g` / `wait_for_break` / `send_ctrl_break` handling from
1.1.0, and closing with `resume: true` so nobody leaves a machine
halted.
- **`/mcp-windbg:windbg-doctor`** - the first thing to run when nothing
works: checks platform, CDB, uv, the `uvx` round trip, and symbols, then
reports what to fix rather than one failure at a time.
- **`crash-analyst`** agent - hand it a dump and a question and it
investigates on its own, returning a verdict, the evidence behind it,
what it ruled out, and what to do next. Its `tools:` list uses the
scoped `mcp__plugin_mcp-windbg_mcp-windbg__*` names.
- A [reference
page](https://github.com/svnscha/mcp-windbg/blob/feat/claude-plugin/docs/reference/plugin.md)
in the docs site, plus plugin sections in the README, getting-started,
and client configuration.
Always-on cost is about 400 tokens; a skill or the agent costs more only
when it fires.
## Symbols are configured, without overriding yours
The plugin sets `_NT_SYMBOL_PATH` as a **default**, not a value:
```json
"_NT_SYMBOL_PATH": "${_NT_SYMBOL_PATH:-SRV*C:\Symbols*https://msdl.microsoft.com/download/symbols}"
```
Claude Code's `.mcp.json` expansion supports `${VAR:-default}`, so an
existing value wins and a symbol path someone tuned themselves is never
overwritten. Without this the out-of-the-box experience is a stack of
`module+0x1234` offsets, which is exactly the case where triage is
guesswork.
## One thing that cannot be declared
**Windows-only.** There is no manifest field for a platform constraint,
so installing on macOS or Linux loads the plugin and the server then
fails to find a debugger. Stated in the plugin README, the marketplace
description, and the reference page; `windbg-doctor` catches it at the
first check and stops there.
## Version drift, closed
release-please now bumps the plugin manifest, the marketplace entry, and
the `uvx` pin along with `pyproject.toml` and `server.json`, and
`check-version-consistency.ps1` checks all three. That is the guard that
a silently-broken `extra-files` entry does not ship - the exact failure
caught by hand during the 1.1.0 release.
The `uvx` pin survives the bump because release-please's `generic-json`
updater does a substring replace against its version regex rather than
overwriting the whole value, so `mcp-windbg@1.1.0` becomes
`mcp-windbg@1.2.0` and not a bare `1.2.0`.
## A bug fixed on the way
`check-version-consistency.ps1` looped with `foreach ($error in
$errors)`. `$error` is a **read-only PowerShell automatic variable**, so
the first time it had a mismatch to report it threw `Cannot overwrite
variable Error` instead of naming the files. The build still failed, so
this was never dangerous - just useless exactly when you needed it.
Verified both ways now: it names the mismatching file, and still exits
1.
## Dependencies
Floors raised to current releases with the major caps unchanged: `mcp`
2.1.1, `starlette` 1.6.0, `uvicorn` 0.52.4, and `pymdown-extensions`
11.0.2 for the docs build. `uv.lock` is regenerated; it had been
stranded at 1.0.1 since the 1.1.0 release, because release-please has no
updater for it. A `uv lock --check` step in CI would catch that drift
and is worth a follow-up.
## Verification
- `claude plugin validate` passes for both the marketplace manifest and
the plugin manifest.
- Full suite green against the upgraded dependencies: 99 passed, 2
skipped (the kernel scenarios, no target attached). Live CDB scenarios
ran.
- `validate-server-schema.py` passes; `uv lock --check` reports the lock
in sync.
- The `.mcp.json` snippet on the reference page is asserted to parse and
to equal the real file, after it shipped with a single-backslash
`C:\Symbols` that did neither.
- The earlier end-to-end check (`claude plugin marketplace add` ->
`install` -> `details`, and a headless session seeing the tools through
`uvx` with nothing pre-installed) was run when the plugin had two skills
and no agent, so it predates the current surface.
## Note
You already have a `svnscha` marketplace pointing at
`svnscha/claude-plugins`. This adds a second, repo-local one. If you
would rather have the plugin listed there instead, say so - the plugin
directory moves as-is and only the marketplace manifest changes.
Closes#78. Lifts the `mcp<2.0.0` cap that 1.0.1 shipped as a stopgap.
## What actually breaks in 2.x
The `McpError` -> `MCPError` rename is the half everyone hits first, but
it was the easy half. 2.0.0 also removed the low-level
`@server.list_tools()` / `@server.call_tool()` decorators that every
tool and prompt was registered through. Handlers are now passed to
`Server(...)` as constructor arguments, take `(ctx, params)`, and return
the SDK's result types instead of bare lists:
| 1.x | 2.x |
| :--- | :--- |
| `@server.list_tools()` -> `list[Tool]` | `on_list_tools=` ->
`ListToolsResult` |
| `@server.call_tool()` -> `list[TextContent]` | `on_call_tool=` ->
`CallToolResult` |
| `@server.list_prompts()` / `@server.get_prompt()` | `on_list_prompts=`
/ `on_get_prompt=` |
| `McpError(ErrorData(code=, message=))` | `MCPError(code, message)` |
Tool dispatch is split from result wrapping, so the dozen handler
returns keep their `list[TextContent]` shape and exactly one place
builds the `CallToolResult`.
## What did not change
- **Clients see nothing.** Same nine tools, same schemas, both
transports.
- **Transports needed no work.** `stdio_server`,
`StreamableHTTPSessionManager`, and `Server.run` are all
signature-compatible.
- **Python support.** The 2.x SDK requires 3.10+, exactly this project's
existing floor.
- **Errors still surface as errors.** Raising `MCPError` from a handler
becomes a JSON-RPC error response; the harness already normalized raised
errors and `isError` alike, so the scenario assertions were unaffected.
## The harness moved too
It drives a real client from the same SDK, so it needed three changes:
`MCPError`, `CallToolResult.is_error` (the wire format is still
`isError` - only the Python attribute is snake_case), and
`streamable_http_client` now yielding two values instead of three.
Its note about the stdio teardown race is corrected rather than deleted:
**2.0.0 fixed that race** - `stdout_reader` now catches
`BrokenResourceError` as well as `ClosedResourceError` around its send.
The guard stays for the other transports, and it only suppresses after
every step has completed, so it cannot mask a real failure.
## Verification, all on mcp 2.0.0
- 89 hermetic tests
- 10 `live` cdb scenarios against real `cdb.exe`
- both kernel scenarios against the live KDNET target
- coverage 91% against the 88% gate
- `mkdocs build --strict` clean, `server.json` valid against the
registry schema, CLI smoke-tested
## Note on releasing
Left under `[Unreleased]`. Whenever you cut it, this plus #80 make it a
1.1.0: new `wait_for_break` tool, kernel fixes, and a dependency floor
move that is breaking for anyone who pinned `mcp` 1.x themselves
(nothing needs to, since installing mcp-windbg pulls the SDK it needs).
Ships the `mcp<2.0.0` cap from #75 as an actual release.
## Why a release and not just `[Unreleased]`
pip reads dependency metadata from the **published wheel**, so merging
the cap to `main` does nothing for anyone hitting #76 - 1.0.0 keeps
resolving to `mcp` 2.x and keeps failing at import. The fix only reaches
users when it is on PyPI.
## Changes
- `pyproject.toml`, `server.json` (top-level and both `packages[*]`),
`CHANGELOG.md` bumped to 1.0.1
- `uv.lock` re-resolved
- CHANGELOG entry crediting @aphroteus and @arjunarjun07
No source changes beyond the dependency cap already merged in #75.
## Verified locally
- `scripts/check-version-consistency.ps1` - all four locations agree on
1.0.1
- `scripts/validate-server-schema.py` - server.json valid against the
MCP registry schema
- `uv run pytest -m "not live"` - 29 passed
- `scripts/Format-Docs.ps1` - clean
- Built wheel metadata reads `Requires-Dist: mcp<2.0.0,>=1.28.1`, which
is the part that actually fixes the user-visible bug
Closes#76.
Porting to the 2.x server API is tracked in #78.
Closes#62. Closes#47.
Kernel debugging never worked: every remote connection was launched with -remote, which is user-mode only, so a -k target could never connect. Fixing it properly meant kd.exe and a tool surface that can tell the two engines apart.
Breaking: every *_windbg_* tool is renamed, and sessions are addressed by an opaque session_id instead of by dump path or connection string. See CHANGELOG.md.
Maintenance round off `main`.
## Dependencies
Refreshed the direct dependency floors to their latest releases and
regenerated `uv.lock`:
| Package | Before | After |
| :------ | :----- | :---- |
| mcp | 1.26.0 | 1.28.1 |
| pydantic | 2.12.5 | 2.13.4 |
| starlette | 0.52.1 | 1.3.1 (0.x to 1.x) |
| uvicorn | 0.42.0 | 0.51.0 |
| pytest (dev/test) | 9.0.2 | 9.1.1 |
Docs deps (`mkdocs`, `mkdocs-material`, `pymdown-extensions`) are
already at their latest floors, so `requirements-docs.txt` is untouched
(Dependabot owns that group).
### The Starlette major bump
Starlette crosses 0.x to 1.x. `mcp` 1.28.1 accepts Starlette 1.x, so the
resolver takes it cleanly. Verified:
- Hermetic suite green: `pytest -m "not live"` -> 17 passed.
- Full suite: 17 passed, 10 live scenarios skipped (no local cdb.exe;
Windows CI covers those).
- Smoke-tested the `streamable-http` transport (the code that actually
uses Starlette/uvicorn, and which is excluded from coverage): the server
boots on uvicorn 0.51 / Starlette 1.3.1 and routes requests.
## Docs
Swapped the README Star History chart for the sealed-token
star-history.com embed with light and dark variants.
CHANGELOG updated under `[Unreleased]`.
## Summary
Release prep for **0.15.0**. Bumps the version in `pyproject.toml`,
`server.json` (top-level and
both package entries), and `uv.lock`, and dates the `0.15.0` CHANGELOG
section.
## Changes since 0.14.0 (from the CHANGELOG)
- **Added**: MkDocs user guide and GitHub Pages deploy; `dump-triage`
prompt reference; usage-guide
pages for HTTP hosting, redaction, and WER capture.
- **Changed**: declarative end-to-end test suite with subprocess
coverage; package metadata;
contributor guide and `.claude/rules/`; docs-tooling floors; LFS dumps
mandatory in tests.
- **Removed**: three unused functions
(`execute_common_analysis_commands`,
`CDBSession.get_session_id`, `prompts.get_available_prompts`).
- **Fixed**: stdio server no longer crashes on a malformed input line
(#45).
## Verification
- `scripts/check-version-consistency.ps1` - all versions consistent at
0.15.0.
- `scripts/validate-server-schema.py` - `server.json` valid against the
MCP schema.
- `scripts/Format-Docs.ps1 -Check` - clean.
- `uv run pytest src/mcp_windbg/tests/` - 27 passed.
- `uv build` + `uv run twine check dist/*` - both artifacts PASSED.
## Releasing
After this merges to `main`, tag `v0.15.0` on the merge commit and push
it. `publish-mcp.yml`
runs the consistency check, tests, build, publishes to PyPI, and creates
the GitHub release.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
Rebuilds the test suite as a declarative end-to-end framework. The
harness hosts a real `python -m mcp_windbg` server (stdio and
streamable-http) and drives it with a real MCP `ClientSession`. The only
faked component is the LLM: each `tests/scenarios/*.yaml` scripts the
tool calls a model would otherwise choose. Real server, real transport,
real `cdb.exe`, real dump.
Adding a test means writing YAML, not Python. See
`src/mcp_windbg/tests/e2e/README.md`.
## What is exercised (27 scenarios)
- **Local dump:** real `cdb.exe -z` against the LFS
`DemoCrash1.exe.7088.dmp` (analyze, run commands, session lifecycle,
symbol-path reuse + combine, `--cdb-path`, `--no-dump-dir-symbols`).
- **Remote:** a real local `cdb .server tcp:` connected via `-remote`
(connect/inspect/close, break-in via `send_ctrl_break`, invalid-endpoint
error).
- **Transports:** stdio and streamable-http, both over the real MCP
protocol.
- **Hermetic (no debugger):** tools contract, list dumps, validation +
unknown-tool/-prompt + non-existent-dump errors, the empty-path branch,
the `dump-triage` prompt, and the full range of filter-script behaviors
(redact in/out, input-only, None / non-string returns, raising /
zero-arg / non-callable / missing hooks).
## Skipping vs. failing
- Missing `cdb.exe` -> the `live`/`remote` scenarios `pytest.skip` (so
`-m "not live"` runs anywhere; 17 hermetic scenarios).
- Missing Git LFS dump -> **hard fail** (`git lfs pull`). The dumps are
mandatory; a half-set-up checkout is a loud error, not silent green.
This fixes the old inconsistency where the remote tests *failed* rather
than skipped on a CDB-less machine.
## Coverage: 91%, enforced
The server runs in a subprocess, so a naive `pytest --cov` measured the
parent and reported `server.py` at a misleading 20%. The harness now
launches the server under `coverage run --parallel-mode`
(`MCP_WINDBG_COVERAGE`), measuring where dispatch actually runs. CI
enforces `coverage report --fail-under=90`.
| Module | naive (parent) | subprocess |
| --- | --- | --- |
| `server.py` | 20% | 90% |
| `cdb_session.py` | 16% | 87% |
| `filter_script.py` | 21% | 100% |
| `__init__.py` (CLI) | 14% | 100% |
| **total** | **19%** | **91%** |
Code that genuinely cannot be line-measured end-to-end is excluded with
documented `# pragma: no cover` / `exclude_also`: the streamable-http
transport (hard-killed on Windows teardown - asyncio's Proactor loop
does not deliver the shutdown signal, so coverage cannot flush; still
verified behaviorally by the HTTP scenario), the atexit cleanup,
debug-only output and low-level IO error handlers, and guards the MCP
layer enforces before they could run.
## Cleanup
- Removed dead code found while raising coverage:
`server.execute_common_analysis_commands`, `CDBSession.get_session_id`,
`prompts.get_available_prompts` (no callers).
- Documented the previously-undocumented `dump-triage` MCP prompt
(`docs/reference/prompts.md`, nav links).
- Corrected the CLAUDE.md testing description (the old "skip cleanly /
unit coverage" claim was false).
- Removed `test_cdb.py`, `test_cli.py`, `test_filter_script.py`,
`test_remote_debugging.py`.
- Adds `pyyaml` and `coverage` as dev dependencies.
## Verification
- `uv run pytest src/mcp_windbg/tests/ -v` - 27 passed (live +
hermetic).
- `uv run pytest src/mcp_windbg/tests/ -m "not live"` - 17 passed, 10
deselected.
- Coverage flow above; `coverage report --fail-under=90` passes at 91%.
- `Format-Docs.ps1 -Check` and `mkdocs build --strict` clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This pull request introduces several significant improvements and new
features to the `mcp-windbg` project, most notably adding HTTP transport
support, enhancing prompt handling, and updating documentation and
dependencies. The release also includes configuration and workflow
enhancements to streamline development and deployment.
References
- #25
- #26
- #28
- #29
- #31
---
**Key highlights:**
- Adds a new HTTP transport option (`--transport streamable-http`) for
broader client compatibility.
- Implements a prompt loading API for AI-assisted crash dump analysis.
- Updates documentation to reflect new features and workflows.
- Improves dependency management and configuration.
- Synchronizes version numbers and updates the changelog for the new
release.
---
### Transport and Server Features
* **HTTP Transport Support:** Adds a new `--transport streamable-http`
option, enabling the MCP server to communicate over HTTP in addition to
the default stdio. This includes new command-line arguments
(`--transport`, `--host`, `--port`) and a new `serve_http` entry point.
[[1]](diffhunk://#diff-177bdd0829daf3f08a40b608b72acee746bef7c01860f8ff146d5a120aef4413L1-R1)
[[2]](diffhunk://#diff-177bdd0829daf3f08a40b608b72acee746bef7c01860f8ff146d5a120aef4413R16-R44)
[[3]](diffhunk://#diff-756c99ad6a15758981c15d6ba32a2d83391908e8e021f0399e9d34339dc4eadaR14-R17)
[[4]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R41-R85)
[[5]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R111-R131)
### Prompt Handling and AI Integration
* **Prompt API and Packaging:** Introduces a prompt loading API in
`src/mcp_windbg/prompts/__init__.py` for managing and retrieving prompt
templates, and updates packaging to include prompt files. Prompt
templates are improved for flexibility by removing hard-coded model
references.
[[1]](diffhunk://#diff-f2aae3b3197f2de648691493917d208fbb4c6e1a510246e39e38b636c07d3aa5R1-R41)
[[2]](diffhunk://#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711R34-R36)
[[3]](diffhunk://#diff-1980162a59c33abb96e8650c4d4ee6f25443def59232cec6f1208549c2706dbbL2-R3)
[[4]](diffhunk://#diff-1980162a59c33abb96e8650c4d4ee6f25443def59232cec6f1208549c2706dbbL77-R76)
[[5]](diffhunk://#diff-1980162a59c33abb96e8650c4d4ee6f25443def59232cec6f1208549c2706dbbL86)
### Dependency and Configuration Management
* **Updated Dependencies and Dependabot:** Updates `pyproject.toml` to
require newer versions of dependencies (`mcp`, `pydantic`, `starlette`,
`uvicorn`), and enhances `.github/dependabot.yml` to provide better
grouping, labeling, and scheduling of dependency updates.
[[1]](diffhunk://#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711R23-R24)
[[2]](diffhunk://#diff-dd4fbda47e51f1e35defb9275a9cd9c212ecde0b870cba89ddaaae65c5f3cd28L3-R48)
### Documentation and Workflow
* **Comprehensive Development Guide:** Replaces `AGENTS.md` with a
detailed development and release guide, covering repository structure,
version management, release process, CI/CD, and troubleshooting.
* **Expanded README:** Documents new transport options, configuration
for HTTP transport, and command-line arguments, making it easier for
users to adopt new features.
[[1]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R41-R85)
[[2]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5R111-R131)
### Release and Versioning
* **Version Bump and Changelog:** Synchronizes version numbers across
`pyproject.toml`, `server.json`, and updates `CHANGELOG.md` for version
0.12.0, summarizing new features, changes, and fixes.
[[1]](diffhunk://#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711L3-R3)
[[2]](diffhunk://#diff-a49a8fd223e4838c13a52213b7ed14b3c5aa03077d9d94b621b27484875be429L10-R16)
[[3]](diffhunk://#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR8-R24)
## [0.10.0] - 2025-10-10
**What's New in This Release**
This release focuses on making mcp-windbg more reliable, faster, and
easier to use for everyone - from beginners to advanced users.
### New Features
**Core**
- Live debugging session support via `open_windbg_remote` and
`close_windbg_remote`
- Extended dump file support for `.mdmp` and `.hdmp` formats
- Microsoft Store WinDbg CDB compatibility
**Devops**
- Set up continuous integration that automatically tests the code with
Python versions 3.10 through 3.14
- Added automatic dependency updates to keep everything secure and
up-to-date
- Streamlined the release process so new versions reach users faster
**Development**
- Switched to `uv` - a lightning-fast Python package manager that's
10-100x faster than pip
- Development setup is now much quicker with commands like `uv sync` and
`uv run`
- More reliable builds with locked dependency versions
**Documentation**
- Added comprehensive debugging instructions for AI assistants
([`AGENTS.md`](AGENTS.md))
- Created structured templates to help analyze crash dumps more
effectively
([`.github/prompts/dump-triage.prompt.md`](.github/prompts/dump-triage.prompt.md))
- All documentation is now available in the [repository
Wiki](https://github.com/svnscha/mcp-windbg/wiki) for easy access
- Simplified the main [`README.md`](README.md) to focus on getting
started quickly
- Added this structured [`CHANGELOG.md`](CHANGELOG.md) to track all
project changes
### Improvements
**Performance Boost**: Build times are significantly faster thanks to
the new tooling
**Enhanced Security**: Automatic scanning and updates keep dependencies
secure
### 🤝 Community Contributions
Special thanks to [@sooknarine](https://github.com/sooknarine) for these
valuable contributions:
- [Find local dumps with other common extensions
#6](https://github.com/svnscha/mcp-windbg/pull/6) - Now finds more crash
dump files automatically
- [Add support for remote debugging
#10](https://github.com/svnscha/mcp-windbg/pull/10) - Connect to live
debugging sessions