topicforge 0.6.1__tar.gz → 0.6.2__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.6.1 → topicforge-0.6.2}/CHANGELOG.md +24 -1
- {topicforge-0.6.1 → topicforge-0.6.2}/PKG-INFO +7 -3
- {topicforge-0.6.1 → topicforge-0.6.2}/README.md +6 -2
- topicforge-0.6.2/docs/CLIENTS.md +280 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/docs/TESTING.md +3 -3
- {topicforge-0.6.1 → topicforge-0.6.2}/plugin/README.md +1 -1
- {topicforge-0.6.1 → topicforge-0.6.2}/pyproject.toml +2 -2
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/__init__.py +1 -1
- topicforge-0.6.2/tests/test_version_consistency.py +150 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/.gitignore +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/LICENSE +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/docs/DDS_QUICKSTART.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/docs/TROUBLESHOOTING.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/docs/TUTORIEL.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/docs/VALIDATION.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/docs/dds-interop-matrix.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/00_hello_pub_sub/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/01_who_is_on_the_bus/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/02_why_cant_they_talk/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/03_a_node_crashed/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/04_late_joiner_misses_data/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/05_reliability_in_code/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/06_durability_late_joiner_in_code/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/07_deadline_in_code/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/08_crash_seen_from_inside/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/10_lidar_silent_after_driver_swap/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/11_who_talks_to_whom/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/12_safety_monitor_dropout/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/13_deadline_not_offered/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/14_restart_loop/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/plugin/LICENSE +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/agent_eval/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/cyclone_c/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/cyclone_cpp/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/cyclone_rust/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/dust_py/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/fast_publisher_cpp/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/fast_py/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/opensplice_publisher/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/rti_c/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/scripts/integration/publishers/rti_cpp/README.md +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/__main__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/base.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/cdr_decoder.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/dds_helpers.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/dds_introspection.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/discovery_tracker.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/endpoints.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/lifecycle.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/metrics_buffer.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/qos_analyzer.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/qos_endpoints.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/qos_normalize.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/qos_scan.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/topic_filter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/common/xtypes.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/composite.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_cyclone/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_cyclone/adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_dust/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_dust/adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_fast/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_fast/adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_opendds/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/dds_opendds/adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_live/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_live/adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_live/echo_parser.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_live/echo_stream.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_live/parsers.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_live/process_tree.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_mock/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_mock/adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/adapters/ros2_mock/fixtures.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/config/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/config/settings.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/constants.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/models/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/models/schemas.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/server/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/server/app.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/services/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/services/bag_service.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/services/bag_stats.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/services/factory.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/services/health.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/services/inspector.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/services/sample_budget.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/telemetry/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/telemetry/client.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/tools/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/src/topicforge/tools/handlers.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/conftest.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/image_noarr.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/image_trunc4.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/scan_edge.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/scan_noarr.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/scan_trunc128.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/scan_trunc3.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/string_latched.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_echo/twist.yaml +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_topic_info_verbose_cmd_vel.txt +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_topic_info_verbose_parameter_events.txt +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_topic_info_verbose_scan.txt +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_topic_info_verbose_tf.txt +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/fixtures/ros2_topic_info_verbose_tf_static.txt +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/ros2/Dockerfile +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/ros2/__init__.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/ros2/entrypoint.sh +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/ros2/publisher.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/ros2/run_bench.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/ros2/test_live_adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/integration/test_real_bus.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_analyze_bag_multi_format.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_bag_omnisim_humble.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_bag_service.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_bag_stats.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_cdr_decoder.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_composite_adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_config.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_cyclone_adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_dds_cross_vendor.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_dds_helpers.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_dds_inactive_reason.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_dds_introspection.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_dds_qos_normalization.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_dds_schemas.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_discovery_tracker.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_dust_adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_echo_parser.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_echo_stream.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_endpoints.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_example_node_spec.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_factory.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_fast_adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_health.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_history_and_hints.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_honest_outputs.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_inspector.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_lifecycle_buffer.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_live_adapter_graph.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_live_adapter_parse.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_live_adapter_subprocess.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_live_sample_notes.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_metrics_buffer.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_mock_adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_opendds_adapter.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_peek_bag_samples.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_process_tree.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_qos_analyzer.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_qos_endpoints.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_qos_scan.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_sample_options.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_telemetry.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_tools_integration.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_topic_metrics.py +0 -0
- {topicforge-0.6.1 → topicforge-0.6.2}/tests/test_xtypes.py +0 -0
|
@@ -5,6 +5,28 @@ All notable changes to TopicForge are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.6.2] - 2026-10-06
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- [docs/CLIENTS.md](docs/CLIENTS.md): ready-to-paste local stdio configs for Claude
|
|
15
|
+
Code, Claude Desktop, Cursor, VS Code / Copilot, Windsurf / Devin, Cline, Roo Code,
|
|
16
|
+
Continue, Zed, JetBrains, Codex CLI, Gemini CLI, Goose, LM Studio, Amazon Q / Kiro
|
|
17
|
+
and Warp, with one-click install links for Cursor and VS Code, and a note on why
|
|
18
|
+
ChatGPT web and a hosted endpoint are out of scope. Linked from the README.
|
|
19
|
+
- `gemini-extension.json` and `GEMINI.md`: install in Gemini CLI with
|
|
20
|
+
`gemini extensions install https://github.com/yaniswav/TopicForge`.
|
|
21
|
+
- `mcpb/`: an MCP Bundle (`uv` server type, no vendored dependencies) for one-click
|
|
22
|
+
Claude Desktop install. The release workflow packs it and attaches it to the GitHub
|
|
23
|
+
release.
|
|
24
|
+
- `publish.yml` publishes `server.json` to the official MCP Registry after the PyPI
|
|
25
|
+
publish succeeds (pinned, checksum-verified `mcp-publisher`, GitHub OIDC), so the
|
|
26
|
+
registry no longer lags behind PyPI.
|
|
27
|
+
- `tests/test_version_consistency.py`: fails when the package, `server.json`, plugin,
|
|
28
|
+
Gemini extension, MCP Bundle and the pins in `docs/CLIENTS.md` disagree.
|
|
29
|
+
|
|
8
30
|
## [0.6.1] - 2026-10-06
|
|
9
31
|
|
|
10
32
|
### Added
|
|
@@ -1294,7 +1316,8 @@ Initial MVP release of TopicForge: ROS Topic Inspector & Bag Analyzer MCP server
|
|
|
1294
1316
|
- The write path (publishing, commanding robots) is intentionally out of scope for the MVP.
|
|
1295
1317
|
- `analyze_bag` in live mode parses `ros2 bag info` text output; deeper anomaly detection remains mock-only for now.
|
|
1296
1318
|
|
|
1297
|
-
[Unreleased]: https://github.com/yaniswav/TopicForge/compare/v0.6.
|
|
1319
|
+
[Unreleased]: https://github.com/yaniswav/TopicForge/compare/v0.6.2...HEAD
|
|
1320
|
+
[0.6.2]: https://github.com/yaniswav/TopicForge/compare/v0.6.1...v0.6.2
|
|
1298
1321
|
[0.6.1]: https://github.com/yaniswav/TopicForge/compare/v0.6.0...v0.6.1
|
|
1299
1322
|
[0.6.0]: https://github.com/yaniswav/TopicForge/compare/v0.5.6...v0.6.0
|
|
1300
1323
|
[0.5.6]: https://github.com/yaniswav/TopicForge/compare/v0.5.5...v0.5.6
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: topicforge
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
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
|
|
@@ -98,7 +98,11 @@ The server speaks MCP over stdio and waits for a client, so wire it into one. Fo
|
|
|
98
98
|
}
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
Then ask it to list the topics or to analyze `/tmp/demo.mcap`. For Claude Code: `claude mcp add topicforge -- topicforge`.
|
|
101
|
+
Then ask it to list the topics or to analyze `/tmp/demo.mcap`. For Claude Code: `claude mcp add topicforge -- topicforge`.
|
|
102
|
+
|
|
103
|
+
**Other MCP clients.** Ready-to-paste configs for Claude Desktop, Cursor, VS Code, Windsurf, Cline, Roo Code, Continue, Zed, JetBrains, Codex, Gemini CLI, Goose and more are in [`docs/CLIENTS.md`](docs/CLIENTS.md). One-click: [Add to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlW2Rkc109PTAuNi4yIiwidG9waWNmb3JnZSJdLCJlbnYiOnsiVE9QSUNGT1JHRV9NT0RFIjoiYXV0byIsIlRPUElDRk9SR0VfRERTX0JBQ0tFTkQiOiJjeWNsb25lIiwiVE9QSUNGT1JHRV9ERFNfRE9NQUlOX0lEIjoiMCJ9fQ%3D%3D) | [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%5Bdds%5D%3D%3D0.6.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D).
|
|
104
|
+
|
|
105
|
+
Setup for a real ROS2 environment (WSL2, Linux, Docker, native Windows) is in [`docs/TESTING.md`](docs/TESTING.md); recurring monitoring prompts and the privacy contract are in [`docs/TUTORIEL.md`](docs/TUTORIEL.md).
|
|
102
106
|
|
|
103
107
|
## Tools
|
|
104
108
|
|
|
@@ -191,7 +195,7 @@ When on, each tool call emits one event with exactly six fields:
|
|
|
191
195
|
| `tool_name` | `"list_topics"` | One of the twelve tools, never argument values |
|
|
192
196
|
| `latency_ms` | `12.34` | Handler wall-clock duration, 2 decimals |
|
|
193
197
|
| `mode` | `"mock"` | Mode of the adapter actually serving: `mock` or `live` |
|
|
194
|
-
| `version` | `"0.6.
|
|
198
|
+
| `version` | `"0.6.2"` | TopicForge server version |
|
|
195
199
|
| `session_id` | `"a1b2c3..."` | Random UUID per process, never persisted |
|
|
196
200
|
| `success` | `true` | Whether the handler returned or raised |
|
|
197
201
|
|
|
@@ -38,7 +38,11 @@ The server speaks MCP over stdio and waits for a client, so wire it into one. Fo
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Then ask it to list the topics or to analyze `/tmp/demo.mcap`. For Claude Code: `claude mcp add topicforge -- topicforge`.
|
|
41
|
+
Then ask it to list the topics or to analyze `/tmp/demo.mcap`. For Claude Code: `claude mcp add topicforge -- topicforge`.
|
|
42
|
+
|
|
43
|
+
**Other MCP clients.** Ready-to-paste configs for Claude Desktop, Cursor, VS Code, Windsurf, Cline, Roo Code, Continue, Zed, JetBrains, Codex, Gemini CLI, Goose and more are in [`docs/CLIENTS.md`](docs/CLIENTS.md). One-click: [Add to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlW2Rkc109PTAuNi4yIiwidG9waWNmb3JnZSJdLCJlbnYiOnsiVE9QSUNGT1JHRV9NT0RFIjoiYXV0byIsIlRPUElDRk9SR0VfRERTX0JBQ0tFTkQiOiJjeWNsb25lIiwiVE9QSUNGT1JHRV9ERFNfRE9NQUlOX0lEIjoiMCJ9fQ%3D%3D) | [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%5Bdds%5D%3D%3D0.6.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D).
|
|
44
|
+
|
|
45
|
+
Setup for a real ROS2 environment (WSL2, Linux, Docker, native Windows) is in [`docs/TESTING.md`](docs/TESTING.md); recurring monitoring prompts and the privacy contract are in [`docs/TUTORIEL.md`](docs/TUTORIEL.md).
|
|
42
46
|
|
|
43
47
|
## Tools
|
|
44
48
|
|
|
@@ -131,7 +135,7 @@ When on, each tool call emits one event with exactly six fields:
|
|
|
131
135
|
| `tool_name` | `"list_topics"` | One of the twelve tools, never argument values |
|
|
132
136
|
| `latency_ms` | `12.34` | Handler wall-clock duration, 2 decimals |
|
|
133
137
|
| `mode` | `"mock"` | Mode of the adapter actually serving: `mock` or `live` |
|
|
134
|
-
| `version` | `"0.6.
|
|
138
|
+
| `version` | `"0.6.2"` | TopicForge server version |
|
|
135
139
|
| `session_id` | `"a1b2c3..."` | Random UUID per process, never persisted |
|
|
136
140
|
| `success` | `true` | Whether the handler returned or raised |
|
|
137
141
|
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Using TopicForge from your MCP client
|
|
2
|
+
|
|
3
|
+
Last checked 2026-10-06.
|
|
4
|
+
|
|
5
|
+
TopicForge (ROS 2 / DDS) is a local, read-only MCP server that speaks stdio.
|
|
6
|
+
Every client below launches it as a child process with the same command:
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
uvx --from "topicforge[dds]==0.6.2" topicforge
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
and the same three environment variables:
|
|
13
|
+
|
|
14
|
+
| Variable | Value | Meaning |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `TOPICFORGE_MODE` | `auto` | Use ROS 2 if it is on PATH, else fixtures. |
|
|
17
|
+
| `TOPICFORGE_DDS_BACKEND` | `cyclone` | Join the DDS bus as a read-only participant (the `[dds]` extra provides the binding). Use `mock` for a demo with no robot. |
|
|
18
|
+
| `TOPICFORGE_DDS_DOMAIN_ID` | `0` | The one DDS domain to observe (0-232). Fixed at startup: restart the server to change it. |
|
|
19
|
+
|
|
20
|
+
The registry name is `io.github.yaniswav/topicforge`. Where a client asks for a
|
|
21
|
+
display name, use **TopicForge (ROS 2 / DDS)**: an unrelated SEO product is also
|
|
22
|
+
called TopicForge in the MCP registries.
|
|
23
|
+
|
|
24
|
+
The version pin (`==0.6.2`) is moved on every release together with the other
|
|
25
|
+
version strings; a test keeps them in sync.
|
|
26
|
+
|
|
27
|
+
## Before you start
|
|
28
|
+
|
|
29
|
+
- **uv.** `uvx` ships with [uv](https://docs.astral.sh/uv/getting-started/installation/).
|
|
30
|
+
Install it once, then check `uvx --version` in a new terminal.
|
|
31
|
+
- **Desktop apps do not inherit your shell PATH.** On Windows especially, an app
|
|
32
|
+
started from the Start menu may not see `uvx`. If a client reports "command not
|
|
33
|
+
found", put the absolute path in `command` (find it with `where uvx` on Windows
|
|
34
|
+
or `which uvx` elsewhere, for example `C:/Users/you/.local/bin/uvx.exe`;
|
|
35
|
+
forward slashes are fine in JSON).
|
|
36
|
+
- **First start is slow.** `uvx` downloads the package and the Cyclone DDS binding
|
|
37
|
+
the first time. Clients with a short startup timeout may need a retry or a
|
|
38
|
+
larger timeout (noted per client below).
|
|
39
|
+
- **If resolution fails on a very new Python** (the Cyclone binding ships wheels for Python 3.10 to 3.13 only), add `"--python", "3.12"` before
|
|
40
|
+
`"--from"` in the args.
|
|
41
|
+
- **pip alternative.** `pip install "topicforge[dds]==0.6.2"`, then use
|
|
42
|
+
`"command": "topicforge"` (or `"command": "python", "args": ["-m", "topicforge"]`)
|
|
43
|
+
with no `args` for uvx. Use the absolute path of the binary if the client does
|
|
44
|
+
not see your venv.
|
|
45
|
+
- **No robot at hand?** Set `TOPICFORGE_DDS_BACKEND` to `mock` to try the tools
|
|
46
|
+
against deterministic fixtures.
|
|
47
|
+
|
|
48
|
+
## What cannot work: ChatGPT and hosted endpoints
|
|
49
|
+
|
|
50
|
+
ChatGPT on the web and in the desktop app cannot run local stdio MCP servers; it
|
|
51
|
+
only talks to remote MCP endpoints. Use Codex (below), which runs local stdio
|
|
52
|
+
servers, or any other client on this page.
|
|
53
|
+
|
|
54
|
+
A hosted TopicForge endpoint is out of scope on purpose. TopicForge has to sit on
|
|
55
|
+
the same network as the DDS participants it observes, and exposing a robot bus to
|
|
56
|
+
the internet would contradict the read-only safety promise the product is built
|
|
57
|
+
on.
|
|
58
|
+
|
|
59
|
+
## The common JSON shape
|
|
60
|
+
|
|
61
|
+
Most clients read an `mcpServers` object like this one. The per-client sections
|
|
62
|
+
say where the file lives and what differs.
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"topicforge": {
|
|
68
|
+
"command": "uvx",
|
|
69
|
+
"args": ["--from", "topicforge[dds]==0.6.2", "topicforge"],
|
|
70
|
+
"env": {
|
|
71
|
+
"TOPICFORGE_MODE": "auto",
|
|
72
|
+
"TOPICFORGE_DDS_BACKEND": "cyclone",
|
|
73
|
+
"TOPICFORGE_DDS_DOMAIN_ID": "0"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Claude Code
|
|
81
|
+
|
|
82
|
+
Plugin (server plus two skills, asks for backend and domain at install):
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
claude plugin marketplace add yaniswav/TopicForge
|
|
86
|
+
claude plugin install topicforge@topicforge
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Or just the server:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
claude mcp add topicforge --env TOPICFORGE_MODE=auto --env TOPICFORGE_DDS_BACKEND=cyclone --env TOPICFORGE_DDS_DOMAIN_ID=0 -- uvx --from "topicforge[dds]==0.6.2" topicforge
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Claude Desktop
|
|
96
|
+
|
|
97
|
+
From 0.6.2: download `topicforge-<version>.mcpb` from the latest GitHub release and double-click it. Claude Desktop asks for the DDS backend and domain id and manages Python and dependencies itself through uv.
|
|
98
|
+
|
|
99
|
+
Or edit the config file by hand: `claude_desktop_config.json` (Settings > Developer > Edit Config):
|
|
100
|
+
`%APPDATA%\Claude\claude_desktop_config.json` on Windows,
|
|
101
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS. Paste
|
|
102
|
+
the common JSON shape above and restart the app completely. On Windows, if
|
|
103
|
+
`uvx` is not found, use its absolute path as `command`.
|
|
104
|
+
|
|
105
|
+
## Cursor
|
|
106
|
+
|
|
107
|
+
The one-click links in this page and in the README are https redirects, because GitHub and PyPI strip `cursor://` and `vscode:` links. Only the raw schemes are documented by Cursor and VS Code; the https forms (`cursor.com/install-mcp`, `vscode.dev/redirect/mcp/install`) were observed to redirect correctly on 2026-10-06 but are not in the vendors' docs (unverified, last checked 2026-10-06). The raw links are given as a fallback.
|
|
108
|
+
|
|
109
|
+
One click: [Add TopicForge to Cursor](https://cursor.com/install-mcp?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlW2Rkc109PTAuNi4yIiwidG9waWNmb3JnZSJdLCJlbnYiOnsiVE9QSUNGT1JHRV9NT0RFIjoiYXV0byIsIlRPUElDRk9SR0VfRERTX0JBQ0tFTkQiOiJjeWNsb25lIiwiVE9QSUNGT1JHRV9ERFNfRE9NQUlOX0lEIjoiMCJ9fQ%3D%3D)
|
|
110
|
+
|
|
111
|
+
If that page does not open Cursor, use the raw deeplink: `cursor://anysphere.cursor-deeplink/mcp/install?name=topicforge&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJ0b3BpY2ZvcmdlW2Rkc109PTAuNi4yIiwidG9waWNmb3JnZSJdLCJlbnYiOnsiVE9QSUNGT1JHRV9NT0RFIjoiYXV0byIsIlRPUElDRk9SR0VfRERTX0JBQ0tFTkQiOiJjeWNsb25lIiwiVE9QSUNGT1JHRV9ERFNfRE9NQUlOX0lEIjoiMCJ9fQ==`
|
|
112
|
+
|
|
113
|
+
Or paste the common JSON shape into `~/.cursor/mcp.json` (all projects) or
|
|
114
|
+
`.cursor/mcp.json` (one project).
|
|
115
|
+
|
|
116
|
+
## VS Code / GitHub Copilot
|
|
117
|
+
|
|
118
|
+
One click: [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=topicforge&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%5Bdds%5D%3D%3D0.6.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D)
|
|
119
|
+
|
|
120
|
+
Fallback, the raw URL handler: `vscode:mcp/install?%7B%22name%22%3A%22topicforge%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22topicforge%5Bdds%5D%3D%3D0.6.2%22%2C%22topicforge%22%5D%2C%22env%22%3A%7B%22TOPICFORGE_MODE%22%3A%22auto%22%2C%22TOPICFORGE_DDS_BACKEND%22%3A%22cyclone%22%2C%22TOPICFORGE_DDS_DOMAIN_ID%22%3A%220%22%7D%7D`
|
|
121
|
+
|
|
122
|
+
Or put this in `.vscode/mcp.json` (the key is `servers`, not `mcpServers`), or run
|
|
123
|
+
"MCP: Add Server" from the Command Palette:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"servers": {
|
|
128
|
+
"topicforge": {
|
|
129
|
+
"type": "stdio",
|
|
130
|
+
"command": "uvx",
|
|
131
|
+
"args": ["--from", "topicforge[dds]==0.6.2", "topicforge"],
|
|
132
|
+
"env": {
|
|
133
|
+
"TOPICFORGE_MODE": "auto",
|
|
134
|
+
"TOPICFORGE_DDS_BACKEND": "cyclone",
|
|
135
|
+
"TOPICFORGE_DDS_DOMAIN_ID": "0"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Windsurf / Devin (Cascade)
|
|
143
|
+
|
|
144
|
+
Windsurf's docs now redirect to Devin's (unverified, last checked 2026-10-06). Edit `%APPDATA%\devin\mcp_config.json`
|
|
145
|
+
(Windows) or `~/.config/devin/mcp_config.json` (macOS, Linux) and paste the common
|
|
146
|
+
JSON shape. Older installs may still use `~/.codeium/windsurf/mcp_config.json` (unverified, last checked 2026-10-06).
|
|
147
|
+
|
|
148
|
+
## Cline
|
|
149
|
+
|
|
150
|
+
Open the MCP Servers icon in the Cline panel, then Configure, then "Configure MCP
|
|
151
|
+
Servers", and paste the common JSON shape (the file is
|
|
152
|
+
`~/.cline/data/settings/cline_mcp_settings.json` per docs.cline.bot on 2026-10-06; older VS Code installs kept it elsewhere, unverified). Optional fields such as
|
|
153
|
+
`"disabled": false` and `"autoApprove": []` are accepted.
|
|
154
|
+
|
|
155
|
+
## Roo Code
|
|
156
|
+
|
|
157
|
+
Project file `.roo/mcp.json` (takes precedence) or the global `mcp_settings.json`
|
|
158
|
+
opened from the MCP view. Paste the common JSON shape. Roo's docs say Windows
|
|
159
|
+
needs a `cmd /c` wrapper for `npx`; for `uvx`, try it directly first and fall back
|
|
160
|
+
to `"command": "cmd", "args": ["/c", "uvx", "--from", "topicforge[dds]==0.6.2",
|
|
161
|
+
"topicforge"]` if it fails to start.
|
|
162
|
+
|
|
163
|
+
## Continue
|
|
164
|
+
|
|
165
|
+
Create `.continue/mcpServers/topicforge.yaml` (MCP works in agent mode only):
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
name: TopicForge (ROS 2 / DDS)
|
|
169
|
+
version: 0.0.1
|
|
170
|
+
schema: v1
|
|
171
|
+
mcpServers:
|
|
172
|
+
- name: topicforge
|
|
173
|
+
type: stdio
|
|
174
|
+
command: uvx
|
|
175
|
+
args:
|
|
176
|
+
- "--from"
|
|
177
|
+
- "topicforge[dds]==0.6.2"
|
|
178
|
+
- "topicforge"
|
|
179
|
+
env:
|
|
180
|
+
TOPICFORGE_MODE: auto
|
|
181
|
+
TOPICFORGE_DDS_BACKEND: cyclone
|
|
182
|
+
TOPICFORGE_DDS_DOMAIN_ID: "0"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Zed
|
|
186
|
+
|
|
187
|
+
In `settings.json`, under `context_servers`:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"context_servers": {
|
|
192
|
+
"topicforge": {
|
|
193
|
+
"command": "uvx",
|
|
194
|
+
"args": ["--from", "topicforge[dds]==0.6.2", "topicforge"],
|
|
195
|
+
"env": {
|
|
196
|
+
"TOPICFORGE_MODE": "auto",
|
|
197
|
+
"TOPICFORGE_DDS_BACKEND": "cyclone",
|
|
198
|
+
"TOPICFORGE_DDS_DOMAIN_ID": "0"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## JetBrains AI Assistant
|
|
206
|
+
|
|
207
|
+
Settings > Tools > AI Assistant > Model Context Protocol (MCP) > Add, then paste the
|
|
208
|
+
common JSON shape. You can also use "Import from Claude" if you already set it up
|
|
209
|
+
there.
|
|
210
|
+
|
|
211
|
+
## OpenAI Codex CLI
|
|
212
|
+
|
|
213
|
+
Codex runs local stdio servers (CLI, IDE extension and desktop app share
|
|
214
|
+
`~/.codex/config.toml`). The default startup timeout is 10 s, which a first `uvx`
|
|
215
|
+
run with the dds extra can exceed, so set it to 60 s:
|
|
216
|
+
|
|
217
|
+
```toml
|
|
218
|
+
[mcp_servers.topicforge]
|
|
219
|
+
command = "uvx"
|
|
220
|
+
args = ["--from", "topicforge[dds]==0.6.2", "topicforge"]
|
|
221
|
+
startup_timeout_sec = 60
|
|
222
|
+
|
|
223
|
+
[mcp_servers.topicforge.env]
|
|
224
|
+
TOPICFORGE_MODE = "auto"
|
|
225
|
+
TOPICFORGE_DDS_BACKEND = "cyclone"
|
|
226
|
+
TOPICFORGE_DDS_DOMAIN_ID = "0"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Gemini CLI
|
|
230
|
+
|
|
231
|
+
As an extension (reads `gemini-extension.json` from this repository):
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
gemini extensions install https://github.com/yaniswav/TopicForge
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Or paste the common JSON shape into `~/.gemini/settings.json` (or
|
|
238
|
+
`.gemini/settings.json` in a project). Add `"timeout": 60000` (milliseconds) for
|
|
239
|
+
the slow first start, and do not set `"trust": true`.
|
|
240
|
+
|
|
241
|
+
## Goose
|
|
242
|
+
|
|
243
|
+
In `~/.config/goose/config.yaml` (macOS, Linux; the Windows location is unverified, last checked 2026-10-06), or via the extensions screen:
|
|
244
|
+
|
|
245
|
+
```yaml
|
|
246
|
+
extensions:
|
|
247
|
+
topicforge:
|
|
248
|
+
name: TopicForge (ROS 2 / DDS)
|
|
249
|
+
type: stdio
|
|
250
|
+
cmd: uvx
|
|
251
|
+
args: [--from, "topicforge[dds]==0.6.2", topicforge]
|
|
252
|
+
enabled: true
|
|
253
|
+
envs: { "TOPICFORGE_MODE": "auto", "TOPICFORGE_DDS_BACKEND": "cyclone", "TOPICFORGE_DDS_DOMAIN_ID": "0" }
|
|
254
|
+
timeout: 300
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## LM Studio
|
|
258
|
+
|
|
259
|
+
Program tab > Install > Edit `mcp.json` (same notation as Cursor), then paste the
|
|
260
|
+
common JSON shape. LM Studio's docs only show remote examples; local command
|
|
261
|
+
servers follow the Cursor notation but are not documented explicitly. Small
|
|
262
|
+
local models may struggle with twelve tools.
|
|
263
|
+
|
|
264
|
+
## Amazon Q Developer / Kiro
|
|
265
|
+
|
|
266
|
+
Kiro: `~/.kiro/settings/mcp.json` (user) or `.kiro/settings/mcp.json` (workspace,
|
|
267
|
+
takes precedence); paste the common JSON shape. Amazon Q Developer CLI uses the
|
|
268
|
+
same shape in `~/.aws/amazonq/mcp.json` (the Amazon Q path and the move to Kiro CLI are unverified, last checked 2026-10-06).
|
|
269
|
+
|
|
270
|
+
## Warp
|
|
271
|
+
|
|
272
|
+
Settings > MCP > "+ Add", then paste the common JSON shape (unverified, last checked 2026-10-06: the Warp docs page could not be fetched).
|
|
273
|
+
|
|
274
|
+
## Troubleshooting
|
|
275
|
+
|
|
276
|
+
- Run the command by hand first: `uvx --from "topicforge[dds]==0.6.2" topicforge --version`.
|
|
277
|
+
- Server starts but sees no DDS participants: check the domain id, and that the
|
|
278
|
+
client machine is on the same network as the robot (DDS discovery uses
|
|
279
|
+
multicast UDP). Ask the assistant to call `health_check`.
|
|
280
|
+
- More in [TROUBLESHOOTING.md](TROUBLESHOOTING.md) and [TESTING.md](TESTING.md).
|
|
@@ -15,7 +15,7 @@ How to get a working ROS2 environment to point TopicForge at, and how to wire it
|
|
|
15
15
|
```bash
|
|
16
16
|
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
|
|
17
17
|
pip install topicforge
|
|
18
|
-
python -m topicforge --version # -> topicforge 0.6.
|
|
18
|
+
python -m topicforge --version # -> topicforge 0.6.2
|
|
19
19
|
TOPICFORGE_MODE=mock python -m topicforge # blocks on stdio; MCP clients spawn it
|
|
20
20
|
```
|
|
21
21
|
|
|
@@ -41,7 +41,7 @@ python3 -m venv ~/topicforge-venv && source ~/topicforge-venv/bin/activate
|
|
|
41
41
|
pip install topicforge # Ubuntu 22.04 ships Python 3.10, which is enough
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Then run live mode with three terminals. In the first, `ros2 run demo_nodes_cpp talker` publishes `/chatter` at about 1 Hz. In the second, `ros2 topic list` should show `/chatter`. In the third, source ROS2, activate the venv and run `TOPICFORGE_MODE=live python -m topicforge`. The startup line reads `topicforge 0.6.
|
|
44
|
+
Then run live mode with three terminals. In the first, `ros2 run demo_nodes_cpp talker` publishes `/chatter` at about 1 Hz. In the second, `ros2 topic list` should show `/chatter`. In the third, source ROS2, activate the venv and run `TOPICFORGE_MODE=live python -m topicforge`. The startup line reads `topicforge 0.6.2 ready (mode=live, requested_mode=live, adapter=ros2_cli, telemetry=off)`; `mode=mock` means `ros2` was not found and the server fell back to fixtures.
|
|
45
45
|
|
|
46
46
|
## Linux native
|
|
47
47
|
|
|
@@ -102,4 +102,4 @@ TopicForge speaks MCP over stdio; any compliant client can spawn it with a comma
|
|
|
102
102
|
}
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
That is the Claude Desktop shape (`claude_desktop_config.json`); restart the app and the twelve tools appear under the hammer icon. For Claude Code run `claude mcp add topicforge -- topicforge`. Cursor, Continue and Cline accept the same stdio config. If the `topicforge` script is not on PATH, use `"command": "python", "args": ["-m", "topicforge"]`, or the absolute path of the binary inside your venv: desktop clients do not inherit your shell's PATH or venv activation.
|
|
105
|
+
That is the Claude Desktop shape (`claude_desktop_config.json`); restart the app and the twelve tools appear under the hammer icon. For Claude Code run `claude mcp add topicforge -- topicforge`. Cursor, Continue and Cline accept the same stdio config; ready-to-paste configs for every major client are in [`CLIENTS.md`](CLIENTS.md). If the `topicforge` script is not on PATH, use `"command": "python", "args": ["-m", "topicforge"]`, or the absolute path of the binary inside your venv: desktop clients do not inherit your shell's PATH or venv activation.
|
|
@@ -4,7 +4,7 @@ TopicForge is a read-only MCP server for ROS 2 and DDS. This plugin bundles the
|
|
|
4
4
|
|
|
5
5
|
## What is included
|
|
6
6
|
|
|
7
|
-
- MCP server `topicforge`, started with `uvx` from the `topicforge` package on PyPI (version pinned to 0.6.
|
|
7
|
+
- MCP server `topicforge`, started with `uvx` from the `topicforge` package on PyPI (version pinned to 0.6.2). It exposes twelve read-only tools: `health_check`, `list_topics`, `get_topic_info`, `sample_messages`, `analyze_bag`, `peek_bag_samples`, `list_participants`, `list_endpoints`, `detect_qos_mismatches`, `participant_events`, `peek_dds_samples`, `topic_metrics`.
|
|
8
8
|
- Skill `diagnose-dds-bus`: what to call, and in which order, when nodes do not talk, a topic gets no data, or a node crashed or restarts.
|
|
9
9
|
- Skill `inspect-ros2-robot`: listing topics, sampling messages and reading bags, including large arrays and simulation time.
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "topicforge"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.2"
|
|
8
8
|
description = "ROS Topic Inspector & Bag Analyzer MCP server for AI agents"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -81,7 +81,7 @@ packages = ["src/topicforge"]
|
|
|
81
81
|
|
|
82
82
|
[tool.hatch.build.targets.sdist]
|
|
83
83
|
include = ["src/topicforge", "tests", "docs", "README.md", "CHANGELOG.md", "LICENSE", "pyproject.toml"]
|
|
84
|
-
exclude = [".claude", "docs/projet-file/**", "docs/projet-file", "tests/fixtures/bags/**", "CLAUDE.md", "*.pdf", ".pytest_cache", "pytest-cache-files-*", "pro"]
|
|
84
|
+
exclude = [".claude", "docs/projet-file/**", "docs/projet-file", "tests/fixtures/bags/**", "CLAUDE.md", "*.pdf", ".pytest_cache", "pytest-cache-files-*", "pro", "mcpb"]
|
|
85
85
|
|
|
86
86
|
[tool.pytest.ini_options]
|
|
87
87
|
testpaths = ["tests"]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Fail when the version strings scattered across the repo drift apart.
|
|
2
|
+
|
|
3
|
+
One release touches the package, the registry manifest, the Claude plugin, the
|
|
4
|
+
Gemini extension, the MCP Bundle and the pins copied into the docs. Forgetting
|
|
5
|
+
one of them ships a client config that installs the wrong version.
|
|
6
|
+
|
|
7
|
+
Repo-only: the sdist does not carry server.json, the plugin or the bundle, so the
|
|
8
|
+
whole module is skipped there. Nothing reads a file at import time.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import base64
|
|
14
|
+
import json
|
|
15
|
+
import re
|
|
16
|
+
import urllib.parse
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
import pytest
|
|
21
|
+
|
|
22
|
+
import topicforge
|
|
23
|
+
|
|
24
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
25
|
+
|
|
26
|
+
pytestmark = pytest.mark.skipif(
|
|
27
|
+
not (ROOT / "server.json").exists(), reason="repo-only test (not in the sdist)"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
PIN_RE = re.compile(r"topicforge\[dds\]==([0-9][^\s\"'\\)&%]*)")
|
|
31
|
+
BARE_PIN_RE = re.compile(r"==(\d+\.\d+\.\d+)")
|
|
32
|
+
VERSION_LINE_RE = re.compile(r'^version\s*=\s*"([^"]+)"', re.MULTILINE)
|
|
33
|
+
LINK_RES = {
|
|
34
|
+
"cursor https": re.compile(r"\((https://cursor\.com/install-mcp\?[^)\s]+)\)"),
|
|
35
|
+
"vscode https": re.compile(r"\((https://vscode\.dev/redirect/mcp/install\?[^)\s]+)\)"),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _text(rel: str) -> str:
|
|
40
|
+
return (ROOT / rel).read_text(encoding="utf-8")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _json(rel: str) -> dict:
|
|
44
|
+
return json.loads(_text(rel))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _toml_version(rel: str) -> str:
|
|
48
|
+
match = VERSION_LINE_RE.search(_text(rel))
|
|
49
|
+
assert match, f"no version line in {rel}"
|
|
50
|
+
return match.group(1)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _pin_in_args(args: list[str]) -> str:
|
|
54
|
+
match = PIN_RE.fullmatch(args[args.index("--from") + 1])
|
|
55
|
+
assert match, f"no topicforge[dds]==X pin in {args}"
|
|
56
|
+
return match.group(1)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _mcpb_pin() -> str:
|
|
60
|
+
match = PIN_RE.search(_text("mcpb/pyproject.toml"))
|
|
61
|
+
assert match, "no topicforge[dds]==X pin in mcpb/pyproject.toml"
|
|
62
|
+
return match.group(1)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _server_args(rel: str) -> list[str]:
|
|
66
|
+
return _json(rel)["mcpServers"]["topicforge"]["args"]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
SOURCES: dict[str, Callable[[], str]] = {
|
|
70
|
+
"pyproject.toml": lambda: _toml_version("pyproject.toml"),
|
|
71
|
+
"server.json": lambda: _json("server.json")["version"],
|
|
72
|
+
"server.json packages[0]": lambda: _json("server.json")["packages"][0]["version"],
|
|
73
|
+
"plugin.json": lambda: _json("plugin/.claude-plugin/plugin.json")["version"],
|
|
74
|
+
"plugin .mcp.json pin": lambda: _pin_in_args(_server_args("plugin/.mcp.json")),
|
|
75
|
+
"gemini-extension.json": lambda: _json("gemini-extension.json")["version"],
|
|
76
|
+
"gemini-extension.json pin": lambda: _pin_in_args(_server_args("gemini-extension.json")),
|
|
77
|
+
"mcpb manifest": lambda: _json("mcpb/manifest.json")["version"],
|
|
78
|
+
"mcpb pyproject version": lambda: _toml_version("mcpb/pyproject.toml"),
|
|
79
|
+
"mcpb pyproject pin": _mcpb_pin,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@pytest.mark.parametrize("name", sorted(SOURCES))
|
|
84
|
+
def test_version_matches_package(name: str) -> None:
|
|
85
|
+
assert SOURCES[name]() == topicforge.__version__, f"{name} drifted from __version__"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_pyproject_matches_package_and_bundle() -> None:
|
|
89
|
+
assert _toml_version("pyproject.toml") == topicforge.__version__
|
|
90
|
+
assert _toml_version("pyproject.toml") == _toml_version("mcpb/pyproject.toml")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@pytest.mark.parametrize("rel", ["docs/CLIENTS.md", "README.md", "docs/TESTING.md"])
|
|
94
|
+
def test_doc_pins_match_package(rel: str) -> None:
|
|
95
|
+
text = _text(rel)
|
|
96
|
+
pins = set(PIN_RE.findall(text)) | set(BARE_PIN_RE.findall(text))
|
|
97
|
+
assert pins <= {topicforge.__version__}, f"{rel} has stale pins: {sorted(pins)}"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _links(text: str) -> dict[str, str]:
|
|
101
|
+
found = {}
|
|
102
|
+
for name, regex in LINK_RES.items():
|
|
103
|
+
match = regex.search(text)
|
|
104
|
+
assert match, f"{name} install link missing"
|
|
105
|
+
found[name] = match.group(1)
|
|
106
|
+
return found
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _decode_cursor(url: str) -> dict:
|
|
110
|
+
query = urllib.parse.parse_qs(urllib.parse.urlsplit(url).query)
|
|
111
|
+
assert query["name"] == ["topicforge"]
|
|
112
|
+
return json.loads(base64.b64decode(query["config"][0]))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _decode_vscode_redirect(url: str) -> dict:
|
|
116
|
+
query = urllib.parse.parse_qs(urllib.parse.urlsplit(url).query)
|
|
117
|
+
assert query["name"] == ["topicforge"]
|
|
118
|
+
return json.loads(query["config"][0])
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_install_links_decode_to_pinned_config() -> None:
|
|
122
|
+
clients = _text("docs/CLIENTS.md")
|
|
123
|
+
links = _links(clients)
|
|
124
|
+
cursor_cfg = _decode_cursor(links["cursor https"])
|
|
125
|
+
vscode_cfg = _decode_vscode_redirect(links["vscode https"])
|
|
126
|
+
assert _pin_in_args(cursor_cfg["args"]) == topicforge.__version__
|
|
127
|
+
assert vscode_cfg == cursor_cfg
|
|
128
|
+
|
|
129
|
+
# Raw scheme fallbacks kept in CLIENTS.md decode to the same config.
|
|
130
|
+
raw_cursor = re.search(r"`(cursor://[^`\s]+)`", clients)
|
|
131
|
+
assert raw_cursor, "raw cursor:// fallback missing"
|
|
132
|
+
assert _decode_cursor(raw_cursor.group(1)) == cursor_cfg
|
|
133
|
+
raw_vscode = re.search(r"`vscode:mcp/install\?([^`\s]+)`", clients)
|
|
134
|
+
assert raw_vscode, "raw vscode: fallback missing"
|
|
135
|
+
assert json.loads(urllib.parse.unquote(raw_vscode.group(1))) == {
|
|
136
|
+
"name": "topicforge",
|
|
137
|
+
**cursor_cfg,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@pytest.mark.parametrize("rel", ["README.md", "docs/TESTING.md"])
|
|
142
|
+
def test_other_docs_links_identical_to_clients_doc(rel: str) -> None:
|
|
143
|
+
text = _text(rel)
|
|
144
|
+
expected = _links(_text("docs/CLIENTS.md"))
|
|
145
|
+
for name, regex in LINK_RES.items():
|
|
146
|
+
found = {m for m in regex.findall(text)}
|
|
147
|
+
if rel == "README.md":
|
|
148
|
+
assert found == {expected[name]}, f"{rel}: {name} link differs from CLIENTS.md"
|
|
149
|
+
else:
|
|
150
|
+
assert found <= {expected[name]}, f"{rel}: {name} link differs from CLIENTS.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/06_durability_late_joiner_in_code/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{topicforge-0.6.1 → topicforge-0.6.2}/examples/dds/10_lidar_silent_after_driver_swap/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|