ROS Topic Inspector & Bag Analyzer MCP server for AI agents
Project description
TopicForge
Stop asking Claude to invent topic names. TopicForge is the MCP server that grounds AI agents in your real ROS2 stack - or a faithful mock when you have no robot at hand.
TopicForge is a production-minded MCP (Model Context Protocol) server that lets AI agents - such as Claude - inspect ROS2 topics and analyze ROS bag files through a clean, structured tool interface. It is designed for robotics developers, ML/CV engineers working with robot data, and teams that want their AI tooling to understand their robotics stack instead of guessing at it.
Why it exists
LLM agents are good at reasoning over text, but ROS2 introspection lives in a CLI + DDS world they cannot directly reach. Without grounding, an LLM will hallucinate topic names, message types, and bag contents. TopicForge bridges that gap with a small, well-typed set of MCP tools:
| Tool | Purpose |
|---|---|
health_check |
Environment & mode introspection |
list_topics |
Discover the ROS graph |
get_topic_info |
Structured info for a single topic |
sample_messages |
Peek recent messages on a topic |
analyze_bag |
Summarize a .mcap / .db3 / .bag recording |
Outputs are structured, JSON-serializable, and stable across runtime modes - they look the same whether the server is talking to a real robot or to its built-in mock fixtures.
30-second demo without ROS2
The mock adapter ships deterministic fixtures for a small differential robot (LIDAR + RGB camera). You do not need ROS2 installed to try the full tool surface - a clean Python 3.11 venv is enough.
pip install topicforge
TOPICFORGE_MODE=mock python -m topicforge
# Windows PowerShell: $env:TOPICFORGE_MODE="mock"; python -m topicforge
Point any MCP client (Claude Desktop, see below) at this server and ask it to list the topics or analyze /tmp/demo.mcap - every tool returns realistic, typed payloads.
Quickstart
pip install topicforge
python -m topicforge --help
TOPICFORGE_MODE=mock python -m topicforge
Architecture
+----------------------+
| MCP client (LLM) |
+----------+-----------+
| (stdio, MCP protocol)
v
+----------+-----------+
| topicforge.server | FastMCP entrypoint, lifecycle, tool registration
+----------+-----------+
|
v
+----------+-----------+
| topicforge.tools | Thin handlers - validate, delegate, serialize
+----------+-----------+
|
v
+----------+-----------+
| topicforge.services | Inspector / Health - orchestration & validation
+----------+-----------+
|
v
+----------+-----------+
| topicforge.adapters | ros2_live - subprocess wrappers over `ros2` CLI
| | ros2_mock - deterministic fixtures
+----------------------+
Layers are strictly separated:
server/wires the whole graph and exposesbuild_app(settings).tools/registers MCP tools on FastMCP. Handlers never call ROS directly.services/validate inputs and orchestrate calls.adapters/are the only code that knows how to talk to a specific backend. New backends (e.g. anrclpy-based adapter) plug in by implementing theRosAdapterprotocol.models/holds Pydantic schemas - the contract with MCP clients.config/resolves runtime settings from the environment.
Runtime modes
| Mode | When to use | Backend |
|---|---|---|
mock |
Local development, demos, CI, screencasts | Deterministic fixtures |
live |
A machine with ROS2 installed and sourced | ros2 CLI wrappers |
auto |
Detect ROS2; fall back to mock if not present | Best available (default) |
Mode is selected via the TOPICFORGE_MODE environment variable.
Install from source
Requires Python 3.11+.
git clone https://github.com/yaniswav/TopicForge.git
cd TopicForge
python -m venv .venv
source .venv/bin/activate # Linux / macOS
# .venv\Scripts\Activate.ps1 # Windows PowerShell
pip install -e ".[dev]"
Or, if you have make:
make dev
Run
Mock mode (no ROS2 required)
TOPICFORGE_MODE=mock python -m topicforge
Or:
make run-mock
Live mode (requires ROS2)
Source your ROS2 distribution first, then:
source /opt/ros/humble/setup.bash
TOPICFORGE_MODE=live python -m topicforge
TopicForge invokes the ros2 CLI under the hood, so it does not require rclpy to be importable. This keeps the live adapter portable across ROS2 distros.
Configure with Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"topicforge": {
"command": "python",
"args": ["-m", "topicforge"],
"env": { "TOPICFORGE_MODE": "auto" }
}
}
}
Test
pytest
# or
make test
Tests run entirely against the mock adapter and the live adapter's pure parsers - they never require a running ROS graph. The full suite completes in well under a second.
Lint & format
make lint # ruff check
make fmt # ruff format
make check # both, plus tests (CI bundle)
Windows note. The
Makefileuses POSIX shell syntax (VAR=value cmd,find … -exec). Run it from Git Bash, WSL, or MSYS2. From a plain PowerShell session, invoke the underlying commands directly:python -m ruff check src tests python -m ruff format src tests python -m pytest $env:TOPICFORGE_MODE = "mock"; python -m topicforge # equivalent of `make run-mock`
Configuration reference
| Variable | Default | Description |
|---|---|---|
TOPICFORGE_MODE |
auto |
mock, live, or auto |
TOPICFORGE_LOG_LEVEL |
INFO |
DEBUG, INFO, WARNING, ERROR |
TOPICFORGE_ROS2_BIN |
ros2 |
Name (or path) of the ROS2 CLI binary |
See .env.example.
Security model
TopicForge is designed for local trust: it runs as a subprocess of your MCP client (Claude Desktop, Claude Code) on a machine you control, and inspects your own ROS2 graph or your own bag files. It is not hardened for adversarial inputs.
TOPICFORGE_ROS2_BINaccepts an arbitrary path - if you point it at a malicious binary, TopicForge will execute it. Treat the variable the way you treatPATH.analyze_bagopens whatever path the MCP client passes (no workspace isolation, no symlink restriction). The threat model assumes the client is your trusted agent acting on your behalf.- All
ros2CLI invocations usesubprocess.runwith an argument list - nevershell=True. Topic names are validated against a strict allowlist (^/[A-Za-z0-9_/]+$) before being passed to the CLI. - No outbound network calls. No telemetry in v0.1.0 (opt-in usage metrics are on the Phase 1 roadmap).
Before exposing TopicForge to untrusted MCP clients (hosted endpoints, shared environments), add path isolation and revisit the TOPICFORGE_ROS2_BIN policy.
MVP limitations
sample_messagesin live mode usesros2 topic echo --oncewith a short timeout; topics with no current publisher will return an empty sample.sample_messagessilently clampscountto 50 to keep tool output bounded; requests for more than 50 messages return at most 50 (theSampleResult.countfield reflects what was actually returned).analyze_bagin live mode shells out toros2 bag infoand parses its text output. Deep anomaly detection is mock-only for now.- No streaming / push subscriptions in the MVP. Tools are strictly request/response.
- Live adapter is CLI-based, not
rclpy-based - by design, for portability.
Roadmap
See docs/product-plan.md for the full product trajectory.
Near-term additions on the bench:
rclpy-backed live adapter for faster & richer sampling- URDF inspector / validator MCP tools
- Bag anomaly detection (clock jumps, gaps, dropped frames, TF tree health)
- Dataset export helpers (rosbag → COCO / HF Datasets)
- Synthetic data pipeline controller (Blender, Gazebo, Isaac Sim)
- Hosted MCP endpoint with auth
Project layout
topicforge-mcp/
├── README.md # You are here
├── Makefile # Common developer tasks
├── pyproject.toml # Build & tooling config
├── .env.example # Example runtime configuration
├── docs/
│ └── product-plan.md # Product strategy & roadmap
├── src/topicforge/
│ ├── __main__.py # `python -m topicforge`
│ ├── server/ # MCP bootstrap & lifecycle
│ ├── tools/ # MCP tool definitions
│ ├── services/ # Domain orchestration
│ ├── adapters/
│ │ ├── ros2_live/ # `ros2` CLI wrappers
│ │ └── ros2_mock/ # Deterministic fixtures
│ ├── models/ # Pydantic schemas
│ └── config/ # Settings & mode resolution
└── tests/ # Pytest suite (mock-only, no ROS2 required)
License
MIT - see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file topicforge-0.1.0.tar.gz.
File metadata
- Download URL: topicforge-0.1.0.tar.gz
- Upload date:
- Size: 31.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0184bb00efdf662fb523960f61b0d2395f1a8fea973071e3bf6fe0f64f869c0a
|
|
| MD5 |
0690f8b0e72646dfec08df8f4b8b2da0
|
|
| BLAKE2b-256 |
d43c3ddce918d38a787aaad67d0db606b717898e19cfc3fdf14c78db2975e9b2
|
Provenance
The following attestation bundles were made for topicforge-0.1.0.tar.gz:
Publisher:
publish.yml on yaniswav/TopicForge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
topicforge-0.1.0.tar.gz -
Subject digest:
0184bb00efdf662fb523960f61b0d2395f1a8fea973071e3bf6fe0f64f869c0a - Sigstore transparency entry: 1523418171
- Sigstore integration time:
-
Permalink:
yaniswav/TopicForge@47fd825e06102a6a00a2d63db9d36a4343585a23 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yaniswav
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@47fd825e06102a6a00a2d63db9d36a4343585a23 -
Trigger Event:
push
-
Statement type:
File details
Details for the file topicforge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: topicforge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cea84a2b54026975d0b8d554f6bebbbe4ff14390263826dd8f0fd6cbe19d8a18
|
|
| MD5 |
a15d2b13391922553477dcac9caf0a70
|
|
| BLAKE2b-256 |
c0cebf80357101a2130fb72a4ca97a17adee4cba529f0530e02c5d3fa622cd7a
|
Provenance
The following attestation bundles were made for topicforge-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on yaniswav/TopicForge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
topicforge-0.1.0-py3-none-any.whl -
Subject digest:
cea84a2b54026975d0b8d554f6bebbbe4ff14390263826dd8f0fd6cbe19d8a18 - Sigstore transparency entry: 1523418176
- Sigstore integration time:
-
Permalink:
yaniswav/TopicForge@47fd825e06102a6a00a2d63db9d36a4343585a23 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yaniswav
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@47fd825e06102a6a00a2d63db9d36a4343585a23 -
Trigger Event:
push
-
Statement type: