7 Commits

Author SHA1 Message Date
Sven Scharmentke 4cce8b1d65 build: add a standalone mcp-windbg.exe build (#143)
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.
2026-10-10 16:47:04 +02:00
Sven Scharmentke 7c55ac325f feat(plugin): package skills and agents as separate plugins (#106)
Separate the MCP server, four debugging skills, and crash-analyst agent into independently installable plugins. Document installation and migration, support existing MCP connections, and validate every marketplace version.
2026-09-10 01:24:35 +02:00
Sven Scharmentke d3ddd90588 feat(plugin): name the marketplace entry by how it ships (#97)
Installing becomes:

```
/plugin marketplace add svnscha/mcp-windbg
/plugin install mcp-windbg-uvx@mcp-windbg
```

This frees the plain `mcp-windbg` name for a self-contained build and
makes room for `mcp-windbg-pipx` beside it. Doing it **before** 1.2.0
rather than after means there is no rename migration to run: the old
name was never published.

## The syntax is plugin@marketplace, not the reverse

Worth stating since it drove the shape here. `claude plugin install
--help`:

> use plugin@marketplace for specific marketplace

So `mcp-windbg@uvx` would mean "plugin `mcp-windbg` from a marketplace
called `uvx`" and would need three separate marketplaces. The variant
has to live in the plugin name, which is what this does.

## The two names do different jobs

`plugin.json`s `name` deliberately stays `mcp-windbg`. I verified the
split by installing a plugin whose two names differed on purpose:

| Name | Governs | Observed |
| :--- | :------ | :------- |
| marketplace entry | install identity, plugin cache directory |
`cache/probe-mp/mcp-windbg-uvx/` |
| `plugin.json` `name` | skill and MCP tool scoping |
`plugin:mcp-windbg:mcp-windbg` |

and a headless session confirmed the skills:

```
/mcp-windbg:analyze-dump
/mcp-windbg:debug-remote
/mcp-windbg:kernel-debug
/mcp-windbg:windbg-doctor
```

That is the good outcome. Every future variant keeps **identical skill
names, identical tool names and one set of documentation** - only the
install command differs. Renaming `plugin.json` instead would have
renamed every skill and every tool with it, and split the docs three
ways.

The distinction is recorded in CLAUDE.md, because nothing about the two
fields makes it obvious.

## Also verified

Installed from the real marketplace under the new name:

```
Source: mcp-windbg-uvx@mcp-windbg
Skills (4)  analyze-dump, debug-remote, kernel-debug, windbg-doctor
Agents (1)  crash-analyst
MCP servers (1)  mcp-windbg
```

`claude plugin validate` passes, docs typography clean, and every
occurrence of the old install command across the README, plugin README,
getting-started, clients, plugin reference and CHANGELOG is updated.
Test state removed afterwards.

## Note on sequencing

The open release PR (#91) predates this, so its 1.2.0 CHANGELOG entry
still shows the old command. Once this merges I will delete the release
branch and let release-please rebuild it, which is the documented way to
refresh a release PR - `sync-lockfile` now re-does the lockfile commit
on its own.
2026-08-27 22:09:51 +02:00
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 Scharmentke 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 Scharmentke 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