5 Commits
Author SHA1 Message Date
Sven Scharmentke 90457306fe feat: ship a Claude Code plugin and host a marketplace for it (#88)
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.
2026-08-27 20:08:07 +02:00
Sven Scharmentke 2ebbe0041b Release 1.0.0: kernel debugging, session ids, and the cdb/kd split
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.
2026-07-16 20:43:47 +02:00
Sven ScharmentkeandClaude Opus 4.8 28444b4f86 docs: user-focused guide overhaul (HTTP, redaction, WER, expectations) (#58)
## Summary

A user-focused pass over the MkDocs guide: close the operational gaps
and tighten every page so
each capability is discoverable as a goal the reader recognizes, and the
limits are stated.

(Supersedes #57, which GitHub auto-closed when its base branch
`test/e2e-framework` was deleted
on the merge of #56. This branch is rebased onto `main` and contains
only the docs changes.)

## New use-case pages

- **Debug from another machine** (`scenarios/http-service.md`) - run the
server over the
streamable-http transport on a Windows host and drive it from your
laptop or a shared
debugging host. Server-side paths, binding/firewall, and a clear
**no-authentication** warning.
- **Redact sensitive data** (`scenarios/redaction.md`) - scrub
secrets/PII from tool output with
a `--filter-script` before it reaches a cloud model. Real script, client
wiring, hook contract.

## Reworked pages

- **Triage** - "Capture crashes automatically" with WER `LocalDumps`
(the registry path behind
  the no-directory `list_windbg_dumps` fallback).
- **Crash dump** - use the `dump-triage` prompt for a structured report.
- **Remote target** - attach-by-PID is unsupported (connect to a
`-server`).
- **Tools** - sessions are concurrent. **cli/clients** HTTP no-auth
note. **Index** scope note,
**getting-started** pointers, new **troubleshooting** entries for HTTP
and filter scripts, and
  cross-links throughout.

## Verification

- `python -m mkdocs build --strict` - clean; all new links and anchors
resolve.
- `pwsh scripts/Format-Docs.ps1 -Check` - no em/en dashes, no emoji.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 23:21:09 +02:00
Sven ScharmentkeandClaude Opus 4.8 642422caab test: rebuild the suite as a declarative end-to-end framework with subprocess coverage (#56)
## 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>
2026-06-08 23:13:31 +02:00
Sven ScharmentkeandClaude Opus 4.8 c3c3c7fa57 docs: onboard MkDocs site and migrate the wiki (#50)
## Summary

Onboards a MkDocs (Material) documentation site, mirroring the
dap-dbgeng setup, and migrates the GitHub wiki into it (trimmed to the
essentials: getting started, use cases, and a lookup reference).

## What's included

**Site infrastructure**
- `mkdocs.yml` - Material theme, VS Code blue palette, light/dark
toggle, the same markdown extensions and nav structure as dap-dbgeng.
- `requirements-docs.txt` - pinned `mkdocs` / `mkdocs-material` /
`pymdown-extensions`.
- `docs/assets/` - `extra.css` (brand color + mermaid styling) and the
self-contained `mermaid.js` loader.

**Pipeline**
- `.github/workflows/pages.yml` - builds with `mkdocs build --strict`
and deploys to GitHub Pages on pushes to `main` that touch docs.

**Content (migrated + trimmed from the wiki)**
- `index.md`, `getting-started.md`
- Use cases: `scenarios/` - analyze a crash dump, debug a remote target,
triage multiple dumps
- Reference: `reference/` - command-line options, tools, client
configuration
- `troubleshooting.md`

**Agent / authoring setup**
- Migrated `AGENTS.md` -> `CLAUDE.md` (concise, dap-dbgeng style).
- Added `.claude/rules/markdown.md` and
`.claude/rules/documentation.md`, plus `scripts/Format-Docs.ps1` to
enforce the typography rules (plain hyphens, no emojis).

**Housekeeping**
- README documentation links now point at the new site.
- `.gitignore` ignores `/site/`.

## Verification

- `mkdocs build --strict` - clean, all internal links resolve.
- `scripts/Format-Docs.ps1 -Check` - passes repo-wide (also fixed a
stray dash + emoji in CHANGELOG).

## One manual step

GitHub Pages is not enabled on the repo yet. After merge, set **Settings
-> Pages -> Build and deployment -> Source = GitHub Actions** (one time)
so `pages.yml` can publish to `https://svnscha.github.io/mcp-windbg/`.
Happy to enable it via API if you'd prefer.

## Notes / decisions

- Use-case pages chosen to match the product: crash dump, remote target,
triage. The wiki's separate per-client install pages are consolidated
into `reference/clients.md`.
- The wiki repo (`mcp-windbg.wiki`) is left untouched; we can archive or
redirect it once this is live.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 04:38:12 +02:00