topicforge 0.1.2__tar.gz → 0.2.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.2 → topicforge-0.2.0}/.gitignore +15 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/CHANGELOG.md +40 -1
- {topicforge-0.1.2 → topicforge-0.2.0}/PKG-INFO +46 -9
- {topicforge-0.1.2 → topicforge-0.2.0}/README.md +41 -8
- topicforge-0.2.0/docs/DDS_QUICKSTART.md +111 -0
- topicforge-0.2.0/docs/MIGRATION_v0.1_to_v0.2.md +140 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/docs/product-plan.md +33 -17
- {topicforge-0.1.2 → topicforge-0.2.0}/pyproject.toml +13 -1
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/__init__.py +1 -1
- topicforge-0.2.0/src/topicforge/adapters/__init__.py +17 -0
- topicforge-0.2.0/src/topicforge/adapters/base.py +105 -0
- topicforge-0.2.0/src/topicforge/adapters/common/__init__.py +5 -0
- topicforge-0.2.0/src/topicforge/adapters/common/qos_analyzer.py +86 -0
- topicforge-0.2.0/src/topicforge/adapters/dds_cyclone/__init__.py +11 -0
- topicforge-0.2.0/src/topicforge/adapters/dds_cyclone/adapter.py +110 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/adapters/ros2_live/adapter.py +49 -8
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/adapters/ros2_mock/adapter.py +38 -3
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/adapters/ros2_mock/fixtures.py +111 -1
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/config/settings.py +58 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/models/__init__.py +6 -0
- topicforge-0.2.0/src/topicforge/models/schemas.py +360 -0
- topicforge-0.2.0/src/topicforge/services/constants.py +21 -0
- topicforge-0.2.0/src/topicforge/services/factory.py +95 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/services/health.py +1 -1
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/services/inspector.py +54 -4
- topicforge-0.2.0/src/topicforge/tools/handlers.py +291 -0
- topicforge-0.2.0/tests/test_cyclone_adapter.py +56 -0
- topicforge-0.2.0/tests/test_dds_schemas.py +168 -0
- topicforge-0.2.0/tests/test_qos_analyzer.py +155 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_tools_integration.py +7 -0
- topicforge-0.1.2/src/topicforge/adapters/__init__.py +0 -5
- topicforge-0.1.2/src/topicforge/adapters/base.py +0 -56
- topicforge-0.1.2/src/topicforge/models/schemas.py +0 -178
- topicforge-0.1.2/src/topicforge/services/factory.py +0 -39
- topicforge-0.1.2/src/topicforge/tools/handlers.py +0 -167
- {topicforge-0.1.2 → topicforge-0.2.0}/LICENSE +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/docs/TESTING.md +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/docs/pro.md +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/docs/v0.1.2-action-plan.md +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/__main__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/adapters/ros2_live/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/adapters/ros2_mock/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/config/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/server/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/server/app.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/services/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/telemetry/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/telemetry/client.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/src/topicforge/tools/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/__init__.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/conftest.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/fixtures/csv_echo_imu.txt +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/fixtures/csv_echo_pose_multi.txt +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_config.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_health.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_inspector.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_live_adapter_parse.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_live_adapter_subprocess.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_mock_adapter.py +0 -0
- {topicforge-0.1.2 → topicforge-0.2.0}/tests/test_telemetry.py +0 -0
|
@@ -197,6 +197,21 @@ CLAUDE*.md
|
|
|
197
197
|
/docs/projet-file/**
|
|
198
198
|
!/docs/projet-file/README.md
|
|
199
199
|
!/docs/projet-file/*-spec.md
|
|
200
|
+
# Traction snapshots are versioned: weekly JSON + summary + folder README.
|
|
201
|
+
# This is the historical curve that informs decision gates G1/G2/G3
|
|
202
|
+
# (product-plan §12). Numeric history must survive across machines.
|
|
203
|
+
!/docs/projet-file/traction/
|
|
204
|
+
!/docs/projet-file/traction/**
|
|
205
|
+
# Launch-post drafts (Reddit, LinkedIn, X). Versioned so the maintainer
|
|
206
|
+
# can diff drafts across releases and keep marketing history auditable.
|
|
207
|
+
# Drafts, not production copy — never the public README.
|
|
208
|
+
!/docs/projet-file/launch-posts/
|
|
209
|
+
!/docs/projet-file/launch-posts/**
|
|
210
|
+
# Audit reports (security, architecture) + audit-followup triage docs.
|
|
211
|
+
# Versioned so audit trails survive across machines and the triage
|
|
212
|
+
# decisions are bisectable per release.
|
|
213
|
+
!/docs/projet-file/*-audit-*.md
|
|
214
|
+
!/docs/projet-file/audit-*.md
|
|
200
215
|
/docs/assets/screencast-raw/
|
|
201
216
|
|
|
202
217
|
|
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning 2.0.0](https://semver.org/spec/
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.0] - 2026-05-14
|
|
11
|
+
|
|
12
|
+
### Strategic
|
|
13
|
+
|
|
14
|
+
- **Mono-MCP pivot (2026-05-14).** The 3-to-5-MCP pack draft is collapsed into a 2-product strategy: TopicForge umbrella (this product — covers ROS2 today and grows a DDS observability module starting with v0.2.0), and **DatasetForge** (Vision Dataset Inspector, the standalone second product). DdsForge as a standalone repo is cancelled — its spec is reframed as the TopicForge DDS module spec at `docs/projet-file/mcp-02-spec.md`. Motif: solo-maintenance cost of two parallel repos was the binding constraint, and ROS2 / DDS are the same problem shape (typed pub/sub graph introspection) under the same `MiddlewareAdapter` superset.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **DDS module — 3 new MCP tools.** `list_participants(domain_id)`, `detect_qos_mismatches(topic)`, `peek_dds_samples(topic, count)`. All read-only ; surface DDS-layer introspection distinct from the ROS2 graph tools. `peek_dds_samples` is deliberately separate from `sample_messages` — different layer, different semantics, distinct tool description so an LLM picks the right one in a mixed setup.
|
|
19
|
+
- **`MiddlewareAdapter` protocol** in `adapters/base.py` — superset of the historical `RosAdapter`. Covers both ROS2 graph methods and the new DDS methods under one contract. `RosAdapter` retained as a backward-compat alias (`RosAdapter = MiddlewareAdapter`).
|
|
20
|
+
- **`CycloneDdsAdapter`** (`adapters/dds_cyclone/`) — lazy-imported only when `TOPICFORGE_DDS_BACKEND=cyclone` and the optional `cyclonedds` extras are installed (`pip install topicforge[dds]`). **v0.2.0 ships a protocol-compliant stub**: the lazy import, `is_available()`, and routing all work ; the 3 DDS methods raise `AdapterError` with a v0.2.x roadmap pointer. The real CycloneDDS discovery (builtin topics, QoS pair extraction, typed reader for samples) lands in a v0.2.x patch. The mock backend (`TOPICFORGE_DDS_BACKEND=mock`, the default) exposes a working DDS surface against deterministic fixtures in the meantime.
|
|
21
|
+
- **3 new Pydantic schemas**: `QosProfile` (Reliability / Durability / History / Deadline at MVP), `ParticipantInfo` (GUID, vendor, hostname, domain_id), `MismatchReport` (incompatible_policies + severity). All frozen, `extra="forbid"`.
|
|
22
|
+
- **Pure analyzer** `adapters/common/qos_analyzer.detect_mismatches` — module-level pure function, testable against synthesized QoS pairs without any DDS middleware installed.
|
|
23
|
+
- **Environment variables**:
|
|
24
|
+
- `TOPICFORGE_DDS_BACKEND` — `mock | cyclone | rti | auto`, default `mock`. The DDS module is opt-in ; existing ROS2-only setups behave unchanged.
|
|
25
|
+
- `TOPICFORGE_DDS_DOMAIN_ID` — DDS domain id observed (0..232), default `0`.
|
|
26
|
+
- **Mock fixtures enriched**: 2 deterministic DDS participants, two-topic scenario (`/dds/well_matched` and `/dds/qos_mismatch`) exercising `detect_qos_mismatches` end-to-end.
|
|
27
|
+
- **`pyproject.toml` extras**: `[dds]` pulls `cyclonedds>=0.10` ; `[all]` aliases `[dds]`. `pip install topicforge` keeps the core + mock only (zero install impact on ROS2-only users).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **`TopicInfo` schema soft-breaking.** Three additive optional fields (`reader_count: int | None`, `writer_count: int | None`, `qos_profile: QosProfile | None`) — all default `None`. Producer side: code constructing `TopicInfo` directly is unaffected (defaults compile). **Strict MCP clients that validated v0.1.x responses against the `TopicInfo` schema with `additionalProperties: false` will reject v0.2.0 responses unless their schema is regenerated. Standard MCP clients that read tool descriptions dynamically are unaffected.**
|
|
32
|
+
- **`HealthReport` schema soft-breaking**, same shape. Three additive optional fields (`dds_backend`, `dds_domain_id`, `middleware_available`) with safe defaults (`"none"`, `None`, `False`).
|
|
33
|
+
- **`RosAdapter` renamed to `MiddlewareAdapter`** in `adapters/base.py`. The old name remains as an alias (`RosAdapter = MiddlewareAdapter`) ; existing imports `from topicforge.adapters import RosAdapter` still type-check. The `Ros2CliAdapter.name` value moves from `"live"` to `"ros2_cli"` — internal tag, separate from the MCP-wire `mode_effective` field which keeps its `Literal["mock", "live"]` contract.
|
|
34
|
+
- **`Settings`** gains `dds_backend` and `dds_domain_id` fields with safe defaults (`"mock"`, `0`). Existing `Settings(...)` constructors are unaffected.
|
|
35
|
+
- **`Ros2CliAdapter` DDS methods raise `AdapterError`** with a clear remediation path (`pip install topicforge[dds]` + `TOPICFORGE_DDS_BACKEND=cyclone`). This is the v0.2.0 MVP limitation D6 (single-adapter-at-a-time) ; a composite adapter that delegates per-tool is a v0.2.x roadmap item.
|
|
36
|
+
|
|
37
|
+
### Internal
|
|
38
|
+
|
|
39
|
+
- `parse_topic_info` and `parse_bag_info` parsers : `mode_effective` kwarg typed as `EffectiveMode` (`Literal["mock", "live"]`) rather than the broader `AdapterName`, cleanly separating the wire-facing mode from the implementation tag.
|
|
40
|
+
- New pytest marker `requires_cyclonedds` for tests that need the SDK. Auto-skips otherwise via `pytest.importorskip`.
|
|
41
|
+
|
|
42
|
+
### Notes
|
|
43
|
+
|
|
44
|
+
- **`cyclonedds` is optional.** Default installs (`pip install topicforge`) are unchanged from v0.1.2 in dependency footprint. Only `pip install topicforge[dds]` pulls the bindings (`cyclonedds>=0.10`).
|
|
45
|
+
- **No code change to the 5 ROS2 tools** — `health_check`, `list_topics`, `get_topic_info`, `sample_messages`, `analyze_bag` behave identically to v0.1.2. The wire contract (`mode_effective: Literal["mock", "live"]`) is unchanged.
|
|
46
|
+
- **v0.2.0 MVP limitation**: single adapter at a time. Users select ROS2 introspection (default) or DDS observability via `TOPICFORGE_DDS_BACKEND=cyclone`, not both simultaneously. The unselected half raises `AdapterError` with a remediation pointer. A composite adapter delegating per-tool category is a v0.2.x roadmap item.
|
|
47
|
+
|
|
10
48
|
## [0.1.2] - 2026-05-13
|
|
11
49
|
|
|
12
50
|
### Fixed
|
|
@@ -67,7 +105,8 @@ Initial MVP release of TopicForge — ROS Topic Inspector & Bag Analyzer MCP ser
|
|
|
67
105
|
- The write path (publishing, commanding robots) is intentionally out of scope for the MVP.
|
|
68
106
|
- `analyze_bag` in live mode parses `ros2 bag info` text output; deeper anomaly detection remains mock-only for now.
|
|
69
107
|
|
|
70
|
-
[Unreleased]: https://github.com/yaniswav/TopicForge/compare/v0.
|
|
108
|
+
[Unreleased]: https://github.com/yaniswav/TopicForge/compare/v0.2.0...HEAD
|
|
109
|
+
[0.2.0]: https://github.com/yaniswav/TopicForge/compare/v0.1.2...v0.2.0
|
|
71
110
|
[0.1.2]: https://github.com/yaniswav/TopicForge/compare/v0.1.1...v0.1.2
|
|
72
111
|
[0.1.1]: https://github.com/yaniswav/TopicForge/compare/v0.1.0...v0.1.1
|
|
73
112
|
[0.1.0]: https://github.com/yaniswav/TopicForge/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: topicforge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: ROS Topic Inspector & Bag Analyzer MCP server for AI agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/yaniswav/TopicForge
|
|
6
6
|
Project-URL: Repository, https://github.com/yaniswav/TopicForge
|
|
@@ -40,6 +40,10 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
40
40
|
Requires-Python: >=3.11
|
|
41
41
|
Requires-Dist: mcp>=1.0.0
|
|
42
42
|
Requires-Dist: pydantic>=2.6
|
|
43
|
+
Provides-Extra: all
|
|
44
|
+
Requires-Dist: cyclonedds>=0.10; extra == 'all'
|
|
45
|
+
Provides-Extra: dds
|
|
46
|
+
Requires-Dist: cyclonedds>=0.10; extra == 'dds'
|
|
43
47
|
Provides-Extra: dev
|
|
44
48
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
45
49
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
@@ -47,9 +51,14 @@ Description-Content-Type: text/markdown
|
|
|
47
51
|
|
|
48
52
|
# TopicForge
|
|
49
53
|
|
|
50
|
-
|
|
54
|
+
[](https://pypi.org/project/topicforge/)
|
|
55
|
+
[](https://pypi.org/project/topicforge/)
|
|
56
|
+
[](https://github.com/yaniswav/TopicForge/blob/main/LICENSE)
|
|
57
|
+
[](https://github.com/yaniswav/TopicForge#security-model)
|
|
51
58
|
|
|
52
|
-
|
|
59
|
+
> **The safety-first read-only MCP for ROS2 robotics — now with a DDS observability module (v0.2.0).** TopicForge lets AI agents inspect your ROS2 graph, ROS bag files, and (since v0.2.0) the raw DDS layer beneath ROS, without ever publishing back to the bus. The MCP client can see the stack ; it cannot touch it.
|
|
60
|
+
|
|
61
|
+
TopicForge is a production-minded MCP (Model Context Protocol) server that lets AI agents — such as Claude — inspect ROS2 topics, analyze ROS bag files, and (since v0.2.0) observe the raw DDS layer through a clean, structured tool interface. It is read-only by **architecture**, not by configuration: there is no write path to misconfigure, no permission system to audit, no liability conversation to have. The MCP client can see the robot stack; it cannot touch it.
|
|
53
62
|
|
|
54
63
|
This stance matters because the ROS-MCP space is no longer empty — general-purpose ROS-MCP servers exist that let an LLM publish topics, call services, and command robots. That shape is fine for demos; it is untenable for production fleets, defense systems, automotive AUTOSAR Adaptive surfaces, or anything safety-certified. TopicForge is the read-only alternative for those audiences, plus the robotics developers, ML/CV engineers, and teams that want their AI tooling to *understand* their robotics stack without commanding it.
|
|
55
64
|
|
|
@@ -179,6 +188,31 @@ TOPICFORGE_MODE=live python -m topicforge
|
|
|
179
188
|
|
|
180
189
|
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.
|
|
181
190
|
|
|
191
|
+
### DDS support (v0.2.0+)
|
|
192
|
+
|
|
193
|
+
Beyond ROS2 graph introspection, TopicForge can also observe a raw DDS bus directly — useful for non-ROS DDS stacks (defense, aerospace, automotive AUTOSAR Adaptive, industrial integration) and for diagnosing why a ROS2 subscriber isn't receiving when the graph says it should. Same safety-first contract : read-only by **architecture**, never publishes back to the bus.
|
|
194
|
+
|
|
195
|
+
Install the optional DDS extras and select a backend :
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install topicforge[dds]
|
|
199
|
+
TOPICFORGE_MODE=live TOPICFORGE_DDS_BACKEND=cyclone python -m topicforge
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Three new MCP tools (in addition to the five ROS2 tools above) :
|
|
203
|
+
|
|
204
|
+
| Tool | Purpose |
|
|
205
|
+
| ----------------------- | -------------------------------------------------------------------------------- |
|
|
206
|
+
| `list_participants` | DDS participants discovered on a domain, with vendor and hostname |
|
|
207
|
+
| `detect_qos_mismatches` | Reader/writer QoS incompatibilities preventing communication on a topic |
|
|
208
|
+
| `peek_dds_samples` | Recent samples on a raw DDS topic (distinct from `sample_messages` on ROS2 graph)|
|
|
209
|
+
|
|
210
|
+
**v0.2.0 limitation.** TopicForge selects one adapter at a time. With `TOPICFORGE_DDS_BACKEND=cyclone`, the 3 DDS tools work and the 5 ROS2 tools raise a clear `AdapterError` — and vice versa with the default `TOPICFORGE_DDS_BACKEND=mock`. The mock backend exposes all 8 tools against deterministic fixtures for local development and tests. Real CycloneDDS discovery (builtin topics, QoS pair extraction, typed reader for samples) ships as a v0.2.x patch ; the v0.2.0 `CycloneDdsAdapter` is a protocol-compliant stub that raises a clear roadmap message. A composite adapter delegating per-tool is a v0.2.x roadmap item.
|
|
211
|
+
|
|
212
|
+
`RTI Connext` and additional vendors will be available in the Pro tier (see `docs/pro.md`).
|
|
213
|
+
|
|
214
|
+
**Full 5-minute walkthrough** — including the canonical QoS-mismatch debugging scenario, the single-adapter limitation matrix, and troubleshooting — lives in [`docs/DDS_QUICKSTART.md`](docs/DDS_QUICKSTART.md).
|
|
215
|
+
|
|
182
216
|
### Configure with Claude Desktop
|
|
183
217
|
|
|
184
218
|
Add to your `claude_desktop_config.json`:
|
|
@@ -226,12 +260,14 @@ make check # both, plus tests (CI bundle)
|
|
|
226
260
|
|
|
227
261
|
## Configuration reference
|
|
228
262
|
|
|
229
|
-
| Variable
|
|
230
|
-
|
|
|
231
|
-
| `TOPICFORGE_MODE`
|
|
232
|
-
| `TOPICFORGE_LOG_LEVEL`
|
|
233
|
-
| `TOPICFORGE_ROS2_BIN`
|
|
234
|
-
| `TOPICFORGE_TELEMETRY`
|
|
263
|
+
| Variable | Default | Description |
|
|
264
|
+
| --------------------------- | ------- | ----------------------------------------------------------------------------- |
|
|
265
|
+
| `TOPICFORGE_MODE` | `auto` | `mock`, `live`, or `auto` |
|
|
266
|
+
| `TOPICFORGE_LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
|
267
|
+
| `TOPICFORGE_ROS2_BIN` | `ros2` | Name (or path) of the ROS2 CLI binary |
|
|
268
|
+
| `TOPICFORGE_TELEMETRY` | `off` | Opt-in anonymous usage telemetry. See [Telemetry](#telemetry). |
|
|
269
|
+
| `TOPICFORGE_DDS_BACKEND` | `mock` | DDS module backend: `mock`, `cyclone`, `rti`, or `auto`. See [DDS support](#dds-support-v020). |
|
|
270
|
+
| `TOPICFORGE_DDS_DOMAIN_ID` | `0` | DDS domain id observed (0..232) when a DDS backend is active. |
|
|
235
271
|
|
|
236
272
|
See [`.env.example`](.env.example).
|
|
237
273
|
|
|
@@ -305,6 +341,7 @@ See [`docs/product-plan.md`](docs/product-plan.md) for the full product trajecto
|
|
|
305
341
|
Near-term additions on the bench:
|
|
306
342
|
|
|
307
343
|
- `rclpy`-backed live adapter for faster & richer sampling
|
|
344
|
+
- DDS observability module (Cyclone DDS first as an `extras` install — `pip install topicforge[dds]` —, RTI Connext later in the Pro tier). Generalizes the existing `RosAdapter` to a `MiddlewareAdapter` protocol. Same safety-first read-only contract.
|
|
308
345
|
- URDF inspector / validator MCP tools
|
|
309
346
|
- Bag anomaly detection (clock jumps, gaps, dropped frames, TF tree health)
|
|
310
347
|
- Dataset export helpers (rosbag → COCO / HF Datasets)
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# TopicForge
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://pypi.org/project/topicforge/)
|
|
4
|
+
[](https://pypi.org/project/topicforge/)
|
|
5
|
+
[](https://github.com/yaniswav/TopicForge/blob/main/LICENSE)
|
|
6
|
+
[](https://github.com/yaniswav/TopicForge#security-model)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
> **The safety-first read-only MCP for ROS2 robotics — now with a DDS observability module (v0.2.0).** TopicForge lets AI agents inspect your ROS2 graph, ROS bag files, and (since v0.2.0) the raw DDS layer beneath ROS, without ever publishing back to the bus. The MCP client can see the stack ; it cannot touch it.
|
|
9
|
+
|
|
10
|
+
TopicForge is a production-minded MCP (Model Context Protocol) server that lets AI agents — such as Claude — inspect ROS2 topics, analyze ROS bag files, and (since v0.2.0) observe the raw DDS layer through a clean, structured tool interface. It is read-only by **architecture**, not by configuration: there is no write path to misconfigure, no permission system to audit, no liability conversation to have. The MCP client can see the robot stack; it cannot touch it.
|
|
6
11
|
|
|
7
12
|
This stance matters because the ROS-MCP space is no longer empty — general-purpose ROS-MCP servers exist that let an LLM publish topics, call services, and command robots. That shape is fine for demos; it is untenable for production fleets, defense systems, automotive AUTOSAR Adaptive surfaces, or anything safety-certified. TopicForge is the read-only alternative for those audiences, plus the robotics developers, ML/CV engineers, and teams that want their AI tooling to *understand* their robotics stack without commanding it.
|
|
8
13
|
|
|
@@ -132,6 +137,31 @@ TOPICFORGE_MODE=live python -m topicforge
|
|
|
132
137
|
|
|
133
138
|
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.
|
|
134
139
|
|
|
140
|
+
### DDS support (v0.2.0+)
|
|
141
|
+
|
|
142
|
+
Beyond ROS2 graph introspection, TopicForge can also observe a raw DDS bus directly — useful for non-ROS DDS stacks (defense, aerospace, automotive AUTOSAR Adaptive, industrial integration) and for diagnosing why a ROS2 subscriber isn't receiving when the graph says it should. Same safety-first contract : read-only by **architecture**, never publishes back to the bus.
|
|
143
|
+
|
|
144
|
+
Install the optional DDS extras and select a backend :
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pip install topicforge[dds]
|
|
148
|
+
TOPICFORGE_MODE=live TOPICFORGE_DDS_BACKEND=cyclone python -m topicforge
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Three new MCP tools (in addition to the five ROS2 tools above) :
|
|
152
|
+
|
|
153
|
+
| Tool | Purpose |
|
|
154
|
+
| ----------------------- | -------------------------------------------------------------------------------- |
|
|
155
|
+
| `list_participants` | DDS participants discovered on a domain, with vendor and hostname |
|
|
156
|
+
| `detect_qos_mismatches` | Reader/writer QoS incompatibilities preventing communication on a topic |
|
|
157
|
+
| `peek_dds_samples` | Recent samples on a raw DDS topic (distinct from `sample_messages` on ROS2 graph)|
|
|
158
|
+
|
|
159
|
+
**v0.2.0 limitation.** TopicForge selects one adapter at a time. With `TOPICFORGE_DDS_BACKEND=cyclone`, the 3 DDS tools work and the 5 ROS2 tools raise a clear `AdapterError` — and vice versa with the default `TOPICFORGE_DDS_BACKEND=mock`. The mock backend exposes all 8 tools against deterministic fixtures for local development and tests. Real CycloneDDS discovery (builtin topics, QoS pair extraction, typed reader for samples) ships as a v0.2.x patch ; the v0.2.0 `CycloneDdsAdapter` is a protocol-compliant stub that raises a clear roadmap message. A composite adapter delegating per-tool is a v0.2.x roadmap item.
|
|
160
|
+
|
|
161
|
+
`RTI Connext` and additional vendors will be available in the Pro tier (see `docs/pro.md`).
|
|
162
|
+
|
|
163
|
+
**Full 5-minute walkthrough** — including the canonical QoS-mismatch debugging scenario, the single-adapter limitation matrix, and troubleshooting — lives in [`docs/DDS_QUICKSTART.md`](docs/DDS_QUICKSTART.md).
|
|
164
|
+
|
|
135
165
|
### Configure with Claude Desktop
|
|
136
166
|
|
|
137
167
|
Add to your `claude_desktop_config.json`:
|
|
@@ -179,12 +209,14 @@ make check # both, plus tests (CI bundle)
|
|
|
179
209
|
|
|
180
210
|
## Configuration reference
|
|
181
211
|
|
|
182
|
-
| Variable
|
|
183
|
-
|
|
|
184
|
-
| `TOPICFORGE_MODE`
|
|
185
|
-
| `TOPICFORGE_LOG_LEVEL`
|
|
186
|
-
| `TOPICFORGE_ROS2_BIN`
|
|
187
|
-
| `TOPICFORGE_TELEMETRY`
|
|
212
|
+
| Variable | Default | Description |
|
|
213
|
+
| --------------------------- | ------- | ----------------------------------------------------------------------------- |
|
|
214
|
+
| `TOPICFORGE_MODE` | `auto` | `mock`, `live`, or `auto` |
|
|
215
|
+
| `TOPICFORGE_LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
|
216
|
+
| `TOPICFORGE_ROS2_BIN` | `ros2` | Name (or path) of the ROS2 CLI binary |
|
|
217
|
+
| `TOPICFORGE_TELEMETRY` | `off` | Opt-in anonymous usage telemetry. See [Telemetry](#telemetry). |
|
|
218
|
+
| `TOPICFORGE_DDS_BACKEND` | `mock` | DDS module backend: `mock`, `cyclone`, `rti`, or `auto`. See [DDS support](#dds-support-v020). |
|
|
219
|
+
| `TOPICFORGE_DDS_DOMAIN_ID` | `0` | DDS domain id observed (0..232) when a DDS backend is active. |
|
|
188
220
|
|
|
189
221
|
See [`.env.example`](.env.example).
|
|
190
222
|
|
|
@@ -258,6 +290,7 @@ See [`docs/product-plan.md`](docs/product-plan.md) for the full product trajecto
|
|
|
258
290
|
Near-term additions on the bench:
|
|
259
291
|
|
|
260
292
|
- `rclpy`-backed live adapter for faster & richer sampling
|
|
293
|
+
- DDS observability module (Cyclone DDS first as an `extras` install — `pip install topicforge[dds]` —, RTI Connext later in the Pro tier). Generalizes the existing `RosAdapter` to a `MiddlewareAdapter` protocol. Same safety-first read-only contract.
|
|
261
294
|
- URDF inspector / validator MCP tools
|
|
262
295
|
- Bag anomaly detection (clock jumps, gaps, dropped frames, TF tree health)
|
|
263
296
|
- Dataset export helpers (rosbag → COCO / HF Datasets)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# DDS quickstart — TopicForge v0.2.0+
|
|
2
|
+
|
|
3
|
+
A 5-minute tour of TopicForge's DDS observability module. Same safety-first read-only contract as the ROS2 tools — the `MiddlewareAdapter` protocol does not expose a write method, so the MCP client can observe the bus but never publish to it.
|
|
4
|
+
|
|
5
|
+
This guide does **not** assume you have ROS2 installed.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Mock mode — 30-second demo
|
|
10
|
+
|
|
11
|
+
The deterministic mock fixtures expose the full DDS tool surface without any DDS SDK or middleware. Useful for evaluating the tools before pulling in a real broker.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install topicforge
|
|
15
|
+
TOPICFORGE_MODE=mock python -m topicforge
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
In the spawned MCP client (Claude Desktop, Claude Code, Cursor, ...), the 3 DDS tools are now available alongside the 5 ROS2 tools:
|
|
19
|
+
|
|
20
|
+
- `list_participants(domain_id=0)` → returns 2 mock participants on domain 0 (vendor `cyclone`, hostnames `mock-robot` and `mock-laptop`).
|
|
21
|
+
- `detect_qos_mismatches(topic=None)` → returns 1 `MismatchReport` for `/dds/qos_mismatch` (deliberate Reliability incompatibility — RELIABLE reader vs BEST_EFFORT writer).
|
|
22
|
+
- `peek_dds_samples(topic="/dds/well_matched", count=3)` → returns 3 deterministic samples ; `peek_dds_samples(topic="/dds/qos_mismatch", count=1)` returns 1 sample with a `qos_note` field annotating the mismatch.
|
|
23
|
+
|
|
24
|
+
Mock fixtures are stable across runs — you can write integration tests against them.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Live mode with CycloneDDS
|
|
29
|
+
|
|
30
|
+
Install the DDS extras and select the Cyclone backend:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install topicforge[dds]
|
|
34
|
+
TOPICFORGE_MODE=live TOPICFORGE_DDS_BACKEND=cyclone python -m topicforge
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`TOPICFORGE_DDS_BACKEND` accepts `mock` (default), `cyclone`, `rti` (Pro tier, not shipped in v0.2.0), or `auto` (resolves to `cyclone` when `cyclonedds` is importable, else `mock`).
|
|
38
|
+
|
|
39
|
+
`TOPICFORGE_DDS_DOMAIN_ID` selects the DDS domain (`0..232`, default `0`).
|
|
40
|
+
|
|
41
|
+
### v0.2.0 stub limitation
|
|
42
|
+
|
|
43
|
+
The v0.2.0 `CycloneDdsAdapter` ships as a **protocol-compliant stub**: the lazy import, `is_available()`, and factory routing all work, but the 3 DDS tools raise an `AdapterError` with a v0.2.x roadmap pointer when invoked. The real CycloneDDS discovery (builtin topics, QoS pair extraction, typed reader for samples) lands in a v0.2.x patch.
|
|
44
|
+
|
|
45
|
+
In the meantime, use `TOPICFORGE_DDS_BACKEND=mock` for end-to-end tool testing.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. The QoS mismatch scenario
|
|
50
|
+
|
|
51
|
+
Mock fixtures encode the canonical "subscriber doesn't receive" debugging case. From an MCP client:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
> Detect QoS mismatches on the current bus.
|
|
55
|
+
|
|
56
|
+
[tool call: detect_qos_mismatches]
|
|
57
|
+
[result]
|
|
58
|
+
[
|
|
59
|
+
{
|
|
60
|
+
"topic": "/dds/qos_mismatch",
|
|
61
|
+
"reader_guid": "010f1c2a-3b4c-5d6e-7f80-000000000001",
|
|
62
|
+
"writer_guid": "010f1c2a-3b4c-5d6e-7f80-000000000002",
|
|
63
|
+
"incompatible_policies": ["Reliability"],
|
|
64
|
+
"severity": "incompatible",
|
|
65
|
+
"mode_effective": "mock"
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
An LLM reading this output has enough information to suggest a concrete fix ("the writer is BEST_EFFORT but the reader requires RELIABLE — either relax the reader or upgrade the writer"). That is the diagnostic loop the DDS module is designed to support.
|
|
71
|
+
|
|
72
|
+
The pure analyzer behind `detect_qos_mismatches` lives in `src/topicforge/adapters/common/qos_analyzer.py` and covers the four MVP policies that explain the bulk of real-world mismatch cases: **Reliability**, **Durability**, **History**, **Deadline**.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 4. Single-adapter limitation (v0.2.0)
|
|
77
|
+
|
|
78
|
+
TopicForge v0.2.0 selects **one adapter at a time** based on `TOPICFORGE_MODE` + `TOPICFORGE_DDS_BACKEND`:
|
|
79
|
+
|
|
80
|
+
| `TOPICFORGE_MODE` | `TOPICFORGE_DDS_BACKEND` | Active adapter | ROS2 tools | DDS tools |
|
|
81
|
+
| ----------------- | ------------------------ | -------------- | ---------- | --------- |
|
|
82
|
+
| `mock` | (any) | `MockAdapter` | work (fixtures) | work (fixtures) |
|
|
83
|
+
| `live` / `auto` | `mock` (default) | `Ros2CliAdapter` | work | raise with remediation pointer |
|
|
84
|
+
| `live` / `auto` | `cyclone` | `CycloneDdsAdapter` (stub) | raise with remediation pointer | raise with v0.2.x roadmap pointer |
|
|
85
|
+
| `live` / `auto` | `rti` | falls back to `Ros2CliAdapter` (Pro not shipped in v0.2.0) | work | raise |
|
|
86
|
+
|
|
87
|
+
A composite adapter that delegates per-tool category (ROS2 graph vs DDS layer) is on the v0.2.x roadmap — see `docs/projet-file/mcp-02-spec.md §7`. For now, restart the server with a different `TOPICFORGE_DDS_BACKEND` to switch sides.
|
|
88
|
+
|
|
89
|
+
The error message from the unselected side is explicit and points at the remediation path — no silent failures.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 5. What's next
|
|
94
|
+
|
|
95
|
+
- **v0.2.x** — Replace the `CycloneDdsAdapter` stub with real CycloneDDS discovery (`BuiltinTopicDcpsParticipant` for participants, `BuiltinTopicDcpsSubscription`/`Publication` for QoS pair extraction, typed reader on builtin topics first then arbitrary user topics).
|
|
96
|
+
- **v0.2.x** — Composite adapter routing ROS2 tools to `Ros2CliAdapter` and DDS tools to `CycloneDdsAdapter` so both surfaces are usable simultaneously.
|
|
97
|
+
- **v0.3.0+** — `RtiConnextAdapter` in the Pro tier (BYO RTI Connext license, gated by `TOPICFORGE_LICENSE_KEY`).
|
|
98
|
+
- **v0.3.0+** — Extended QoS mismatch coverage (Liveliness, Ownership, Partition, TimeBasedFilter, LatencyBudget).
|
|
99
|
+
|
|
100
|
+
Full strategic roadmap lives in `docs/product-plan.md §5` (Phase 1 remaining) and `docs/projet-file/mcp-02-spec.md §7` (DDS module phasing).
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 6. Troubleshooting
|
|
105
|
+
|
|
106
|
+
- **`pip install topicforge[dds]` fails on Windows / macOS Python 3.13+** — `cyclonedds` wheels are typically published for Python 3.8 to 3.12. Pin Python 3.11 or 3.12 for the install host.
|
|
107
|
+
- **`pip install topicforge[dds]` fails with `CYCLONEDDS_HOME`** — pip is trying to build `cyclonedds` from source because no wheel matches your platform/Python combination. Either switch to a supported Python (3.11/3.12) or install the native CycloneDDS C library first (see Eclipse CycloneDDS releases).
|
|
108
|
+
- **DDS tool returns "v0.2.0 stub" error** — expected with `TOPICFORGE_DDS_BACKEND=cyclone` in v0.2.0. Use `TOPICFORGE_DDS_BACKEND=mock` for end-to-end testing until the v0.2.x patch lands.
|
|
109
|
+
- **DDS tool returns "DDS module is not active" error** — your `TOPICFORGE_DDS_BACKEND` resolves to neither `cyclone` nor `mock` (likely you're in `live` mode with the default backend). Set `TOPICFORGE_DDS_BACKEND=cyclone` or `=mock` explicitly.
|
|
110
|
+
|
|
111
|
+
Report issues at https://github.com/yaniswav/TopicForge/issues.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Migrating from TopicForge v0.1.x to v0.2.0
|
|
2
|
+
|
|
3
|
+
Reading time : 5 minutes. v0.2.0 is mostly additive over v0.1.2, but two surfaces are soft-breaking and worth a once-over before you upgrade.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Who needs to read this
|
|
8
|
+
|
|
9
|
+
| Setup | Action |
|
|
10
|
+
| ----- | ------ |
|
|
11
|
+
| You use TopicForge through Claude Desktop / Claude Code / Cursor / Cline with `pip install topicforge` and no custom code | **Read §1 and §4 only.** Everything else is internal to the server. |
|
|
12
|
+
| You import `topicforge` modules in your own Python code | **Read all sections.** Two soft-breaking changes affect imports and schemas. |
|
|
13
|
+
| You validate MCP responses against a pinned JSON Schema with `additionalProperties: false` | **Read §2 carefully.** v0.2.0 adds optional fields to `TopicInfo` and `HealthReport`. |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. New tools and env vars (additive — no migration needed)
|
|
18
|
+
|
|
19
|
+
v0.2.0 ships 3 new MCP tools alongside the existing 5 ROS2 tools :
|
|
20
|
+
|
|
21
|
+
- `list_participants(domain_id)` → `list[ParticipantInfo]`
|
|
22
|
+
- `detect_qos_mismatches(topic)` → `list[MismatchReport]`
|
|
23
|
+
- `peek_dds_samples(topic, count)` → `SampleResult`
|
|
24
|
+
|
|
25
|
+
Existing clients see the new tools the next time they query `list_tools()` ; no client code change required to ignore them.
|
|
26
|
+
|
|
27
|
+
Two new env vars — both optional, safe defaults :
|
|
28
|
+
|
|
29
|
+
- `TOPICFORGE_DDS_BACKEND` — `mock | cyclone | rti | auto`, default `mock`. DDS module is opt-in.
|
|
30
|
+
- `TOPICFORGE_DDS_DOMAIN_ID` — `0..232`, default `0`.
|
|
31
|
+
|
|
32
|
+
If you don't set them, v0.2.0 behaves exactly like v0.1.2 from the client's perspective, plus three new tools that raise an `AdapterError` with a remediation pointer when invoked.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 2. Soft-breaking schema changes
|
|
37
|
+
|
|
38
|
+
### 2.1 `TopicInfo` schema
|
|
39
|
+
|
|
40
|
+
Three additive optional fields were added — all default `None` :
|
|
41
|
+
|
|
42
|
+
- `reader_count: int | None`
|
|
43
|
+
- `writer_count: int | None`
|
|
44
|
+
- `qos_profile: QosProfile | None`
|
|
45
|
+
|
|
46
|
+
**Producer side** : Python code constructing `TopicInfo` directly is unaffected. The defaults compile and v0.1.x constructor calls still work.
|
|
47
|
+
|
|
48
|
+
**Client side (over MCP)** : additive on the wire — an MCP client consuming JSON sees three extra optional keys per `TopicInfo` and is unaffected unless it strictly validates against the v0.1.x schema with `additionalProperties: false`. **Strict MCP clients that validated v0.1.x responses against the `TopicInfo` schema with `additionalProperties: false` will reject v0.2.0 responses unless their schema is regenerated. Standard MCP clients that read tool descriptions dynamically are unaffected.**
|
|
49
|
+
|
|
50
|
+
### 2.2 `HealthReport` schema
|
|
51
|
+
|
|
52
|
+
Same shape : three additive optional fields with safe defaults :
|
|
53
|
+
|
|
54
|
+
- `dds_backend: Literal["mock", "cyclone", "rti", "none"] = "none"`
|
|
55
|
+
- `dds_domain_id: int | None = None`
|
|
56
|
+
- `middleware_available: bool = False`
|
|
57
|
+
|
|
58
|
+
Same remediation as `TopicInfo` — regenerate strict schemas pinned to v0.1.x.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 3. Renamed protocol (backward-compat alias kept)
|
|
63
|
+
|
|
64
|
+
The `RosAdapter` protocol in `topicforge.adapters.base` has been generalized into `MiddlewareAdapter` — a superset covering both ROS2 graph methods and the new DDS methods under one contract.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# v0.1.x
|
|
68
|
+
from topicforge.adapters.base import RosAdapter
|
|
69
|
+
|
|
70
|
+
# v0.2.0 — both still work
|
|
71
|
+
from topicforge.adapters.base import RosAdapter # backward-compat alias
|
|
72
|
+
from topicforge.adapters.base import MiddlewareAdapter # canonical name
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`RosAdapter` is preserved as a type alias `RosAdapter = MiddlewareAdapter`, so any import of `RosAdapter` keeps type-checking. Internal `Ros2CliAdapter.name` value moved from `"live"` to `"ros2_cli"` — an internal tag, not the MCP-wire `mode_effective` field. The wire-facing `mode_effective: Literal["mock", "live"]` is unchanged.
|
|
76
|
+
|
|
77
|
+
Two new types live alongside :
|
|
78
|
+
|
|
79
|
+
- `AdapterName = Literal["mock", "ros2_cli", "cyclone", "rti"]` — internal tag, widened to support DDS.
|
|
80
|
+
- `EffectiveMode = Literal["mock", "live"]` — extracted, wire-facing.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 4. Optional install for DDS
|
|
85
|
+
|
|
86
|
+
The default install footprint of `pip install topicforge` is **unchanged from v0.1.2**. No new dependency.
|
|
87
|
+
|
|
88
|
+
To unlock the DDS module on a real broker, opt into the extras :
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install topicforge[dds]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This pulls `cyclonedds>=0.10` (BSD-licensed Python bindings, ~20 MB on install). Mock and ROS2-only installs are unaffected.
|
|
95
|
+
|
|
96
|
+
`pip install topicforge[all]` is an alias of `[dds]` for now ; future extras will join it.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 5. v0.2.0 MVP limitation
|
|
101
|
+
|
|
102
|
+
TopicForge v0.2.0 runs **one adapter at a time** — selected by `TOPICFORGE_MODE` plus `TOPICFORGE_DDS_BACKEND`. With `TOPICFORGE_DDS_BACKEND=cyclone`, the 3 DDS tools work and the 5 ROS2 tools raise `AdapterError` with a clear remediation pointer. Reverse holds for the default `TOPICFORGE_DDS_BACKEND=mock`.
|
|
103
|
+
|
|
104
|
+
A composite adapter that delegates per-tool category is a v0.2.x roadmap item. The full matrix lives in `docs/DDS_QUICKSTART.md §4`.
|
|
105
|
+
|
|
106
|
+
For end-to-end testing of all 8 tools simultaneously, use `TOPICFORGE_MODE=mock` — the mock adapter serves both ROS2 and DDS surfaces from deterministic fixtures.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 6. Testing the migration
|
|
111
|
+
|
|
112
|
+
After `pip install --upgrade topicforge`, sanity-check :
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
TOPICFORGE_MODE=mock python -m topicforge
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
In your MCP client, you should see **8 tools** in `list_tools()`. If you only see 5, the upgrade didn't take effect ; verify with `python -c "import topicforge; print(topicforge.__version__)"` — should be `0.2.0`.
|
|
119
|
+
|
|
120
|
+
For a real broker test, follow `docs/DDS_QUICKSTART.md §2`.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 7. Rollback
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pip install "topicforge==0.1.2"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
v0.1.x and v0.2.0 share the same MCP wire surface for the 5 ROS2 tools, so a rollback is safe — clients see 5 tools instead of 8, the additive `TopicInfo` fields disappear (back to v0.1.x shape), env vars `TOPICFORGE_DDS_*` are silently ignored.
|
|
131
|
+
|
|
132
|
+
If you migrated client code to import `MiddlewareAdapter`, switch the import back to `RosAdapter` — the v0.1.x name.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 8. Full changelog
|
|
137
|
+
|
|
138
|
+
See `CHANGELOG.md` section `[0.2.0] - 2026-05-14` for the complete list of changes, additions, soft-breaks, and notes.
|
|
139
|
+
|
|
140
|
+
Issues or unexpected migration breaks : https://github.com/yaniswav/TopicForge/issues.
|