Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Channel message routing: inbound notifications and outbound verification #36

Description

@joshuajbouw

Parent: #32
Blocked by: All prior sub-issues

Problem

Two halves of channel messaging are broken:

Inbound: The bridge's runtime.channel.reply() sends notifications/astrid.inboundMessage to the Rust host (see astrid_bridge.mjs:116-123). But AstridClientHandler (in astrid-mcp) doesn't handle this notification — messages are silently dropped.

Outbound: When the agent calls a send tool, it needs to route through the plugin. This is likely automatic once Items 1+2 land — if the Unicity plugin registers a send tool via registerTool(), the tool wiring makes it reachable. Verify before building anything.

Approach — Inbound

  1. Define an InboundChannelMessage struct with fields: plugin_id, context (the context object from the bridge), and content
  2. Add a bounded mpsc::channel(256) sender to either AstridClientHandler or McpPlugin's notification path
  3. Handle notifications/astrid.inboundMessage in the notification dispatch — validate payload size (<1MB), extract fields, send through the channel
  4. The DaemonServer consumes from the receiver, finds the appropriate agent session, and injects the message as a new user turn

The notification arrives via the rmcp ClientHandler trait. Check AstridClientHandler in crates/astrid-mcp/src/capabilities.rs — it currently handles on_tool_list_changed (line 682). Custom notifications may need a different hook point; check rmcp's ClientHandler trait for a on_notification or similar method.

Approach — Outbound

Verify after Items 1-3: load the Unicity plugin and check what tools it exports. If it registers a send tool via registerTool(), Items 1+2 make it automatically available (appears in LLM tool list, dispatches through Peer<RoleClient>, bridge routes to handler). If no send tool exists, add a synthetic one or use an MCP notification path.

Key Files

  • crates/astrid-mcp/src/capabilities.rsAstridClientHandler (line 419), rmcp ClientHandler impl (line 445)
  • crates/astrid-plugins/src/mcp_plugin.rsMcpPlugin notification handling
  • crates/astrid-gateway/src/server.rsDaemonServer and session routing
  • crates/openclaw-bridge/bridge/astrid_bridge.mjsruntime.channel.reply() (line 116-123) shows the notification format

Gotchas

  • The bridge sends: { method: "notifications/astrid.inboundMessage", params: { pluginId, context, content } }
  • Use a bounded channel (mpsc::channel(256)) to prevent unbounded memory growth. Log a warning and drop on full.
  • Validate payload size before forwarding — reject >1MB to prevent DoS from a compromised plugin.
  • The DaemonServer doesn't currently have a message router — this may need a simple lookup from plugin ID to session. Consider which session should receive the message (the most recent one? all of them?).
  • This is the most architecturally involved item. It may be worth splitting into two sub-PRs: (a) notification capture + channel, (b) session injection + routing.

Verification

  • Send a message through the bridge's channel.reply() → verify it appears on the Rust receiver
  • Outbound: verify Unicity's send tool appears in tool list and is callable
  • End-to-end: CLI → agent → Unicity channel → verify round-trip
  • cargo test --workspace -- --quiet passes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/gatewayastrid-gateway: API server and routingarea/mcpastrid-mcp: MCP bridge and tool dispatchblockedBlocked on an external dependency or decisionfeatNew feature or capabilityp2Normal — standard priority

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions