Skip to main content
Glama

get_topic_info

Read-onlyIdempotent

Retrieve details for a fully qualified ROS 2 topic, including publisher and subscriber counts, QoS reliability/durability, and node names, to inspect graph state and identify latched topics.

Instructions

ROS 2 graph only; on a DDS-only setup use list_endpoints. Describe one ROS 2 topic (fully qualified, e.g. /cmd_vel) as a TopicInfo: counts and, in live mode, publisher_qos / subscription_qos (reliability, durability where transient_local marks a latched topic such as /tf_static, endpoint_count; a null side says why in its _note) and publisher_nodes / subscriber_nodes. Raises an MCP error for a malformed or unknown topic, or without a ros2 CLI. Duration: ROS 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": "get_topic_info"
  }
}

Input Schema

NameRequiredDescriptionDefault
topicYesFully qualified ROS 2 topic name starting with `/`, e.g. `/cmd_vel`. Segments are letters, digits and underscores (not starting with a digit); anything else is rejected before reaching the `ros2` CLI.

Output Schema

NameRequiredDescriptionDefault
nameYes
noteNoOne sentence of context, or `None`.
message_typeYes
publisher_qosNoQoS of the publishers. `None` when it was not read: see `publisher_qos_note`.
mode_effectiveYes`live` or `mock` (fixtures).
publisher_countYes
publisher_nodesNoPublisher node names (`ros2 topic info --verbose`); empty when unknown.
subscriber_countYes
subscriber_nodesNoSubscriber node names; empty when unknown.
subscription_qosNoQoS of the subscriptions. `None` when it was not read: see `subscription_qos_note`.
publisher_qos_noteNoWhy `publisher_qos` is `None`. `None` when it is set.
subscription_qos_noteNoWhy `subscription_qos` is `None`. `None` when it is set.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed11 schema fields changedv0.8.0
    • 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 / publisher_qos / default
      Removed value: -null
    • removedOutput schema / properties / publisher_qos_note / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / publisher_qos_note / default
      Removed value: -null
    • addedOutput schema / properties / publisher_qos_note / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / subscription_qos / default
      Removed value: -null
    • removedOutput schema / properties / subscription_qos_note / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / subscription_qos_note / default
      Removed value: -null
    • addedOutput schema / properties / subscription_qos_note / type
      Added value: +[
      +  "string",
      +  "null"
      +]
  2. Changed28 schema fields changedv0.7.1
    • changedInput schema / properties / topic / description
      Previous value: -"Fully 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 underscores; everything else (whitespace, quotes, shell metacharacters, `//`, trailing `/`) is rejected before reaching the `ros2` CLI."New value: +"Fully qualified ROS 2 topic name starting with `/`, e.g. `/cmd_vel`. Segments are letters, digits and underscores (not starting with a digit); anything else is rejected before reaching the `ros2` CLI."
    • removedInput schema / properties / topic / title
      Removed value: -"Topic"
    • removedInput schema / title
      Removed value: -"get_topic_infoArguments"
    • removedOutput schema / $defs / QosProfile
      Removed value: -{
      -  "additionalProperties": false,
      -  "description": "QoS profile of one DDS endpoint (reader or writer).\n\nCovers the policies behind most \"subscriber receives nothing\" cases.\nVendor-specific extensions are ignored.",
      -  "properties": {
      -    "data_representation": {
      -      "anyOf": [
      -        {
      -          "items": {
      -            "type": "string"
      -          },
      -          "type": "array"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Data representations the endpoint accepts or offers, from `XCDR1` and `XCDR2`. `None` when not announced.",
      -      "title": "Data Representation"
      -    },
      -    "deadline_ns": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Deadline QoS in nanoseconds. `None` means no deadline (infinite, the DDS default). A reader deadline tighter (smaller) than a writer deadline is incompatible: the writer cannot guarantee the reader's promise.",
      -      "title": "Deadline Ns"
      -    },
      -    "destination_order": {
      -      "anyOf": [
      -        {
      -          "enum": [
      -            "BY_RECEPTION_TIMESTAMP",
      -            "BY_SOURCE_TIMESTAMP"
      -          ],
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "DestinationOrder QoS. `None` when not announced.",
      -      "title": "Destination Order"
      -    },
      -    "durability": {
      -      "description": "DDS Durability QoS. `VOLATILE` writers do not retain samples for late joiners; `TRANSIENT_LOCAL` writers do. A `TRANSIENT_LOCAL` reader cannot match a `VOLATILE` writer.",
      -      "enum": [
      -        "VOLATILE",
      -        "TRANSIENT_LOCAL",
      -        "TRANSIENT",
      -        "PERSISTENT"
      -      ],
      -      "title": "Durability",
      -      "type": "string"
      -    },
      -    "history": {
      -      "anyOf": [
      -        {
      -          "enum": [
      -            "KEEP_LAST",
      -            "KEEP_ALL"
      -          ],
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "DDS History QoS. `KEEP_LAST` keeps a bounded ring buffer of size `history_depth`; `KEEP_ALL` keeps every sample (memory permitting). Mixed `KEEP_ALL` reader with `KEEP_LAST` writer is risky but not strictly incompatible. `None` when it is not known: DDS discovery does not carry History, so it is reported only for TopicForge's own endpoints and for Cyclone DDS peers that set something other than the default (see `history_note`).",
      -      "title": "History"
      -    },
      -    "history_depth": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Depth for `KEEP_LAST`. `None` for `KEEP_ALL` or when `history` is `None`.",
      -      "title": "History Depth"
      -    },
      -    "history_note": {
      -      "anyOf": [
      -        {
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Set when `history` was left out because discovery did not announce it.",
      -      "title": "History Note"
      -    },
      -    "latency_budget_ns": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "LatencyBudget QoS in nanoseconds (a delivery-delay hint). `0` is the DDS default. `None` means infinite or not announced.",
      -      "title": "Latency Budget Ns"
      -    },
      -    "liveliness_kind": {
      -      "anyOf": [
      -        {
      -          "enum": [
      -            "AUTOMATIC",
      -            "MANUAL_BY_PARTICIPANT",
      -            "MANUAL_BY_TOPIC"
      -          ],
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Liveliness QoS kind. `AUTOMATIC` is asserted by the middleware; the two `MANUAL_*` kinds need the application to write or assert liveliness, and the endpoint is declared not alive when it does not within `liveliness_lease_ns`. `None` when not announced.",
      -      "title": "Liveliness Kind"
      -    },
      -    "liveliness_lease_ns": {
      -      "anyOf": [
      -        {
      -          "minimum": 0,
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Liveliness lease duration in nanoseconds. `None` means infinite (the DDS default) or not announced.",
      -      "title": "Liveliness Lease Ns"
      -    },
      -    "ownership_kind": {
      -      "anyOf": [
      -        {
      -          "enum": [
      -            "SHARED",
      -            "EXCLUSIVE"
      -          ],
      -          "type": "string"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Ownership QoS kind. With `EXCLUSIVE`, only the writer with the highest `ownership_strength` delivers samples to a reader. `None` when not announced.",
      -      "title": "Ownership Kind"
      -    },
      -    "ownership_strength": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Ownership strength of a writer (`EXCLUSIVE` ownership). `None` when not announced.",
      -      "title": "Ownership Strength"
      -    },
      -    "partitions": {
      -      "anyOf": [
      -        {
      -          "items": {
      -            "type": "string"
      -          },
      -          "type": "array"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Partition names the endpoint's Publisher or Subscriber belongs to. No Partition policy is the default partition, reported as `[\"\"]` (never an empty list). Endpoints only match when their partitions intersect. `None` only when the backend cannot read partitions at all (unknown, not the default).",
      -      "title": "Partitions"
      -    },
      -    "reliability": {
      -      "description": "DDS Reliability QoS. `RELIABLE` retries lost samples; `BEST_EFFORT` does not. A `RELIABLE` reader cannot match a `BEST_EFFORT` writer.",
      -      "enum": [
      -        "RELIABLE",
      -        "BEST_EFFORT"
      -      ],
      -      "title": "Reliability",
      -      "type": "string"
      -    },
      -    "unknown_policies": {
      -      "anyOf": [
      -        {
      -          "items": {
      -            "type": "string"
      -          },
      -          "type": "array"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "default": null,
      -      "description": "Policies the endpoint announced but whose value could not be read (for example `Deadline`). Their duration fields are `None` here, which does NOT mean infinite for these: the scan does not compare them.",
      -      "title": "Unknown Policies"
      -    }
      -  },
      -  "required": [
      -    "reliability",
      -    "durability"
      -  ],
      -  "title": "QosProfile",
      -  "type": "object"
      -}
    • addedOutput schema / $defs / SideQos
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "durability": {
      +      "description": "Shared durability of this side, or `mixed`; `transient_local` marks a latched topic such as `/tf_static`.",
      +      "enum": [
      +        "volatile",
      +        "transient_local",
      +        "mixed"
      +      ],
      +      "type": "string"
      +    },
      +    "endpoint_count": {
      +      "description": "Endpoints of this side the values were read from.",
      +      "minimum": 1,
      +      "type": "integer"
      +    },
      +    "reliability": {
      +      "description": "Reliability shared by the endpoints of this side, or `mixed` when they disagree.",
      +      "enum": [
      +        "reliable",
      +        "best_effort",
      +        "mixed"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "reliability",
      +    "durability",
      +    "endpoint_count"
      +  ],
      +  "type": "object"
      +}
    • changedOutput schema / description
      Previous value: -"Description of a single ROS2 topic.\n\nCarries optional DDS-side enrichment fields when the active middleware\nbackend can resolve them (CycloneDDS / Fast DDS). The ROS2 CLI adapter and\nthe mock ROS2 path leave them `None`."New value: +"Detail of a single ROS2 topic: counts, QoS per side and the nodes on each side."
    • removedOutput schema / properties / message_type / description
      Removed value: -"ROS2 message type, e.g. `geometry_msgs/msg/Twist`."
    • removedOutput schema / properties / message_type / title
      Removed value: -"Message Type"
    • 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"
    • removedOutput schema / properties / name / description
      Removed value: -"Fully qualified topic name, e.g. `/cmd_vel`."
    • removedOutput schema / properties / name / title
      Removed value: -"Name"
    • addedOutput schema / properties / note
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "One sentence of context, or `None`."
      +}
    • removedOutput schema / properties / publisher_count / description
      Removed value: -"Publishers known to the graph."
    • removedOutput schema / properties / publisher_count / title
      Removed value: -"Publisher Count"
    • addedOutput schema / properties / publisher_nodes
      Added value: +{
      +  "description": "Publisher node names (`ros2 topic info --verbose`); empty when unknown.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / publisher_qos
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/SideQos"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "QoS of the publishers. `None` when it was not read: see `publisher_qos_note`."
      +}
    • addedOutput schema / properties / publisher_qos_note
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Why `publisher_qos` is `None`. `None` when it is set."
      +}
    • removedOutput schema / properties / qos_durability
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Durability announced by the topic's publishers: `volatile`, `transient_local` (late subscribers receive the last samples; typical of latched topics such as `/tf_static`), or `mixed` when publishers disagree. `null` when unknown, with the same rules as `qos_reliability`.",
      -  "title": "Qos Durability"
      -}
    • removedOutput schema / properties / qos_profile
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "$ref": "#/$defs/QosProfile"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Effective 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 representative endpoint if reader/writer QoS differ)."
      -}
    • removedOutput schema / properties / qos_reliability
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Reliability announced by the topic's publishers: `reliable`, `best_effort`, or `mixed` when publishers disagree. `null` when unknown: the topic has no publisher, or the value was not read (`list_topics` does not read QoS; `get_topic_info` does).",
      -  "title": "Qos Reliability"
      -}
    • removedOutput schema / properties / reader_count
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "DDS reader-endpoint count when the active backend can resolve endpoint-level info (Cyclone / Fast DDS). `None` from the ROS2 CLI adapter or when the DDS module is inactive.",
      -  "title": "Reader Count"
      -}
    • removedOutput schema / properties / subscriber_count / description
      Removed value: -"Subscribers known to the graph."
    • removedOutput schema / properties / subscriber_count / title
      Removed value: -"Subscriber Count"
    • addedOutput schema / properties / subscriber_nodes
      Added value: +{
      +  "description": "Subscriber node names; empty when unknown.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / subscription_qos
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/SideQos"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "QoS of the subscriptions. `None` when it was not read: see `subscription_qos_note`."
      +}
    • addedOutput schema / properties / subscription_qos_note
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Why `subscription_qos` is `None`. `None` when it is set."
      +}
    • removedOutput schema / properties / writer_count
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "minimum": 0,
      -      "type": "integer"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "DDS 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.",
      -  "title": "Writer Count"
      -}
  3. First observedv0.5.6

TDQS

A4.6/5.0
Behavior5/5

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

Beyond the read-only and idempotent annotations, it discloses errors for malformed or unknown topics and a missing `ros2` CLI, live-only QoS fields, explanatory `null` `_note` values, and the significance of `transient_local`. It also documents serialized ROS locking, a 45-second bound, and `busy` behavior when the lock is held.

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?

Scope and sibling routing are front-loaded, followed by purpose, failure modes, and timing in a logical order. The definition is information-dense and generally useful, but the long nested `TopicInfo`/QoS sentence is harder to scan and explains return fields despite the presence of an output schema.

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?

For a one-parameter read tool with an output schema, this covers environment scope, an alternative, result interpretation, CLI dependency, error cases, concurrency, and expected duration. An agent has enough context to select and invoke it correctly without further return-value documentation.

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

Parameters3/5

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

The schema already fully documents `topic`'s fully qualified syntax, allowed segments, and rejection behavior, so the description's `/cmd_vel` example mostly repeats that guidance. It adds that unknown names produce an MCP error, but offers little other new input-parameter meaning; the QoS discussion concerns outputs.

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 description uses a specific verb and resource—"Describe one ROS 2 `topic`"—and identifies the `TopicInfo` result, including counts, QoS, and associated nodes. Opening with "ROS 2 graph only" and the `list_endpoints` alternative also distinguishes its graph-inspection role from DDS endpoint discovery.

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

Usage Guidelines5/5

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

It explicitly limits use to ROS 2 graph setups and directs agents to `list_endpoints` on a DDS-only setup. Specifying that it describes one fully qualified topic further clarifies the intended singular-inspection use case.

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