Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

TopicForge

PYPI · TOPICFORGE · SCANNED SEP 20

Read-only MCP server for ROS2 and DDS: topics, participants, QoS mismatches, bags.

Available components

+19 this week 74 Trust /100
Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security100
  • No malware found by supply-chain analysis.Pass
  • No known CVEs affecting this package version or its production dependencies.Pass
  • Runs hatchling.build at install time, a recognised native-build step with no shell scripting around it. View diagnostics → Pass
  • 0 of 29 dependencies flagged as unhealthy. View diagnostics → Pass
Provenance & Transparency35
  • Source repository is publicly reachable at the declared URL. View diagnostics → Pass
  • Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
  • License check failed: the license (MIT License) isn't a recognized OSI-approved license. See how to fix → Fail
  • Actively maintained (last published 28 days ago).Pass
  • Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability65
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 3659 tokens (~332/item across 11 items; 11 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management50
  • Stability observed for 15 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 100% of tool parameters carry a description.Pass
  • Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety100
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • We read all 11 captured tool definition(s), and no name or description among them implies an irreversible operation.Pass
  • An AI judge read all 11 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Install

How do I install the TopicForge MCP server?

TopicForge runs locally as a PyPI package, launched with uvx topicforge. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

pypi · topicforge

# add to Claude Code
claude mcp add yaniswav-topicforge -- uvx topicforge
// .cursor/mcp.json
{
  "mcpServers": {
    "yaniswav-topicforge": {
      "command": "uvx",
      "args": [
        "topicforge"
      ]
    }
  }
}
// .vscode/mcp.json
{
  "servers": {
    "yaniswav-topicforge": {
      "command": "uvx",
      "args": [
        "topicforge"
      ]
    }
  }
}
# add to Codex CLI
codex mcp add yaniswav-topicforge -- uvx topicforge
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "yaniswav-topicforge": {
      "type": "local",
      "command": [
        "uvx",
        "topicforge"
      ],
      "enabled": true
    }
  }
}
# add to OpenClaw
openclaw mcp add yaniswav-topicforge --command uvx --arg topicforge
# ~/.hermes/config.yaml
mcp_servers:
  yaniswav-topicforge:
    command: "uvx"
    args: ["topicforge"]
// ~/.netclaw/config/netclaw.json
{
  "McpServers": {
    "yaniswav-topicforge": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "topicforge"
      ]
    }
  }
}
# add to Vellum
assistant mcp add yaniswav-topicforge -t stdio -c uvx -a topicforge
// mcp.json
{
  "mcpServers": {
    "yaniswav-topicforge": {
      "command": "uvx",
      "args": [
        "topicforge"
      ]
    }
  }
}
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 20 Sept 26 +16
    • Malware scan: unverified → pass security
  • 18 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 40 to 43. That category is still filling its 30-day observation window: 12 days of observed history at the previous scan, 13 at this one. The score rises as the window fills, whether or not the server changes.

  • 16 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 33 to 37. That category is still filling its 30-day observation window: 10 days of observed history at the previous scan, 11 at this one. The score rises as the window fills, whether or not the server changes.

  • 14 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 27 to 30. That category is still filling its 30-day observation window: 8 days of observed history at the previous scan, 9 at this one. The score rises as the window fills, whether or not the server changes.

  • 11 Sept 26 +3
    • Stability: unverified → 0.20 functional
  • 5 Sept 26 52

    First indexed and scored.

Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 20 Sept 2026 · Analysed pypi/topicforge@0.5.2

Provenance No attestation

The registry publishes no build provenance for this version, so there is nothing to verify.

Result No attestation
Ecosystem pypi

Background: How many MCP packages publish verified provenance →

Install scripts 1 script
Hook Tier Command
build_backend allowlisted hatchling.build

Background: Why install scripts are a supply-chain risk →

Dependencies 29 packages
Packages resolved 29
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 11 exposed · ~3,659 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
analyze_bag ~244

Summarize a ROS2 bag at `path`. Returns a `BagAnalysis` carrying storage format, total duration, message count, per-topic stats, detected anomalies, and `mode_effective` (`"live"` or `"mock"`) so callers can tell a real bag analysis from a mock fixture. **Live mode** shells out to `ros2 bag info` and accepts `.mcap`, `.db3`, and `.bag` files plus `rosbag2_*` directories ; **mock mode** returns rich fixture data regardless of path suffix (except blatantly non-bag extensions). **Raises an MCP error** if the path is malformed, missing in live mode, or unparseable. Deep anomaly detection is mock-only at MVP. Read-only ; no side effects.

NameTypeReqDescription
pathstringyesPath to a ROS2 bag: a file ending in `.mcap`, `.db3`, or `.bag`, or a `rosbag2_*` directory. Leading/trailing whitespace is stripped. Null bytes and otherwise malformed filesystem paths are rejected.…
NameTypeReqDescription
anomaliesarrayHuman-readable notes about gaps, clock jumps, or other oddities. MVP populates this in mock mode; live anomaly detection is roadmap.
bag_formatConcrete bag container format detected by the reader — `mcap` (Foxglove MCAP), `db3` (ROS2 rosbag2 SQLite), `bag` (ROS1 legacy chunked), or `unknown` when the reader could not classify. `None` for th…
duration_secondsnumberyesTotal bag duration, in seconds (wall clock between first and last message).
message_countintegeryesTotal number of messages across all recorded topics.
mode_effectivestringyesRuntime mode the adapter actually served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Always carried by the response so a downstream LLM can distinguish a re…
participants_recordedarrayDDS participants recorded in the bag when the container format embeds participant metadata. MCAP can carry it via channel metadata records ; ROS2 `.db3` and ROS1 `.bag` generally do not. Empty list w…
pathstringyesPath to the analyzed bag, as supplied by the caller. May point to a file (`.mcap`, `.db3`, `.bag`) or to a `rosbag2_*` directory.
recording_duration_nsRecording duration in nanoseconds when readable from the bag's index. `None` when the v0.3.0 text-parsed path runs ; `duration_seconds` (float) is the always-populated fallback that downstream LLM co…
samples_decoded_countintegerTotal decoded sample count across all topics produced by the bag reader. `0` when the reader only parsed metadata (the v0.3.0 text-parsed path) or when `rosbags` is not installed on the host. Use `pe…
storage_format`mcap`, `sqlite3`, or other storage identifier when known.
topicsarrayyesPer-topic statistics for every topic present in the bag.

No examples provided.

detect_qos_mismatches ~251

Detect DDS QoS incompatibilities between reader and writer endpoints on the bus. Returns `list[MismatchReport]` — one entry per incompatible (reader, writer) pair, listing the policies that block or risk degrading communication (Reliability, Durability, History, Deadline at MVP). Each report carries `severity` (`incompatible` strictly blocks communication per the DDS spec ; `risky` may degrade but is not strictly blocked) and `mode_effective` (`"live"`/`"mock"`). Pass `topic` to scope to a single topic ; omit for an exhaustive scan. **Use this when** an LLM is debugging why a subscriber doesn't receive. **Read-only by architecture** — the analyzer compares observed QoS profiles ; no method on this tool can rewrite QoS or alter the bus. **Raises an MCP error** when no DDS module is active or, in v0.2.0, when the `CycloneDdsAdapter` stub is active ; mock backend returns deterministic fixtures.

NameTypeReqDescription
topicOptional topic name to scope the scan to (`/foo/bar` shape). `None` (default) returns all mismatches across all topics.
NameTypeReqDescription
resultarrayyes

No examples provided.

get_topic_info ~189

Return detailed info for a single ROS2 topic. `topic` must be a fully qualified topic name, e.g. `/cmd_vel`. Returns a `TopicInfo` carrying `mode_effective` (`"live"` or `"mock"`) so callers can distinguish a real-graph hit from a mock fixture. **Raises an MCP error** (isError=true) if the topic name is malformed or the topic is unknown to the active graph. Read-only ; no side effects.

NameTypeReqDescription
topicstringyesFully qualified ROS2 topic name starting with `/`, e.g. `/cmd_vel` or `/camera/image_raw`. Each `/`-separated segment must start with a letter or underscore and contain only letters, digits, and unde…
NameTypeReqDescription
message_typestringyesROS2 message type, e.g. `geometry_msgs/msg/Twist`.
mode_effectivestringyesRuntime mode the adapter actually served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Always carried by the response so a downstream LLM can distinguish a re…
namestringyesFully qualified topic name, e.g. `/cmd_vel`.
publisher_countintegeryesPublishers known to the graph.
qos_profileEffective DDS QoS profile for this topic when resolvable. `None` from the ROS2 CLI adapter or when the DDS module is inactive. The DDS module populates this on a best-effort basis (picks one represen…
qos_reliabilityQoS reliability policy if known: `reliable` or `best_effort`.
reader_countDDS reader-endpoint count when the active backend can resolve endpoint-level info (Cyclone / RTI). `None` from the ROS2 CLI adapter or when the DDS module is inactive.
subscriber_countintegeryesSubscribers known to the graph.
writer_countDDS writer-endpoint count when the active backend can resolve endpoint-level info. `None` from the ROS2 CLI adapter or when the DDS module is inactive.

No examples provided.

health_check ~116

Report TopicForge environment state — effective runtime mode (`"live"` or `"mock"`), whether the `ros2` CLI is on PATH, `ROS_DISTRO`, the server version, the server-side sample cap, the active DDS backend (`mock`/`cyclone`/`rti`/`none`), and the observed DDS domain id when applicable. Returns a `HealthReport`. **Always succeeds** — call this first when something looks wrong, since every other tool may raise. Read-only ; no side effects.

Input schema present but exposes no named parameters.

NameTypeReqDescription
dds_backendstringActive DDS module backend. `none` when the DDS module is not active (default for ROS2-only installs). `mock` for synthetic fixtures. **OSS tier** — `cyclone` requires `pip install topicforge[dds-cycl…
dds_domain_idDDS domain id observed when the DDS module is active.
max_sample_countintegeryesServer-side cap on the number of samples returned per `sample_messages` call. Requests above this limit are silently clamped; the value is exposed here so a client can size its requests proactively.…
middleware_availablebooleanWhether the configured DDS backend is importable. False when the DDS module is inactive (`dds_backend == 'none'`) or when the backend's Python bindings are not installed.
modestringyesEffective runtime mode: `mock` or `live`.
requested_modestringyesMode requested via configuration (may be `auto`).
ros2_availablebooleanyesWhether a `ros2` CLI is on PATH.
ros2_distroValue of `ROS_DISTRO` if set in the environment. **Env disclosure, by design** — under the local-trust threat model (see README 'Security model'), the MCP client is a trusted agent on a machine the u…
ros_backendstringActive ROS2 backend. `ros2_cli` when the `ros2` CLI is on PATH and live mode resolves to a Ros2CliAdapter (alone or as the ROS half of a composite). `mock` when MockAdapter serves the ROS surface. `n…
server_versionstringyesTopicForge server version (matches the PyPI release of the `topicforge` package).

No examples provided.

list_participants ~267

List DDS participants observed on a domain. Returns `list[ParticipantInfo]` — each entry carries `guid`, `vendor` (`cyclone`/`rti`/`mock`/`unknown`), optional `hostname`, `domain_id`, and `mode_effective` (`"live"`/`"mock"`). **Distinct from ROS2 graph nodes** — operates at the raw DDS layer beneath ROS, useful for non-ROS DDS stacks or for diagnosing why a participant isn't seen by the ROS graph. **Read-only by architecture** — the underlying `MiddlewareAdapter` protocol does not expose a write method, so this tool cannot publish, modify QoS, or alter the bus. **Raises an MCP error** when no DDS module is active (install `pip install topicforge[dds]` and set `TOPICFORGE_DDS_BACKEND=cyclone`). With the v0.2.0 `CycloneDdsAdapter` stub, also raises with a v0.2.x roadmap pointer ; mock backend returns deterministic fixtures.

NameTypeReqDescription
domain_idintegerDDS domain id to observe (0..232). Defaults to 0 — the same default used by `cyclonedds` and the implicit default of most ROS2 setups.
NameTypeReqDescription
resultarrayyes

No examples provided.

list_topics ~114

List every ROS2 topic on the current graph (or the deterministic mock graph in mock mode). Returns `list[TopicInfo]` — each entry carries `name`, `message_type`, `publisher_count`, `subscriber_count`, `qos_reliability`, and `mode_effective` (`"live"` or `"mock"`) so a downstream LLM can distinguish a real graph from demo fixtures. **Empty list** when the graph has no topics or when live discovery times out. Read-only ; no side effects.

Input schema present but exposes no named parameters.

NameTypeReqDescription
resultarrayyes

No examples provided.

participant_events ~407

Return DDS participant lifecycle events (`discovered` / `lost`) captured over a recent window. Use this when an LLM needs to answer *'who was on the bus 5 minutes ago and left?'* or *"when did this participant first appear?"*. Returns `list[ParticipantEvent]` — each entry carries `guid`, `event_type`, `vendor`, `timestamp_ns` (wall-clock ns since epoch), optional `hostname`, `domain_id`, and `mode_effective` (`"live"`/`"mock"`). Sorted newest-first. Hard cap at 200 events (silent truncation, mirrors `sample_messages`'s 50 cap — reduce `lookback_seconds` if you hit it). **Read-only by architecture** — the underlying `MiddlewareAdapter` protocol does not expose a write method. **Backend caveats**: Fast DDS captures arrivals AND removals via listener callbacks ; Cyclone tracks lifecycle only across `list_participants` calls (a participant that joined and left between two polls is invisible) ; mock returns a deterministic fixture timeline. **Raises an MCP error** when no DDS module is active (install `pip install topicforge[dds]` and set `TOPICFORGE_DDS_BACKEND=cyclone|fast`). Added in v0.4.0 Phase 1 — the 9th MCP tool ; v0.3.0 clients are unaffected until they call it.

NameTypeReqDescription
domain_idintegerDDS domain id to filter events on (0..232). Defaults to 0 — the same default used by `cyclonedds` and most ROS2 setups.
lookback_secondsintegerWindow (in seconds) over which to return events. Defaults to 300 (5 minutes). Range: 1..86400 (1 second to 24 hours). Larger windows may hit the 200-event cap — narrow the window or filter on `domain…
NameTypeReqDescription
resultarrayyes

No examples provided.

peek_bag_samples ~555

Peek up to `count` recent samples from a recorded bag file. **Distinct from `peek_dds_samples`** (live bus introspection) and `sample_messages` (ROS2 graph live peek) — this tool operates on **offline bag content** for post-mortem analysis. Supported formats: MCAP (`.mcap`), ROS2 rosbag2 SQLite (`.db3`), ROS1 legacy chunked binary (`.bag`). The reader auto-detects format from the file extension. Returns a `SampleResult` envelope identical in shape to `peek_dds_samples` — each sample's `payload` carries the same `_decode_status` annotation (`full` / `partial` / `raw`) so an LLM consumer reads one shape across live and recorded sources. `count` defaults to 5 and is silently clamped to 50. **Requires the `rosbags` library** (`pip install topicforge[bags]`) — without it, raises an `AdapterError` with the install command. The mock backend returns deterministic fixture samples on canned bag paths. **Read-only by architecture** — no method writes to the bag file. **Raises an MCP error** when the bag path does not exist, the topic is not present in the bag, or rosbags is not installed. Added in v0.4.0 Phase 3 — the 11th MCP tool ; 8-tool ceiling break #3, acknowledged in CHANGELOG.

NameTypeReqDescription
countintegerMaximum number of recent messages to return. Defaults to 5; silently clamped to 50 (the hard cap that keeps tool output bounded — read it from `health_check.max_sample_count`). Negative values raise…
pathstringyesPath to a ROS2 bag: a file ending in `.mcap`, `.db3`, or `.bag`, or a `rosbag2_*` directory. Leading/trailing whitespace is stripped. Null bytes and otherwise malformed filesystem paths are rejected.…
topicstringyesFully qualified ROS2 topic name starting with `/`, e.g. `/cmd_vel` or `/camera/image_raw`. Each `/`-separated segment must start with a letter or underscore and contain only letters, digits, and unde…
NameTypeReqDescription
countintegeryesNumber of samples actually returned. May be 0 (no publisher active in live mode, or empty mock fixture), less than the requested count (topic yielded fewer messages within the timeout), or capped by…
mode_effectivestringyesRuntime mode the adapter actually served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Always carried by the response so a downstream LLM can distinguish a re…
samplesarrayyesThe sampled messages, ordered as received from the backend.
topicstringyesTopic the samples were taken from, echoed from the request.

No examples provided.

peek_dds_samples ~548

Peek up to `count` recent samples on a raw DDS topic. **Distinct from `sample_messages`** — `sample_messages` operates on the ROS2 graph via `ros2 topic echo` ; this tool reads directly from the DDS layer (Cyclone / Fast / RTI / mock). Use this for non-ROS DDS topics or when the ROS2 CLI is not available. Returns a `SampleResult` envelope `{topic, count, samples, mode_effective}` — identical shape to `sample_messages`. `count` defaults to 5 and is silently clamped to 50. **Topic categories** (v0.4.0 Phase 1): (a) The 4 builtin DCPS topics (`DCPSParticipant`, `DCPSSubscription`, `DCPSPublication`) always return structured discovery payloads. (b) User-defined topics return best-effort decoded payloads — each sample's payload may carry `_decode_status` (`full`/`partial`/`raw`), `_decode_note` (short diagnostic when not `full`), and `_raw_bytes_hex` (serialized-bytes preview). **Caveat**: on the current user-topic `raw` path this preview is empty — a `raw` status means 'topic present on the bus but not decoded', not 'here are the bytes to re-decode' (capturing the on-wire CDR bytes is roadmapped). Cyclone uses `cyclonedds.dynamic` for full/partial decode ; Fast DDS 2.6.x lands on the raw path more often because its dynamic XTypes binding is partial. **Read-only by architecture** — the `MiddlewareAdapter` protocol does not expose a write method. **Raises an MCP error** when no DDS module is active OR when the topic is not announced on the bus.

NameTypeReqDescription
countintegerMaximum number of recent messages to return. Defaults to 5; silently clamped to 50 (the hard cap that keeps tool output bounded — read it from `health_check.max_sample_count`). Negative values raise…
topicstringyesFully qualified ROS2 topic name starting with `/`, e.g. `/cmd_vel` or `/camera/image_raw`. Each `/`-separated segment must start with a letter or underscore and contain only letters, digits, and unde…
NameTypeReqDescription
countintegeryesNumber of samples actually returned. May be 0 (no publisher active in live mode, or empty mock fixture), less than the requested count (topic yielded fewer messages within the timeout), or capped by…
mode_effectivestringyesRuntime mode the adapter actually served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Always carried by the response so a downstream LLM can distinguish a re…
samplesarrayyesThe sampled messages, ordered as received from the backend.
topicstringyesTopic the samples were taken from, echoed from the request.

No examples provided.

sample_messages ~485

Peek up to `count` recent ROS2 messages from `topic`, sampled from the runtime graph. `topic` must be a fully qualified name (see the `topic` parameter description). `count` defaults to 5 and is silently clamped to 50 — request more and you receive at most 50 without warning. Returns a `SampleResult` envelope `{topic, count, samples, mode_effective}` where `count` is the actual number of samples returned (may be 0) and `mode_effective` is `"live"` or `"mock"`. **Live mode** shells out to `ros2 topic echo --csv --once` with a short timeout, so the result is empty when no publisher is currently active. `samples[i].timestamp_ns` is the message's `header.stamp` (publish time) when the message is `Header`-stamped, and 0 for headerless types (e.g. `std_msgs/String`). The live parser exposes fields as positional CSV columns under `samples[i].payload` keys `col_0`, `col_1`, ..., with the verbatim CSV row under the reserved `_raw_text` key. **Mock mode** returns deterministic samples with monotonically increasing timestamps for the fictional demo robot (and no `_raw_text` key, since the payload is already structured). Read-only ; never publishes to the bus. **Distinct from `peek_dds_samples`** — that tool reads the raw DDS layer ; this one reads the ROS2 graph.

NameTypeReqDescription
countintegerMaximum number of recent messages to return. Defaults to 5; silently clamped to 50 (the hard cap that keeps tool output bounded — read it from `health_check.max_sample_count`). Negative values raise…
topicstringyesFully qualified ROS2 topic name starting with `/`, e.g. `/cmd_vel` or `/camera/image_raw`. Each `/`-separated segment must start with a letter or underscore and contain only letters, digits, and unde…
NameTypeReqDescription
countintegeryesNumber of samples actually returned. May be 0 (no publisher active in live mode, or empty mock fixture), less than the requested count (topic yielded fewer messages within the timeout), or capped by…
mode_effectivestringyesRuntime mode the adapter actually served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Always carried by the response so a downstream LLM can distinguish a re…
samplesarrayyesThe sampled messages, ordered as received from the backend.
topicstringyesTopic the samples were taken from, echoed from the request.

No examples provided.

topic_metrics ~483

Return temporal metrics (frequency, sequence gaps, latency percentiles) for a DDS topic over a recent time window. Use this when an LLM needs to diagnose *'is this topic actually publishing at the rate its QoS Deadline declares?'*, *'are there missing sequence numbers?'*, or *'what is the p99 latency on this topic?'*. Returns a `TopicMetrics` payload carrying `samples_observed`, `frequency_hz_observed`, `frequency_hz_declared` (from QoS Deadline when known), `sequence_gaps_count`, `latency_ns_p50/p95/p99`, and boolean availability flags. **Opportunistic fill caveat**: the metrics buffer accumulates samples only as `peek_dds_samples` flows them through the adapter — neither cyclonedds nor fastdds 2.6.x Python bindings expose at-sample-receive callbacks, so a topic that hasn't been peeked recently returns `samples_observed=0`. To get useful metrics, call `peek_dds_samples` on the topic first, then this tool. **Read-only by architecture** — no method on this tool writes to the bus. **Raises an MCP error** when no DDS module is active or `window_seconds` is out of range (1..3600). Added in v0.4.0 Phase 2 ; the 10th MCP tool — the 8-tool ceiling from mcp-02-spec.md §2 was first broken at Phase 1 (`participant_events`), this is the second explicit acknowledgement.

NameTypeReqDescription
domain_idintegerDDS domain id to scope the metrics to (0..232). Defaults to 0 — the same default as the rest of the DDS tools.
topicstringyesFully qualified ROS2 topic name starting with `/`, e.g. `/cmd_vel` or `/camera/image_raw`. Each `/`-separated segment must start with a letter or underscore and contain only letters, digits, and unde…
window_secondsintegerWindow in seconds over which to compute metrics (1..3600). Defaults to 60 seconds. Smaller windows reflect more recent state ; larger windows smooth transient anomalies.
NameTypeReqDescription
frequency_hz_declaredDeclared frequency extracted from the topic's QoS Deadline policy when the adapter resolved it (Deadline period → 1 / period_seconds). `None` when the QoS profile does not include Deadline or the ada…
frequency_hz_observed`samples_observed / window_seconds_actual`. `None` when fewer than 2 samples were observed (a single sample does not define a frequency).
latency_availablebooleanTrue when at least one sample in the window carried both a publish timestamp and a receive timestamp. The percentile fields are `None` when this is False.
latency_ns_p50Median publish-to-receive latency in nanoseconds, computed only when the sample type exposes a publish timestamp (typically via `header.stamp` on `Header`-stamped messages). `None` when `latency_avai…
latency_ns_p9595th-percentile publish-to-receive latency (ns).
latency_ns_p9999th-percentile publish-to-receive latency (ns).
mode_effectivestringyesRuntime mode the adapter actually served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Always carried by the response so a downstream LLM can distinguish a re…
samples_observedintegeryesNumber of samples in the buffer matching `topic` within the window. `0` means TopicForge has not seen any sample on this topic recently — it does NOT mean the topic has no publisher, only that no `pe…
sequence_gaps_countintegerNumber of missing sequence numbers detected in the buffered samples. `0` either means no gaps observed OR the sample type did not expose a sequence number (check `sequence_numbers_available` to disam…
sequence_numbers_availablebooleanTrue when the adapter successfully extracted sequence numbers from at least one sample. Sequence number support depends on the message type — `Header`-stamped messages with a `seq` field expose it ;…
topicstringyesTopic the metrics were computed for.
window_secondsintegeryesRequested window in seconds (1..3600). Echoed back from the tool call so the LLM can correlate the request.
window_seconds_actualnumberyesActual elapsed seconds within the window. May be smaller than `window_seconds` when the adapter buffered samples for less time than the requested window (e.g., the server just started). `0.0` when `s…

No examples provided.

Common questions

What is the TopicForge MCP server?

TopicForge is an MCP server listed in the public MCP registry as io.github.yaniswav/topicforge. Read-only MCP server for ROS2 and DDS: topics, participants, QoS mismatches, bags. This page covers its PyPI package (topicforge).

Is the TopicForge MCP server safe to use?

TopicForge scores 74 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the TopicForge MCP server expose?

TopicForge exposes 11 tools: health_check, list_topics, get_topic_info, sample_messages, analyze_bag, and 6 more. Their descriptions and schemas cost roughly 3,659 tokens of context every time the server is loaded.

Is the TopicForge MCP server still maintained?

TopicForge is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.