oh-mcp-dap

oh-mcp-dap

An MCP server that provides a real debugger via the Debug Adapter Protocol, exposing a single 'debug' tool to launch/attach, control execution, and inspect program state across gdb, lldb, debugpy, and more.

Category
Visit Server

README

oh-mcp-dap

An MCP server that gives an AI agent a real debugger. It speaks the Debug Adapter Protocol (DAP) to gdb, lldb, debugpy, delve, and any other adapter you configure — launch or attach to a program, set breakpoints, step, and inspect threads, frames, variables, memory, and disassembly.

It is a thin MCP wrapper around the DAP engine from oh-my-pi (@oh-my-pi/pi-coding-agent), reusing its session manager and adapter-config system rather than reimplementing DAP. See Attribution.

⚗️ Experiment. This is an exploratory project — an experiment in reusing oh-my-pi's DAP engine behind a single-tool MCP server. Interfaces may change, it has not been battle-tested, and it has not yet been run end-to-end against a live client in this form. Feedback and breakage reports welcome.

Runs on Bun (see Requirements).


Why one tool (the design difference)

Most MCP DAP servers expose one MCP tool per DAP operation: set_breakpoint, continue, step_over, evaluate, stack_trace, read_memory, … — twenty-plus separate tools.

oh-mcp-dap exposes a single debug tool with an action field that selects the operation. This is the same shape oh-my-pi uses internally, and it's a deliberate choice:

Tool-per-function Single action tool (this server)
Tools added to the model's context 20–30 1
Token cost of the tool list High, always present Low
Where the operation lives The tool name The action argument
Adding a new DAP op New tool, new registration New action enum value
Discoverability for the model Many shallow tools One tool whose description lists the workflow

Why the single tool wins for a debugger specifically:

  • Context economy. Every registered tool's name + schema sits in the model's context on every turn. A debugger's operations are numerous but individually tiny; paying 25 tool-schemas' worth of tokens to describe them crowds out the tools the agent actually reasons about. One tool keeps the surface flat.
  • The operations are one workflow, not 25 capabilities. launch → set_breakpoint → continue → stack_trace → variables → step is a single stateful conversation with one session. Modeling it as one tool with an action mirrors that: the description teaches the flow, and the shared parameter set (file, line, frame_id, expression, …) is documented once.
  • Coherent state. There is exactly one active session. A single tool makes that constraint obvious instead of spreading it across many tools that all implicitly mutate the same hidden session.
  • Cheap evolution. New adapter capabilities become new action values; no client re-discovery churn.

The tradeoff is honest: a single tool has a broader input schema, and a client UI that renders per-tool affordances sees only one entry. For an agent driving a debugger, the context savings and workflow clarity are worth it. If you want the per-tool model instead, this server isn't that — by design.


What it exposes

One tool, debug. Required field action; the rest are that action's arguments. Actions:

Session: launch, attach, terminate, sessions, output Breakpoints: set_breakpoint, remove_breakpoint, set_instruction_breakpoint, remove_instruction_breakpoint, data_breakpoint_info, set_data_breakpoint, remove_data_breakpoint Execution: continue, step_over, step_in, step_out, pause Inspection: threads, stack_trace, scopes, variables, evaluate, modules, loaded_sources, read_memory, write_memory, disassemble Escape hatch: custom_request (any raw DAP request)

Typical flow:

{ "action": "launch", "program": "./my_app" }
{ "action": "set_breakpoint", "file": "src/main.c", "line": 42 }
{ "action": "continue" }
{ "action": "stack_trace" }
{ "action": "scopes", "frame_id": 0 }
{ "action": "variables", "scope_id": 1001 }
{ "action": "terminate" }

Requirements

  • Bun ≥ 1.3.14. The upstream DAP engine is Bun-native (ships TypeScript, uses Bun's YAML). This server runs on Bun; Node is not supported.
  • The debug adapter(s) for your language on PATH (e.g. gdb, lldb-dap, debugpy, dlv). Adapters are external programs — this server only drives them.

Install

git clone <this-repo> oh-mcp-dap
cd oh-mcp-dap
bun install

Smoke-check that it starts (it will wait on stdin for a client — Ctrl-C to exit):

bun run src/server.ts --workspace .

Configure your MCP client

Point your client at the server with Bun. Set the workspace to the project you want to debug — that's where dap.json and root markers are resolved from.

Claude Code / Claude Desktop (mcpServers):

{
  "mcpServers": {
    "dap": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/oh-mcp-dap/src/server.ts"],
      "env": { "OH_MCP_DAP_WORKSPACE": "/absolute/path/to/your/project" }
    }
  }
}

The workspace can be set three ways (first wins): --workspace <dir> / -w <dir> arg, OH_MCP_DAP_WORKSPACE env, else the server's process.cwd(). Any individual call may also override it with a cwd argument.


Adapter configuration (dap.json)

Adapters are configured exactly as in oh-my-pi. A set of built-in adapters ships out of the box and any dap.json you provide is merged over them, so you can add new debuggers or tweak existing ones without redefining everything.

Built-ins include: gdb, lldb-dap, codelldb, debugpy, dlv, js-debug-adapter, netcoredbg, kotlin-debug-adapter, rdbg, php-debug-adapter, bash-debug-adapter, dart, flutter, elixir-ls-debugger.

Add any adapter

Drop a dap.json in your workspace (the file is auto-discovered — see discovery order). Example: a custom 4D adapter that this repo ships in dap.json:

{
  "adapters": {
    "4d": {
      "command": "node",
      "args": ["4d-dap-bridge.js", "${port}"],
      "connectMode": "tcp",
      "languages": ["4d"],
      "fileTypes": [".4dm"],
      "rootMarkers": [".4DProject", "Project"],
      "launchDefaults": { "request": "launch" },
      "attachDefaults": { "request": "attach" }
    }
  }
}

Adapter fields

Field Meaning
command Adapter executable (resolved on PATH, or a relative/absolute path).
args Launch args. ${port} is substituted with a free port for socket/tcp adapters.
connectMode "stdio" (default), "socket", or "tcp". How the server talks to the adapter.
languages Language ids this adapter serves (informational / selection).
fileTypes File extensions (e.g. .py) used to auto-select the adapter for a target.
rootMarkers Files/dirs that mark a project root (e.g. Cargo.toml), used for selection.
launchDefaults / attachDefaults Default DAP request bodies merged into every launch/attach.
acceptsDirectoryProgram true if the adapter accepts a directory as program (e.g. dlv).

Auto-selection: when a call omits adapter, the server picks one by the target's file type and nearest root marker. Pass adapter to force a choice.

Discovery order

dap.json (also .dap.json, dap.yaml, dap.yml) is discovered from, and merged in this precedence (later overrides earlier), all on top of the built-ins:

  1. built-in defaults
  2. ~/dap.json (home)
  3. user config dirs
  4. project config dirs (relative to the workspace)
  5. <workspace>/dap.json

So a workspace-local dap.json has the final say.


How it works

MCP client ──stdio JSON-RPC──▶ src/server.ts        (one "debug" tool)
                                   │
                                   ▼
                              src/dispatch.ts        (action → engine → text)
                                   │
                                   ▼
                              src/dap-core.ts  ──▶  @oh-my-pi/pi-coding-agent/dap
                                                     • dapSessionManager (the real DAP client + session)
                                                     • dap.json config + adapter selection
  • src/server.ts — MCP stdio server; registers the single tool and routes calls.
  • src/schema.ts — the tool's JSON Schema + description.
  • src/dispatch.ts — the action switch (adapted from oh-my-pi's debug tool, agent-framework couplings removed).
  • src/format.ts — plain-text renderers for DAP responses.
  • src/dap-core.ts — the single import seam onto the engine.

Depending vs. vendoring

This server depends on the published @oh-my-pi/pi-coding-agent package and imports its official /dap subpath — no engine code is copied in. That keeps the debugger logic upstream (bug fixes flow in) at the cost of pulling a large dep tree at install time (only DAP-reachable code loads at runtime).

If you ever need to cut that dependency, everything the engine provides is behind src/dap-core.ts. Vendoring packages/coding-agent/src/dap/** (MIT) and its few internal helpers, then rewriting only that one file, is the supported escape hatch.

A note on stdout

The MCP stdio transport owns stdout for JSON-RPC. The server forces the upstream logger's console transport off and mirrors diagnostics to stderr, so adapter/engine logs never corrupt the protocol stream. Watch stderr for [oh-mcp-dap] lines.


Attribution

Built on oh-my-pi by Mario Zechner and Can Bölük (MIT). The DAP engine is used as a dependency; the formatters and dispatch logic are adapted from packages/coding-agent/src/tools/debug.ts. See NOTICE and LICENSE.

This project is MIT-licensed.

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
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
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
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
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
E2B

E2B

Using MCP to run code via e2b.

Official
Featured