topicforge 0.1.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.
- topicforge-0.1.0/.gitignore +194 -0
- topicforge-0.1.0/CHANGELOG.md +33 -0
- topicforge-0.1.0/LICENSE +21 -0
- topicforge-0.1.0/PKG-INFO +292 -0
- topicforge-0.1.0/README.md +245 -0
- topicforge-0.1.0/docs/product-plan.md +141 -0
- topicforge-0.1.0/pyproject.toml +71 -0
- topicforge-0.1.0/src/topicforge/__init__.py +5 -0
- topicforge-0.1.0/src/topicforge/__main__.py +68 -0
- topicforge-0.1.0/src/topicforge/adapters/__init__.py +5 -0
- topicforge-0.1.0/src/topicforge/adapters/base.py +44 -0
- topicforge-0.1.0/src/topicforge/adapters/ros2_live/__init__.py +5 -0
- topicforge-0.1.0/src/topicforge/adapters/ros2_live/adapter.py +283 -0
- topicforge-0.1.0/src/topicforge/adapters/ros2_mock/__init__.py +5 -0
- topicforge-0.1.0/src/topicforge/adapters/ros2_mock/adapter.py +68 -0
- topicforge-0.1.0/src/topicforge/adapters/ros2_mock/fixtures.py +172 -0
- topicforge-0.1.0/src/topicforge/config/__init__.py +5 -0
- topicforge-0.1.0/src/topicforge/config/settings.py +68 -0
- topicforge-0.1.0/src/topicforge/models/__init__.py +19 -0
- topicforge-0.1.0/src/topicforge/models/schemas.py +158 -0
- topicforge-0.1.0/src/topicforge/server/__init__.py +5 -0
- topicforge-0.1.0/src/topicforge/server/app.py +43 -0
- topicforge-0.1.0/src/topicforge/services/__init__.py +7 -0
- topicforge-0.1.0/src/topicforge/services/factory.py +39 -0
- topicforge-0.1.0/src/topicforge/services/health.py +32 -0
- topicforge-0.1.0/src/topicforge/services/inspector.py +92 -0
- topicforge-0.1.0/src/topicforge/tools/__init__.py +5 -0
- topicforge-0.1.0/src/topicforge/tools/handlers.py +146 -0
- topicforge-0.1.0/tests/__init__.py +0 -0
- topicforge-0.1.0/tests/conftest.py +29 -0
- topicforge-0.1.0/tests/test_config.py +58 -0
- topicforge-0.1.0/tests/test_health.py +49 -0
- topicforge-0.1.0/tests/test_inspector.py +121 -0
- topicforge-0.1.0/tests/test_live_adapter_parse.py +129 -0
- topicforge-0.1.0/tests/test_live_adapter_subprocess.py +134 -0
- topicforge-0.1.0/tests/test_mock_adapter.py +122 -0
- topicforge-0.1.0/tests/test_tools_integration.py +84 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# =========================================================================
|
|
2
|
+
# TopicForge — .gitignore
|
|
3
|
+
#
|
|
4
|
+
# Anything matched here is local-only: it must never appear in a clone,
|
|
5
|
+
# a sdist, a wheel, or a screen share with a client. Add new patterns
|
|
6
|
+
# above the matching section header so the rationale stays close.
|
|
7
|
+
# =========================================================================
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# -------------------------------------------------------------------------
|
|
11
|
+
# Python: bytecode, caches, packaging
|
|
12
|
+
# -------------------------------------------------------------------------
|
|
13
|
+
__pycache__/
|
|
14
|
+
*.py[cod]
|
|
15
|
+
*$py.class
|
|
16
|
+
*.pyo
|
|
17
|
+
*.pyd
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# -------------------------------------------------------------------------
|
|
21
|
+
# Virtual environments
|
|
22
|
+
# -------------------------------------------------------------------------
|
|
23
|
+
.venv/
|
|
24
|
+
venv/
|
|
25
|
+
env/
|
|
26
|
+
ENV/
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# -------------------------------------------------------------------------
|
|
30
|
+
# Build artifacts and packaging tooling
|
|
31
|
+
# -------------------------------------------------------------------------
|
|
32
|
+
build/
|
|
33
|
+
dist/
|
|
34
|
+
*.egg
|
|
35
|
+
*.egg-info/
|
|
36
|
+
pip-wheel-metadata/
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
.Python
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# -------------------------------------------------------------------------
|
|
43
|
+
# Testing, coverage, profiling
|
|
44
|
+
# -------------------------------------------------------------------------
|
|
45
|
+
.pytest_cache/
|
|
46
|
+
pytest-cache-files-*/
|
|
47
|
+
.coverage
|
|
48
|
+
.coverage.*
|
|
49
|
+
htmlcov/
|
|
50
|
+
coverage.xml
|
|
51
|
+
*.cover
|
|
52
|
+
.hypothesis/
|
|
53
|
+
.tox/
|
|
54
|
+
.nox/
|
|
55
|
+
*.prof
|
|
56
|
+
flamegraph.svg
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# -------------------------------------------------------------------------
|
|
60
|
+
# Linters and type checkers
|
|
61
|
+
# -------------------------------------------------------------------------
|
|
62
|
+
.mypy_cache/
|
|
63
|
+
.ruff_cache/
|
|
64
|
+
.pyright/
|
|
65
|
+
.pytype/
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# -------------------------------------------------------------------------
|
|
69
|
+
# Editors and IDEs (per-developer; never shared)
|
|
70
|
+
# -------------------------------------------------------------------------
|
|
71
|
+
.idea/
|
|
72
|
+
.vscode/
|
|
73
|
+
.vs/
|
|
74
|
+
*.iml
|
|
75
|
+
*.swp
|
|
76
|
+
*.swo
|
|
77
|
+
*~
|
|
78
|
+
.history/
|
|
79
|
+
.spyderproject
|
|
80
|
+
.spyproject
|
|
81
|
+
*.sublime-workspace
|
|
82
|
+
*.sublime-project
|
|
83
|
+
.project
|
|
84
|
+
.classpath
|
|
85
|
+
.settings/
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# -------------------------------------------------------------------------
|
|
89
|
+
# OS metadata
|
|
90
|
+
# -------------------------------------------------------------------------
|
|
91
|
+
.DS_Store
|
|
92
|
+
._*
|
|
93
|
+
Thumbs.db
|
|
94
|
+
ehthumbs.db
|
|
95
|
+
Desktop.ini
|
|
96
|
+
$RECYCLE.BIN/
|
|
97
|
+
*.lnk
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# -------------------------------------------------------------------------
|
|
101
|
+
# Secrets — NEVER commit
|
|
102
|
+
# Use `.env.example` for documentation; real `.env` files stay local.
|
|
103
|
+
# -------------------------------------------------------------------------
|
|
104
|
+
.env
|
|
105
|
+
.env.*
|
|
106
|
+
!.env.example
|
|
107
|
+
*.pem
|
|
108
|
+
*.key
|
|
109
|
+
*.crt
|
|
110
|
+
*.cer
|
|
111
|
+
*.pfx
|
|
112
|
+
*.p12
|
|
113
|
+
id_rsa*
|
|
114
|
+
id_ed25519*
|
|
115
|
+
*.token
|
|
116
|
+
secrets/
|
|
117
|
+
secrets.yaml
|
|
118
|
+
secrets.yml
|
|
119
|
+
secrets.json
|
|
120
|
+
credentials.json
|
|
121
|
+
credentials.yaml
|
|
122
|
+
.netrc
|
|
123
|
+
.npmrc
|
|
124
|
+
.pypirc
|
|
125
|
+
|
|
126
|
+
# Cloud provider configs (often carry usable credentials)
|
|
127
|
+
.aws/
|
|
128
|
+
.gcp/
|
|
129
|
+
.azure/
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# -------------------------------------------------------------------------
|
|
133
|
+
# Logs, runtime state, dumps
|
|
134
|
+
# -------------------------------------------------------------------------
|
|
135
|
+
*.log
|
|
136
|
+
logs/
|
|
137
|
+
*.pid
|
|
138
|
+
*.dump
|
|
139
|
+
*.dmp
|
|
140
|
+
dump.rdb
|
|
141
|
+
*.sql
|
|
142
|
+
*.sql.gz
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# -------------------------------------------------------------------------
|
|
146
|
+
# Backup / scratch / editor-locks
|
|
147
|
+
# -------------------------------------------------------------------------
|
|
148
|
+
*.bak
|
|
149
|
+
*.orig
|
|
150
|
+
*.rej
|
|
151
|
+
*.tmp
|
|
152
|
+
*.temp
|
|
153
|
+
.~lock.*
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# -------------------------------------------------------------------------
|
|
157
|
+
# ROS / robotics recordings — often huge and frequently confidential
|
|
158
|
+
# -------------------------------------------------------------------------
|
|
159
|
+
*.bag
|
|
160
|
+
*.db3
|
|
161
|
+
*.mcap
|
|
162
|
+
rosbag2_*/
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# -------------------------------------------------------------------------
|
|
166
|
+
# Local notes and per-developer overrides
|
|
167
|
+
# These are private to the contributor and must not ship with the repo.
|
|
168
|
+
# -------------------------------------------------------------------------
|
|
169
|
+
NOTES.md
|
|
170
|
+
TODO.local.md
|
|
171
|
+
SCRATCH.md
|
|
172
|
+
notes/
|
|
173
|
+
private/
|
|
174
|
+
personal/
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# -------------------------------------------------------------------------
|
|
178
|
+
# Claude Code internals
|
|
179
|
+
# Operating manual, sub-agents, project skills, prompts, scripts, and
|
|
180
|
+
# settings live entirely on the contributor's machine. They reveal
|
|
181
|
+
# internal process and AI-assisted workflows that have no business
|
|
182
|
+
# being in a client-facing repo. The sdist already excludes them via
|
|
183
|
+
# `[tool.hatch.build.targets.sdist] exclude` in pyproject.toml; this
|
|
184
|
+
# rule additionally hides them from the GitHub clone.
|
|
185
|
+
# -------------------------------------------------------------------------
|
|
186
|
+
.claude/
|
|
187
|
+
CLAUDE*.md
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
# -------------------------------------------------------------------------
|
|
191
|
+
# Project-local docs and drafts kept out of the package / out of clients
|
|
192
|
+
# -------------------------------------------------------------------------
|
|
193
|
+
docs/projet-file/
|
|
194
|
+
docs/assets/screencast-raw/
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to TopicForge are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-05-12
|
|
11
|
+
|
|
12
|
+
Initial MVP release of TopicForge — ROS Topic Inspector & Bag Analyzer MCP server.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Five read-only MCP tools exposed over FastMCP: `health_check`, `list_topics`, `get_topic_info`, `sample_messages`, and `analyze_bag`.
|
|
17
|
+
- `RosAdapter` protocol in `adapters/base.py` defining the contract every backend implements.
|
|
18
|
+
- Mock adapter (`adapters/ros2_mock/`) with deterministic fixtures modeling a small differential mobile robot equipped with a LIDAR and an RGB camera.
|
|
19
|
+
- Live adapter (`adapters/ros2_live/`) built on subprocess wrappers around the `ros2` CLI, with pure module-level parsers tested independently of any ROS2 install.
|
|
20
|
+
- Three runtime modes selectable via `TOPICFORGE_MODE`: `mock`, `live`, and `auto`. The `auto` resolution lives in `Settings.effective_mode`; the live-to-mock fallback when the adapter cannot start lives in `services/factory.py`.
|
|
21
|
+
- Windows-first cross-platform support: executable resolution via `shutil.which` (handles `ros2.cmd` / `ros2.bat` shims), `subprocess.run` called with absolute paths and never `shell=True`, all filesystem paths via `pathlib.Path`.
|
|
22
|
+
- Pydantic v2 schemas in `models/` configured with `extra="forbid"` and `frozen=True`, returned as the structured payload of every tool.
|
|
23
|
+
- Pytest suite that runs entirely without a ROS2 environment, covering services, mock adapter, and live-adapter parsers.
|
|
24
|
+
- Build, lint, and tooling configuration: Python 3.11+, `mcp >= 1.0.0` (FastMCP), `pydantic >= 2.6`, pytest, ruff, hatchling.
|
|
25
|
+
- Licensed under the MIT License.
|
|
26
|
+
|
|
27
|
+
### Notes
|
|
28
|
+
|
|
29
|
+
- The write path (publishing, commanding robots) is intentionally out of scope for the MVP.
|
|
30
|
+
- `analyze_bag` in live mode parses `ros2 bag info` text output; deeper anomaly detection remains mock-only for now.
|
|
31
|
+
|
|
32
|
+
[Unreleased]: https://github.com/yaniswav/TopicForge/compare/v0.1.0...HEAD
|
|
33
|
+
[0.1.0]: https://github.com/yaniswav/TopicForge/releases/tag/v0.1.0
|
topicforge-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yanis ETHVIGNOT
|
|
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,292 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: topicforge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ROS Topic Inspector & Bag Analyzer MCP server for AI agents
|
|
5
|
+
Project-URL: Homepage, https://github.com/yaniswav/TopicForge
|
|
6
|
+
Project-URL: Repository, https://github.com/yaniswav/TopicForge
|
|
7
|
+
Project-URL: Issues, https://github.com/yaniswav/TopicForge/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/yaniswav/TopicForge/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Yanis ETHVIGNOT <ethvignot.yanis@gmail.com>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Yanis ETHVIGNOT
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: ai,claude,mcp,model-context-protocol,robotics,ros2
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Requires-Python: >=3.11
|
|
41
|
+
Requires-Dist: mcp>=1.0.0
|
|
42
|
+
Requires-Dist: pydantic>=2.6
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# TopicForge
|
|
49
|
+
|
|
50
|
+
> 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.
|
|
51
|
+
|
|
52
|
+
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.
|
|
53
|
+
|
|
54
|
+
## Why it exists
|
|
55
|
+
|
|
56
|
+
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:
|
|
57
|
+
|
|
58
|
+
| Tool | Purpose |
|
|
59
|
+
| ----------------- | ------------------------------------------------------ |
|
|
60
|
+
| `health_check` | Environment & mode introspection |
|
|
61
|
+
| `list_topics` | Discover the ROS graph |
|
|
62
|
+
| `get_topic_info` | Structured info for a single topic |
|
|
63
|
+
| `sample_messages` | Peek recent messages on a topic |
|
|
64
|
+
| `analyze_bag` | Summarize a `.mcap` / `.db3` / `.bag` recording |
|
|
65
|
+
|
|
66
|
+
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.
|
|
67
|
+
|
|
68
|
+
## 30-second demo without ROS2
|
|
69
|
+
|
|
70
|
+
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.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install topicforge
|
|
74
|
+
TOPICFORGE_MODE=mock python -m topicforge
|
|
75
|
+
# Windows PowerShell: $env:TOPICFORGE_MODE="mock"; python -m topicforge
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
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.
|
|
79
|
+
|
|
80
|
+
## Quickstart
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install topicforge
|
|
84
|
+
python -m topicforge --help
|
|
85
|
+
TOPICFORGE_MODE=mock python -m topicforge
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Architecture
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
+----------------------+
|
|
92
|
+
| MCP client (LLM) |
|
|
93
|
+
+----------+-----------+
|
|
94
|
+
| (stdio, MCP protocol)
|
|
95
|
+
v
|
|
96
|
+
+----------+-----------+
|
|
97
|
+
| topicforge.server | FastMCP entrypoint, lifecycle, tool registration
|
|
98
|
+
+----------+-----------+
|
|
99
|
+
|
|
|
100
|
+
v
|
|
101
|
+
+----------+-----------+
|
|
102
|
+
| topicforge.tools | Thin handlers - validate, delegate, serialize
|
|
103
|
+
+----------+-----------+
|
|
104
|
+
|
|
|
105
|
+
v
|
|
106
|
+
+----------+-----------+
|
|
107
|
+
| topicforge.services | Inspector / Health - orchestration & validation
|
|
108
|
+
+----------+-----------+
|
|
109
|
+
|
|
|
110
|
+
v
|
|
111
|
+
+----------+-----------+
|
|
112
|
+
| topicforge.adapters | ros2_live - subprocess wrappers over `ros2` CLI
|
|
113
|
+
| | ros2_mock - deterministic fixtures
|
|
114
|
+
+----------------------+
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Layers are strictly separated:
|
|
118
|
+
|
|
119
|
+
- **`server/`** wires the whole graph and exposes `build_app(settings)`.
|
|
120
|
+
- **`tools/`** registers MCP tools on FastMCP. Handlers never call ROS directly.
|
|
121
|
+
- **`services/`** validate inputs and orchestrate calls.
|
|
122
|
+
- **`adapters/`** are the *only* code that knows how to talk to a specific backend. New backends (e.g. an `rclpy`-based adapter) plug in by implementing the `RosAdapter` protocol.
|
|
123
|
+
- **`models/`** holds Pydantic schemas - the contract with MCP clients.
|
|
124
|
+
- **`config/`** resolves runtime settings from the environment.
|
|
125
|
+
|
|
126
|
+
## Runtime modes
|
|
127
|
+
|
|
128
|
+
| Mode | When to use | Backend |
|
|
129
|
+
| ------- | --------------------------------------------------- | ----------------------------- |
|
|
130
|
+
| `mock` | Local development, demos, CI, screencasts | Deterministic fixtures |
|
|
131
|
+
| `live` | A machine with ROS2 installed and sourced | `ros2` CLI wrappers |
|
|
132
|
+
| `auto` | Detect ROS2; fall back to mock if not present | Best available (default) |
|
|
133
|
+
|
|
134
|
+
Mode is selected via the `TOPICFORGE_MODE` environment variable.
|
|
135
|
+
|
|
136
|
+
## Install from source
|
|
137
|
+
|
|
138
|
+
Requires Python 3.11+.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
git clone https://github.com/yaniswav/TopicForge.git
|
|
142
|
+
cd TopicForge
|
|
143
|
+
python -m venv .venv
|
|
144
|
+
source .venv/bin/activate # Linux / macOS
|
|
145
|
+
# .venv\Scripts\Activate.ps1 # Windows PowerShell
|
|
146
|
+
pip install -e ".[dev]"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Or, if you have `make`:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
make dev
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Run
|
|
156
|
+
|
|
157
|
+
### Mock mode (no ROS2 required)
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
TOPICFORGE_MODE=mock python -m topicforge
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Or:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
make run-mock
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Live mode (requires ROS2)
|
|
170
|
+
|
|
171
|
+
Source your ROS2 distribution first, then:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
source /opt/ros/humble/setup.bash
|
|
175
|
+
TOPICFORGE_MODE=live python -m topicforge
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
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.
|
|
179
|
+
|
|
180
|
+
### Configure with Claude Desktop
|
|
181
|
+
|
|
182
|
+
Add to your `claude_desktop_config.json`:
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"mcpServers": {
|
|
187
|
+
"topicforge": {
|
|
188
|
+
"command": "python",
|
|
189
|
+
"args": ["-m", "topicforge"],
|
|
190
|
+
"env": { "TOPICFORGE_MODE": "auto" }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Test
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
pytest
|
|
200
|
+
# or
|
|
201
|
+
make test
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
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.
|
|
205
|
+
|
|
206
|
+
## Lint & format
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
make lint # ruff check
|
|
210
|
+
make fmt # ruff format
|
|
211
|
+
make check # both, plus tests (CI bundle)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
> **Windows note.** The `Makefile` uses POSIX shell syntax (`VAR=value cmd`,
|
|
215
|
+
> `find … -exec`). Run it from Git Bash, WSL, or MSYS2. From a plain
|
|
216
|
+
> PowerShell session, invoke the underlying commands directly:
|
|
217
|
+
>
|
|
218
|
+
> ```powershell
|
|
219
|
+
> python -m ruff check src tests
|
|
220
|
+
> python -m ruff format src tests
|
|
221
|
+
> python -m pytest
|
|
222
|
+
> $env:TOPICFORGE_MODE = "mock"; python -m topicforge # equivalent of `make run-mock`
|
|
223
|
+
> ```
|
|
224
|
+
|
|
225
|
+
## Configuration reference
|
|
226
|
+
|
|
227
|
+
| Variable | Default | Description |
|
|
228
|
+
| ------------------------ | ------- | ----------------------------------------------------------------- |
|
|
229
|
+
| `TOPICFORGE_MODE` | `auto` | `mock`, `live`, or `auto` |
|
|
230
|
+
| `TOPICFORGE_LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
|
231
|
+
| `TOPICFORGE_ROS2_BIN` | `ros2` | Name (or path) of the ROS2 CLI binary |
|
|
232
|
+
|
|
233
|
+
See [`.env.example`](.env.example).
|
|
234
|
+
|
|
235
|
+
## Security model
|
|
236
|
+
|
|
237
|
+
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.
|
|
238
|
+
|
|
239
|
+
- `TOPICFORGE_ROS2_BIN` accepts an arbitrary path - if you point it at a malicious binary, TopicForge will execute it. Treat the variable the way you treat `PATH`.
|
|
240
|
+
- `analyze_bag` opens 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.
|
|
241
|
+
- All `ros2` CLI invocations use `subprocess.run` with an argument list - never `shell=True`. Topic names are validated against a strict allowlist (`^/[A-Za-z0-9_/]+$`) before being passed to the CLI.
|
|
242
|
+
- No outbound network calls. No telemetry in v0.1.0 (opt-in usage metrics are on the Phase 1 roadmap).
|
|
243
|
+
|
|
244
|
+
Before exposing TopicForge to *untrusted* MCP clients (hosted endpoints, shared environments), add path isolation and revisit the `TOPICFORGE_ROS2_BIN` policy.
|
|
245
|
+
|
|
246
|
+
## MVP limitations
|
|
247
|
+
|
|
248
|
+
- `sample_messages` in live mode uses `ros2 topic echo --once` with a short timeout; topics with no current publisher will return an empty sample.
|
|
249
|
+
- `sample_messages` silently clamps `count` to 50 to keep tool output bounded; requests for more than 50 messages return at most 50 (the `SampleResult.count` field reflects what was actually returned).
|
|
250
|
+
- `analyze_bag` in live mode shells out to `ros2 bag info` and parses its text output. Deep anomaly detection is mock-only for now.
|
|
251
|
+
- No streaming / push subscriptions in the MVP. Tools are strictly request/response.
|
|
252
|
+
- Live adapter is CLI-based, not `rclpy`-based - by design, for portability.
|
|
253
|
+
|
|
254
|
+
## Roadmap
|
|
255
|
+
|
|
256
|
+
See [`docs/product-plan.md`](docs/product-plan.md) for the full product trajectory.
|
|
257
|
+
|
|
258
|
+
Near-term additions on the bench:
|
|
259
|
+
|
|
260
|
+
- `rclpy`-backed live adapter for faster & richer sampling
|
|
261
|
+
- URDF inspector / validator MCP tools
|
|
262
|
+
- Bag anomaly detection (clock jumps, gaps, dropped frames, TF tree health)
|
|
263
|
+
- Dataset export helpers (rosbag → COCO / HF Datasets)
|
|
264
|
+
- Synthetic data pipeline controller (Blender, Gazebo, Isaac Sim)
|
|
265
|
+
- Hosted MCP endpoint with auth
|
|
266
|
+
|
|
267
|
+
## Project layout
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
topicforge-mcp/
|
|
271
|
+
├── README.md # You are here
|
|
272
|
+
├── Makefile # Common developer tasks
|
|
273
|
+
├── pyproject.toml # Build & tooling config
|
|
274
|
+
├── .env.example # Example runtime configuration
|
|
275
|
+
├── docs/
|
|
276
|
+
│ └── product-plan.md # Product strategy & roadmap
|
|
277
|
+
├── src/topicforge/
|
|
278
|
+
│ ├── __main__.py # `python -m topicforge`
|
|
279
|
+
│ ├── server/ # MCP bootstrap & lifecycle
|
|
280
|
+
│ ├── tools/ # MCP tool definitions
|
|
281
|
+
│ ├── services/ # Domain orchestration
|
|
282
|
+
│ ├── adapters/
|
|
283
|
+
│ │ ├── ros2_live/ # `ros2` CLI wrappers
|
|
284
|
+
│ │ └── ros2_mock/ # Deterministic fixtures
|
|
285
|
+
│ ├── models/ # Pydantic schemas
|
|
286
|
+
│ └── config/ # Settings & mode resolution
|
|
287
|
+
└── tests/ # Pytest suite (mock-only, no ROS2 required)
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT - see [LICENSE](LICENSE).
|