Skip to main content
Glama

get_topic_info

Read-onlyIdempotent

Inspect a ROS 2 topic's publishers, subscribers, endpoint counts, and live QoS details by fully qualified name; returns typed info or an error for unknown 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. Read-only; no side effects. Duration: ros2 CLI behind the ROS lock, one call at a time; ends within 45 s; busy error if the lock is held (retry).

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.5/5.0
Behavior4/5

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

Goes well beyond the annotations by disclosing the ROS lock, the 45 s bound, the single-call-at-a-time serialization, the `busy`/retry path, and the MCP error conditions (malformed/unknown topic, missing CLI). Safety is already covered by readOnly/idempotent hints, so the only minor gap is that it does not say how counts behave when the topic exists but has no endpoints.

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?

Front-loaded with the routing constraint and then the operation, with a labeled Duration clause at the end. The QoS field enumeration is dense but earns its place; slightly heavy for one sentence's worth of content.

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

Completeness4/5

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

Covers routing, error modes, timing and lock behavior for a single-parameter read tool with an output schema that already explains the return shape. Only minor omission is what happens for a valid topic with zero endpoints (empty lists vs error).

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% and the schema already constrains the format, so baseline is 3; the description adds value by restating the fully qualified requirement as a precondition for calling and by noting rejection happens before the CLI is reached, which hints at fast-fail behavior.

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?

Specific verb + resource: 'Describe one ROS 2 `topic` ... as a `TopicInfo`', with the fully qualified name format given inline. It distinguishes itself from siblings list_topics (list vs describe) and list_endpoints (ROS 2 graph vs DDS-only) explicitly.

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?

Opens with the ROS 2 graph constraint and names the exact alternative for a DDS-only setup (`list_endpoints`). It also states the retry condition on `busy`, so the agent knows what to do rather than giving up.

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