cdbmcp

cdbmcp

Enables AI clients to inspect live memory of a running C++ process on Windows using cdb.exe, providing tools to evaluate expressions, retrieve map entries, and enumerate containers without modifying target code.

Category
Visit Server

README

cdbmcp

A standalone MCP (Model Context Protocol) server for Windows that attaches to a running C++ process and exposes three toolsevaluate, 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 obj->member.field
Call an out-of-line function (singleton accessor) ⚠️ opt-in needs --allow-calls; Instance()->field (runs target code)
Dump a whole struct / container (??) ✅ (text) default evaluate
List elements of any container enumerate (STL walker first, dx/NatVis fallback)
Call inlined STL (map::find, map::operator[], vector::operator[]) use map_get / enumerate, or an out-of-line accessor

These limits come from the C++ evaluator / MSVC STL, not from cdbmcp — cdbmcp only passes the expression through.

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\x64 paths, --cdb-path, or CDB_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.exe

Client 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 SECRET

Endpoint: 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.py drives cdbmcp over stdio and python tests/demo_http_session.py drives 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.

⚠️ .call runs 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
cdbmcp/cdb_controller.py Resident cdb subprocess; attach / interrupt / go / detach; query serialization; watchdog break
cdbmcp/cdb_protocol.py Byte-oriented reader with sentinel-based delimiting (cdb has no GDB/MI)
cdbmcp/evaluator.py evaluate: validate → interrupt → ?? (text) / dx (json tree) → resume; resolve_calls (.call, opt-in); error mapping
cdbmcp/container_query.py map_get / enumerate: STL walker first, dx/NatVis fallback
cdbmcp/stl_walker.py Walk MSVC STL tree / unordered (_Hash) / vector internals via the C++ EE — no inferior calls
cdbmcp/formatters.py text/json rendering; prompt/banner cleanup; dx tree → typed JSON parser
cdbmcp/watchdog.py Cancellable wall-clock timer → forced break
cdbmcp/errors.py Error classification + friendly messages
cdbmcp/auth.py Shared-secret bearer auth + pure-ASGI middleware (HTTP transport)
cdbmcp/http_transport.py Streamable-HTTP transport (uvicorn) with bearer auth
cdbmcp/lifecycle.py atexit + console-control handlers → clean detach
cdbmcp/mcp_server.py FastMCP server registering the three tools
cdbmcp/config.py Config load (JSON + CLI + cdb discovery)
cdbmcp/__main__.py 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 (_Hash chain) and vector internals are walked directly via the C++ EE (no inferior calls); dx/NatVis is the fallback for anything else.
  • Interrupt: -exec interruptGenerateConsoleCtrlEvent (Ctrl-Break to cdb's process group). A raw 0x03 byte 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/-gPDB + _NT_SYMBOL_PATH / --symbol-path.
  • Attach overhead: a live C++ target raises first-chance exceptions constantly; cdbmcp runs sxn eh so the engine does not break on them.
  • Transports: stdio (default) and HTTP (streamable-http) with shared-secret bearer auth.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured