An AI-powered control layer for BLE devices. Runs on a Raspberry Pi (or any machine with Bluetooth), monitors sensors, detects device presence, reacts to events, and acts autonomously — no rules engine, no rigid automation. Just tell it what you want.
Connects to BLE hardware via the BLE MCP Server. Exposes itself as an MCP server so you can chat with it from Claude Desktop, Claude mobile, or any MCP client.
Built with fast-agent.
The gateway has two agents:
Controller (autonomous, uses Sonnet) — the brain:
- Receives BLE notifications in real time
- Creates and manages plugins for continuous monitoring
- Writes and fixes its own code — verifies plugins work, debugs when they don't
- Stores all events and rules in a SQLite database
- Acts on rules set by the user
User agent (interactive, uses Haiku) — the interface:
- Presents data to the user (queries database)
- Passes user instructions to the controller in plain language
- Handles one-off BLE operations (quick scans, reads)
- Explains what happened and who did what
You BLE hardware
| |
├── terminal ──┐ |
| | |
└─ Claude ─────┤ |
Desktop | |
v |
[User agent] ──> [Controller agent] ──stdio──> [BLE MCP Server] ──BLE──> [Devices]
(Haiku) | (Sonnet)
v
[SQLite DB]
rules, events,
telemetry
- Python 3.11+
- BLE MCP Server installed (
pip install ble-mcp-server) - mcp-server-sqlite installed (
pip install mcp-server-sqlite) - An Anthropic API key
pip install fast-agent-mcpexport ANTHROPIC_API_KEY=sk-...
python agent.pyThen just talk to it:
"Scan for BLE devices every 30 seconds and log what you find"
The user agent passes this to the controller. The controller creates a rule in the database, writes a scanner plugin, loads it, starts it, and verifies it works — all autonomously.
"What devices have been found?"
The user agent queries the database and shows results.
"Stop the scanner"
The user agent tells the controller. The controller stops the task, disables the rule, logs the action.
# Terminal 1: start as MCP server
python agent.py --server --transport http --port 9000
# Terminal 2: expose via tunnel
cloudflared tunnel --url http://localhost:9000Add the cloudflared URL in Claude Desktop. Same capabilities, accessible from anywhere.
Rules are stored in a SQLite database, not config files. You set them in natural language through the user agent, and the controller interprets and executes them.
Setting a rule:
You: "Monitor temperature on the Arduino, alert if above 30C"
→ User agent tells the controller
→ Controller creates a rule in the DB
→ Controller creates a plugin for the Arduino
→ Controller starts monitoring
→ Controller verifies it's working
Checking rules:
You: "What rules are active?"
→ User agent queries the DB directly, shows results
Removing a rule:
You: "Stop monitoring temperature"
→ User agent tells the controller
→ Controller stops the task, disables the rule, cleans up
The controller checks rules on startup and whenever it receives a BLE notification. It acts on events autonomously — no periodic polling.
The controller creates BLE plugins autonomously — Python modules that run background tasks inside the BLE server. When you ask for continuous monitoring, the controller:
- Gets a plugin template from the BLE server
- Writes custom plugin code based on your requirements
- Loads it into the BLE server
- Starts the background task
- Verifies it works — checks for data in the DB, task status, errors
- Fixes bugs if the plugin isn't working — reads the code, identifies issues, patches, reloads
Plugins can:
- Run periodic BLE scans (device presence tracking)
- Read characteristics on a schedule (sensor polling)
- Subscribe to notifications (real-time data streaming)
- Write directly to SQLite for telemetry persistence
- Send notifications back to the controller via
state.on_log_cb
Manage running tasks:
ble_tasks_list— see all background tasks with statusble_tasks_cancel— stop a task
default_model: sonnet
mcp:
targets:
- name: ble
target: "ble_mcp"
env:
BLE_MCP_ALLOW_WRITES: "true"
BLE_MCP_PLUGINS: "all"
- name: db
target: "mcp-server-sqlite --db-path telemetry.db"
- name: filesystem
target: "npx -y @modelcontextprotocol/server-filesystem ."Three MCP servers:
- ble — BLE device operations + plugin system
- db — SQLite for rules, events, telemetry
- filesystem — read/write plugin files
The controller uses Sonnet (writes and debugs code). The user agent uses Haiku (fast, cheap for presentation). Set in agent.py:
@fast.agent(name="controller", model="sonnet", ...)
@fast.agent(name="user", model="haiku", ...)| Variable | Description |
|---|---|
ANTHROPIC_API_KEY |
Anthropic API key |
- Control layer (controller agent): monitors devices, makes decisions, acts. Runs 24/7. Processes BLE notifications autonomously.
- Presentation layer (user agent): you check in when you want. Queries the database for what happened. Passes instructions to the controller.
The database is the shared state:
- Controller writes: rules, events, sensor readings, task logs
- User agent writes: nothing (delegates to controller for rules)
- Both read: everything
The BLE server sends MCP log notifications for:
- New device found during a scan
- Device disconnected unexpectedly
- BLE characteristic notification arrived
- Plugin-generated events
The controller receives these via a notification callback (requires fast-agent fork with notification support). Notifications are processed autonomously — the controller checks rules and acts.
[Controller + Local LLM] <--stdio--> [BLE MCP Server] <--BLE--> [Devices]
|
+<--HTTPS-- [Claude Desktop] (presentation only)
Sensor data never leaves your network. Claude Desktop becomes a window into a fully local system.
- Smart home without rules: "Keep the house comfortable" — the controller monitors sensors and makes judgment calls, no if/then rules
- Device fleet tracking: "Scan every 30 seconds and log what you find" — the controller creates a scanner plugin, tracks devices in the database
- Remote monitoring: Check BLE sensors from your phone via Claude Desktop — "What's the temperature?"
- Presence detection: "Tell me when my phone appears" — scanner plugin detects BLE advertisements
- Device exploration: "Connect to this unknown device and figure out what it does" — the controller explores services, creates specs and plugins
- Telemetry collection: "Monitor temperature and store it" — the controller creates the schema, subscribes, persists readings
- BLE MCP Server — the BLE interface
- fast-agent — the agent framework
- fast-agent fork — with MCP notification support (PR pending)
- cloudflared — tunnel for remote access
MIT