Skip to main content
Glama

topic_metrics

Read-onlyIdempotent

Return temporal metrics—frequency, sequence gaps, and latency percentiles—for a DDS topic over a recent window, plus status flags that show when data is unsupported or insufficient.

Instructions

Return temporal metrics (frequency, sequence gaps, latency percentiles) for a DDS topic over a recent window as a TopicMetrics. Read status first: unsupported_user_topic means the payload is not decoded, so no metric exists: every null or 0 is not a measurement; no_samples_yet is too little buffered or read. Limits: frequency_basis reader_arrivals (decoding on) is a real publish rate from a bounded read of up to 10 s; otherwise the buffer fills only when peek_dds_samples runs, so observed_frequency_hz is how often it was called. declared_frequency_hz is 1 / deadline of the shortest writer Deadline announced in discovery (declared, not measured; null when none). Also sequence_gaps_count, latency_ns_p50/p95/p99 and availability flags. Read-only by architecture. Raises an MCP error when no DDS module is active or window_s is outside 1..3600. Right after start the call waits up to 3 s for discovery. Duration: DDS lock, one call at a time, ends within 45 s; busy if held.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "topic": "<topic>"
    },
    "name": "topic_metrics"
  }
}

Input Schema

NameRequiredDescriptionDefault
topicYesDDS topic name: bare (`scan`), ROS 2 mangled (`rt/scan`) or a builtin discovery topic (`DCPSParticipant`, `DCPSSubscription`, `DCPSPublication`). Letters, digits, `_`, `/` and `::` only.
window_sNoWindow in seconds, 1..3600, default 60.
domain_idNoIgnored: it does not switch domains and is only range-checked (0..232). The domain observed is the one joined at startup (`TOPICFORGE_DDS_DOMAIN_ID`), reported in the response `domain_id`; `note` flags a different non-zero value.

Output Schema

NameRequiredDescriptionDefault
noteNoOne sentence of context, or `None`.
topicYes
statusNo`ok`; `no_samples_yet`; `unsupported_user_topic` (payload not decoded).
window_sYesRequested window in seconds (echoed).
latency_ns_p50NoMedian publish-to-receive latency in ns; `None` unless `latency_available`.
latency_ns_p95No95th-percentile publish-to-receive latency (ns).
latency_ns_p99No99th-percentile publish-to-receive latency (ns).
mode_effectiveYes`live` or `mock` (fixtures).
frequency_basisNoWhat the rate measures.
window_actual_sYesSeconds actually covered; shorter than `window_s` after a recent start; `0.0` without samples.
samples_observedYesSamples buffered or read. `0` does NOT mean no publisher, only that no peek or read captured one.
latency_availableNoTrue when a sample carried both a publish and a receive timestamp.
sequence_gaps_countNoMissing sequence numbers in the buffered samples; `0` also when none exist (see `sequence_numbers_available`).
declared_frequency_hzNo`1 / deadline` of the shortest announced writer Deadline: promised, not observed; `None` when none announced.
observed_frequency_hzNoSee `frequency_basis`; `None` under 2 samples.
sequence_numbers_availableNoTrue when a sequence number could be read from a sample.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changedv0.10.0
    • addedOutput schema / properties / frequency_basis
      Added value: +{
      +  "description": "What the rate measures.",
      +  "enum": [
      +    "peek_cadence",
      +    "reader_arrivals",
      +    null
      +  ],
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • changedOutput schema / properties / observed_frequency_hz / description
      Previous value: -"`samples_observed / window_actual_s`; `None` under 2 samples."New value: +"See `frequency_basis`; `None` under 2 samples."
    • changedOutput schema / properties / samples_observed / description
      Previous value: -"Samples buffered in the window. `0` does NOT mean no publisher, only that no `peek_dds_samples` call captured one."New value: +"Samples buffered or read. `0` does NOT mean no publisher, only that no peek or read captured one."
    • changedOutput schema / properties / status / description
      Previous value: -"`ok`; `no_samples_yet` (empty buffer); `unsupported_user_topic` (payload not decoded: null fields are not measurements)."New value: +"`ok`; `no_samples_yet`; `unsupported_user_topic` (payload not decoded)."
  2. Changed1 schema field changedv0.9.0
    • changedOutput schema / properties / declared_frequency_hz / description
      Previous value: -"`1 / deadline` of the shortest writer Deadline announced: the promised rate, not the observed one; `None` when none announced."New value: +"`1 / deadline` of the shortest announced writer Deadline: promised, not observed; `None` when none announced."
  3. Changed25 schema fields changedv0.8.0
    • removedOutput schema / properties / declared_frequency_hz / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / declared_frequency_hz / default
      Removed value: -null
    • addedOutput schema / properties / declared_frequency_hz / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / properties / latency_available / default
      Removed value: -false
    • removedOutput schema / properties / latency_ns_p50 / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / latency_ns_p50 / default
      Removed value: -null
    • addedOutput schema / properties / latency_ns_p50 / minimum
      Added value: +0
    • addedOutput schema / properties / latency_ns_p50 / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / properties / latency_ns_p95 / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / latency_ns_p95 / default
      Removed value: -null
    • addedOutput schema / properties / latency_ns_p95 / minimum
      Added value: +0
    • addedOutput schema / properties / latency_ns_p95 / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / properties / latency_ns_p99 / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / latency_ns_p99 / default
      Removed value: -null
    • addedOutput schema / properties / latency_ns_p99 / minimum
      Added value: +0
    • addedOutput schema / properties / latency_ns_p99 / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / properties / note / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / note / default
      Removed value: -null
    • addedOutput schema / properties / note / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / observed_frequency_hz / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / observed_frequency_hz / default
      Removed value: -null
    • addedOutput schema / properties / observed_frequency_hz / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / properties / sequence_gaps_count / default
      Removed value: -0
    • removedOutput schema / properties / sequence_numbers_available / default
      Removed value: -false
    • removedOutput schema / properties / status / default
      Removed value: -"ok"
  4. Changed36 schema fields changedv0.7.1
    • changedInput schema / properties / domain_id / description
      Previous value: -"Accepted for compatibility (0..232). TopicForge observes the domain it joined at startup (TOPICFORGE_DDS_DOMAIN_ID); this argument does not switch domains, and the response `domain_id` says which one was observed."New value: +"Ignored: it does not switch domains and is only range-checked (0..232). The domain observed is the one joined at startup (`TOPICFORGE_DDS_DOMAIN_ID`), reported in the response `domain_id`; `note` flags a different non-zero value."
    • removedInput schema / properties / domain_id / title
      Removed value: -"Domain Id"
    • changedInput schema / properties / topic / description
      Previous value: -"DDS topic name. Bare DDS names such as `scan` are valid, as are ROS 2 mangled names such as `rt/scan` and the builtin discovery topics `DCPSParticipant`, `DCPSSubscription`, `DCPSPublication`. Letters, digits, `_`, `/` and `::` are allowed; anything else is rejected."New value: +"DDS topic name: bare (`scan`), ROS 2 mangled (`rt/scan`) or a builtin discovery topic (`DCPSParticipant`, `DCPSSubscription`, `DCPSPublication`). Letters, digits, `_`, `/` and `::` only."
    • removedInput schema / properties / topic / title
      Removed value: -"Topic"
    • addedInput schema / properties / window_s
      Added value: +{
      +  "default": 60,
      +  "description": "Window in seconds, 1..3600, default 60.",
      +  "maximum": 3600,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • removedInput schema / properties / window_seconds
      Removed value: -{
      -  "default": 60,
      -  "description": "Window in seconds over which to compute metrics (1..3600). Defaults to 60 seconds. Smaller windows reflect more recent state; larger windows smooth transient anomalies.",
      -  "maximum": 3600,
      -  "minimum": 1,
      -  "title": "Window Seconds",
      -  "type": "integer"
      -}
    • removedInput schema / title
      Removed value: -"topic_metricsArguments"
    • changedOutput schema / description
      Previous value: -"Temporal metrics for a single DDS topic over a recent window.\n\nBuilt from samples that pass through `peek_dds_samples`. The buffer is\nfilled on demand because neither the `cyclonedds` nor the `fastdds`\nPython binding has a reliable per-sample callback, so a burst between two\ncalls is not seen.\n\nNumeric fields are `None` (`0` for `sequence_gaps_count`) when the data is\nmissing: no samples, no source timestamps, no sequence number in the\npayload. `samples_observed=0` is a valid result, not an error."New value: +"Temporal metrics for a single DDS topic over a recent window."
    • addedOutput schema / properties / declared_frequency_hz
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "`1 / deadline` of the shortest writer Deadline announced: the promised rate, not the observed one; `None` when none announced."
      +}
    • removedOutput schema / properties / frequency_hz_declared
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "number"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Declared, not measured: `1 / deadline` for the shortest QoS Deadline period announced by a writer on this topic in discovery. `None` when no writer announced a finite Deadline or the topic is not announced. It is the rate the application promised, not the rate observed.",
      -  "title": "Frequency Hz Declared"
      -}
    • removedOutput schema / properties / frequency_hz_observed
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "number"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "`samples_observed / window_seconds_actual`. `None` when fewer than 2 samples were observed (a single sample does not define a frequency).",
      -  "title": "Frequency Hz Observed"
      -}
    • changedOutput schema / properties / latency_available / description
      Previous value: -"True 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."New value: +"True when a sample carried both a publish and a receive timestamp."
    • removedOutput schema / properties / latency_available / title
      Removed value: -"Latency Available"
    • changedOutput schema / properties / latency_ns_p50 / description
      Previous value: -"Median 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_available=False`."New value: +"Median publish-to-receive latency in ns; `None` unless `latency_available`."
    • removedOutput schema / properties / latency_ns_p50 / title
      Removed value: -"Latency Ns P50"
    • removedOutput schema / properties / latency_ns_p95 / title
      Removed value: -"Latency Ns P95"
    • removedOutput schema / properties / latency_ns_p99 / title
      Removed value: -"Latency Ns P99"
    • changedOutput schema / properties / mode_effective / description
      Previous value: -"Runtime mode the adapter served this response in: `live` (real ROS2 introspection) or `mock` (deterministic fixtures). Lets a caller tell a real graph from a demo one without calling `health_check`."New value: +"`live` or `mock` (fixtures)."
    • removedOutput schema / properties / mode_effective / title
      Removed value: -"Mode Effective"
    • addedOutput schema / properties / note
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "One sentence of context, or `None`."
      +}
    • addedOutput schema / properties / observed_frequency_hz
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "`samples_observed / window_actual_s`; `None` under 2 samples."
      +}
    • changedOutput schema / properties / samples_observed / description
      Previous value: -"Number 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 `peek_dds_samples` call captured one in the window."New value: +"Samples buffered in the window. `0` does NOT mean no publisher, only that no `peek_dds_samples` call captured one."
    • removedOutput schema / properties / samples_observed / title
      Removed value: -"Samples Observed"
    • changedOutput schema / properties / sequence_gaps_count / description
      Previous value: -"Number 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 disambiguate)."New value: +"Missing sequence numbers in the buffered samples; `0` also when none exist (see `sequence_numbers_available`)."
    • removedOutput schema / properties / sequence_gaps_count / title
      Removed value: -"Sequence Gaps Count"
    • changedOutput schema / properties / sequence_numbers_available / description
      Previous value: -"True 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; primitives like `std_msgs/String` do not."New value: +"True when a sequence number could be read from a sample."
    • removedOutput schema / properties / sequence_numbers_available / title
      Removed value: -"Sequence Numbers Available"
    • changedOutput schema / properties / status / description
      Previous value: -"How to read the numbers. `unsupported_user_topic`: the topic is a user topic, whose payload is not decoded, so no metric exists and the null fields are not a measurement. `no_samples_yet`: a supported topic with nothing buffered in the window. `ok`: metrics computed from buffered samples."New value: +"`ok`; `no_samples_yet` (empty buffer); `unsupported_user_topic` (payload not decoded: null fields are not measurements)."
    • removedOutput schema / properties / status / title
      Removed value: -"Status"
    • removedOutput schema / properties / topic / description
      Removed value: -"Topic the metrics were computed for."
    • removedOutput schema / properties / topic / title
      Removed value: -"Topic"
    • addedOutput schema / properties / window_actual_s
      Added value: +{
      +  "description": "Seconds actually covered; shorter than `window_s` after a recent start; `0.0` without samples.",
      +  "minimum": 0,
      +  "type": "number"
      +}
    • addedOutput schema / properties / window_s
      Added value: +{
      +  "description": "Requested window in seconds (echoed).",
      +  "maximum": 3600,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • removedOutput schema / properties / window_seconds
      Removed value: -{
      -  "description": "Requested window in seconds (1..3600). Echoed back from the tool call so the LLM can correlate the request.",
      -  "maximum": 3600,
      -  "minimum": 1,
      -  "title": "Window Seconds",
      -  "type": "integer"
      -}
    • removedOutput schema / properties / window_seconds_actual
      Removed value: -{
      -  "description": "Actual 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 `samples_observed=0`.",
      -  "minimum": 0,
      -  "title": "Window Seconds Actual",
      -  "type": "number"
      -}
    • changedOutput schema / required
      Previous value: -[
      -  "topic",
      -  "window_seconds",
      -  "window_seconds_actual",
      -  "samples_observed",
      -  "mode_effective"
      -]New value: +[
      +  "topic",
      +  "window_s",
      +  "window_actual_s",
      +  "samples_observed",
      +  "mode_effective"
      +]
  5. First observedv0.5.6

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only/idempotent/non-destructive, and the description adds substantial context beyond them: the `frequency_basis` distinction (real publish rate vs. how often `peek_dds_samples` ran), that `declared_frequency_hz` is declared not measured, error conditions (no DDS module, `window_s` out of range), a 3 s discovery wait after start, a 45 s duration bound with a single DDS lock and `busy` outcome.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose, then status handling, limits, errors, and timing in bold-labeled blocks, so an agent can scan to what it needs. It is dense and long for a three-parameter tool, with several clauses packed into single sentences, but almost every sentence carries non-redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and the description still covers the interpretation-critical statuses, measurement caveats, error paths, and timing/locking behavior. Nothing an agent needs to call this correctly or read the result safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description goes further by tying `window_s` to an error condition (outside 1..3600) and to the bounded 10 s read that governs `frequency_basis`, and by reinforcing that `domain_id` is range-checked but not honored. It adds behavioral meaning to parameters rather than restating their types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a specific verb and resource ('Return temporal metrics ... for a DDS topic over a recent window') and enumerates the metrics (frequency, sequence gaps, latency percentiles) plus the return type `TopicMetrics`. This clearly separates it from siblings like `peek_dds_samples` (raw samples) and `get_topic_info` (metadata).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit preconditions and interpretation rules ('Read `status` first', `unsupported_user_topic` means no metric exists, `no_samples_yet` is too little buffered), and explains the relationship to `peek_dds_samples` filling the buffer. What is missing is direct routing guidance — it never states when to prefer `get_topic_info` or `peek_dds_samples` over this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.