Skip to content

Commit cd8a20e

Browse files
committed
fix(MCP,CLI): sync MCP tools, autoApprove, CLI docs with actual implementation
- MCP: add get_symbols tool, inject add verify param, test_serial add timeout param - mcp.json: autoApprove add missing get_symbols, serial_send, test_serial, file_list, file_stat, file_download - steering: update mcp-fpbinject.md tool count to 21, add get_symbols entry - Docs/CLI.md: document all 21 commands and missing global options (was only 9)
1 parent c9c84cf commit cd8a20e

4 files changed

Lines changed: 214 additions & 9 deletions

File tree

.kiro/settings/mcp.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,23 @@
1212
"decompile",
1313
"signature",
1414
"search",
15+
"get_symbols",
1516
"compile_patch",
1617
"info",
1718
"serial_read",
19+
"serial_send",
1820
"connect",
1921
"inject",
2022
"unpatch",
2123
"disconnect",
24+
"test_serial",
25+
"file_list",
26+
"file_stat",
27+
"file_download",
2228
"mem_read",
2329
"mem_write",
2430
"mem_dump"
2531
]
2632
}
2733
}
28-
}
34+
}

.kiro/steering/mcp-fpbinject.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ inclusion: auto
44

55
# FPBInject MCP Server
66

7-
项目内置 MCP server(`Tools/WebServer/fpb_mcp_server.py`),提供 20 个 tools 用于 ARM 固件分析和运行时注入。
7+
项目内置 MCP server(`Tools/WebServer/fpb_mcp_server.py`),提供 21 个 tools 用于 ARM 固件分析和运行时注入。
88

99
## Tools 一览
1010

1111
| 类别 | Tool | 说明 |
1212
|------|------|------|
13-
| 离线 | `search` | 按名称搜索符号表 |
13+
| 离线 | `search` | 按名称搜索函数(最多 20 个结果) |
14+
| 离线 | `get_symbols` | 获取完整符号表(支持过滤和限制数量) |
1415
| 离线 | `analyze` | 分析函数(地址、签名、汇编行数) |
1516
| 离线 | `disasm` | 反汇编函数 |
1617
| 离线 | `decompile` | Ghidra 反编译(需安装) |
@@ -33,7 +34,7 @@ inclusion: auto
3334

3435
## 使用流程
3536

36-
1.`search` / `analyze` / `disasm` 了解目标函数
37+
1.`search` / `get_symbols` / `analyze` / `disasm` 了解目标函数
3738
2. 编写补丁 `.c` 文件(必须含 `/* FPB_INJECT */` 标记)
3839
3. `compile_patch` 离线验证编译
3940
4. `connect``inject``serial_read` 观察效果

Docs/CLI.md

Lines changed: 177 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,16 @@ fpb_cli.py [OPTIONS] <command> [args...]
2727

2828
Options:
2929
-v, --verbose Enable verbose output
30+
--version Show version
3031
--port, -p <device> Serial port (e.g., /dev/ttyACM0, COM3)
3132
--baudrate, -b <rate> Serial baudrate (default: 115200)
3233
--elf <path> Path to ELF file (global default)
3334
--compile-commands <path> Path to compile_commands.json
35+
--tx-chunk-size <bytes> TX chunk size for serial commands (0=disabled, default: 0)
36+
--tx-chunk-delay <secs> Delay between TX chunks in seconds (default: 0.005)
37+
--max-retries <num> Maximum retry attempts for file transfer (default: 10)
38+
--direct Force direct serial connection (skip WebServer proxy detection)
39+
--server-url <url> WebServer URL for proxy mode (default: http://localhost:5500)
3440
```
3541

3642
## Commands
@@ -105,12 +111,40 @@ fpb_cli.py search <elf_path> <pattern>
105111
}
106112
```
107113

108-
#### 6. `compile` - Compile patch source (offline validation)
114+
#### 6. `get-symbols` - Get all symbols from ELF
115+
116+
More comprehensive than `search` — returns all symbol types via `nm`, with optional filtering.
117+
118+
```bash
119+
fpb_cli.py get-symbols <elf_path> [--filter <pattern>] [--limit <num>]
120+
```
121+
122+
**Options:**
123+
- `--filter <pattern>` — Case-insensitive substring filter (default: all symbols)
124+
- `--limit <num>` — Maximum results, 0 for unlimited (default: 0)
125+
126+
**Output:**
127+
```json
128+
{
129+
"success": true,
130+
"count": 3,
131+
"total": 150,
132+
"symbols": [
133+
{"name": "gpio_init", "addr": "0x08001000", "type": "func"},
134+
{"name": "gpio_pin_map", "addr": "0x08002000", "type": "other"}
135+
]
136+
}
137+
```
138+
139+
#### 7. `compile` - Compile patch source (offline validation)
109140

110141
```bash
111142
fpb_cli.py compile <source_file> --elf <elf> --compile-commands <path> [--addr <base_addr>]
112143
```
113144

145+
**Options:**
146+
- `--addr <base_addr>` — Base address for patch code (default: 0x20001000)
147+
114148
**Output:**
115149
```json
116150
{
@@ -121,9 +155,25 @@ fpb_cli.py compile <source_file> --elf <elf> --compile-commands <path> [--addr <
121155
}
122156
```
123157

158+
### Connection Commands
159+
160+
#### 8. `connect` - Connect to device
161+
162+
```bash
163+
fpb_cli.py --port /dev/ttyACM0 connect
164+
```
165+
166+
Establishes a serial connection. Required before any online command when using `--direct` mode.
167+
168+
#### 9. `disconnect` - Disconnect from device
169+
170+
```bash
171+
fpb_cli.py disconnect
172+
```
173+
124174
### Online Commands (Device Required)
125175

126-
#### 7. `info` - Get device FPB info
176+
#### 10. `info` - Get device FPB info
127177

128178
```bash
129179
fpb_cli.py --port /dev/ttyACM0 info
@@ -141,7 +191,7 @@ fpb_cli.py --port /dev/ttyACM0 info
141191
}
142192
```
143193

144-
#### 8. `inject` - Inject patch to device
194+
#### 11. `inject` - Inject patch to device
145195

146196
```bash
147197
fpb_cli.py --port <device> --elf <elf> --compile-commands <path> \
@@ -178,13 +228,136 @@ fpb_cli.py --port /dev/ttyACM0 --elf firmware.elf \
178228
}
179229
```
180230

181-
#### 9. `unpatch` - Remove patch
231+
#### 12. `unpatch` - Remove patch
182232

183233
```bash
184234
fpb_cli.py --port /dev/ttyACM0 unpatch --comp <slot>
185235
fpb_cli.py --port /dev/ttyACM0 unpatch --all
186236
```
187237

238+
#### 13. `test-serial` - Test serial throughput
239+
240+
3-phase probing to find optimal transfer parameters.
241+
242+
```bash
243+
fpb_cli.py --port /dev/ttyACM0 test-serial [options]
244+
245+
Options:
246+
--start-size <bytes> Starting test size (default: 16)
247+
--max-size <bytes> Maximum test size (default: 4096)
248+
--timeout <secs> Timeout per test (default: 2.0)
249+
```
250+
251+
### Serial I/O Commands (Device Required)
252+
253+
#### 14. `serial-send` - Send data to device
254+
255+
```bash
256+
fpb_cli.py --port /dev/ttyACM0 serial-send <data> [options]
257+
258+
Options:
259+
--no-read Don't read response after sending
260+
--timeout <secs> Response read timeout (default: 1.0)
261+
```
262+
263+
**Output:**
264+
```json
265+
{
266+
"success": true,
267+
"sent": "ps",
268+
"response": " PID GROUP PRI POLICY TYPE NPX STATE ..."
269+
}
270+
```
271+
272+
> WARNING: Avoid sending `fl` commands directly — use `inject`/`unpatch`/`info` instead.
273+
274+
#### 15. `serial-read` - Read serial output
275+
276+
```bash
277+
fpb_cli.py --port /dev/ttyACM0 serial-read [options]
278+
279+
Options:
280+
--timeout <secs> How long to wait for data (default: 1.0)
281+
--lines <num> Max log lines to return (default: 50)
282+
```
283+
284+
**Output:**
285+
```json
286+
{
287+
"success": true,
288+
"new_data": "Patched: pin=13 val=1\r\n",
289+
"log": ["Patched: pin=13 val=1"],
290+
"log_count": 1,
291+
"total_buffered": 1
292+
}
293+
```
294+
295+
### Memory Access Commands (Device Required)
296+
297+
#### 16. `mem-read` - Read device memory
298+
299+
```bash
300+
fpb_cli.py --port /dev/ttyACM0 mem-read <addr> <length> [--fmt hex|raw|u32]
301+
```
302+
303+
**Example:**
304+
```bash
305+
fpb_cli.py --port /dev/ttyACM0 mem-read 0x20000000 64 --fmt hex
306+
```
307+
308+
#### 17. `mem-write` - Write to device memory
309+
310+
```bash
311+
fpb_cli.py --port /dev/ttyACM0 mem-write <addr> <hex_data>
312+
```
313+
314+
**Example:**
315+
```bash
316+
fpb_cli.py --port /dev/ttyACM0 mem-write 0x20001000 DEADBEEF01020304
317+
```
318+
319+
#### 18. `mem-dump` - Dump memory to file
320+
321+
```bash
322+
fpb_cli.py --port /dev/ttyACM0 mem-dump <addr> <length> <output_file>
323+
```
324+
325+
**Example:**
326+
```bash
327+
fpb_cli.py --port /dev/ttyACM0 mem-dump 0x20000000 4096 /tmp/ram.bin
328+
```
329+
330+
### File Transfer Commands (Device Required)
331+
332+
#### 19. `file-list` - List device directory
333+
334+
```bash
335+
fpb_cli.py --port /dev/ttyACM0 file-list [path]
336+
```
337+
338+
Default path is `/`.
339+
340+
#### 20. `file-stat` - Get file info
341+
342+
```bash
343+
fpb_cli.py --port /dev/ttyACM0 file-stat <path>
344+
```
345+
346+
Returns size, modification time, and type (file/dir).
347+
348+
#### 21. `file-download` - Download file from device
349+
350+
```bash
351+
fpb_cli.py --port /dev/ttyACM0 file-download <remote_path> <local_path>
352+
```
353+
354+
Transfers via chunked Base64 encoding with CRC verification.
355+
356+
**Example:**
357+
```bash
358+
fpb_cli.py --port /dev/ttyACM0 file-download /data/log.bin /tmp/log.bin
359+
```
360+
188361
## Typical Workflow
189362
190363
```bash

Tools/WebServer/fpb_mcp_server.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,26 @@ def search(elf_path: str, pattern: str) -> dict:
172172
return _capture_cli_output(cli.search, elf_path, pattern)
173173

174174

175+
@mcp.tool()
176+
def get_symbols(
177+
elf_path: str,
178+
pattern: str = "",
179+
limit: int = 0,
180+
) -> dict:
181+
"""Get all symbols from an ELF binary via nm.
182+
183+
Returns a complete symbol list with optional filtering and limiting.
184+
More comprehensive than search() - includes all symbol types, not just functions.
185+
186+
Args:
187+
elf_path: Path to the ELF firmware file
188+
pattern: Filter pattern (case-insensitive substring match, default: "" for all)
189+
limit: Maximum number of results (0 for unlimited, default: 0)
190+
"""
191+
cli = _get_cli(elf_path=elf_path)
192+
return _capture_cli_output(cli.get_symbols, elf_path, pattern, limit)
193+
194+
175195
@mcp.tool()
176196
def compile_patch(
177197
source_file: str,
@@ -260,6 +280,7 @@ def inject(
260280
port: Optional[str] = None,
261281
patch_mode: str = "trampoline",
262282
comp: int = -1,
283+
verify: bool = False,
263284
) -> dict:
264285
"""Inject a patch to replace a function on the device.
265286
@@ -276,6 +297,7 @@ def inject(
276297
port: Serial port (uses existing connection if omitted)
277298
patch_mode: Patch mode - trampoline, debugmon, or direct (default: trampoline)
278299
comp: FPB slot number, -1 for auto-assign (default: -1)
300+
verify: Verify patch after injection (default: False)
279301
"""
280302
cli = _get_cli(port=port, elf_path=elf_path, compile_commands=compile_commands)
281303
return _capture_cli_output(
@@ -286,6 +308,7 @@ def inject(
286308
compile_commands,
287309
patch_mode,
288310
comp,
311+
verify,
289312
)
290313

291314

@@ -311,6 +334,7 @@ def test_serial(
311334
port: Optional[str] = None,
312335
start_size: int = 16,
313336
max_size: int = 4096,
337+
timeout: float = 2.0,
314338
) -> dict:
315339
"""Test serial throughput with 3-phase probing to find optimal parameters.
316340
@@ -325,9 +349,10 @@ def test_serial(
325349
port: Serial port (uses existing connection if omitted)
326350
start_size: Starting test size in bytes for upload probe (default: 16)
327351
max_size: Maximum test size in bytes for upload probe (default: 4096)
352+
timeout: Timeout per test in seconds (default: 2.0)
328353
"""
329354
cli = _get_cli(port=port)
330-
return _capture_cli_output(cli.test_serial, start_size, max_size)
355+
return _capture_cli_output(cli.test_serial, start_size, max_size, timeout)
331356

332357

333358
# ============================================================

0 commit comments

Comments
 (0)