0xPlaygrounds / 0xPlaygrounds/rig

Improve RMCP tool registration ergonomics around RunningService lifetimes

Offen
#2,200 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Rust
Sterne
8.6k
Forks
960
Ø Merge
4 Std. 18 Min.
Gemergte PRs (30 T.)
124

Beschreibung

## Summary

Manual RMCP tool registration currently makes it easy to accidentally drop the `RunningService` while keeping only a cloned peer/sink in Rig's tool registry. The resulting behavior is confusing: tools can appear available immediately after setup, then disappear later when the agent is stored in application state and prompted again.

Related bug/repro issue: #2199
Broken user gist: https://gist.github.com/arcayr/1ebb21ee4fe80d5d3fa3f454c3f2f578
Corrected lifetime example: https://gist.github.com/gold-silver-copper/46bee9339c5d0b1f33c03394feece4b7

## Problem

This shape looks reasonable at first glance:

```rust
let srv = client_info.clone().serve(transport).await?;

for tool in srv.list_all_tools().await? {
tool_server = tool_server.rmcp_tool(tool, srv.peer().clone());
}

let handle = tool_server.run();
let agent = client.agent(model).tool_server_handle(handle).build();
```

But `srv.peer().clone()` does not keep `srv` alive. `RunningService` owns the live RMCP connection/task. When `srv` falls out of scope, RMCP closes/cancels the transport. Rig later observes the peer sink as closed and retires the MCP tool registration.

The first prompt can still appear to work because shutdown is asynchronous, so this presents as an intermittent or state-hoisting bug rather than an obvious lifetime issue.

## Why this is ergonomic/documentation debt

The current API accepts the exact thing users naturally have at registration time: a `Tool` plus a cloned peer/sink. That makes it easy to miss that another value, the `RunningService`, must be owned somewhere else for the registered tool to remain usable.

The intended long-lived app shape is closer to:

```rust
struct AppModel {
agent: Agent<...>,
mcp_services: Vec>,
}
```

For dynamic/server-backed RMCP tools, the `McpClientHandler + ToolServerHandle` path also makes this clearer because `connect(...)` returns the service that must be retained.

## Possible improvements

A few options, not mutually exclusive:

- Document prominently on `ToolServer::rmcp_tool`, `ToolServer::rmcp_tool_with_timeout`, `AgentBuilder::rmcp_tool`, and `AgentBuilder::rmcp_tools` that the caller must retain the `RunningService` backing the peer.
- Add an example showing manual registration from `list_all_tools()` with a struct that stores both `Agent` and `Vec>`.
- Consider renaming docs/parameters from `client`/`peer` to something that hints it is only a sink handle, not the connection owner.
- Consider a higher-level helper that returns both a tool-server handle update and a guard/service value that must be retained.
- Consider a diagnostic log when directly registered RMCP tools are retired because their peer sink is closed, including a hint about keeping `RunningService` alive.

## Acceptance Criteria

Users following docs/examples for runtime RMCP tool registration should understand that `peer().clone()` is insufficient to own the connection lifetime, and should have an obvious pattern for storing the returned `RunningService` alongside their app model/agent state.

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Das Issue betrifft die RMCP-Tool-Registrierungs-API in Rig, einem Rust-LLM-Framework. Beginne damit, die verlinkten Gists zu lesen, um den Bug und das korrigierte Muster zu verstehen. Sieh dir die Typen `rmcp::service::RunningService` und `ToolServer` an, mit Fokus auf die Methode `rmcp_tool` und ihre Dokumentation. Das Ziel ist, die Ergonomie zu verbessern, damit Nutzer wissen, dass sie den `RunningService` behalten müssen. Überprüfe bestehende Beispiele und Dokumentation für manuelle Registrierung. 'Erledigt' bedeutet, dass die API oder ihre Dokumentation Nutzer klar dazu anleitet, den Service neben ihrem Agenten zu speichern.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Bereich
backend-api-design, tooling
Issue-Typ
Refactoring
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Ruhig
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.