mirror of
https://github.com/svnscha/mcp-windbg.git
synced 2026-10-19 14:22:23 +08:00
develop
15 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b2f8b36f7a | fix(cdb): open a remote session whose target is running (#145) | ||
|
|
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.
|
||
|
|
a376c7c4ce |
feat: open kernel crash dumps with open_kd_dump (#120)
Adds open_kd_dump, which opens a kernel crash dump with kd.exe -z as a kd session. Closes #111 |
||
|
|
f998e614c9 |
feat: run init commands on every new session (#121)
## What this changes
Adds a way to run debugger commands automatically when a session opens,
for example to `.load`
a debugger extension.
- `--init-command COMMAND` (repeatable), or `MCP_WINDBG_INIT_COMMANDS`
with one command per line
when no flag is given. These run on every `open_*` tool (dump, remote,
kernel), right after the
session opens and before triage. An extension loaded with `.load` is
therefore available to
`!analyze -v` and every later command.
- `--kernel-init-command COMMAND` (repeatable), or
`MCP_WINDBG_KERNEL_INIT_COMMANDS`, for commands
that only apply to kernel targets. They run after the shared commands,
on `open_kd_session`
and on dumps whose header is a kernel dump (`PAGEDUMP`/`PAGEDU64`), even
when opened with
`open_cdb_dump`. User-mode dumps (`MDMP`) and `open_cdb_remote` skip
them.
- Output from both lists leads the open result under `###
Initialization`, each command echoed
as `> command`.
- Docs: new "Init commands" section and two option rows in
`docs/reference/cli.md`; CHANGELOG
entry under Unreleased.
## Why
In-house and third-party debugger extensions (an OS-version helper,
driver-specific dumpers,
`.loadby sos clr` for .NET) have to be loaded by hand in every session,
and the model does not
know to do it. There was no hook for this: the server reads no
environment configuration, and
`additional_args` is not exposed on the CLI.
Some of these commands only make sense on a kernel target. For example,
reading the Windows
edition and LCU from the kernel just prints an error on a user-mode
minidump, which carries no
such data. So kernel-only commands get their own list. The server
decides by dump header rather
than by which tool opened the dump, because kernel dumps are often
opened with `open_cdb_dump`.
## How it was verified
Through the real MCP server over stdio (WinDbg 1.2606.22001.0),
configured as it would be in an
MCP client's `env` block:
`MCP_WINDBG_INIT_COMMANDS=".load <ext>.dll"`,
`MCP_WINDBG_KERNEL_INIT_COMMANDS="!winver"`.
| Dump | Initialization output |
|---|---|
| 66 GB complete kernel dump (`MEMORY.DMP`, `PAGEDU64`), via
`open_cdb_dump` | `.load` then `!winver`, which printed `Windows:
Windows 10 Enterprise ... build 28020, LCU 10.0.28000.2818` |
| `DemoCrash1.exe.7088.dmp` (user-mode, `MDMP`) | `.load` only;
`!winver` skipped |
On the kernel dump, the extension stayed loaded: `!winver` via
`run_cdb_command` later in the same
session worked. Section order was Initialization, then Crash
Information, then Crash Analysis.
Tests:
- New `init_commands.yaml` scenario against real cdb: shared commands
run before
Crash Information, and a `--kernel-init-command` is absent on a
user-mode dump.
- New hermetic tests in `test_init_commands.py`:
- shared commands run before triage on all three `open_*` tools
- no `Initialization` section when nothing is configured
- kernel-only commands run on `open_kd_session` and on
`PAGEDU64`/`PAGEDUMP` dumps, and not on
`MDMP` dumps or `open_cdb_remote`
- an unreadable dump is treated as user mode
- both environment variables are parsed one command per line, and CLI
flags take precedence
- Full suite: `uv run pytest src/mcp_windbg/tests/` gives 147 passed, 2
skipped (the live
kernel-target scenarios; no `MCP_WINDBG_KERNEL_CONNECTION` target was
configured).
- `pwsh scripts/Format-Docs.ps1 -Check` and `mkdocs build --strict` are
clean.
Note: if #120 (`open_kd_dump`) merges first, its handler needs the same
one-line call,
`results.extend(_init_sections(session, _init_for(kernel=True),
effective))`. I can rebase
to add it.
---------
Co-authored-by: Sven Scharmentke <sven.scharmentke@liasoft.de>
|
||
|
|
c8e2355696 |
fix(debugger): preserve output on command timeout (#114)
Fixes #112. ## What this changes - Preserve the debugger lines already read when a marked CDB command times out. - Bound timeout diagnostics to 2,000 lines and 64 KiB, with a truncation note. - Document the preserved output in the timeout troubleshooting guide and changelog. ## Why The reader kept output in a private buffer until the completion marker arrived. A runaway SOS command such as `!clrstack` could therefore print useful frames and then lose all of them when the timeout path fired. The timeout error now includes that partial output and also exposes it on `DebuggerError.partial_output`; marker synchronization and the existing manual break-in warning are unchanged. ## How it was verified - The new timeout regression fails on `35b6cdb` and passes with the fix; the same test asserts the preserved line and the bounded diagnostic behavior. - `test_debug_session.py`: 66 passed. - Hermetic suite: 103 passed, 12 deselected; full suite: 103 passed, 12 skipped because this host has no CDB/KD or Git LFS debugger dumps. - `uv lock --check`, MCP schema validation, docs formatter, `compileall`, `uv build`, `twine check`, and `git diff --check` passed. Co-authored-by: Oscar <319719771+Oscar-Williams@users.noreply.github.com> Co-authored-by: Sven Scharmentke <sven.scharmentke@liasoft.de> |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
30c7dd9d9f |
Fix kernel go/break-in handling, add wait_for_break (#80)
Fixes #71, #72, #73. Supersedes #74. @TempAccountNull diagnosed all three bugs correctly. This keeps every fix and the credit, but replaces the patch - it had a defect that would have broken stepping - and adds one more bug found by backtesting against a real kernel target. ## The three reported bugs - **Named pipe / COM sessions always timed out** (#71). `kd` announces a pipe or serial link with `Kernel Debugger connection established`, not the KDNET `Connected to target ...`. Only the latter was matched, so `open_kd_session` sat waiting for a banner that was never coming on a target that had in fact attached. - **`g` re-froze the target it had just released** (#72). Go-class commands hand the CPU back and the debugger stops reading stdin, so the marker protocol's `.echo` sat unread, the command hit its timeout, and the cancel-on-timeout CTRL+BREAK halted the machine again. - **Any command after `g` did the same** (#73), through the same path - the session had no concept of "the target is running". ## Why #74 is not merged as-is Its `_GO_COMMANDS` set includes `p`, `t`, `pa`, `ta`. Those are *step* commands: they execute one instruction or line and come straight back to the prompt. Treating them as fire-and-forget swallows their output, returns `"Target resumed."` instead, and leaves the session believing the target is running - so the next command fires a spurious CTRL+BREAK. Stepping would have become unusable. The step family keeps the marker round-trip here, with a test pinning it. ## The fourth bug, found by backtesting `_resume_target` wrote `g` and returned immediately. Until `kd` reads it, `kd` is still at its prompt with the resume unread - and a CTRL+BREAK arriving in that window is answered by the prompt rather than reaching the target. The break is silently lost and the caller then waits out a full `wait_for_break` timeout on a machine nothing will stop. That is exactly the sequence a tool caller writes, because `run_kd_command("g")` now returns instantly. Measured on the live KDNET target: | gap after `g` | result | | :--- | :--- | | 0.00s | **break lost** (every attempt) | | 0.05s | landed in 0.04s | | 0.25s / 1s / 2s | landed | The resume is now probed with a marker the debugger can only answer from a prompt. Silence means it stopped reading stdin - the target is away and the resume can no longer swallow a break. An answer means the target never left, which is a bonus fix: a `gu` that returns in microseconds, or a breakpoint hit at once, now reports what it printed instead of falsely claiming the target is running. ## Also in here - `wait_for_break` - block until a target stops (bugcheck, breakpoint, manual break) and return what it printed. Asks the debugger rather than trusting a flag, so it is right about targets this server never resumed. If the wait expires the target is left **running**. - Compound forms: `bp nt!X; g` runs the breakpoint first and returns its result, so a typo'd symbol surfaces as `Couldn't resolve error` rather than a 300s wait for a break that can never come. A `;` inside a quoted command string is left alone. - Qualified forms `~0 g` / `~*g` are recognized. - One operation at a time per session; closing a session ends a wait parked on it. ## Verification Against the real kernel target (Windows 11 26100, KDNET): - `scenarios/kernel_resume_and_wait.yaml` - new, covers resume, auto break-in, and the zero-gap break. **Verified to fail without the fix** with exactly the lost-break symptom, and to pass with it. - `scenarios/kernel_session.yaml` - still passes. - Machine confirmed left running afterwards, with no breakpoints behind. Hermetic and user-mode: - 89 hermetic tests pass (was 29 on `main`). - 10 `live` user-mode scenarios pass, including the new `resume_and_wait.yaml` against a real `cdb.exe`. - Coverage 91% under CI's conditions, against the 88% gate. - `mkdocs build --strict` clean; `docs/reference/tools.md` documents the resume semantics. **One limitation worth stating:** #71 is the one fix I could not exercise end to end - this box has a KDNET target, not a pipe one. It is covered hermetically for both banner wordings, and I did capture `Kernel Debugger connection established.` verbatim from real `kd` output during a KDNET reconnect, so the string is genuine. That it appears *instead of* the KDNET wording on a pipe transport rests on @TempAccountNull's report and their verified before/after. --------- Co-authored-by: TempAccountNull <TempAccountNull@users.noreply.github.com> |
||
|
|
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. |
||
|
|
3bf2c0be13 |
docs: add Autohand Code MCP setup (#63)
## Summary Add an Autohand Code command beside the existing Claude Code registration. The note explains that the server inherits `_NT_SYMBOL_PATH` from the environment that launches Autohand. ## Verification - `git diff --check` - `uv run pytest` cannot collect on macOS because the Windows-only server imports `winreg`; Windows CI remains the appropriate runtime check --------- Co-authored-by: Sven Scharmentke <24257042+svnscha@users.noreply.github.com> |
||
|
|
0c01c283ed |
docs: add Claude Code client guide and simplify README config
Document `claude mcp add` for Claude Code (both uvx and python -m) in docs/reference/clients.md, mirroring the project-scoped setup in ~/.claude.json. Trim the README's duplicated filter-script and HTTP/VS Code blocks down to the two common setups (VS Code, Claude Code) plus a uvx note, linking the docs for the rest. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |