cdbmcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cdbmcpevaluate global_config.timeout"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cdbmcp
A standalone MCP (Model Context Protocol) server for Windows that attaches
to a running C++ process and exposes three tools — evaluate, map_get,
enumerate — to inspect the target's live memory via a resident cdb.exe
subprocess.
It is a faithful Windows port of gdbmcp: zero source-level intrusion (no target code or build is modified). The AI writes the field/path it wants as a C++ expression; cdbmcp passes it verbatim to cdb, which resolves symbols from the target's PDB and returns the value.
MCP client ──stdio or HTTP──▶ cdbmcp (Python) ──text cmds──▶ cdb.exe ──debug attach──▶ target C++ process (+PDB)What works (and what doesn't) — read this first
cdb's C++ expression evaluator is powerful but has the same hard limit as GDB on a stock MSVC STL target: inlined STL methods cannot be called.
Want | Works? | How |
Read a field / follow pointers | ✅ |
|
Call an out-of-line function (singleton accessor) | ⚠️ opt-in | needs |
Dump a whole struct / container ( | ✅ (text) | default |
List elements of any container | ✅ |
|
Call inlined STL ( | ❌ | use |
These limits come from the C++ evaluator / MSVC STL, not from cdbmcp — cdbmcp only passes the expression through.
Related MCP server: MCP Server for WinDbg Crash Analysis
Target pause model
cdb attaches with a debug attach, which stops the target at the initial
breakpoint. cdbmcp keeps the target running between queries and briefly
interrupts it (Ctrl-Break) per tool call — a few milliseconds for a pure data
read, longer if the expression triggers an inferior function call. A wall-clock
watchdog (which forces a break into the engine) aborts any call that does not
return. On cdbmcp exit (stdin closed, Ctrl-C/Break, console close) it
detaches (qd, never kills) the target, which resumes normal execution.
Set "pause_mode": "frozen" to instead break once at attach and keep the target
stopped for the whole session (debug fallback; freezes the live process).
Requirements
Windows x64.
cdb.exe (Windows Debugging Tools / Windows Kits). Auto-detected from the usual
Windows Kits\10\Debuggers\x64paths,--cdb-path, orCDB_PATH.A target built with debug info (a matching PDB) for symbol resolution.
Privilege to attach to the target (same user / same integrity, or run elevated if the target is elevated). Only one debugger may attach at a time.
Install
pip install -e .(Adds the mcp dependency and an entry point cdbmcp.)
Run
cdbmcp is always a single standalone process that attaches to the target PID at startup and stays attached for its whole life (it never respawns cdb per query). The only difference between the two modes is the transport:
┌──────────────────────────────────────────┐
AI client ─stdio/──▶│ cdbmcp.exe (standalone, long-running) │
HTTP │ · attaches to target PID at startup │──▶ live C++ target (+PDB)
(Claude Code / │ · resident cdb, read-only │
Cursor / remote / │ · stdio OR streamable-http + bearer │
many at once) └──────────────────────────────────────────┘stdio (default): the MCP client launches cdbmcp as its own subprocess and talks over stdin/stdout. Simplest for a local Claude Code / Cursor.
HTTP: you start cdbmcp yourself as a long-running service; many and/or remote clients then connect to
http://<host>:<port>/mcp. This is the model when cdbmcp should be one shared process serving several AI clients.
Common flags (both modes): --pid <PID> (required), --cdb-path D:\Debuggers\cdb.exe,
--symbol-path "srv*C:\Symbols;D:\your\app", --pause-mode per_query|frozen,
--config config.json. Run python -m cdbmcp --help for the full list.
stdio
python -m cdbmcp --pid <PID> --cdb-path D:\Debuggers\cdb.exeClient config (Claude Code / Cursor) — client launches cdbmcp:
{
"mcpServers": {
"cdbmcp": { "command": "python",
"args": ["-m", "cdbmcp", "--pid", "12345",
"--cdb-path", "D:\\Debuggers\\cdb.exe"] }
}
}HTTP (standalone service, multi/remote client)
Start cdbmcp once as a service (it attaches immediately and stays up):
python -m cdbmcp --transport http --host 0.0.0.0 --port 8000 ^
--pid <PID> --cdb-path D:\Debuggers\cdb.exe ^
--symbol-path "srv*C:\Symbols;D:\your\app" ^
--auth-token SECRETEndpoint: POST http://<host>:8000/mcp (MCP streamable-http). Clients connect
to the URL with the bearer token:
{
"mcpServers": {
"cdbmcp": { "url": "http://your-host:8000/mcp",
"headers": { "Authorization": "Bearer SECRET" } }
}
}Security: evaluate reads arbitrary target memory, so any remote exposure
must be authenticated. Without --auth-token / CDBMCP_TOKEN cdbmcp warns
and forces 127.0.0.1-only. For production put a reverse proxy (nginx/caddy,
TLS) in front and bind loopback — otherwise the token travels in cleartext.
Queries are serialized through one cdb session, so concurrent clients queue
cleanly rather than stepping on each other.
The tools
All three are called the same way — a tools/call JSON-RPC over stdio or HTTP,
after the standard initialize / notifications/initialized handshake.
End-to-end demos (build the fixture first, see below):
python tests/demo_ai_session.pydrives cdbmcp over stdio andpython tests/demo_http_session.pydrives a standalone HTTP cdbmcp, each running real AI-style queries against the fixture.
evaluate(expression, format="text")
Evaluate a read-only C++ expression. text is a WinDbg-style recursive dump;
json returns a typed tree {name, type, value|children} parsed from
cdb's dx/NatVis — scalars coerced to int/float/bool, std::string shown as
its content, structs/containers recursed (depth/width capped), STL bookkeeping
([Raw View]/size/capacity/allocator…) pruned. On error returns a plain
diagnostic string; server, debugger and target never crash.
Inferior function calls (--allow-calls)
cdb's C++ evaluator (??) cannot call functions, so an expression like
GameWorld::Instance()->players fails with "Extra character error". With
--allow-calls (or "allow_inferior_calls": true in config) cdbmcp resolves a
leading accessor call via cdb .call (it runs the function in the target,
reads the returned pointer) and rewrites the rest to member access — so
GameWorld::Instance()->players, map_get("GameWorld::Instance()->players", "1001")
etc. work. Nested calls (A()->B()) are not flattened; prefer the leading
accessor + member access + the container tools.
⚠️
.callruns target code (side effects, possible deadlock) and breaks the read-only guarantee — hence OFF by default. cdbmcp prints a warning when it is on. Only the leading call is executed; everything after it stays member-access-only.
map_get(map_expr, key_expr, format="text")
Look up one element by key in std::map / multimap without calling any
inlined STL method. std::map/multimap (red-black tree) and
std::unordered_map/unordered_multimap (_Hash element chain) are walked
directly and the key is compared in-engine (first == key_expr). Struct keys
without a usable == fall back to a dx dump. Use a C-style cast for struct
keys: map_get("world->m_players", "(EntityID)1002").
enumerate(container_expr, limit=100, format="text")
List up to limit elements of any STL container. map/set/multimap/
multiset (tree), unordered_* (_Hash chain) and vector are all walked
directly (no inferior calls); anything unrecognised falls back to dx/NatVis.
Test fixture
tests/fixtures/target.cpp is a tiny C++ process with a singleton GameWorld
holding std::map<int,Player>, std::unordered_map<int,Item> and
std::vector<Item>, plus out-of-line accessors.
cd tests\fixtures
build.bat :: produces target.exe + target.pdb
target.exe :: prints PID=..., then idles
:: in another shell:
python -m cdbmcp --pid <that PID>Architecture / code map
File | Role |
| Resident cdb subprocess; attach / interrupt / go / detach; query serialization; watchdog break |
| Byte-oriented reader with sentinel-based delimiting (cdb has no GDB/MI) |
|
|
|
|
| Walk MSVC STL tree / unordered ( |
| text/json rendering; prompt/banner cleanup; |
| Cancellable wall-clock timer → forced break |
| Error classification + friendly messages |
| Shared-secret bearer auth + pure-ASGI middleware (HTTP transport) |
| Streamable-HTTP transport (uvicorn) with bearer auth |
| atexit + console-control handlers → clean detach |
| FastMCP server registering the three tools |
| Config load (JSON + CLI + cdb discovery) |
| CLI entry: parse args, attach, serve stdio or HTTP |
Differences from gdbmcp
Engine: GDB/MI subprocess → resident cdb.exe subprocess (text protocol with sentinel delimiting, since cdb has no MI).
STL layout: libstdc++/libc++ → MSVC STL. Tree (
_Tree), unordered (_Hashchain) and vector internals are walked directly via the C++ EE (no inferior calls);dx/NatVis is the fallback for anything else.Interrupt:
-exec interrupt→GenerateConsoleCtrlEvent(Ctrl-Break to cdb's process group). A raw0x03byte on cdb's piped stdin does NOT break a running target — console control events don't flow through pipes — so cdbmcp launches cdb in its own process group and signals it (allocating a console when cdbmcp itself has none, e.g. under an MCP client).Symbols: DWARF/
-g→ PDB +_NT_SYMBOL_PATH/--symbol-path.Attach overhead: a live C++ target raises first-chance exceptions constantly; cdbmcp runs
sxn ehso the engine does not break on them.Transports: stdio (default) and HTTP (streamable-http) with shared-secret bearer auth.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/luckinbyte/cdbmcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server