内容
# jdb-mcp — 让您的LLM调试Java(JDB / JDI via MCP,适用于Claude Code及任何MCP客户端)
**jdb-mcp** 将LLM转化为Java调试器。它公开了 **JDI** —— 与 `jdb` 背后的同一引擎——以及 **JDWP** 协议,作为 **MCP** 服务器,以便Claude Code等AI代理可以设置断点、逐步执行代码、捕获异常并检查实时JVM。核心优势:AI **预先声明确切需要的值**,在断点触发 **之前**,`jdb-mcp` 只返回那些值作为紧凑的结构化快照 —— 没有堆转储,没有栈遍历,没有上下文爆炸。只需AI需要的数据,按需提供。
> **关键词:** `LLM` · `AI代理` · `Java调试` · `JDB` · `JDI` · `JDWP` · `MCP` · `Claude Code` · `断点` · `实时JVM检查`
### 为什么选择jdb-mcp?
- **设计上适合LLM使用。** 捕获-快照模式意味着模型永远不会看到原始堆 —— 只看到它命名的少数字段/路径。保持令牌成本和幻觉风险低。
- **两种调试模式。** 模式A:后台触发并缓冲,稍后轮询快照。模式B:非阻塞地武装断点,然后 `resume` 阻塞直到命中,以便AI可以 `explore` / `step` / `get_variables` 交互式地。
- **表达式引擎。** 读取路径,如 `this.user.id`,`args[0].items`,`arr.length`,`list[i]`,`sorted[mid]`,`obj.getX()` —— 并带有空值中断报告(您知道 *哪里* 路径变为空值)。
- **防成瘾。** 会话计数器在8次以上调试操作后发出警告 —— 调试成本高,因此该工具引导AI首先使用日志/测试。
- **零配置。** 无需配置文件,无需环境变量。将目标信息传递给 `start_session`;`npm` 启动器自动检测您的JDK 17+。
- **生产安全选项。** `safeMode=true` 禁用所有方法调用(无 `toString` / `getter` 副作用)—— 仅限字段读取和数组索引。
## 设计
```
分析代码 -> 形成假设(“我怀疑 user.id 为空”)-> 设置断点 + 声明捕获
-> 工具提取确切声明的内容 -> AI 获取结构化结果 -> 验证/修复
```
两种模式:
- **模式A** (默认,非阻塞):断点在后台触发,捕获存储到HitBuffer,线程自动恢复。AI轮询 `list_hits` 获取快照。
- **模式B** (交互式):`set_breakpoint(mode=B)` 武装 **非阻塞** 并立即返回。AI触发其请求(`curl` / 手动),然后调用 `resume`,它 **阻塞直到命中** —— JVM暂停以便通过 `explore`、`get_frames`、`get_variables`、`step` 或 `eval`(危险)进行检查,然后再次 `resume` 继续。每个 `set_breakpoint(mode=B)` 只有一个交互式命中;后续命中降级为模式A(缓冲)—— 重新武装模式B以再次检查。`set_breakpoint` 永远不会阻塞;`resume` 执行等待。
> **谨慎调试。** 调试成本高(目标JVM时间 + 上下文)。仅在有具体假设且日志、检查和测试无法解决时使用。与服务器指令和每个工具描述都强调这一点,会话级计数器在8次以上调试操作后发出警告。
## 快速入门
### 通过npm(推荐 —— 无源代码,无需构建)
```bash
npm install -g jdb-mcp
```
要求:**JDK 17+** 和 **Node.js 16+**。就是这样 —— 无需Maven,无需源代码,无需配置文件。
`jdb-mcp` 命令自动检测您的JDK(`JAVA_HOME` → `PATH` → 常用安装位置),并通过stdio启动捆绑的调试服务器。如果您的JDK不在PATH上,请将 `JAVA_HOME` 指向它:
```bash
# Linux / macOS
export JAVA_HOME=/path/to/jdk-17
jdb-mcp
# Windows (Git Bash / cmd / PowerShell)
set JAVA_HOME=F:\path\to\jdk-17
jdb-mcp
```
### 通过 `npx`(无需全局安装)
```bash
npx jdb-mcp
```
### 从源代码(用于开发)
要求JDK 17+ 和 Maven 3.6+ 在您的PATH上。
```bash
git clone https://github.com/ylw/jdb-mcp.git
cd java-debug
export JAVA_HOME=/path/to/jdk-17
mvn package -DskipTests
# fat jar: jdb-mcp/target/jdb-mcp-1.0.0.jar
java -jar jdb-mcp/target/jdb-mcp-1.0.0.jar
```
## Claude Code 连接
### 使用npm(推荐)
```json
{
"mcpServers": {
"jdb-mcp": {
"command": "npx",
"args": ["jdb-mcp"]
}
}
}
```
或者,在全局安装后,直接使用 `jdb-mcp` 二进制文件:
```json
{
"mcpServers": {
"jdb-mcp": {
"command": "jdb-mcp"
}
}
}
```
如果您的JDK不在PATH上,请通过 `env` 字段内联设置 `JAVA_HOME`(启动器读取它):
```json
{
"mcpServers": {
"jdb-mcp": {
"command": "npx",
"args": ["jdb-mcp"],
"env": { "JAVA_HOME": "/path/to/jdk-17" }
}
}
}
```
### 直接jar
```json
{
"mcpServers": {
"jdb-mcp": {
"command": "/path/to/jdk-17/bin/java",
"args": ["-jar", "/path/to/jdb-mcp-1.0.0.jar"]
}
}
}
```
无需配置文件,无需环境变量(可选 `JDB_MCP_LOG` 用于日志级别)。AI直接将目标信息传递给 `start_session`。
## 工具列表
| 工具 | 用途 |
|---|---|
| `start_session` | **步骤1.** 启动目标(jar或mainClass+classpath)或附加到正在运行的JVM。零配置:直接传递参数。 |
| `stop_session` | 分离并终止目标。清除所有断点和命中。 |
| `configure` | 调整会话限制/预算(防成瘾:提高默认跟踪)。 |
| `session_status` | 附件状态,断点,命中次数,限制,预算。 |
| `list_debuggable_jvms` | **预连接发现。** 扫描带有JDWP代理的正在运行的JVM(`jps -lv`)。无需会话。 |
| `resolve_class` | 模糊解析类名以确认FQCN,然后设置断点。 |
| `list_classes` | 加载的类的分页枚举(前缀过滤器,偏移量/限制)。 |
| `set_breakpoint` | **核心。** 预先声明捕获 + 模式A/B。每个bp限制覆盖支持。 |
| `set_exception_breakpoint` | 当抛出异常时触发。捕获使用 `e` 根作为异常对象。 |
| `list_hits` | 轮询断点的快照(模式A检索)。`limit` + `compact` 以保持输出小。 |
| `remove_breakpoint` | 禁用并删除断点(也清除其捕获的命中)。 |
| `resume` | 在 `set_breakpoint(mode=B)` 后:阻塞直到命中。检查后:继续。 |
| `get_frames` | 模式B。暂停线程的完整调用栈。 |
| `get_variables` | 模式B。帧的局部变量,可选扩展路径。 |
| `step` | 模式B。逐步执行(有预算,默认5/suspend)。 |
| `explore` | 模式B。在暂停帧上评估读取路径(有预算)。 |
| `eval` | 模式B。危险:调用任意无参方法(默认禁用,需要allowEval=true)。 |
## 表达式语法(捕获,探索,扩展路径)
```
this 当前对象
this.field / obj.field 字段读取
a.b.c.d.e 嵌套路径(默认最大5次解引用)
obj.getX() / obj.isX() 无参getter(get*/is* + size/isEmpty/length/toString)
args[N] 按位置的方法参数
arr[i] / list[i] 数组索引或java.util.List索引(使用get(int))
arr.length 数组长度(镜像为int)
sorted[mid] 按命名局部变量索引(运行时解析)
e.getMessage() 异常根(仅限异常断点)
```
根节点为:`this`、`args[N]`、`e`(异常bp)或命名局部变量。
**空值中断**:中间空值 -> `status=null_break, nullBreakAt="<segment>"` — 您知道 **哪里** 出现中断。
**限制**(默认值,可通过 `configure` 或 `start_session` 调整):
- 路径深度:5,toString:500字符,集合:20个元素,字段:50
- 渲染节点预算:每个捕获1000(爆炸防护;裸 `this` 渲染较浅 — 仅直接字段)
- 模式B预算:探索5,评估2,步进5每次暂停
**安全模式**(`safeMode=true`):不进行方法调用 — 不调用getter,不调用toString,不扩展List。仅限字段读取和数组索引。建议用于生产调试,以避免toString/equals实现不可预测的副作用。
## 测试
```bash
export JAVA_HOME=/path/to/jdk-17
mvn -pl jdb-mcp -am test
```
- `DebugSessionIT`(集成测试,17个测试):模式A(空值中断,集合截断,getter路径,List索引,命名参数,this字段,装箱原始类型,安全模式),模式B(非阻塞武装 + resume阻塞 + 探索 + 获取帧/变量/步进),解析类,异常断点(`e.getMessage()`/`e.reason`),`list_debuggable_jvms`,`configure`,`remove_breakpoint` 清除命中,`list_classes` 子字符串过滤,浅层裸根渲染,渲染预算截断,数组长度捕获,`[var]` 索引解析。
- `ExprCaptureTest`(3个单元测试):有效表达式,语法错误,空白。
## 项目结构
```
java-debug/
pom.xml # 父pom(模块:demo,jdb-mcp)
README.md
LICENSE # MIT
demo/ # 调试目标(可执行jar)
jdb-mcp/
pom.xml # mcp,slf4j-simple;shade fat jar
src/main/java/com/ylw/jdbmcp/
Main.java # 入口:stdio MCP服务器,零配置
Defaults.java # 默认常量
StartParams.java # start_session 参数
mcp/ # MCP层(ToolDefs,McpJson,ToolResponses)
debug/ # JDI核心(DebugSession,JdiEventLoop,SessionConfig,
# BreakpointManager,Breakpoint,ClassResolver,ProxyFilter,
# ExprCapture,ExprEval,TargetLauncher,TargetSpec,CommandBus)
snapshot/ # POJO模型(Hit,HitBuffer,ValueNode,CaptureResult)
src/test/java/... # 集成 + 单元测试
```
包命名:`com.ylw.jdbmcp`(`.mcp` / `.debug` / `.snapshot`)。
## 许可证
**MIT License** —— 最宽容的开源许可证。商业使用,分叉,修改,发布,均无附加条件。鼓励但不要求署名。
参见 [LICENSE](LICENSE) 以获取完整文本。
版权所有 © 2026 ylw.