bluespy-mcp 1.2.0__tar.gz
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.
- bluespy_mcp-1.2.0/.claude/settings.local.json +11 -0
- bluespy_mcp-1.2.0/.gitignore +10 -0
- bluespy_mcp-1.2.0/.mcp.json +12 -0
- bluespy_mcp-1.2.0/CLAUDE.md +55 -0
- bluespy_mcp-1.2.0/LICENSE +21 -0
- bluespy_mcp-1.2.0/PKG-INFO +390 -0
- bluespy_mcp-1.2.0/README.md +363 -0
- bluespy_mcp-1.2.0/docs/demo-prompts.md +138 -0
- bluespy_mcp-1.2.0/docs/hardware-lifecycle.md +240 -0
- bluespy_mcp-1.2.0/pyproject.toml +54 -0
- bluespy_mcp-1.2.0/scripts/test.sh +57 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/__init__.py +3 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/__main__.py +5 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/_vendor/__init__.py +0 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/_vendor/bluespy.py +1345 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/analysis_core.py +731 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/analyzer.py +208 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/capture.py +290 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/hardware.py +547 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/loader.py +161 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/packet_cache.py +214 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/server.py +565 -0
- bluespy_mcp-1.2.0/src/bluespy_mcp/worker.py +388 -0
- bluespy_mcp-1.2.0/tests/__init__.py +0 -0
- bluespy_mcp-1.2.0/tests/conftest.py +129 -0
- bluespy_mcp-1.2.0/tests/e2e/__init__.py +1 -0
- bluespy_mcp-1.2.0/tests/e2e/conftest.py +141 -0
- bluespy_mcp-1.2.0/tests/e2e/fixtures/__init__.py +1 -0
- bluespy_mcp-1.2.0/tests/e2e/fixtures/prompts.py +7 -0
- bluespy_mcp-1.2.0/tests/e2e/results/.gitignore +2 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T021703Z_Load_the_capture_file_at__nonexistent_pa.json +10 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T021952Z_Load_the_capture_file_at__nonexistent_pa.json +10 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022106Z_Load_the_capture_file_at__nonexistent_pa.json +20 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022145Z_Load_the_capture_file_at__nonexistent_pa.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022221Z_Use_the_load_capture_tool_to_load_the_ca.json +10 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022310Z_Use_the_load_capture_tool_to_load_the_ca.json +20 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022344Z_Use_the_load_capture_tool_to_load_the_ca.json +20 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022411Z_Load_the_capture_file_at__Users_mafaneh.json +27 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022505Z_Load__Users_mafaneh_Projects_bluespy_mcp.json +142 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022539Z_Load__Users_mafaneh_Projects_bluespy_mcp.json +34 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022625Z_Do_a_complete_analysis_of__Users_mafaneh.json +66 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T022803Z_Use_the_load_capture_tool_to_load_the_ca.json +20 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023028Z_Use_the_load_capture_tool_to_load_the_ca.json +20 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023057Z_Load_the_capture_file_at__Users_mafaneh.json +27 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023132Z_Load__Users_mafaneh_Projects_bluespy_mcp.json +79 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023202Z_Load__Users_mafaneh_Projects_bluespy_mcp.json +36 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023345Z_Do_a_complete_analysis_of__Users_mafaneh.json +220 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023618Z_Use_the_load_capture_tool_to_load_the_ca.json +20 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023646Z_Load_the_capture_file_at__Users_mafaneh.json +27 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023723Z_Load__Users_mafaneh_Projects_bluespy_mcp.json +99 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023801Z_Load__Users_mafaneh_Projects_bluespy_mcp.json +36 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T023832Z_Do_a_complete_analysis_of__Users_mafaneh.json +57 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T024120Z_Connect_to_the_BlueSPY_sniffer.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T024229Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T024515Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T025726Z_Connect_to_the_BlueSPY_sniffer.json +20 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T025758Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T025845Z_Connect_to_the_sniffer__capture_for_5_se.json +50 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T025931Z_Connect_to_the_sniffer__start_a_continuo.json +60 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T030514Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T030605Z_Connect_to_the_sniffer__capture_for_5_se.json +50 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T030641Z_Connect_to_the_sniffer__start_a_continuo.json +50 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T030739Z_Connect_to_the_sniffer__start_capturing.json +80 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T030823Z_Connect_to_the_sniffer__capture_for_5_se.json +66 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T031338Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T031437Z_Connect_to_the_sniffer__capture_for_5_se.json +57 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T031518Z_Connect_to_the_sniffer__start_a_continuo.json +46 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T031625Z_Connect_to_the_sniffer__start_capturing.json +102 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T031710Z_Connect_to_the_sniffer__capture_for_5_se.json +69 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T032151Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T032247Z_Connect_to_the_sniffer__capture_for_5_se.json +58 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T032347Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T032435Z_Connect_to_the_sniffer__capture_for_5_se.json +76 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T032512Z_Connect_to_the_sniffer__start_a_continuo.json +48 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T032626Z_Connect_to_the_sniffer__start_capturing.json +121 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T032717Z_Connect_to_the_sniffer__capture_for_5_se.json +68 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T035142Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T035332Z_Connect_to_the_sniffer__capture_for_5_se.json +71 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T035408Z_Connect_to_the_sniffer__start_a_continuo.json +48 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T035515Z_Connect_to_the_sniffer__start_capturing.json +117 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T035606Z_Connect_to_the_sniffer__capture_for_5_se.json +75 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T035647Z_Connect_to_the_sniffer__start_a_continuo.json +62 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260301T035744Z_Connect_to_the_sniffer__start_a_continuo.json +55 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260302T074314Z_Check_the_hardware_status__If_anything_i.json +18 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260302T074403Z_Connect_to_the_sniffer__capture_for_5_se.json +53 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260302T074444Z_Connect_to_the_sniffer__start_a_continuo.json +46 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260302T074526Z_Connect_to_the_sniffer__start_capturing.json +70 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260302T074614Z_Connect_to_the_sniffer__capture_for_5_se.json +68 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260302T074652Z_Connect_to_the_sniffer__start_a_continuo.json +57 -0
- bluespy_mcp-1.2.0/tests/e2e/results/20260302T074933Z_Connect_to_the_sniffer__start_a_continuo.json +59 -0
- bluespy_mcp-1.2.0/tests/e2e/scenario.py +426 -0
- bluespy_mcp-1.2.0/tests/e2e/scenarios/__init__.py +1 -0
- bluespy_mcp-1.2.0/tests/e2e/scenarios/test_error_handling.py +92 -0
- bluespy_mcp-1.2.0/tests/e2e/scenarios/test_file_analysis.py +109 -0
- bluespy_mcp-1.2.0/tests/e2e/scenarios/test_hardware_capture.py +110 -0
- bluespy_mcp-1.2.0/tests/e2e/scenarios/test_live_analysis.py +115 -0
- bluespy_mcp-1.2.0/tests/e2e/test_scenario.py +295 -0
- bluespy_mcp-1.2.0/tests/fixtures/.gitkeep +0 -0
- bluespy_mcp-1.2.0/tests/fixtures/5_sec_capture.pcapng +0 -0
- bluespy_mcp-1.2.0/tests/fixtures/smart_home_capture_10min.pcapng +0 -0
- bluespy_mcp-1.2.0/tests/test_analysis_core.py +597 -0
- bluespy_mcp-1.2.0/tests/test_analyzer.py +42 -0
- bluespy_mcp-1.2.0/tests/test_capture.py +254 -0
- bluespy_mcp-1.2.0/tests/test_hardware.py +441 -0
- bluespy_mcp-1.2.0/tests/test_integration.py +311 -0
- bluespy_mcp-1.2.0/tests/test_loader.py +63 -0
- bluespy_mcp-1.2.0/tests/test_packet_cache.py +415 -0
- bluespy_mcp-1.2.0/tests/test_server.py +124 -0
- bluespy_mcp-1.2.0/tests/test_server_hardware.py +440 -0
- bluespy_mcp-1.2.0/tests/test_worker.py +586 -0
- bluespy_mcp-1.2.0/uv.lock +1560 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"bluespy": {
|
|
4
|
+
"command": "/Users/mafaneh/Projects/bluespy-mcp/.venv/bin/python",
|
|
5
|
+
"args": ["-m", "bluespy_mcp"],
|
|
6
|
+
"env": {
|
|
7
|
+
"BLUESPY_LIBRARY_PATH": "/Applications/blueSPY.app/Contents/Frameworks/libblueSPY.dylib",
|
|
8
|
+
"BLE_CAPTURES_DIR": "/Users/mafaneh/Projects/bluespy-captures"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
## What This Is
|
|
4
|
+
|
|
5
|
+
Open-source MCP server for the BlueSPY Bluetooth LE protocol analyzer. Lets AI assistants load and analyze .pcapng capture files.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
Flat Python package:
|
|
10
|
+
|
|
11
|
+
- `server.py` — FastMCP server, 16 tools + 2 resources + 3 prompts
|
|
12
|
+
- `capture.py` — CaptureManager wrapping BlueSPY's global file state
|
|
13
|
+
- `analyzer.py` — Packet classification, filtering, summarization
|
|
14
|
+
- `hardware.py` — HardwareManager: subprocess isolation, file lock, state machine
|
|
15
|
+
- `worker.py` — Worker subprocess: executes bluespy hardware commands
|
|
16
|
+
- `loader.py` — Auto-discovers bluespy.py (installed > bundled fallback)
|
|
17
|
+
- `_vendor/bluespy.py` — Bundled fallback BlueSPY API
|
|
18
|
+
|
|
19
|
+
## Development
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Setup
|
|
23
|
+
python -m venv .venv
|
|
24
|
+
source .venv/bin/activate
|
|
25
|
+
pip install -e .
|
|
26
|
+
|
|
27
|
+
# Run tests (no hardware needed)
|
|
28
|
+
python -m pytest tests/ -v
|
|
29
|
+
|
|
30
|
+
# Run integration tests (needs BlueSPY hardware + dylib)
|
|
31
|
+
python -m pytest tests/ -v -m hardware
|
|
32
|
+
|
|
33
|
+
# Run server locally
|
|
34
|
+
bluespy-mcp
|
|
35
|
+
# or
|
|
36
|
+
python -m bluespy_mcp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Key Patterns
|
|
40
|
+
|
|
41
|
+
- **Lazy loading**: BlueSPY module loaded on first use, not at import time
|
|
42
|
+
- **One file at a time**: BlueSPY uses global state. CaptureManager wraps this.
|
|
43
|
+
- **Defensive queries**: Every packet attribute access wrapped in try/except
|
|
44
|
+
- **JSON responses**: All tools return JSON. Errors are `{"error": "message"}`.
|
|
45
|
+
- **50K packet cap**: Summary operations cap iteration to prevent hanging on huge captures.
|
|
46
|
+
- **Subprocess isolation**: All hardware calls run in a child process. If ctypes hangs, the subprocess is killed — MCP server stays responsive.
|
|
47
|
+
- **File lock**: `~/.bluespy-mcp.lock` ensures single-client hardware access.
|
|
48
|
+
- **Reboot on connect**: Every connect_hardware() reboots the device first to avoid stale state.
|
|
49
|
+
|
|
50
|
+
## Adding New Tools
|
|
51
|
+
|
|
52
|
+
1. Add analysis function to `analyzer.py`
|
|
53
|
+
2. Add `@mcp.tool` function to `server.py` (follows the pattern of existing tools)
|
|
54
|
+
3. Add tests to the corresponding test file
|
|
55
|
+
4. Update README.md tool table
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Novel Bits
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bluespy-mcp
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: MCP server for BlueSPY Bluetooth LE protocol analyzer
|
|
5
|
+
Project-URL: Homepage, https://github.com/novelbits/bluespy-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/novelbits/bluespy-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/novelbits/bluespy-mcp/issues
|
|
8
|
+
Author-email: Mohammad Afaneh <mafaneh@novelbits.io>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ble,bluespy,bluetooth,mcp,protocol-analyzer,sniffer
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
23
|
+
Provides-Extra: e2e
|
|
24
|
+
Requires-Dist: claude-code-sdk; extra == 'e2e'
|
|
25
|
+
Requires-Dist: pytest-asyncio; extra == 'e2e'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# BlueSPY MCP Server
|
|
29
|
+
|
|
30
|
+
MCP server for the [BlueSPY](https://rfcreations.com) Bluetooth LE protocol analyzer. Gives AI assistants direct access to .pcapng capture analysis — turn packet captures into conversations instead of writing scripts or scrolling through Wireshark.
|
|
31
|
+
|
|
32
|
+
Works with Claude Desktop, Claude Code, and Cursor.
|
|
33
|
+
|
|
34
|
+
## What It Does
|
|
35
|
+
|
|
36
|
+
Instead of writing Python scripts or manually filtering packets, just ask:
|
|
37
|
+
|
|
38
|
+
> "Load this capture and tell me what's going on."
|
|
39
|
+
|
|
40
|
+
The AI loads your capture file, classifies 54,000+ packets, identifies 219 devices, maps 25 connections, and gives you a structured breakdown — in seconds.
|
|
41
|
+
|
|
42
|
+
### Example: Analyzing a Restaurant Bluetooth LE Environment
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
You: Load the First Watch capture and summarize it.
|
|
46
|
+
|
|
47
|
+
Claude: Loaded First Watch Carmel.pcapng — 54,195 packets over 32 seconds.
|
|
48
|
+
|
|
49
|
+
219 devices detected, 25 active connections.
|
|
50
|
+
|
|
51
|
+
Packet breakdown:
|
|
52
|
+
→ 11,671 ADV_IND (connectable advertisements)
|
|
53
|
+
→ 4,738 ADV_NONCONN_IND (beacons)
|
|
54
|
+
→ 6,554 LE_DATA (active data transfer)
|
|
55
|
+
→ 5,642 SCAN_REQ / 5,014 SCAN_RSP
|
|
56
|
+
→ 113 CRC errors from RF congestion
|
|
57
|
+
→ 33 new connections initiated
|
|
58
|
+
|
|
59
|
+
You: Show me the advertising for the first device.
|
|
60
|
+
|
|
61
|
+
Claude: Device BC:57:29:01:00:42 — 34 advertisements found.
|
|
62
|
+
Channels: 37, 38, 39
|
|
63
|
+
RSSI: min -82, max -48, avg -65.2
|
|
64
|
+
|
|
65
|
+
You: Find all the errors.
|
|
66
|
+
|
|
67
|
+
Claude: 113 errors found — all CRC failures on advertising channels,
|
|
68
|
+
consistent with a congested RF environment (219 devices in range).
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
No scripts. No manual filtering. Just a conversation.
|
|
72
|
+
|
|
73
|
+
## Prerequisites
|
|
74
|
+
|
|
75
|
+
- **Python 3.10+**
|
|
76
|
+
- **BlueSPY application** (free) — provides the native `libblueSPY` library required for packet parsing
|
|
77
|
+
|
|
78
|
+
Download BlueSPY for your platform from [rfcreations.com/bluespy-software](https://www.rfcreations.com/bluespy-software):
|
|
79
|
+
|
|
80
|
+
| Platform | Download |
|
|
81
|
+
|----------|----------|
|
|
82
|
+
| macOS 11.0+ | [blueSPY-Darwin.pkg](https://private.rfcreations.com/bin/latest?q=blueSPY-~-Darwin.pkg) |
|
|
83
|
+
| Windows 7+ | [blueSPY-win64.msi](https://private.rfcreations.com/bin/latest?q=blueSPY-~-win64.msi) |
|
|
84
|
+
| Windows 7+ (Portable) | [blueSPY-win64.7z](https://private.rfcreations.com/bin/latest?q=blueSPY-~-win64.7z) |
|
|
85
|
+
| Linux (glibc 2.27+) | [blueSPY-Linux.7z](https://private.rfcreations.com/bin/latest?q=blueSPY-~-Linux.7z) |
|
|
86
|
+
| Linux (arm64) | [blueSPY-Linux-arm64.7z](https://private.rfcreations.com/bin/latest?q=blueSPY-~-Linux-arm64.7z) |
|
|
87
|
+
| Linux (Headless) | [blueSPY-Linux-Headless.7z](https://private.rfcreations.com/bin/latest?q=blueSPY-~-Linux-Headless.7z) |
|
|
88
|
+
|
|
89
|
+
No hardware needed to get started — download the [example captures](https://www.rfcreations.com/bluespy-software) from the same page and use them with the file analysis tools.
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install bluespy-mcp
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Or install from source:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
git clone https://github.com/novelbits/bluespy-mcp.git
|
|
101
|
+
cd bluespy-mcp
|
|
102
|
+
pip install .
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Configuration
|
|
106
|
+
|
|
107
|
+
### Claude Desktop
|
|
108
|
+
|
|
109
|
+
Add to your `claude_desktop_config.json`:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"bluespy": {
|
|
115
|
+
"command": "bluespy-mcp",
|
|
116
|
+
"env": {
|
|
117
|
+
"BLUESPY_LIBRARY_PATH": "/Applications/blueSPY.app/Contents/Frameworks/libblueSPY.dylib"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Claude Code
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
claude mcp add bluespy -- bluespy-mcp
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Or add to your `.mcp.json`:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"bluespy": {
|
|
135
|
+
"command": "bluespy-mcp",
|
|
136
|
+
"env": {
|
|
137
|
+
"BLUESPY_LIBRARY_PATH": "/Applications/blueSPY.app/Contents/Frameworks/libblueSPY.dylib"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Cursor
|
|
144
|
+
|
|
145
|
+
Add to your MCP server configuration:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"bluespy": {
|
|
150
|
+
"command": "bluespy-mcp",
|
|
151
|
+
"env": {
|
|
152
|
+
"BLUESPY_LIBRARY_PATH": "/Applications/blueSPY.app/Contents/Frameworks/libblueSPY.dylib"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Environment Variables
|
|
159
|
+
|
|
160
|
+
| Variable | Description | Required |
|
|
161
|
+
|----------|-------------|----------|
|
|
162
|
+
| `BLUESPY_LIBRARY_PATH` | Path to `libblueSPY.dylib` / `.so` / `.dll` | Yes |
|
|
163
|
+
| `BLUESPY_API_PATH` | Path to directory containing `bluespy.py` (auto-discovered if not set) | No |
|
|
164
|
+
| `BLE_CAPTURES_DIR` | Default directory for capture files (default: `captures/`) | No |
|
|
165
|
+
|
|
166
|
+
### Platform-Specific Library Paths
|
|
167
|
+
|
|
168
|
+
| Platform | Path |
|
|
169
|
+
|----------|------|
|
|
170
|
+
| macOS | `/Applications/blueSPY.app/Contents/Frameworks/libblueSPY.dylib` |
|
|
171
|
+
| Windows | `C:\Program Files\blueSPY\libblueSPY.dll` |
|
|
172
|
+
| Linux | `/usr/local/lib/libblueSPY.so` |
|
|
173
|
+
|
|
174
|
+
## Tools
|
|
175
|
+
|
|
176
|
+
### File Management
|
|
177
|
+
|
|
178
|
+
| Tool | Description |
|
|
179
|
+
|------|-------------|
|
|
180
|
+
| `load_capture(file_path)` | Load a .pcapng capture file for analysis |
|
|
181
|
+
| `close_capture()` | Close the currently loaded file |
|
|
182
|
+
| `list_captures(directory?)` | List .pcapng files in a directory |
|
|
183
|
+
|
|
184
|
+
### Discovery
|
|
185
|
+
|
|
186
|
+
| Tool | Description |
|
|
187
|
+
|------|-------------|
|
|
188
|
+
| `capture_summary()` | Packet counts by type, duration, device/connection counts |
|
|
189
|
+
| `list_devices()` | All Bluetooth devices with addresses and names |
|
|
190
|
+
| `list_connections()` | All connections with parameters |
|
|
191
|
+
|
|
192
|
+
### Analysis
|
|
193
|
+
|
|
194
|
+
| Tool | Description |
|
|
195
|
+
|------|-------------|
|
|
196
|
+
| `search_packets(summary_contains?, packet_type?, channel?, max_results?)` | Filter packets by criteria |
|
|
197
|
+
| `inspect_connection(connection_index)` | Deep-dive connection analysis with packet breakdown |
|
|
198
|
+
| `inspect_advertising(device_index)` | Per-device advertising analysis with RSSI and channel stats |
|
|
199
|
+
| `inspect_all_devices()` | Batch advertising analysis for ALL devices in a single pass (much faster than per-device calls) |
|
|
200
|
+
| `inspect_all_connections()` | Batch connection analysis for ALL connections in a single pass (much faster than per-connection calls) |
|
|
201
|
+
| `find_capture_errors(max_results?)` | Error, failure, disconnect, and timeout packets |
|
|
202
|
+
|
|
203
|
+
### Live Hardware
|
|
204
|
+
|
|
205
|
+
| Tool | Description |
|
|
206
|
+
|------|-------------|
|
|
207
|
+
| `connect_hardware(serial, force)` | Connect to first available device (or specify serial) |
|
|
208
|
+
| `disconnect_hardware()` | Disconnect from hardware |
|
|
209
|
+
| `start_capture(filename, duration_seconds, LE, CL, QHS, wifi, CS)` | Start live capture |
|
|
210
|
+
| `stop_capture()` | Stop active capture |
|
|
211
|
+
| `hardware_status()` | Get current hardware state |
|
|
212
|
+
|
|
213
|
+
### Resources
|
|
214
|
+
|
|
215
|
+
| Resource | Description |
|
|
216
|
+
|----------|-------------|
|
|
217
|
+
| `capture://status` | Current loaded file metadata (JSON) |
|
|
218
|
+
| `bluespy://hardware` | Current hardware connection state (JSON) |
|
|
219
|
+
| `bluespy://capture` | Current live capture state (JSON) |
|
|
220
|
+
|
|
221
|
+
### Prompts
|
|
222
|
+
|
|
223
|
+
| Prompt | Description |
|
|
224
|
+
|--------|-------------|
|
|
225
|
+
| `analyze-capture` | Guided workflow to load and analyze a capture file |
|
|
226
|
+
| `quick-capture` | Quick-start workflow for live hardware capture |
|
|
227
|
+
| `debug-connection` | Troubleshoot hardware connection issues |
|
|
228
|
+
|
|
229
|
+
## Try It Without Hardware
|
|
230
|
+
|
|
231
|
+
Download the [example captures](https://www.rfcreations.com/bluespy-software) from RFcreations (free) and try these prompts. No sniffer needed — just the BlueSPY application installed.
|
|
232
|
+
|
|
233
|
+
### Example Captures
|
|
234
|
+
|
|
235
|
+
| File | Packets | Devices | Connections | What's inside |
|
|
236
|
+
|------|---------|---------|-------------|---------------|
|
|
237
|
+
| `LE_Phone_Alert_Status_Profile.pcapng` | 2,359 | 16 | 2 | Simple Bluetooth LE GATT profile with scanning and data exchange |
|
|
238
|
+
| `Encrypted Advertising Data.pcapng` | 1,547 | 13 | 0 | Advertising only — no connections, good for device discovery analysis |
|
|
239
|
+
| `AVDTP_and_eSCO.pcapng` | — | — | — | Bluetooth Classic audio (A2DP streaming + voice calls) |
|
|
240
|
+
| `BIS.pcapng` | — | — | — | LE Audio Broadcast Isochronous Stream |
|
|
241
|
+
| `CIS_and_AVDTP_and_HCI.pcapng` | — | — | — | Mixed: LE Audio CIS + Classic audio + HCI commands |
|
|
242
|
+
| `audiopod_LE_Audio_CIG.pcapng` | 53,887 | 186 | 14 | Dense LE Audio capture — NRF5340 devices, CRC errors, encrypted traffic |
|
|
243
|
+
|
|
244
|
+
### Start here: simple Bluetooth LE profile
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
Load LE_Phone_Alert_Status_Profile.pcapng and tell me what's going on.
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
Inspect all connections. What protocols are being used?
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Advertising-only analysis
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
Load Encrypted Advertising Data.pcapng. How many devices are advertising? Inspect all of them.
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
Search for SCAN_REQ packets. Which devices are being actively scanned?
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Stress test: large LE Audio capture
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
Load audiopod_LE_Audio_CIG.pcapng and summarize it.
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
Inspect all 14 connections at once. Which ones have the most data packets?
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
Find all errors. What's causing the CRC failures?
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
Look at connection 9 — that's the NRF5340_AUDIO device. What's it doing?
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Or use the built-in `analyze-capture` prompt for a guided walkthrough of any file.
|
|
283
|
+
|
|
284
|
+
## Live Hardware Capture
|
|
285
|
+
|
|
286
|
+
If you have a BlueSPY sniffer connected via USB, the MCP server can control it directly — connect, start/stop captures, and analyze results in real time.
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
You: Connect to my sniffer and capture Bluetooth LE traffic for 10 seconds.
|
|
290
|
+
|
|
291
|
+
Claude: Connected to Moreph serial 2411001234.
|
|
292
|
+
Capturing Bluetooth LE packets for 10 seconds...
|
|
293
|
+
Capture complete — saved to ble_capture_20260228.pcapng (12,847 packets).
|
|
294
|
+
|
|
295
|
+
You: Summarize what you captured.
|
|
296
|
+
|
|
297
|
+
Claude: 12,847 packets over 10 seconds.
|
|
298
|
+
87 devices detected, 12 active connections.
|
|
299
|
+
→ 4,231 ADV_IND (connectable advertisements)
|
|
300
|
+
→ 1,892 ADV_NONCONN_IND (beacons)
|
|
301
|
+
→ 3,104 LE_DATA (active data transfer)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Hardware access is subprocess-isolated — if a hardware call hangs, the MCP server kills the worker process and stays responsive. A file lock (`~/.bluespy-mcp.lock`) ensures only one client controls the hardware at a time.
|
|
305
|
+
|
|
306
|
+
## Model Recommendations
|
|
307
|
+
|
|
308
|
+
This MCP server works with any LLM that supports tool use. The built-in prompt templates (`analyze-capture`, `quick-capture`, `debug-connection`) guide even smaller models through the correct multi-step workflows.
|
|
309
|
+
|
|
310
|
+
| Tier | Models | Best For |
|
|
311
|
+
|------|--------|----------|
|
|
312
|
+
| **Minimum** | Haiku 4.5, GPT-4o mini, Gemini Flash | Loading captures, running guided workflows, basic summaries. Handles the full tool chain reliably. |
|
|
313
|
+
| **Recommended** | Sonnet 4.5, GPT-4o, Gemini Pro | Deeper protocol analysis — correlating error patterns across connections, interpreting RSSI trends, diagnosing RF interference, generating actionable recommendations. |
|
|
314
|
+
| **Advanced** | Opus, o3, Gemini Ultra | Multi-capture comparison, cross-referencing against Bluetooth spec, complex protocol-level debugging. Rarely needed. |
|
|
315
|
+
|
|
316
|
+
**Key factors for good results:**
|
|
317
|
+
- **Use the prompt templates.** They walk any model through load → summarize → analyze → inspect in the right order.
|
|
318
|
+
- **Tool-use reliability matters more than model size.** A mid-tier model that follows tool sequences correctly will outperform a large model that skips steps.
|
|
319
|
+
- **Domain knowledge helps but isn't required.** The server returns structured JSON with classified packet types, so the model doesn't need to know Bluetooth LE internals to report useful findings.
|
|
320
|
+
|
|
321
|
+
## Development
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
git clone https://github.com/novelbits/bluespy-mcp.git
|
|
325
|
+
cd bluespy-mcp
|
|
326
|
+
pip install -e .
|
|
327
|
+
pytest
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
To run the full test suite including end-to-end and hardware tests (requires a BlueSPY sniffer connected via USB):
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
pip install -e ".[e2e]"
|
|
334
|
+
bash scripts/test.sh all
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Troubleshooting
|
|
338
|
+
|
|
339
|
+
### "BlueSPY library not found"
|
|
340
|
+
|
|
341
|
+
Ensure `BLUESPY_LIBRARY_PATH` points to the correct native library for your platform. The BlueSPY application must be installed from [rfcreations.com](https://rfcreations.com).
|
|
342
|
+
|
|
343
|
+
### "No capture file loaded"
|
|
344
|
+
|
|
345
|
+
Use `load_capture()` with a path to your .pcapng file before calling analysis tools.
|
|
346
|
+
|
|
347
|
+
### Claude Desktop crashes on startup
|
|
348
|
+
|
|
349
|
+
If you're using FastMCP v3.0.2+, ensure the server runs with `show_banner=False` (this is the default in bluespy-mcp). The FastMCP banner corrupts the MCP stdio protocol.
|
|
350
|
+
|
|
351
|
+
### Hardware: "bluespy_init failed"
|
|
352
|
+
|
|
353
|
+
The MCP server retries automatically when this happens, but if it persists:
|
|
354
|
+
|
|
355
|
+
1. **Connect directly to your computer** — do not use a USB hub. The Moreph sniffer requires a direct USB connection for reliable communication.
|
|
356
|
+
2. **Close the BlueSPY desktop app** if it's open. Only one application can control the hardware at a time. Check the device LED: green means it's in use, blue means it's available.
|
|
357
|
+
3. **Unplug and replug** the device, then try again.
|
|
358
|
+
|
|
359
|
+
### Hardware: "in use by another session"
|
|
360
|
+
|
|
361
|
+
This means the file lock (`~/.bluespy-mcp.lock`) is held by another MCP session. If no other session is actually running (e.g., a previous session crashed), use the `force` parameter:
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
connect_hardware(force=True)
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
This removes the stale lock file and proceeds with the connection.
|
|
368
|
+
|
|
369
|
+
### Hardware: Python crash on exit
|
|
370
|
+
|
|
371
|
+
You may see a macOS crash report (`Python quit unexpectedly`) after using hardware tools. This is a known issue with the BlueSPY native library's cleanup routine (`bluespy_deinit`) and does not affect capture data or MCP server operation. The crash occurs during process exit and can be safely dismissed.
|
|
372
|
+
|
|
373
|
+
### Module not found errors
|
|
374
|
+
|
|
375
|
+
Ensure you're using Python 3.10+ and have installed the package:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
python --version # Should be 3.10+
|
|
379
|
+
pip install bluespy-mcp
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## License
|
|
383
|
+
|
|
384
|
+
MIT License. See [LICENSE](LICENSE) for details.
|
|
385
|
+
|
|
386
|
+
## Links
|
|
387
|
+
|
|
388
|
+
- [BlueSPY by RFcreations](https://rfcreations.com)
|
|
389
|
+
- [MCP Protocol](https://modelcontextprotocol.io)
|
|
390
|
+
- [Issues](https://github.com/novelbits/bluespy-mcp/issues)
|