dap-mcp-server 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +31 -0
- package/.forgejo/workflows/publish.yml +63 -0
- package/CLAUDE.md +71 -0
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/SKILL.md +62 -0
- package/build/adapters/builtin.d.ts +24 -0
- package/build/adapters/builtin.js +46 -0
- package/build/adapters/builtin.js.map +1 -0
- package/build/adapters/detect.d.ts +23 -0
- package/build/adapters/detect.js +36 -0
- package/build/adapters/detect.js.map +1 -0
- package/build/adapters/registry.d.ts +39 -0
- package/build/adapters/registry.js +79 -0
- package/build/adapters/registry.js.map +1 -0
- package/build/dap/dap-client.d.ts +46 -0
- package/build/dap/dap-client.js +190 -0
- package/build/dap/dap-client.js.map +1 -0
- package/build/dap/protocol.d.ts +32 -0
- package/build/dap/protocol.js +71 -0
- package/build/dap/protocol.js.map +1 -0
- package/build/dap/ring-buffer.d.ts +35 -0
- package/build/dap/ring-buffer.js +57 -0
- package/build/dap/ring-buffer.js.map +1 -0
- package/build/dap/types.d.ts +87 -0
- package/build/dap/types.js +25 -0
- package/build/dap/types.js.map +1 -0
- package/build/index.d.ts +24 -0
- package/build/index.js +30 -0
- package/build/index.js.map +1 -0
- package/build/server.d.ts +24 -0
- package/build/server.js +735 -0
- package/build/server.js.map +1 -0
- package/build/session/session-manager.d.ts +32 -0
- package/build/session/session-manager.js +60 -0
- package/build/session/session-manager.js.map +1 -0
- package/build/session/session.d.ts +85 -0
- package/build/session/session.js +374 -0
- package/build/session/session.js.map +1 -0
- package/docs/plans/2026-03-05-dap-wrapper-mcp-design.md +326 -0
- package/docs/plans/2026-03-05-dap-wrapper-mcp-implementation.md +2815 -0
- package/package.json +43 -0
- package/src/adapters/builtin.ts +47 -0
- package/src/adapters/detect.test.ts +36 -0
- package/src/adapters/detect.ts +36 -0
- package/src/adapters/registry.test.ts +73 -0
- package/src/adapters/registry.ts +86 -0
- package/src/dap/dap-client.test.ts +87 -0
- package/src/dap/dap-client.ts +216 -0
- package/src/dap/protocol.test.ts +82 -0
- package/src/dap/protocol.ts +78 -0
- package/src/dap/ring-buffer.test.ts +82 -0
- package/src/dap/ring-buffer.ts +64 -0
- package/src/dap/types.ts +92 -0
- package/src/index.ts +30 -0
- package/src/integration/debug-lifecycle.test.ts +107 -0
- package/src/server.ts +866 -0
- package/src/session/session-manager.test.ts +74 -0
- package/src/session/session-manager.ts +67 -0
- package/src/session/session.test.ts +84 -0
- package/src/session/session.ts +435 -0
- package/src/test-fixtures/crash-adapter.js +23 -0
- package/src/test-fixtures/mock-adapter.js +142 -0
- package/src/test-fixtures/silent-adapter.js +24 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# DAP Wrapper MCP Server — Design Document
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-03-05
|
|
4
|
+
**Status**: Approved
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
An MCP server that wraps the Debug Adapter Protocol (DAP), enabling AI agents (Claude, etc.) to use real debuggers instead of relying on print statements and log analysis. The server spawns debug adapters as child processes and exposes a coarse-grained set of MCP tools optimized for agent-driven debugging workflows.
|
|
9
|
+
|
|
10
|
+
## Decisions
|
|
11
|
+
|
|
12
|
+
- **Language**: TypeScript (Node.js)
|
|
13
|
+
- **Transport**: MCP over stdio; DAP over child process stdin/stdout
|
|
14
|
+
- **Adapter management**: Config-based with a registration tool + built-in defaults for Python (debugpy), Node.js (js-debug), Go (delve), C/C++ (lldb-dap)
|
|
15
|
+
- **Tool granularity**: Coarse-grained (~12 tools), composite responses
|
|
16
|
+
- **Execution model**: Synchronous stepping with configurable timeout — `step` blocks until the debuggee stops and returns the new state
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
┌──────────────────────────────────────────────────┐
|
|
22
|
+
│ MCP Server (Node.js) │
|
|
23
|
+
│ │
|
|
24
|
+
│ ┌──────────┐ ┌─────────────────────────────┐ │
|
|
25
|
+
│ │ Adapter │ │ Session Manager │ │
|
|
26
|
+
│ │ Registry │ │ │ │
|
|
27
|
+
│ │ │ │ Session ──► DAP Client ─────┼───┼──► adapter (child process)
|
|
28
|
+
│ │ - python │ │ • state (running/stopped) │ │ (stdin/stdout)
|
|
29
|
+
│ │ - node │ │ • breakpoints map │ │
|
|
30
|
+
│ │ - go │ │ • output ring buffer │ │
|
|
31
|
+
│ │ - cppdbg │ │ • event queue │ │
|
|
32
|
+
│ │ - custom │ │ • focused thread │ │
|
|
33
|
+
│ └──────────┘ └─────────────────────────────┘ │
|
|
34
|
+
│ │
|
|
35
|
+
│ ┌───────────────────────────────────────────┐ │
|
|
36
|
+
│ │ MCP Layer (stdio transport) │ │
|
|
37
|
+
│ │ - 12 Tool handlers │ │
|
|
38
|
+
│ │ - Resource: dap://sessions │ │
|
|
39
|
+
│ └───────────────────────────────────────────┘ │
|
|
40
|
+
└──────────────────────────────────────────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Components
|
|
44
|
+
|
|
45
|
+
1. **Adapter Registry** — Stores adapter configurations. Each config: `type`, `runtime` (optional), `program` (path to adapter binary), `args`, `launchDefaults`. Built-in defaults for common adapters. Persisted to `~/.dap-mcp/adapters.json` (global) and `./.dap-mcp/adapters.json` (project-local).
|
|
46
|
+
|
|
47
|
+
2. **Session Manager** — Manages active debug sessions. Each session owns a `DAPClient`, tracks state (`idle | configuring | running | stopped | terminated`), maintains breakpoints map, buffers output in a ring buffer (10,000 lines max), and handles adapter crash detection.
|
|
48
|
+
|
|
49
|
+
3. **DAP Client** — Low-level protocol handler. Spawns adapter child process, sends/receives DAP messages with `Content-Length` framing, correlates request/response by `seq`, emits events to the session. Includes startup timeout (10s default).
|
|
50
|
+
|
|
51
|
+
4. **MCP Layer** — Registers tools, handles tool calls, serves the `dap://sessions` resource.
|
|
52
|
+
|
|
53
|
+
## Tools (12)
|
|
54
|
+
|
|
55
|
+
### Session Lifecycle
|
|
56
|
+
|
|
57
|
+
#### `debug_launch`
|
|
58
|
+
Start a new debug session by launching a program.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
Input: {
|
|
62
|
+
adapter: string, // "python" | "node" | "go" | "cppdbg" | custom
|
|
63
|
+
program: string,
|
|
64
|
+
args?: string[],
|
|
65
|
+
cwd?: string,
|
|
66
|
+
env?: Record<string, string>,
|
|
67
|
+
stopOnEntry?: boolean, // default: true
|
|
68
|
+
breakpoints?: Array<{
|
|
69
|
+
file: string,
|
|
70
|
+
lines: Array<{
|
|
71
|
+
line: number,
|
|
72
|
+
condition?: string,
|
|
73
|
+
hitCondition?: string,
|
|
74
|
+
logMessage?: string
|
|
75
|
+
}>
|
|
76
|
+
}>,
|
|
77
|
+
exceptionBreakpoints?: string[], // e.g., ["uncaught"]
|
|
78
|
+
adapterConfig?: Record<string, any> // pass-through to adapter
|
|
79
|
+
}
|
|
80
|
+
Output: { sessionId: string, state: StoppedState | RunningState }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### `debug_attach`
|
|
84
|
+
Attach to a running process.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
Input: {
|
|
88
|
+
adapter: string,
|
|
89
|
+
processId?: number,
|
|
90
|
+
host?: string,
|
|
91
|
+
port?: number,
|
|
92
|
+
adapterConfig?: Record<string, any>
|
|
93
|
+
}
|
|
94
|
+
Output: { sessionId: string, state: StoppedState | RunningState }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### `debug_restart`
|
|
98
|
+
Restart the current debug session with the same configuration.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
Input: { sessionId?: string }
|
|
102
|
+
Output: { sessionId: string, state: StoppedState | RunningState }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### `debug_disconnect`
|
|
106
|
+
End a debug session.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
Input: {
|
|
110
|
+
sessionId?: string,
|
|
111
|
+
terminateDebuggee?: boolean // default: true for launch, false for attach
|
|
112
|
+
}
|
|
113
|
+
Output: { success: boolean }
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Breakpoints
|
|
117
|
+
|
|
118
|
+
#### `set_breakpoints`
|
|
119
|
+
Set or replace breakpoints in a source file. Replaces all breakpoints in the specified file (DAP semantics).
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
Input: {
|
|
123
|
+
sessionId?: string,
|
|
124
|
+
file: string,
|
|
125
|
+
breakpoints: Array<{
|
|
126
|
+
line: number,
|
|
127
|
+
condition?: string,
|
|
128
|
+
hitCondition?: string,
|
|
129
|
+
logMessage?: string
|
|
130
|
+
}>
|
|
131
|
+
}
|
|
132
|
+
Output: {
|
|
133
|
+
breakpoints: Array<{
|
|
134
|
+
id: number,
|
|
135
|
+
verified: boolean,
|
|
136
|
+
line: number,
|
|
137
|
+
message?: string
|
|
138
|
+
}>
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `set_exception_breakpoints`
|
|
143
|
+
Configure which exceptions cause the debugger to break.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
Input: {
|
|
147
|
+
sessionId?: string,
|
|
148
|
+
filters: string[] // adapter-specific, e.g., ["uncaught", "raised"]
|
|
149
|
+
}
|
|
150
|
+
Output: { filters: string[] }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### State Inspection
|
|
154
|
+
|
|
155
|
+
#### `get_state`
|
|
156
|
+
Get current debuggee state. When stopped: threads + stack trace + scopes + variables. When running: status + buffered output.
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
Input: {
|
|
160
|
+
sessionId?: string,
|
|
161
|
+
threadId?: number, // default: thread that triggered stop
|
|
162
|
+
depth?: number, // stack frames to return, default 10
|
|
163
|
+
variableDepth?: number, // nested expansion depth, default 1
|
|
164
|
+
timeout?: number // ms to wait if running, default 0
|
|
165
|
+
}
|
|
166
|
+
Output: StoppedState | RunningState
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### `evaluate`
|
|
170
|
+
Evaluate an expression in the debuggee's context.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
Input: {
|
|
174
|
+
sessionId?: string,
|
|
175
|
+
expression: string,
|
|
176
|
+
frameId?: number, // default: top frame
|
|
177
|
+
context?: "repl" | "watch" | "hover" // default: "repl"
|
|
178
|
+
}
|
|
179
|
+
Output: {
|
|
180
|
+
result: string,
|
|
181
|
+
type?: string,
|
|
182
|
+
hasChildren: boolean,
|
|
183
|
+
variablesReference: number
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### `get_output`
|
|
188
|
+
Get buffered program output.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
Input: {
|
|
192
|
+
sessionId?: string,
|
|
193
|
+
category?: "stdout" | "stderr" | "console", // default: all
|
|
194
|
+
clear?: boolean // clear buffer after reading, default false
|
|
195
|
+
}
|
|
196
|
+
Output: {
|
|
197
|
+
output: Array<{ category: string, text: string, timestamp: string }>,
|
|
198
|
+
truncated: boolean
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Execution Control
|
|
203
|
+
|
|
204
|
+
#### `step`
|
|
205
|
+
Control execution. Synchronous: blocks until debuggee stops or timeout.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
Input: {
|
|
209
|
+
sessionId?: string,
|
|
210
|
+
action: "continue" | "next" | "stepIn" | "stepOut" | "pause",
|
|
211
|
+
threadId?: number,
|
|
212
|
+
timeout?: number // ms, default 30000
|
|
213
|
+
}
|
|
214
|
+
Output: StoppedState | { status: "running", elapsedMs: number }
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Adapter Management
|
|
218
|
+
|
|
219
|
+
#### `configure_adapter`
|
|
220
|
+
Register or update a debug adapter configuration.
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
Input: {
|
|
224
|
+
type: string, // adapter identifier
|
|
225
|
+
runtime?: string, // e.g., "node", "python3"
|
|
226
|
+
program: string, // path to adapter binary/script
|
|
227
|
+
args?: string[],
|
|
228
|
+
launchDefaults?: Record<string, any>,
|
|
229
|
+
scope?: "global" | "project" // default: "project"
|
|
230
|
+
}
|
|
231
|
+
Output: { success: boolean }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### `list_adapters`
|
|
235
|
+
List available debug adapter configurations with availability status.
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
Input: {}
|
|
239
|
+
Output: {
|
|
240
|
+
adapters: Array<{
|
|
241
|
+
type: string,
|
|
242
|
+
source: "builtin" | "global" | "project",
|
|
243
|
+
available: boolean, // binary exists on system
|
|
244
|
+
program: string,
|
|
245
|
+
installHint?: string // e.g., "pip install debugpy"
|
|
246
|
+
}>
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Common Response Types
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
interface StoppedState {
|
|
254
|
+
status: "stopped";
|
|
255
|
+
reason: "breakpoint" | "step" | "exception" | "pause" | "entry";
|
|
256
|
+
location: {
|
|
257
|
+
file: string;
|
|
258
|
+
line: number;
|
|
259
|
+
column?: number;
|
|
260
|
+
functionName?: string;
|
|
261
|
+
};
|
|
262
|
+
threads: Array<{ id: number; name: string; stopped: boolean }>;
|
|
263
|
+
stackTrace: Array<{
|
|
264
|
+
id: number;
|
|
265
|
+
name: string;
|
|
266
|
+
file: string;
|
|
267
|
+
line: number;
|
|
268
|
+
column?: number;
|
|
269
|
+
}>;
|
|
270
|
+
scopes: Array<{
|
|
271
|
+
name: string;
|
|
272
|
+
variables: Array<{
|
|
273
|
+
name: string;
|
|
274
|
+
value: string;
|
|
275
|
+
type?: string;
|
|
276
|
+
hasChildren: boolean;
|
|
277
|
+
variablesReference: number;
|
|
278
|
+
}>;
|
|
279
|
+
}>;
|
|
280
|
+
output?: string[];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
interface RunningState {
|
|
284
|
+
status: "running";
|
|
285
|
+
output?: string[];
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Built-in Adapter Defaults
|
|
290
|
+
|
|
291
|
+
| Type | Adapter | Detection | Install Hint |
|
|
292
|
+
|---|---|---|---|
|
|
293
|
+
| `python` | debugpy | `python3 -c "import debugpy"` | `pip install debugpy` |
|
|
294
|
+
| `node` | js-debug-dap | `which js-debug-dap` or bundled | Ships with MCP |
|
|
295
|
+
| `go` | delve | `which dlv` | `go install github.com/go-delve/delve/cmd/dlv@latest` |
|
|
296
|
+
| `cppdbg` | lldb-dap | `which lldb-dap` | `apt install lldb` / `brew install llvm` |
|
|
297
|
+
|
|
298
|
+
## Error Handling
|
|
299
|
+
|
|
300
|
+
All execution errors use MCP's `isError: true` in tool results (not JSON-RPC protocol errors), so the AI can read and self-correct.
|
|
301
|
+
|
|
302
|
+
| Scenario | Behavior |
|
|
303
|
+
|---|---|
|
|
304
|
+
| Adapter binary not found | `isError: true` with install instructions |
|
|
305
|
+
| Adapter crash (child exit) | Session marked `terminated`, stderr in error message |
|
|
306
|
+
| DAP protocol error | Adapter's error message surfaced verbatim |
|
|
307
|
+
| Timeout on step/continue | Return `{ status: "running", elapsedMs }` — not an error |
|
|
308
|
+
| Invalid session ID | Error listing available sessions |
|
|
309
|
+
| Expression eval failure | Adapter's error message (e.g., "NameError: ...") |
|
|
310
|
+
|
|
311
|
+
## MCP Resource
|
|
312
|
+
|
|
313
|
+
- `dap://sessions` — List of active sessions with status summary. Subscribable (emits `notifications/resources/updated` on session state changes).
|
|
314
|
+
|
|
315
|
+
## Config Files
|
|
316
|
+
|
|
317
|
+
- `~/.dap-mcp/adapters.json` — Global adapter configurations
|
|
318
|
+
- `./.dap-mcp/adapters.json` — Project-local adapter overrides (takes precedence)
|
|
319
|
+
|
|
320
|
+
## Key Design Principles
|
|
321
|
+
|
|
322
|
+
1. **One call, maximum info**: Composite responses (stack + variables + threads) reduce round-trips
|
|
323
|
+
2. **Smart defaults**: Auto-select single session, auto-select stopped thread, `stopOnEntry: true`
|
|
324
|
+
3. **Errors are information**: Execution errors in results (not protocol errors) let the AI self-correct
|
|
325
|
+
4. **Bounded resources**: Output ring buffer (10K lines), variable depth limits, stack frame limits
|
|
326
|
+
5. **Crash resilience**: Adapter process monitoring with clear error reporting
|