Plain-English analysis of robotics, drone, and IoT data, with intelligent edge data reduction.
io.github.Extelligence-ai/bagel MCP Server
Extelligence-ai/bagel provides plain-English analysis for robotics, drone, and IoT data, including intelligent edge data reduction. It is packaged as an MCP server (Model Context Protocol) and focuses on processing data formats commonly used in robotics and telemetry workflows.
🛠️ Key Features
Plain-English analysis for robotics, drone, and IoT data
Intelligent edge data reduction
Supports topics including robotics tooling such as ROS/ROS 2
🚀 Use Cases
Analyzing drone and robotics telemetry for easier interpretation
Reducing edge-side data before further processing
⚡ Developer Benefits
MCP integration via Model Context Protocol (mcp-server, model-context-protocol)
Uses data tooling/topics such as duckdb, mcap, and IoT workflows
⚠️ Limitations
Server capability details (e.g., specific tools or toolCount) are not provided in the available source data.
Bagel by Extelligence lets you ask questions about robotics, drone, and IoT data in plain English.
Every calculation over your message data is DuckDB SQL, not model guesswork, and
Bagel shows you the query so you can audit it.
Is my IMU sensor overheating?
Bagel also has an intelligent edge data reduction pipeline: describe an event and
Bagel runs the detection on the robot, keeping the windows that matter and dropping
the rest. An MCP server puts all of it in your LLM's hands: Claude Code, Gemini,
Cursor, or a fully local model.
Bagel was the first MCP server to ship a real analysis toolkit for robotics data,
and it keeps the LLM where it belongs: in front of your logs, never in your robot's
control loop.
🥯 Key Features
Ask in plain language: No deep domain expertise needed.
Transparent calculations: Deterministic SQL queries. No black-box LLM math.
Natural-language pipelines: "Keep 10s around every hard brake, drop the rest":
one sentence becomes an auditable pipeline: previewed
before a byte is written, then run once, across a fleet, or standing at the edge.
Broad LLM support: Claude Code, Gemini, Cursor, Codex, and more.
Dockerized environments: No local dependencies required.
Extensible capabilities: Bagel can learn new tricks.
Wide format coverage: Missing your data format? Open a ticket.
🥯 Try it in 60 seconds
No MCP client, no LLM, no config: run the same deterministic checks against a
bundled sample log and get a robot-health report card straight to your
terminal.
bash
docker run -it --rm ghcr.io/extelligence-ai/bagel/px4:latest demo
code
sample.ulg - 41.5s, 2018 messages, 77 topics
Power ⚠️ min 21.07V, largest drop 2.37V at ~t=+4.8s, end 23.45V (battery_status_0)
IMU ✅ accel_z stddev 1.6x the log baseline at ~t=+36.8s (sensor_combined_0)
GPS — skipped: no GPS topic
Data gaps ✅ no gap > 1.05x median interval (checked battery_status_0, sensor_combined_0)
...
The ROS2 images (ros2-kilted, ros2-jazzy, ros2-iron, ros2-humble) run
demo the same way, against a lighter bundled sample (px4 is the one that
ships with a flight log rich enough to show every check). Point it at your
own log with demo /path/to/log (mount it with -v first), or keep reading
for the full MCP setup below.
⚡️ Quickstart
TIP
Already have Claude Code? Just paste the link to this repo and tell Claude
what environment you want:
git clone https://github.com/Extelligence-ai/bagel.git && cd bagel
docker compose run --service-ports ros2-kilted
TIP
Port 8000 already in use? Set MCP_SERVER_PORT to something else, for example
MCP_SERVER_PORT=8100 docker compose run --service-ports ros2-kilted, and use
that port in step 2.
Pick the service that matches your environment:
Service
Use case
ros2-kilted
ROS2 Kilted (latest)
ros2-jazzy
ROS2 Jazzy
ros2-iron
ROS2 Iron
ros2-humble
ROS2 Humble
ros1-noetic
ROS1 Noetic
ros1-noetic-cv
ROS1 Noetic + CV
px4
PX4 flight logs
ardupilot
ArduPilot flight logs
betaflight
Betaflight flight logs
iot
IoT / MQTT (live)
TIP
To give Bagel access to your local files, edit compose.yaml before starting Docker:
uncomment and update the volumes section under your chosen service.
Wait for this output:
code
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
2. Connect Claude Code
In a new terminal:
bash
claude mcp add --transport sse bagel http://localhost:8000/sse
NOTE
The MCP endpoint is bound to localhost only (not exposed to the LAN) for security.
To share it with other machines, drop the 127.0.0.1 prefix in compose.yaml and
put an authenticated proxy in front: see SECURITY.md.
3. Prompt
bash
claude
Summarize the metadata of the ROS2 bag "./data/sample/ros2/mcap".
That’s it: you’re chatting with your data.
🔒 Prefer fully offline?
Swap step 2 for a local model: your data and your LLM stay on the machine:
Bagel ships an agent plugin: four skills that teach the agent when and how
to drive the server (log triage, pipeline authoring, live sinks, visualization
export) plus the MCP connection, wired automatically. The same plugin/
directory serves both Claude Code and OpenAI Codex.
Codex and ChatGPT users: install bagel from the
OpenAI Plugins Directory
(one click), or clone the repo and add it as a plugin marketplace (the repo
carries .agents/plugins/marketplace.json). Directory installs bundle the
skills only, so also connect the server once in ~/.codex/config.toml:
Repo-marketplace and Claude Code installs wire this connection automatically.
Then start the container for your data format (see Quickstart): the plugin
connects to http://localhost:8000/mcp by default. Any other MCP client can
discover the same workflows server-side via the list_agent_capabilities tool.
Keep what matters, drop the rest
A robot records more data than you can afford to move. Bagel turns a question into
a detector, runs it where the data is recorded, and ships only the windows around
real events.
Here it is in one conversation:
The session above: a 20-minute (1,200 s) recording and the prompt "keep 10 seconds
before and after every deceleration harder than −10 m/s²". The preview detects
7 events, merges them into 4 windows, and keeps 92 s of the 1,200 (7.6%); the run
writes a 2.1 GB bag down to 161 MB. These figures are illustrative demo output, not
a measured benchmark: the ratio is event-window duration over total duration, so it
depends entirely on your workload.
WaffleForm snapshots (.waffleform.yaml), auto-detected via waffle-iron · beta
🆚 Bagel vs. the Tools You Already Use
You already have ros2 *, PlotJuggler, and grep. Bagel doesn't replace them: it
answers the questions they make you work for, then hands off to them:
You do this today
Ask Bagel instead
ros2 bag info for metadata
"Summarize this bag": same prompt works on PX4, ArduPilot, MCAP, MQTT, Postgres
ros2 topic echo /imu and eyeball raw values
"What's the peak z-deceleration in /imu? Running average over 5 s?" · real SQL underneath: peaks, running averages, percentiles, cross-topic correlations
Scrub PlotJuggler timelines hunting for the event
"Find every deceleration under −10 m/s² and cut ±30 s snippets": then open the result in PlotJuggler with a pre-framed layout
rqt_console, or grep ~/.ros/log
"Read the ERRORs from ~/.ros/log and tell me what went wrong": tracebacks included, no bag needed
Echo two topics in two terminals, correlate in a spreadsheet
"What's the correlation between current and voltage?": topics live in one SQL relation, so joins and corr() are one question
scp/aws s3 sync scripts to ship data off the robot
Upload to S3, GCS, or Azure as a pipeline step, checksum-skipping files already there
A different viewer per format: FlightPlot for PX4, MAVExplorer for ArduPilot, Blackbox Explorer for Betaflight
The same conversation for all of them, and ROS, MCAP, MQTT, Postgres, InfluxDB
Write a one-off pandas script per question
Ask the question; Bagel writes and runs the query
One sentence of plain language, one answer, instead of a pipeline of commands and
a script you'll delete tomorrow.
💬 What Can I Prompt?
You can ask Bagel almost anything. For example:
What’s the correlation between current and voltage in the /spot/status/battery_states topic?
I think the robot hit a pothole. Can you check for sudden deceleration on the z-axis to confirm?
Every time the drone decelerates harder than -10 m/s², keep 10 seconds before and after. Drop everything else.
Did anything change on this robot since last week?
Time to put Bagel to the test: can it catch a drone doing barrel rolls? Spoiler: 🎉 It totally can.
image
💡 How Bagel Works
When you ask a question, Bagel analyzes your data source’s metadata and topics to
build a high-level understanding.
Based on your prompt, if further inspection is needed, Bagel identifies the most relevant topics
and interprets their meaning and structure. Bagel then writes the relevant topic messages
to an Apache Arrow file and uses DuckDB to generate and execute queries against it.
This process is repeated as needed, running new queries until Bagel finds the best answer
to your question.
LLMs excel at language but struggle with math. Bagel overcomes this by generating deterministic
DuckDB SQL queries. These queries are displayed for you to audit, and you can guide Bagel to
correct any errors.
🐶 Teach Bagel a New Trick
Bagel learns new capabilities through POML
files: a structured set of instructions that describe a “trick,”
such as computing latency statistics.
✍️ Create a .poml file
For example, let’s define ./src/agent/examples/woof.poml.
poml
<poml>
<task>
Count the topics in the data source.
If the count is odd, say "woof", else say "meow".
</task>
<output-format>
Return the sound, the topic count, and a few cute emojis. Nothing else.
</output-format>
</poml>
🗣️ Use the capability
Prompt Bagel:
Run the POML capability "./src/agent/examples/woof.poml" on the ROS2 bag "./data/sample/ros2/mcap".
Result:
code
meow 🐱 4 topics 🐱💤🎯
Teach it your own tricks (no rebuild)
Bagel discovers your own capabilities from ~/.bagel/capabilities/:
In conversation: do a workflow once, then say "save that as a
capability called battery-triage" — Claude calls save_agent_capability
and it's reusable in any future session.
As a file: drop a markdown file with your steps (or a
POML file, if you want parameterized
templates — see src/agent/compose/pipeline.poml for the house style)
into ~/.bagel/capabilities/.
Either way it shows up in list_agent_capabilities as user/<name> and runs
with run_poml_capability — from Claude Code, Claude Desktop, or any MCP
client. Teams: keep the directory in your own git repo and sync it to every
robot; it's just files. On Linux, run mkdir -p ~/.bagel/capabilities once
before starting the container so the mount is owned by you, not root.
📚 Guides
Natural-language pipelines · the model: a cadence, gates,
and tasks; preview → run → save → batch → standing at the edge
Event-driven data reduction · detect events, keep
windows around them (snippets or one reduced bag), batch across fleets, upload to the cloud
Cloudini · decode cloudini-compressed pointclouds, or compress a bag's PointCloud2 topics into CompressedPointCloud2
Slack · pipelines post to your ops channel when they fire: "🚨 hard brake on {asset}"
LeRobot(beta) · detected events become training episodes: a LeRobotDataset v3.0
🚧 Limitations
Rough edges we know about, so you don't find them the hard way:
Two formats are beta. The automotive MDF4/CAN readers are verified against
files we generate with the same libraries that read them (asammdf, python-can);
real CANape/INCA/Vector-produced captures haven't crossed our test bench yet.
LeRobot exports load-test clean with the real lerobot package, but no policy
has been trained from a Bagel export yet.
Reduction ratios are workload-dependent, and unbenchmarked. The ratio is
event-window duration over total duration: quiet recordings reduce dramatically,
eventful ones much less. The figures in this README are illustrative demo output,
not a measured benchmark.
No authentication on the MCP endpoint. By design it binds to localhost only;
treat it like a database socket and see SECURITY.md before
sharing it beyond your machine.
Small local models struggle with multi-step pipelines. A 4-8B model handles
tool selection and simple SQL; event-windowed reduction and multi-topic joins
want a bigger model. See the Local LLMs guide.
Live-database end-to-end tests run outside CI. The InfluxDB and Postgres
suites' pure tests run in CI; their live end-to-end cases only execute against
an instance you point them at. Everything else, including the ROS bag write
paths, runs in CI.
🫶 Contributing
We’d love your help! The easiest way to support the project is by giving it a ⭐ on GitHub.
Other great ways to contribute:
Request new features
Report bugs
Improve documentation
Add new capabilities
Before contributing, please review the guidelines.
Join the conversation in our Discord server.
We hang out there regularly.