Skip to main content
Glama

participant_events

Read-onlyIdempotent

Query DDS participant lifecycle events (discovered/lost) from a recent window to identify who joined or left a ROS 2 graph, with GUID, name, hostname, and timestamps.

Instructions

Return DDS participant lifecycle events (discovered / lost) from a recent window, e.g. 'who left in the last 5 minutes?', as a ParticipantEventListing, newest first: guid, event_type, vendor, timestamp_ns, time_source, observed_ns, age_s (seconds before the response; live only), optional name (announced name), hostname and domain_id. time_source is dds_source_timestamp (timestamp of the announcement or dispose) or observed_local (when TopicForge noticed, weakest). Crash caveat: a lost timestamp is an upper bound of the death: exact after a clean shutdown, the lease expiry after a crash, so the process died up to one lease earlier (10 s Cyclone, 20 s Fast DDS, 100 s RTI); the two cases cannot be told apart. Restarts: a restarted node is a new participant (one lost and one discovered, different guid, same name); restarts_by_name gives lives and departures per name over the window, so do not count GUIDs by hand. Capped at 200 events (truncated, note; reduce lookback_s). TopicForge only knows what happened since it started watching (health_check.observer_started_ns). Backends: Fast DDS uses listener callbacks; Cyclone polls discovery in the background every 0.5 s, so a participant cycle faster than the reader's history depth between two passes can be missed; mock returns a fixture timeline. Right after start the call waits up to 3 s for discovery. Read-only by architecture. Raises an MCP error when no DDS module is active. Duration: DDS binding behind the DDS lock, one call at a time; ends within 45 s; busy error if the lock is held (retry).

Input Schema

NameRequiredDescriptionDefault
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.
lookback_sNoWindow in seconds, 1..86400, default 300. A larger window may hit the 200-event cap.

Output Schema

NameRequiredDescriptionDefault
noteNoOne sentence of context, or `None`.
totalYes
eventsYes
returnedYes
domain_idYesDDS domain observed (joined at startup).
truncatedYesTrue when cut to the 200-event cap.
restarts_noteNoSet when unnamed participants were left out of `restarts_by_name`.
mode_effectiveYes`live` or `mock` (fixtures).
restarts_by_nameNoNames seen with several GUIDs or lost at least once (absent: ran once and stayed). A restart is a new GUID with the same name. Window only.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed22 schema fields changedv0.8.0
    • removedOutput schema / $defs / ParticipantEvent / properties / age_s / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / ParticipantEvent / properties / age_s / default
      Removed value: -null
    • addedOutput schema / $defs / ParticipantEvent / properties / age_s / minimum
      Added value: +0
    • addedOutput schema / $defs / ParticipantEvent / properties / age_s / type
      Added value: +[
      +  "number",
      +  "null"
      +]
    • removedOutput schema / $defs / ParticipantEvent / properties / hostname / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / ParticipantEvent / properties / hostname / default
      Removed value: -null
    • addedOutput schema / $defs / ParticipantEvent / properties / hostname / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / $defs / ParticipantEvent / properties / name / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / ParticipantEvent / properties / name / default
      Removed value: -null
    • addedOutput schema / $defs / ParticipantEvent / properties / name / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / $defs / ParticipantEvent / properties / observed_ns / anyOf
      Removed value: -[
      -  {
      -    "minimum": 0,
      -    "type": "integer"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / $defs / ParticipantEvent / properties / observed_ns / default
      Removed value: -null
    • addedOutput schema / $defs / ParticipantEvent / properties / observed_ns / minimum
      Added value: +0
    • addedOutput schema / $defs / ParticipantEvent / properties / observed_ns / type
      Added value: +[
      +  "integer",
      +  "null"
      +]
    • removedOutput schema / $defs / ParticipantEvent / properties / time_source / default
      Removed value: -"observed_local"
    • removedOutput schema / description
      Removed value: -"Envelope returned by `participant_events`."
    • 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 / restarts_note / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • removedOutput schema / properties / restarts_note / default
      Removed value: -null
    • addedOutput schema / properties / restarts_note / type
      Added value: +[
      +  "string",
      +  "null"
      +]
  2. Changed43 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"
    • addedInput schema / properties / lookback_s
      Added value: +{
      +  "default": 300,
      +  "description": "Window in seconds, 1..86400, default 300. A larger window may hit the 200-event cap.",
      +  "maximum": 86400,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • removedInput schema / properties / lookback_seconds
      Removed value: -{
      -  "default": 300,
      -  "description": "Window (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_id` when that happens.",
      -  "maximum": 86400,
      -  "minimum": 1,
      -  "title": "Lookback Seconds",
      -  "type": "integer"
      -}
    • removedInput schema / title
      Removed value: -"participant_eventsArguments"
    • addedOutput schema / $defs / NameLifecycle
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "departures": {
      +      "description": "Times a participant with this name was lost.",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "lives": {
      +      "description": "Distinct GUIDs that carried this name; restarts = `lives` - 1.",
      +      "minimum": 1,
      +      "type": "integer"
      +    }
      +  },
      +  "required": [
      +    "lives",
      +    "departures"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / $defs / ParticipantEvent / description
      Removed value: -"A point-in-time lifecycle event (discovered or lost) for a DDS participant.\n\n`ParticipantInfo` is the current state; this is one event in its history.\nReturned by `participant_events`."
    • addedOutput schema / $defs / ParticipantEvent / properties / age_s
      Added value: +{
      +  "anyOf": [
      +    {
      +      "minimum": 0,
      +      "type": "number"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Seconds between `timestamp_ns` and this response; `None` in mock mode."
      +}
    • removedOutput schema / $defs / ParticipantEvent / properties / domain_id / description
      Removed value: -"DDS domain id the event occurred on."
    • removedOutput schema / $defs / ParticipantEvent / properties / domain_id / title
      Removed value: -"Domain Id"
    • changedOutput schema / $defs / ParticipantEvent / properties / event_type / description
      Previous value: -"`discovered` when the participant first joined the bus (or rejoined after leaving). `lost` when TopicForge observed a `REMOVED` callback (Fast DDS) or a polling delta where the GUID no longer appears in the DCPSParticipant builtin reader snapshot (Cyclone). The transition is reported once per state change."New value: +"`discovered` (joined or rejoined) or `lost` (removed, or gone from discovery); reported once per change."
    • removedOutput schema / $defs / ParticipantEvent / properties / event_type / title
      Removed value: -"Event Type"
    • removedOutput schema / $defs / ParticipantEvent / properties / guid / description
      Removed value: -"DDS Global Unique Identifier of the participant involved."
    • removedOutput schema / $defs / ParticipantEvent / properties / guid / title
      Removed value: -"Guid"
    • removedOutput schema / $defs / ParticipantEvent / properties / hostname / description
      Removed value: -"Hostname announced by the participant when known, else `None`."
    • removedOutput schema / $defs / ParticipantEvent / properties / hostname / title
      Removed value: -"Hostname"
    • removedOutput schema / $defs / ParticipantEvent / properties / mode_effective
      Removed value: -{
      -  "description": "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`.",
      -  "enum": [
      -    "mock",
      -    "live"
      -  ],
      -  "title": "Mode Effective",
      -  "type": "string"
      -}
    • removedOutput schema / $defs / ParticipantEvent / properties / name / description
      Removed value: -"Participant name (EntityName QoS) when known, else `None`."
    • removedOutput schema / $defs / ParticipantEvent / properties / name / title
      Removed value: -"Name"
    • changedOutput schema / $defs / ParticipantEvent / properties / observed_ns / description
      Previous value: -"Local wall-clock time (ns since epoch) at which TopicForge noticed the event. Always at or after `timestamp_ns` when the latter is DDS-derived. `None` when not tracked."New value: +"Local ns when TopicForge noticed the event, never before a DDS-derived `timestamp_ns`; `None` when untracked."
    • removedOutput schema / $defs / ParticipantEvent / properties / observed_ns / title
      Removed value: -"Observed Ns"
    • changedOutput schema / $defs / ParticipantEvent / properties / time_source / description
      Previous value: -"Where `timestamp_ns` comes from. `dds_source_timestamp`: the DDS timestamp of the discovery announcement or dispose. For a `lost` event it is an upper bound: exact after a clean shutdown, the lease expiry after a crash (the process died up to one lease earlier: 10 s Cyclone default, 20 s Fast, 100 s RTI), and the two cannot be told apart. `observed_local`: the moment TopicForge noticed (weakest)."New value: +"`dds_source_timestamp` (DDS timestamp of the announcement or dispose; for `lost` an upper bound of the death) or `observed_local` (when TopicForge noticed, weakest)."
    • removedOutput schema / $defs / ParticipantEvent / properties / time_source / title
      Removed value: -"Time Source"
    • changedOutput schema / $defs / ParticipantEvent / properties / timestamp_ns / description
      Previous value: -"Wall-clock timestamp (nanoseconds since epoch) when TopicForge captured the event. For Fast DDS this is when the listener callback ran; for Cyclone this is when the polling delta was computed; for mock fixtures this is a deterministic anchor."New value: +"Wall-clock ns of the event; its origin is `time_source`."
    • removedOutput schema / $defs / ParticipantEvent / properties / timestamp_ns / title
      Removed value: -"Timestamp Ns"
    • removedOutput schema / $defs / ParticipantEvent / properties / vendor / description
      Removed value: -"DDS implementation tag for the participant involved, decoded the same way as `ParticipantInfo.vendor`."
    • removedOutput schema / $defs / ParticipantEvent / properties / vendor / title
      Removed value: -"Vendor"
    • changedOutput schema / $defs / ParticipantEvent / required
      Previous value: -[
      -  "guid",
      -  "event_type",
      -  "vendor",
      -  "timestamp_ns",
      -  "domain_id",
      -  "mode_effective"
      -]New value: +[
      +  "guid",
      +  "event_type",
      +  "vendor",
      +  "timestamp_ns",
      +  "domain_id"
      +]
    • removedOutput schema / $defs / ParticipantEvent / title
      Removed value: -"ParticipantEvent"
    • addedOutput schema / additionalProperties
      Added value: +false
    • addedOutput schema / description
      Added value: +"Envelope returned by `participant_events`."
    • addedOutput schema / properties / domain_id
      Added value: +{
      +  "description": "DDS domain observed (joined at startup).",
      +  "maximum": 232,
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • addedOutput schema / properties / events
      Added value: +{
      +  "items": {
      +    "$ref": "#/$defs/ParticipantEvent"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / mode_effective
      Added value: +{
      +  "description": "`live` or `mock` (fixtures).",
      +  "enum": [
      +    "mock",
      +    "live"
      +  ],
      +  "type": "string"
      +}
    • addedOutput schema / properties / note
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "One sentence of context, or `None`."
      +}
    • addedOutput schema / properties / restarts_by_name
      Added value: +{
      +  "additionalProperties": {
      +    "$ref": "#/$defs/NameLifecycle"
      +  },
      +  "description": "Names seen with several GUIDs or lost at least once (absent: ran once and stayed). A restart is a new GUID with the same name. Window only.",
      +  "type": "object"
      +}
    • addedOutput schema / properties / restarts_note
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Set when unnamed participants were left out of `restarts_by_name`."
      +}
    • removedOutput schema / properties / result
      Removed value: -{
      -  "items": {
      -    "$ref": "#/$defs/ParticipantEvent"
      -  },
      -  "title": "Result",
      -  "type": "array"
      -}
    • addedOutput schema / properties / returned
      Added value: +{
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • addedOutput schema / properties / total
      Added value: +{
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "True when cut to the 200-event cap.",
      +  "type": "boolean"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "result"
      -]New value: +[
      +  "events",
      +  "returned",
      +  "total",
      +  "truncated",
      +  "domain_id",
      +  "mode_effective"
      +]
    • changedOutput schema / title
      Previous value: -"participant_eventsOutput"New value: +"ParticipantEventListing"
  3. First observedv0.5.6

TDQS

A4.4/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, yet the description adds far more: the crash caveat (lost timestamp is an upper bound, lease expiry of 10s/20s/100s), restart semantics, the 200-event cap with truncated/note, the observer-start limitation, backend-specific behavior (Cyclone's 0.5s poll can miss fast cycles), an MCP error when no DDS module, and lock/busy/duration behavior. This is behavior the agent cannot get from annotations or schema.

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?

Purpose and output shape are front-loaded, and bold section labels (crash caveat, restarts, backends) make the dense block scannable. It is long, but nearly every clause carries distinct behavioral information for a genuinely complex tool.

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, yet the description still clarifies the non-obvious return semantics (time_source strengths, age_s being live-only, restarts_by_name), and covers the operational constraints an agent needs. Nothing required to call it correctly is missing.

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?

Schema coverage is 100%, so both parameters are already documented, including the 'domain_id is ignored' caveat and lookback_s range. The description only restates the window-to-cap relationship ('reduce `lookback_s`'), which adds little beyond the schema's own note that a larger window may hit the cap.

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?

States a specific verb and resource ('Return DDS participant lifecycle events (`discovered` / `lost`)') with a concrete example query ('who left in the last 5 minutes?'). The event/lifecycle focus clearly distinguishes it from sibling list_participants, which reports current membership rather than a history of joins and leaves.

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?

Gives a clear usage scenario via the example query and actionable recovery steps ('reduce `lookback_s`' when truncated, 'retry' on `busy`). It never explicitly names a sibling (e.g. list_participants) as the alternative for the current-state case, so the when-not condition is left implicit.

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