mcp-debugger

io.github.debugmcp由 GitHub 账号 debugmcp 发布v0.26.0更新于 Oct 31, 2026

Step-through debugging for AI agents: breakpoints, stepping and live variables in ten languages

概览

AI 生成的概览

基于 MCP 的无界面单步调试器:让助手在十种语言中设置断点、单步执行、查看变量并求值表达式。

可以做什么
  • 创建、列出、重启和关闭调试会话,并列出支持的语言与适配器
  • 设置、列出、删除和清空断点,支持按内容、按函数以及日志断点
  • 启动脚本或失败的测试、附加到运行中的进程、分离,并暂停或继续执行
  • 单步跳过、步入和步出,并阻塞等待下一次停止
  • 查看线程、调用栈、作用域、局部变量和变量,并求值表达式
  • 读取缓冲的程序输出、获取源码上下文、热重载,并为 IDE 开放只读 DAP 镜像
适用场景
适合需要定位运行中程序根因而非仅凭源码猜测的场景:失败的测试、崩溃、变量值异常,或容器与 Pod 中行为异常的服务。也适合 CI 运行器、容器和云端沙箱等没有 IDE 的无界面环境。
运行要求
通过 npx 或 Docker 以 stdio 在本地运行;npm 包需要 Node.js 22+。每种被调试语言还需各自的工具链(如 debugpy、rdbg、Delve、JDK 21+、.NET SDK、Rust 工具链、C/C++ 编译器、GnuCOBOL 或 Dart/Flutter SDK)。未声明认证或环境变量。
安装前请注意
它会启动并附加到真实进程,可暂停、重启或热重载这些进程,请只对允许运行的代码使用。远程附加和可选的 HTTP 模式可访问其他机器;HTTP 端点无认证,仅靠回环主机检查保护,除非另行配置允许的主机。默认开启敏感信息脱敏,但变量与输出内容仍会传给模型。

安装

在 SourceWeft 中

  1. 打开 控制台中的 mcp-debugger,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

mcp-debugger

A headless, agentic debugger over MCP — let your AI agents debug running programs in ten languages.

[CI] [codecov] [npm version] [Docker Pulls] [License: MIT] [OpenSSF Scorecard] [OpenSSF Best Practices]

🎯 Overview

mcp-debugger is a Model Context Protocol (MCP) server that exposes step-through debugging as structured tool calls. It lets AI agents set breakpoints, inspect variables, evaluate expressions, and step through running programs across ten languages — driving real language debuggers through the Debug Adapter Protocol (DAP).

No IDE required. mcp-debugger runs anywhere Node.js runs: CI runners, Docker containers, Kubernetes pods, SSH boxes, and the sandboxes that cloud coding agents live in. It's the debugger for where IDEs can't go.

When to use mcp-debugger vs an IDE-bound debug server

Microsoft's DebugMCP exposes VS Code's debugger over MCP and is a good choice when your agent works inside a running VS Code. The two projects make different structural trade-offs:

mcp-debuggermicrosoft/DebugMCP
Runs headless (CI, containers, k8s, cloud agents)✅ standalone Node process❌ requires a running VS Code
Transportsstdio + Streamable HTTPStreamable HTTP (localhost)
Distributionnpx, npm, Docker imageVS Code Marketplace extension
Remote attach without an IDE✅ debugpy / rdbg / JDWP, incl. pods via port-forward❌
Per-session process isolation✅ one proxy process per sessionshares the VS Code instance
Java hot-swap and Flutter hot reload (hot_reload)✅❌
Debuggee output as subscribable MCP resource✅❌
In-IDE debugging UX alongside the agent✅ read-only IDE mirror (expose_session) — the IDE joins the agent's live session✅ native
Logpoints without pausing (prod-safe value watching)✅ logMessage breakpoints✅ via VS Code
Content/function-addressed breakpoints (statement:, function:, expectedContent)✅ agent-native addressing that survives edits—
Secret redaction on by default✅ variable/evaluate/output masking + least-privilege mode—
Kubernetes ephemeral debug sidecar (native attach-by-PID)✅ kubectl debug flow❌
C/C++✅ via CodeLLDB (launch + attach-by-PID)✅ via VS Code extensions
COBOL✅ via GnuCOBOL + CodeLLDB (launch + attach-by-PID, COBOL-shaped variables)—
Dart/Flutter✅ via the SDK's own debug adapters (launch + attach by VM-service URI, or by deviceId for an app on an Android device; Dart programs and tests, Flutter apps and tests on desktop, web, Android emulators and devices, macOS and the iOS simulator; hot reload and hot restart)—
PHP❌✅ via VS Code extensions
LanguagesPython, JS/TS, Ruby, Rust, Go, Java, .NET, C/C++, COBOL, Dart/FlutterPython, JS/TS, Ruby, Rust, Go, Java, .NET, C/C++, PHP

If your agent runs in a terminal, a pipeline, or a cloud sandbox — or needs to attach to a process on another machine — you want mcp-debugger.

🆕 v0.26.0 — Dart and Flutter debugging lands (the SDK's own debug adapters: Dart programs and tests, Flutter apps and tests on desktop, web, Android and the iOS simulator, hot reload and hot restart), every stop answer carries a snapshot of the exception, top frames and locals (a repeated stop reports only what changed), wait_for_stop blocks until the next stop instead of polling, and one-call failing-test debugging for pytest pauses at the failing assert with no breakpoint set. Also new: one launch contract for every language (a short hold, then pending: true), dryRunSpawn as a side-effect-free query, hot_reload (replacing redefine_classes, kept as a deprecated alias), Streamable HTTP spec conformance checked in CI, and host/Docker build caches that no longer collide. See the CHANGELOG for the full release history.

✨ Key Features

  • 🌐 Multi-language support – Clean adapter pattern for any language
  • 🐍 Python debugging via debugpy – Full DAP protocol support
  • 💎 Ruby debugging via rdbg – Launch and attach workflows, including remote attach to containers and Kubernetes pods
  • 🟨 JavaScript (Node.js) debugging via js-debug – VSCode's proven debugger
  • 🦀 Rust debugging via CodeLLDB – Debug Rust & Cargo projects (Linux/macOS; Windows needs the GNU toolchain — see Rust on Windows)
  • 🐹 Go debugging via Delve – Full DAP support for Go programs
  • ☕ Java debugging via JDI bridge – Launch and attach modes with JDK 21+
  • 🔷 .NET/C# debugging via netcoredbg – Debug .NET applications with full DAP support
  • ⚙️ C/C++ debugging via CodeLLDB – Launch prebuilt binaries or lone source files (auto-compiled), attach by PID; core dumps and gdbserver/rr targets via config pass-through
  • 🧮 COBOL debugging via GnuCOBOL + CodeLLDB – Launch .cob/.cbl sources (auto-compiled with cobc) or prebuilt executables, attach by PID; WORKING-STORAGE / LOCAL-STORAGE / LINKAGE scopes with DISPLAY, COMP, COMP-3 and 88-level values decoded, breakpoints in copybooks, statement-granular stepping, and a pause on libcob runtime errors (the S0C7/SSRANGE analogues) — built for mainframe-to-GnuCOBOL migrations (guide)
  • 🐦 Dart/Flutter debugging via the SDK's own debug adapters – Launch Dart programs and package:test files (dart debug_adapter) or Flutter apps and tests (flutter debug-adapter), the runner auto-detected from pubspec.yaml and the program path; attach to a running VM by service URI or service-info file; conditional breakpoints, logpoints, Unhandled/All exception filters, noDebug. Nothing is vendored — the Dart or Flutter SDK on the machine is the debugger. Flutter runs on Windows, macOS and Linux desktops, in Chrome or Edge, on Android emulators and devices and on the iOS simulator, with hot_reload and a hot restart_debugging once the app has started; an app on an Android device attaches by deviceId alone (guide)
  • 🧪 Mock adapter for testing – Test without external dependencies
  • 🛰️ Out-of-IDE & remote attach – Attach over host/port to a process on another machine or inside a container (Python via debugpy, Ruby via rdbg, JavaScript via the V8 inspector, Java via JDWP, Dart/Flutter via the VM-service URI) with source-path mapping, or by PID for native code (C/C++, COBOL) and for a local Node.js process, whose inspector mcp-debugger opens for you (JavaScript). Python and Ruby attach direct-connect — the debug engine already runs inside the target, so no local Python or Ruby is needed; JavaScript, Java, .NET, C/C++, COBOL and Dart/Flutter spawn a local adapter instead; of those, only Java (a JDK), .NET (netcoredbg) and Dart/Flutter (the Dart or Flutter SDK, whose own debug adapter does the work) need a toolchain you install, since the JavaScript, C/C++ and COBOL debug engines ship with the package. list_supported_languages reports per-mode availability with reasons
  • 🎯 Breakpoints that survive edits – Address by content (statement: "total = sum(prices)"), by symbol (function: "main"), or assert line content with expectedContent; anchors re-resolve across restart_debugging and weak matches warn loudly
  • 🪵 Logpoints – set_breakpoint with logMessage: "x={x}" streams interpolated values into get_output without pausing — prod-safe value watching on hot paths
  • 🧰 Full breakpoint lifecycle – list_breakpoints / remove_breakpoint / clear_breakpoints work live mid-run; restart_debugging relaunches with the same config and re-applies everything in one call
  • 📡 Buffered program output – get_output returns debuggee stdout/stderr with a cursor, and each session exposes its transcript as a subscribable MCP resource
  • 💥 Crash-state debugging by default – Launch sessions pause on uncaught exceptions with stack and locals live (breakOnExceptions; exception class/message surfaced via lastStop)
  • 🪞 Read-only IDE mirror – expose_session opens a loopback, token-gated DAP endpoint so a human's IDE can inspect the agent's live session without taking control
  • ☸️ Kubernetes debugging – port-forward attach for interpreted runtimes, kubectl debug --target + attach-by-PID for native processes (recipe, turnkey manifests)
  • 🔌 STDIO and Streamable HTTP transports – Works with any MCP client
  • 📦 Zero-runtime dependencies – Self-contained bundles via esbuild + tsup
  • ⚡ npx ready – Run directly with npx @debugmcp/mcp-debugger - no installation needed
  • 🐳 Docker and npm packages – Deploy anywhere
  • 🤖 Built for AI agents – Structured JSON responses for easy parsing
  • 🔒 Secret redaction on by default – Credential-shaped values (API keys, tokens, private keys) are masked as labeled placeholders in variable, evaluate, and output results before they reach the agent (details; opt out with DEBUG_MCP_NO_REDACT=1)
  • 🛡️ Path validation – Prevents crashes from non-existent files
  • 📝 AI-aware line context – Intelligent breakpoint placement with code context
  • ✅ Comprehensive test suite – unit, integration, and end-to-end coverage across every adapter (CI status)

🧠 Agent Skill

Tools tell an agent what it can do; a skill teaches it how to debug well. This repo ships an agent skill covering the session golden path, root-cause discipline (bisection over line-by-line stepping), attach/remote recipes, and per-language quirks:

bash
# Claude Code (user-level)cp -r skills/debugging ~/.claude/skills/mcp-debugger# Cross-agent directories (Copilot CLI and friends)cp -r skills/debugging ~/.agents/skills/mcp-debugger

The server also serves condensed guidance in-band: MCP instructions on connect, plus a debugging-workflow prompt any MCP client can request. See skills/debugging/README.md for details.

🎬 See It In Action

  • Auto-debug failing CI tests – a composite GitHub Action that launches mcp-debugger + an agent on a test failure and posts the root-cause analysis
  • Sick pod walkthrough – attach to a misbehaving Python service in Kubernetes via port-forward (tutorial)
  • Native sick pod – same story for compiled code: ephemeral debug sidecar + attach-by-PID, no in-process agent required

🚀 Quick Start

Requirements: Node.js 22+ for the server. Each language you debug also needs its own toolchain installed (Python + debugpy, Ruby + the debug gem / rdbg, Node.js, Go + Delve, JDK 21+, .NET SDK, the Rust toolchain, a C/C++ compiler — g++/clang++, only needed for source-file launch — GnuCOBOL 3.1.2+ for COBOL source launch, or the Dart SDK — Flutter bundles one — for Dart/Flutter). Not sure what's installed? Run npx @debugmcp/mcp-debugger doctor for a per-adapter toolchain report.

CodeLLDB platform note (npx/npm installs): the CodeLLDB debug engine ships as per-platform optional dependencies (@debugmcp/codelldb-win32-x64, -darwin-x64, -darwin-arm64, -linux-x64, -linux-arm64) — npm installs exactly the one matching your platform, so Rust and C/C++ debugging work out of the box everywhere npm serves. If you install with --omit=optional, set CODELLDB_PATH to a CodeLLDB release binary instead, or use the Docker image.

For MCP Clients (Claude Desktop, etc.)

Add to your MCP settings configuration:

json
{  "mcpServers": {    "mcp-debugger": {      "command": "node",      "args": ["C:/path/to/mcp-debugger/dist/index.js", "stdio", "--log-level", "debug", "--log-file", "C:/path/to/logs/debug-mcp-server.log"],      "disabled": false,      "autoApprove": ["create_debug_session", "set_breakpoint", "get_variables"]    }  }}

For Codex CLI, desktop, and IDE

Register the published stdio server with the Codex CLI:

bash
codex mcp add mcp-debugger -- npx -y @debugmcp/mcp-debugger stdiocodex mcp list

Codex stores this entry in ~/.codex/config.toml. The ChatGPT desktop app, Codex CLI, and Codex IDE extension share that configuration when they run on the same Codex host. Restart the active desktop client or IDE extension (or start a new CLI session), then use /mcp to confirm that mcp-debugger is connected. See the official Codex MCP documentation for configuration and troubleshooting details.

Developing mcp-debugger itself? Use the restartable source dev proxy instead of the published package.

For Claude Code CLI

For Claude Code users, we provide an automated installation script:

Prerequisite: The Claude CLI must be installed and available on your PATH before running the installation script. See Claude Code documentation for installation instructions.

bash
# Clone the repositorygit clone https://github.com/debugmcp/mcp-debugger.gitcd mcp-debugger
# Run the installation script./scripts/install-claude-mcp.sh
# Verify the connection (use 'claude mcp list' if claude is on your PATH)claude mcp list

Important: The stdio argument is required to prevent console output from corrupting the JSON-RPC protocol. See CLAUDE.md for detailed setup and troubleshooting.

For the pi coding agent

pi 0.99 and later has built-in MCP support. The published @debugmcp/mcp-debugger package is also a pi package: one install adds the mcp-debugger agent skill and an extension that registers the server with pi's MCP support:

bash
pi install npm:@debugmcp/mcp-debugger  # the mcp-debugger skill, and the server via pi's built-in MCPpi list                                # shows the package

The extension runs the CLI that pi install put on disk, so the server matches the skill and starts without an npx download. It registers with deferred exposure: pi lists the debugger in its system prompt, and the model loads the tools it needs with tool_search, named mcp__mcp_debugger__<tool>. /mcp shows the server and changes its exposure for a session. A mcp-debugger entry in ~/.pi/agent/mcp.json replaces the registration, for example to debug a source build through the dev proxy.

To add only the server, without the skill: pi mcp add mcp-debugger -- npx -y @debugmcp/mcp-debugger stdio. pi older than 0.99 has no built-in MCP support; the extension then does nothing, so upgrade pi.

Using Docker

bash
docker run -i --rm -v $(pwd):/workspace debugmcp/mcp-debugger:latest

The Docker image debugs Python, JavaScript, Java, Rust, C/C++, COBOL, and Dart natively (toolchains — GnuCOBOL and the Dart SDK included — plus a shared vendored CodeLLDB), plus the mock adapter. Flutter is host-only: the image carries no Flutter SDK. Ruby is attach-only in the image (the adapter ships without a Ruby runtime — attach to any rdbg --open process, local or remote). Only Go and .NET are disabled in the container — run those via npm/npx next to your local toolchain. Host-built Rust/C++ binaries debugged in the container get an auto-derived source map back to /workspace. list_supported_languages reports per-mode availability (modes.launch / modes.attach) with reasons. See Docker support.

Using npm

bash
npm install -g @debugmcp/mcp-debuggermcp-debugger --help

Or use without installation via npx:

bash
npx @debugmcp/mcp-debugger --help

Over the network (Streamable HTTP)

stdio is the default and is what most clients want. When the server has to run somewhere else — a CI runner, a container, a Kubernetes pod — start it on a port instead:

bash
mcp-debugger http --port 3001            # or: node dist/index.js http -p 3001

and point the client at it:

json
{  "mcpServers": {    "mcp-debugger": {      "type": "http",      "url": "http://127.0.0.1:3001/mcp"    }  }}

Each HTTP client gets its own isolated server: debug sessions are never visible to another client. A client that disconnects without DELETE /mcp keeps its debug sessions — and any paused attach target — alive until the server reaps it: 2 minutes after its SSE stream dropped (MCP_HTTP_STREAM_LOST_SESSION_MS), or 30 minutes idle if it never opened one (MCP_HTTP_STALE_SESSION_MS). GET /health lists what each session is holding.

The port defaults to 3001, and the server listens on 127.0.0.1 only. --bind 0.0.0.0 (or MCP_HTTP_BIND=0.0.0.0) listens on every interface — pair it with --allowed-host for the names other machines will use; --bind localhost means 127.0.0.1, and only IP addresses are accepted. GET /health on the same port answers a liveness check and reports the bound address and port under listening.

The server accepts only loopback Host headers by default — localhost, 127.0.0.1, [::1] — as DNS-rebinding protection for an unauthenticated endpoint that can spawn processes and attach to PIDs. A client on another machine reaches it through a port-forward or an SSH tunnel (ssh -L 3001:127.0.0.1:3001 user@server, then http://127.0.0.1:3001/mcp), or you bind an interface with --bind; any other Host gets a 403 that says so. To accept a service name directly — http://mcp-debugger:3001/mcp on a container network — start the server with --allowed-host mcp-debugger (repeatable) or MCP_HTTP_ALLOWED_HOSTS=mcp-debugger (comma-separated). That opt-in means another access control fronts the server; there is no wildcard. Browser clients are checked against the same list by their Origin, so a cross-site page cannot drive the debugger.

📚 How It Works

mcp-debugger exposes debugging operations as MCP tools that can be called with structured JSON parameters:

json
// Tool: create_debug_session// Request:{  "language": "python",  // or "ruby", "javascript", "rust", "go", "java", "dotnet", "cpp", "cobol", "dart", or "mock" for testing  "name": "My Debug Session"}// Response:{  "success": true,  "sessionId": "a4d1acc8-84a8-44fe-a13e-28628c5b33c7",  "message": "Created python debug session: My Debug Session"}

🛠️ Available Tools

All 29 tools below are implemented — see the tool reference for parameters and response shapes.

ToolDescriptionStatus
create_debug_sessionCreate a new debugging session✅ Implemented
list_debug_sessionsList all active sessions✅ Implemented
list_supported_languagesShow available language adapters✅ Implemented
set_breakpointSet a breakpoint in a file✅ Implemented
list_breakpointsList a session's breakpoints with verified state✅ Implemented
remove_breakpointRemove a breakpoint by id or file+line✅ Implemented
clear_breakpointsRemove all breakpoints (optionally per file)✅ Implemented
start_debuggingStart debugging a script — or a failing test in one call (testRunner: "pytest")✅ Implemented
restart_debuggingRelaunch with the same config, breakpoints re-applied✅ Implemented
attach_to_processAttach debugger to a running process✅ Implemented
detach_from_processDetach debugger from a process✅ Implemented
expose_sessionOpen a read-only DAP mirror endpoint so an IDE can attach and inspect✅ Implemented
unexpose_sessionClose the mirror endpoint and disconnect IDE clients✅ Implemented
get_stack_traceGet the current stack trace✅ Implemented
list_threadsList all threads in the debug session✅ Implemented
get_scopesGet variable scopes for a frame✅ Implemented
get_variablesGet variables in a scope✅ Implemented
get_local_variablesGet local variables in current frame✅ Implemented
step_overStep over the current line✅ Implemented
step_intoStep into a function✅ Implemented
step_outStep out of a function✅ Implemented
continue_executionContinue running✅ Implemented
wait_for_stopBlock until the session next pauses or ends✅ Implemented
pause_executionPause running execution✅ Implemented
evaluate_expressionEvaluate expressions in debug context✅ Implemented
get_source_contextGet source code context✅ Implemented
get_outputRead captured debuggee output (stdout/stderr)✅ Implemented
close_debug_sessionClose a session✅ Implemented
hot_reloadApply changed code to the running program and keep its state — Flutter hot reload, Java class redefinition (redefine_classes is a deprecated alias)✅ Implemented

🏗️ Architecture: Dynamic Adapter Loading

Version 0.10.0 introduces a clean adapter pattern that separates language-agnostic core functionality from language-specific implementations:

┌─────────────┐     ┌────────────────┐     ┌──────────────┐     ┌─────────────────┐│ MCP Client  │────▶│ DebugMcpServer │────▶│SessionManager│────▶│ AdapterRegistry │└─────────────┘     └────────────────┘     └──────────────┘     └─────────────────┘                            │                      │                            ▼                      ▼                    ┌──────────────┐      ┌─────────────────┐                    │ ProxyManager │◀─────│ Language Adapter│                    └──────────────┘      └─────────────────┘                                                  │              ┌───────────┬───────────┬───────────┼───────────┬───────────┬───────────┬───────────┬───────────┬───────────┬───────────┐              │           │           │           │           │           │           │           │           │           │           │        ┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐┌─────▼────┐        │Python    ││Ruby      ││JavaScript││Rust      ││Go        ││Java      ││.NET      ││C/C++     ││COBOL     ││Dart      ││Mock      │        │Adapter   ││Adapter   ││Adapter   ││Adapter   ││Adapter   ││Adapter   ││Adapter   ││Adapter   ││Adapter   ││Adapter   ││Adapter   │        └──────────┘└──────────┘└──────────┘└──────────┘└──────────┘└──────────┘└──────────┘└──────────┘└──────────┘└──────────┘└──────────┘

Adding Language Support

Want to add debugging support for your favorite language? Check out the Adapter Development Guide!

💡 Example: Debugging Python Code

Here's a complete debugging session example:

python
# buggy_swap.pydef swap_variables(a, b):    a = b  # Bug: loses original value of 'a'    b = a  # Bug: 'b' gets the new value of 'a'    return a, b

Step 1: Create a Debug Session

json
// Tool: create_debug_session// Request:{  "language": "python",  "name": "Swap Bug Investigation"}// Response:{  "success": true,  "sessionId": "a4d1acc8-84a8-44fe-a13e-28628c5b33c7",  "message": "Created python debug session: Swap Bug Investigation"}

Step 2: Set Breakpoints

json
// Tool: set_breakpoint// Request:{  "sessionId": "a4d1acc8-84a8-44fe-a13e-28628c5b33c7",  "file": "C:\\path\\to\\buggy_swap.py",  "line": 2}// Response:{  "success": true,  "breakpointId": "28e06119-619e-43c0-b029-339cec2615df",  "file": "C:\\path\\to\\buggy_swap.py",  "line": 2,  "verified": false,  "message": "Breakpoint set at C:\\path\\to\\buggy_swap.py:2"}

Step 3: Start Debugging

json
// Tool: start_debugging// Request:{  "sessionId": "a4d1acc8-84a8-44fe-a13e-28628c5b33c7",  "scriptPath": "C:\\path\\to\\buggy_swap.py"}// Response:{  "success": true,  "state": "paused",  "message": "Debugging started for C:\\path\\to\\buggy_swap.py. Current state: paused",  "data": {    "message": "Debugging started for C:\\path\\to\\buggy_swap.py. Current state: paused",    "reason": "breakpoint"  }}

Step 4: Inspect Variables

First, get the scopes:

json
// Tool: get_scopes// Request:{  "sessionId": "a4d1acc8-84a8-44fe-a13e-28628c5b33c7",  "frameId": 3}// Response:{  "success": true,  "scopes": [    {      "name": "Locals",      "variablesReference": 5,      "expensive": false,      "presentationHint": "locals",      "source": {}    },    {      "name": "Globals",       "variablesReference": 6,      "expensive": false,      "source": {}    }  ]}

Then get the local variables:

json
// Tool: get_variables// Request:{  "sessionId": "a4d1acc8-84a8-44fe-a13e-28628c5b33c7",  "scope": 5}// Response:{  "success": true,  "variables": [    {"name": "a", "value": "10", "type": "int", "variablesReference": 0, "expandable": false},    {"name": "b", "value": "20", "type": "int", "variablesReference": 0, "expandable": false}  ],  "count": 2,  "variablesReference": 5}

📖 Documentation

🤝 Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.

bash
# Development setupgit clone https://github.com/debugmcp/mcp-debugger.gitcd mcp-debugger
# Install dependencies and vendor debug adapterspnpm install# Vendored debug engines (Microsoft's js-debug; CodeLLDB, shared by Rust, C/C++ and COBOL)# are downloaded automatically and verified against committed SHA-256 digest pins
# Build the projectpnpm build
# Run testspnpm test
# Check adapter vendoring statuspnpm vendor:status
# Force re-vendor all adapters (if needed)pnpm vendor:force

Debug Adapter Vendoring

The project automatically vendors debug adapters during pnpm install:

  • JavaScript: Downloads Microsoft's js-debug from GitHub releases
  • Rust, C/C++ & COBOL: Download a single shared copy of CodeLLDB for the current platform (packages/codelldb-common)
  • Integrity: Every download is verified against the pinned SHA-256 digests in the packages' vendor-manifest.json; mismatches fail the build
  • CI Environment: Set SKIP_ADAPTER_VENDOR=true to skip vendoring

To manually manage adapters:

bash
# Check current vendoring statuspnpm vendor:status
# Re-vendor all adapterspnpm vendor
# Clean and re-vendor (force)pnpm vendor:force
# Clean vendor directories onlypnpm clean:vendor

Running Container Tests Locally

We use Act to run GitHub Actions workflows locally:

bash
# Build the Docker image firstdocker build -t mcp-debugger:local .
# Run tests with Act (use WSL2 on Windows)act -j build-and-test --matrix os:ubuntu-latest

See tests/README.md for detailed testing instructions.

📊 Project Status

  • ✅ Production Ready: ten language adapters, 29 tools, and polished multi-language distribution
  • ✅ Clean architecture with a dynamic adapter pattern
  • ✅ Python · Ruby · JavaScript/TypeScript · Go · Java · .NET/C#: Full step-through debugging
  • 🦀 Rust: Full support on Linux/macOS/Windows (Windows requires the GNU toolchain; MSVC is not supported by CodeLLDB)
  • ⚙️ C/C++: Full step-through debugging via CodeLLDB (launch + attach-by-PID; on Windows prefer MinGW/DWARF — MSVC PDB fidelity is partial)
  • 🧮 COBOL: Step-through debugging via GnuCOBOL + CodeLLDB (launch + attach-by-PID; verified with GnuCOBOL 3.1.2/3.2 on Linux and Windows/MSYS2; PERFORM-aware stepping, paragraph breakpoints and {WS-NAME} logpoints)
  • 🐦 Dart/Flutter: Step-through debugging through the SDK's own debug adapters (dart debug_adapter, flutter debug-adapter; launch + attach by VM-service URI, or by deviceId on Android). Dart programs and dart test; Flutter apps and tests on desktop, web (Chrome/Edge), Android emulators and devices, macOS and the iOS simulator; hot reload and hot restart
  • 🟢 Runtime: Node.js 22+
  • 📈 Active Development: Regular updates and improvements — see the Roadmap for the path to 1.0

🏛️ Who Maintains This

mcp-debugger is stewarded by Sycamore LLC and led by John Franklin (@debugmcpdev). The project uses an agent-first development model with human accountability: AI agents write most of the code; a human maintainer makes every merge, release, and security decision. See MAINTAINERS.md, GOVERNANCE.md, and SUPPORT.md (including commercial support).

Supply-chain posture: pinned CI actions, OIDC trusted publishing, sigstore provenance on every npm package, SBOMs attached to releases, and an OpenSSF Scorecard score we actively maintain — details in SUPPLY-CHAIN-SECURITY.md. Report vulnerabilities via SECURITY.md.

📄 License

MIT License - see LICENSE for details.

👥 Contributors

🙏 Acknowledgments

Built with:


Give your AI agents a real debugger — in any language.

来源:README.md,提交 3473aac

工具

29

create_debug_session

Create a new debugging session. Passing port, processId or an adapterConfig that names a target (a debugger URI: vmServiceUri, websocketAddress, vmServiceInfoFile; or a Flutter deviceId, for an app running on an Android device) attaches to a running process in the same call, with every attach argument attach_to_process takes (host alone does not); omit them for launch mode. Attaching pauses the target unless stopOnEntry is false

输入参数hostnameporttimeoutlanguage必填processIdjustMyCodesourcePathsstopOnEntryadapterConfigverifyTimeoutexecutablePath另有 1 个

list_supported_languages

List all supported debugging languages with metadata

无需输入参数。

list_debug_sessions

List all active debugging sessions. Paused sessions include lastStop with the reason for the most recent stop (e.g. "breakpoint" vs "exception")

无需输入参数。

set_breakpoint

Set a breakpoint. Setting breakpoints on non-executable lines (structural, declarative) may lead to unexpected behavior

输入参数filelinefunctionnearLineconditionsessionId必填statementlogMessagesuspendPolicyexpectedContent

list_breakpoints

List all breakpoints in a session with their verified state and adapter-assigned ids. Session-global function breakpoints appear separately as functionBreakpoints (omitted when filtering by file). Works before launch (queued, verified=false), while running or paused, and after the program exits

输入参数filesessionId必填

remove_breakpoint

Remove a breakpoint by breakpointId (returned by set_breakpoint / list_breakpoints), by function name, or by file + line (removes all breakpoints at that location). Takes effect immediately while the program is running or paused; also works after the program exits, before a relaunch

输入参数filelinefunctionsessionId必填breakpointId

clear_breakpoints

Remove all breakpoints in a session, or all breakpoints in one file. Clearing zero breakpoints is success. Takes effect immediately while the program is running or paused

输入参数filesessionId必填

start_debugging

Start debugging a script. Answers when the launched program stops, when it ends, or after a short hold — whichever comes first, and the same way in every language: "paused" with a reason and, as wait_for_stop answers a stop, the location, its source context and a note (a breakpoint reached as the program starts is answered here), "stopped" with the exit code, or "running" with pending:true when the program has not stopped yet; the message says what is armed. The hold is not a limit on the program — nothing is cancelled when it passes and breakpoints stay armed: call wait_for_stop to block until the program stops or ends (for a server, after sending the request that reaches your breakpoint). A stopOnEntry launch is answered at its entry stop

输入参数argssessionId必填scriptPath必填testRunnertestTargetdryRunSpawndapLaunchArgsbreakOnExceptionsadapterLaunchConfig

restart_debugging

Restart the debuggee: terminate the current program (if still running) and relaunch it with the same configuration as the last start_debugging. All current breakpoints are re-applied automatically. The get_output buffer starts fresh — read from since=0 after a restart. Works while running, paused, or after the program has exited. Not available for attach sessions or sessions never launched. Answers like start_debugging, including "running" with pending:true when the relaunch has not stopped within the same short hold (then call wait_for_stop)

输入参数sessionId必填

attach_to_process

Attach to a running process for debugging. After the handshake the target is verified by polling for threads; if none are reported within verifyTimeout (~20s default) the attach fails and the proxy is torn down. When a requested post-attach pause is accepted but no stopped event arrives within its bounded wait, returns state "running" with pending:true; the late event alone changes the session to "paused" — call wait_for_stop to block until it does

输入参数hostporttimeoutprocessIdsessionId必填justMyCodesourcePathsstopOnEntryadapterConfigverifyTimeoutbreakOnExceptions

detach_from_process

Detach from the debugged process without terminating it

输入参数sessionId必填terminateProcess

expose_session

Expose a debug session as a read-only DAP mirror endpoint on 127.0.0.1 so an IDE (e.g. VS Code) can attach as a second debug client and inspect live state: threads, stack, scopes, variables, evaluate. Returns host, port, and a session token the IDE must include as "mirrorToken" in its attach configuration. The mirror never drives execution — continue/step/pause and breakpoint changes are rejected; control stays with this MCP session. Requires an active session (launched or attached); works while running or paused. Calling it again returns the same endpoint. The endpoint closes on unexpose_session, close_debug_session, restart, or debuggee exit

输入参数sessionId必填

unexpose_session

Close a session's DAP mirror endpoint and disconnect any attached IDE clients. Succeeds as a no-op if the session is not exposed

输入参数sessionId必填

close_debug_session

Close a debugging session

输入参数sessionId必填

step_over

Step over the current line. Waits briefly for the program to stop; if the step is still executing after ~5s (e.g. stepping over a long-running call), returns success with state "running" and pending:true — the step is still in effect and the session becomes "paused" when it completes (call wait_for_stop to block until then, or pause_execution to interrupt)

输入参数sessionId必填

step_into

Step into the current call. Waits briefly for the program to stop; if the step is still executing after ~5s, returns success with state "running" and pending:true — the session becomes "paused" when the step completes (call wait_for_stop to block until then)

输入参数sessionId必填

step_out

Step out of the current function. Waits briefly for the program to stop; if the step is still executing after ~5s (e.g. the rest of the function is long-running), returns success with state "running" and pending:true — the session becomes "paused" when the step completes (call wait_for_stop to block until then)

输入参数sessionId必填

continue_execution

Continue execution. Returns immediately after the adapter acknowledges; does not wait for the next stop. Call wait_for_stop to block until the program stops again or ends — it reports why (lastStop, e.g. "breakpoint" vs "exception") and where; list_debug_sessions and get_stack_trace show the same without waiting. Use get_output to read the program's stdout/stderr

输入参数sessionId必填

wait_for_stop

Block until the session next pauses or ends, then say why and where. Call it after continue_execution (which does not wait) and whenever a tool answers pending:true, instead of polling list_debug_sessions. Answers at once when the session is already paused (state "paused" with lastStop — the same record list_debug_sessions shows — and the top frame as location) or already over (the terminal state, with exitCode when the debuggee reported one); note says when the answer is anchored on a thread other than the one the stop was reported on, or when no frame of the shown stack is program code. If neither happens within the timeout it answers state "running" with pending:true: nothing was cancelled, breakpoints and exception filters stay armed — call it again to keep waiting, or pause_execution to interrupt

输入参数timeoutsessionId必填

pause_execution

Pause a running program. Waits briefly for the stop; if the program cannot stop within ~5s (e.g. blocked in native code, or an idle server waiting for input), returns success with pending:true and the session reports "paused" the next time the program runs code (call wait_for_stop to block until then). An observed stop answers with stopReason, the first visible frame as location (with its source context), and note when the stop was reported on a thread with no program frame — a sibling thread in program code is shown instead, or, when none has one, the note says no program frame is active. Fails with an actionable error if the session has no debuggable target to pause (e.g. a js attach whose target session was never adopted or has ended)

输入参数threadIdsessionId必填

list_threads

List all threads in the debugged process

输入参数sessionId必填

get_variables

Get variables (scope is variablesReference: number). Responses are size-guarded: oversized values are cut (truncated:true) and very large scopes return a capped list with a truncation notice — pass names:[...] to fetch specific variables in full

输入参数namesscope必填sessionId必填

get_local_variables

Get local variables for the shared inspection anchor. If the stopped thread is frameless, a sibling with policy-recognized user frames is preferred, adopted, and disclosed in note. At a breakpoint or step inside a frame the stack display hides as internal (a node_modules dependency), the anchor is that frame — the one the program stopped in — and note says so. A JavaScript frame with no Local/block scope returns empty with guidance instead of mislabeling Global bindings. Responses are size-guarded; pass names:[...] to fetch specific variables in full

输入参数namessessionId必填includeSpecial

get_stack_trace

Get stack trace. The response includes stopReason — why the session is paused. For an implicit frameless stopped thread, a sibling with policy-recognized user frames is preferred and adopted, with the switch disclosed in note. Internal/runtime frames are filtered by default; when any are hidden the response carries hiddenFrames and a note. When the frame the program is paused in is itself internal, pausedFrame names it (kept: whether it was retained as stackFrames[0]) and the note says so. The note also says when the top frame's file is newer than the compiled file the debugger binds it through (a stale build)

输入参数threadIdsessionId必填includeInternals

get_scopes

Get scopes for a stack frame

输入参数frameId必填sessionId必填

evaluate_expression

Evaluate expression in the current debug context. Without frameId, uses the same adopted top frame as stack and locals — at a breakpoint or step that is the frame the program stopped in even when the stack display would hide it — and discloses an automatic thread switch or a hidden paused frame in anchorNote; frame names the frame that was used, on success and on failure. Expressions can read and modify program state. Waits up to 30s by default

输入参数frameIdtimeoutsessionId必填expression必填

get_source_context

Get source context around a specific line in a file

输入参数file必填line必填sessionId必填linesContext

get_output

Get debuggee output (stdout/stderr/console) captured for a session. Buffered per launch (last 1000 entries; adapter telemetry and known adapter-internal diagnostics — e.g. LLDB DWARF-parser noise — filtered out). Works while the program is running and after it finishes, until the session is closed. Pass since=nextSince from the previous response to fetch only new output

输入参数limitsincesessionId必填

hot_reload

Apply changed code to the running program and keep its state — the adapter's own live update. Flutter: the SDK adapter's hot reload (the app must have started; the reassemble runs build(), so a breakpoint there is reported by this call as the stop, with its location and snapshot; widget state, counters and timers survive; a reload sent to a paused program lands when it resumes). Java: class redefinition (JDI HotSwap) — scans classesDir for .class files modified after sinceTimestamp, redefines the ones the JVM has loaded, re-plants breakpoints, and returns which classes were redefined and the newest file timestamp (pass it as sinceTimestamp next time for an incremental update). Statement-anchored breakpoints are re-resolved against the new source after the update (anchorResolution reports moved/stale). Refused by name on the other languages. redefine_classes is a deprecated alias of this tool.

输入参数timeoutsessionId必填classesDirsinceTimestamp

版本历史

2
  1. v0.26.0最新Oct 31, 2026
  2. v0.25.1Oct 1, 2026

评分

已满足适用检查项的 90%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分
  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分