inspect_tf
Rebuild the ROS 2 TF tree from /tf_static and /tf to diagnose broken lookups, reporting stale, disconnected, cyclic, or ambiguous frames plus paths and URDF gaps.
Instructions
ROS 2 graph only. Rebuild the TF tree from the transforms on /tf_static (latched) and /tf (listened to for window_s) and flag what breaks lookups. Returns a TfReport: frames (parent, kind static/dynamic/both, age_s, stale, observed_frequency_hz on wall time, sim_frequency_hz on stamps), roots, counts and findings {kind, frames, text}: stale (a frame trails the newest /tf stamp by more than stale_after_s), two_parents, disconnected (several roots), static_and_dynamic, cycle, no_path. Ages and rates use header stamps, so they hold on sim time (real_time_factor far from 1 means sim). Give source_frame and target_frame for the path between them. It also reads /robot_description and flags URDF links with no frame (declared_not_published). Empty frames when nothing is published (read note). The listening is capped (3000 messages): echo can drop messages at high rates, so the tree is exact but frequencies are approximate (truncated). Raises an MCP error without a ros2 CLI. Mock mode: a fixed 5 s capture of the demo robot with one stale frame. 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
| Name | Required | Description | Default |
|---|---|---|---|
| window_s | No | Seconds to listen to `/tf`, 1..20, default 5. | |
| source_frame | No | Frame name, e.g. `base_link`. Give `source_frame` and `target_frame` together to get the chain between them in `path`. | |
| target_frame | No | See `source_frame`. | |
| stale_after_s | No | A frame is stale past this many seconds of stamp time, default 2. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | One sentence of context, or `None`. | |
| path | No | Frames from `source_frame` to `target_frame`. | |
| hints | Yes | ||
| roots | Yes | Frames with no parent; one in a sound tree. | |
| frames | Yes | Sorted by name. | |
| findings | Yes | Empty when the tree is sound. | |
| window_s | Yes | ||
| path_note | No | Why `path` is `None`, or context. | |
| truncated | Yes | Messages were dropped or the cap was hit. | |
| urdf_note | No | ||
| frame_count | Yes | ||
| stale_count | Yes | ||
| urdf_source | No | ||
| reference_ns | Yes | Newest `/tf` stamp: the clock for `age_s`. | |
| stamp_span_s | Yes | ||
| static_count | Yes | Frames with a static transform. | |
| dynamic_count | Yes | Frames with a dynamic transform. | |
| message_count | Yes | Transforms captured, repeats included. | |
| mode_effective | Yes | `live` or `mock` (fixtures). | |
| transform_count | Yes | Distinct parent-child pairs. | |
| urdf_link_count | No | ||
| window_actual_s | Yes | ||
| real_time_factor | Yes | Stamp time over wall time: about 1 on a real robot, other on sim. | |
| frames_not_in_urdf | No | TF frames not in the URDF (`map`, `odom` are normal). | |
| declared_frames_missing | No | URDF links with no TF frame. |