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.
Files changed (37) hide show
  1. topicforge-0.1.0/.gitignore +194 -0
  2. topicforge-0.1.0/CHANGELOG.md +33 -0
  3. topicforge-0.1.0/LICENSE +21 -0
  4. topicforge-0.1.0/PKG-INFO +292 -0
  5. topicforge-0.1.0/README.md +245 -0
  6. topicforge-0.1.0/docs/product-plan.md +141 -0
  7. topicforge-0.1.0/pyproject.toml +71 -0
  8. topicforge-0.1.0/src/topicforge/__init__.py +5 -0
  9. topicforge-0.1.0/src/topicforge/__main__.py +68 -0
  10. topicforge-0.1.0/src/topicforge/adapters/__init__.py +5 -0
  11. topicforge-0.1.0/src/topicforge/adapters/base.py +44 -0
  12. topicforge-0.1.0/src/topicforge/adapters/ros2_live/__init__.py +5 -0
  13. topicforge-0.1.0/src/topicforge/adapters/ros2_live/adapter.py +283 -0
  14. topicforge-0.1.0/src/topicforge/adapters/ros2_mock/__init__.py +5 -0
  15. topicforge-0.1.0/src/topicforge/adapters/ros2_mock/adapter.py +68 -0
  16. topicforge-0.1.0/src/topicforge/adapters/ros2_mock/fixtures.py +172 -0
  17. topicforge-0.1.0/src/topicforge/config/__init__.py +5 -0
  18. topicforge-0.1.0/src/topicforge/config/settings.py +68 -0
  19. topicforge-0.1.0/src/topicforge/models/__init__.py +19 -0
  20. topicforge-0.1.0/src/topicforge/models/schemas.py +158 -0
  21. topicforge-0.1.0/src/topicforge/server/__init__.py +5 -0
  22. topicforge-0.1.0/src/topicforge/server/app.py +43 -0
  23. topicforge-0.1.0/src/topicforge/services/__init__.py +7 -0
  24. topicforge-0.1.0/src/topicforge/services/factory.py +39 -0
  25. topicforge-0.1.0/src/topicforge/services/health.py +32 -0
  26. topicforge-0.1.0/src/topicforge/services/inspector.py +92 -0
  27. topicforge-0.1.0/src/topicforge/tools/__init__.py +5 -0
  28. topicforge-0.1.0/src/topicforge/tools/handlers.py +146 -0
  29. topicforge-0.1.0/tests/__init__.py +0 -0
  30. topicforge-0.1.0/tests/conftest.py +29 -0
  31. topicforge-0.1.0/tests/test_config.py +58 -0
  32. topicforge-0.1.0/tests/test_health.py +49 -0
  33. topicforge-0.1.0/tests/test_inspector.py +121 -0
  34. topicforge-0.1.0/tests/test_live_adapter_parse.py +129 -0
  35. topicforge-0.1.0/tests/test_live_adapter_subprocess.py +134 -0
  36. topicforge-0.1.0/tests/test_mock_adapter.py +122 -0
  37. 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
@@ -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).