Skip to main content
This page lists the versions and features that the Rust SDK supports, what agents see, how its hooks, errors and delivery behave, what it sends, and the limits that you can hit. Rust: rmcp shows how to track a server, Rust runtimes covers how it runs, and the crate guide on docs.rs is the full reference.

Supported versions

  • Rust. Rust 1.88 or later. The minimum supported Rust version (MSRV) is the MSRV of rmcp 3, and it is never higher than the MSRV of the rmcp versions that the crate supports. The MSRV is always a Rust release that is at least 6 months old. An MSRV increase is a minor release and has its own CHANGELOG section.
  • rmcp. rmcp 3.0.0 or a later 3.x release. CI tests the latest patch of each 3.x minor release.
  • tokio. A tokio runtime with the time driver (see The tokio runtime). The local feature of rmcp is not supported.

Features

Turn on one TLS feature. To use native-tls, turn off the default features (default-features = false) and turn on native-tls. Without a TLS feature, the SDK can send events only to an http: URL. It logs a warning when the URL is an https: URL.

What agents see

The SDK changes the tool list that tools/list returns:
  • Each tool gets a context parameter, in which the agent says why it calls the tool (see Tool Call Context).
  • Each tool gets a session_id parameter, which ties the calls of one task together (see Stateless Servers).
  • With enable_agent_tracking(true), each tool gets an agent_id parameter, in which the agent names itself.
  • The list gets one more tool, get_more_tools, through which agents report a tool that they miss (see Agent Feedback).
A tool that declares its own parameter with one of these names keeps it, and the SDK does not add its own. Before your tool runs, the SDK removes the parameters that it added from the arguments, so your tool never sees them. The first call of a task gets a text block that begins [session_id issued before the content of the tool’s own result. An error result gets the block too. A JSON-RPC error (Err(ErrorData)) has no content, so it gets no block. A session_id that is neither start nor a valid ses_ ID gets a text block that begins [session_id unrecognized, and the call then has no session. When a tool declares an output schema, the SDK adds an mcp_session property to the schema. A structured result of that tool then gets mcp_session as its first key, with the session ID, the agent ID when the agent sent one, and a status.

Hooks, errors and delivery

Hooks get a ToolCall

The hooks get a ToolCall, not the raw request and the handler context (see Rust: the ToolCall). They are async closures that return a Result: an Err gives no value, and the SDK logs it.

Hooks that do not complete

The SDK stops a call hook (identify, event_tags, event_properties or resolve_session_id) that has not completed within 30 seconds, and sends the event without its value.

Errors

  • JSON-RPC errors. A tool that returns Err(ErrorData) gives the client a JSON-RPC error, as rmcp sends it. The event gets the name of the JSON-RPC error code as error.type.
  • No stack frames. The error of an event has the platform rust and no stack frames.
  • Cancelled calls. A tool call that is cancelled (its future dropped) gives an event with the error type cancelled.
  • Panics. When a tool panics, the SDK records the panic as the error of the call, then lets the panic go on unchanged.
rmcp turns an error that a tool returns into the text of an error result, so the event gets only that text. Call capture_error before the tool returns the error. The event then also gets the type of the error and the texts of its source() chain:
When a tool calls capture_error more than once, the last error counts. It works in the tool’s own future only: in a task that the tool spawns, or in a thread that it starts, it does nothing. The result and the error of the tool reach the client unchanged.

Delivery and shutdown

  • One queue for each handle. Each AgentCat handle has its own queue and API URL.
  • No signal handlers. AgentCat::flush, AgentCat::shutdown and the drain of the last drop deliver the queued events. The SDK installs no signal or exit handler (see Flush and shutdown).

Switches, tests and logging

  • AGENTCAT_ENABLED turns the SDK off with no code (see Environment variables).
  • testing::Fake, behind the test-util feature, builds handles whose events stay in the process. It records each event as a real handle sends it, after the hooks and the redaction, and assert_tracked, assert_tracked_count, assert_custom_event_published, assert_nothing_tracked and events check what it recorded. The Testing section of the crate guide has a complete test.
  • LogDestination::Tracing sends the log lines of the SDK to tracing (see Logging). Without it, the SDK writes ~/agentcat.log.
  • flush_blocking and shutdown_blocking wait for the delivery without a tokio runtime.

Not in this release

The Rust SDK has no exporters (OpenTelemetry, Datadog, Sentry, PostHog) and no SDK diagnostics yet, and Options has no setter for either.

What the Rust SDK sends

  • Tool calls and custom events. The SDK publishes one event for each tools/call request, and the custom events that your code publishes. Tool listings, resources and prompts give no events.
  • Request headers and URL. On a streamable HTTP server, the event of a tool call carries every request header of that call, authorization and cookie included, under parameters.extra.requestInfo.headers, and the URL of the request under parameters.extra.requestInfo.url. Header names are in lower case. The values of a repeated header are joined with , (; for cookie), and a repeated set-cookie keeps its last value. A stdio server sends no headers. Remove what you do not want in a redact_event hook (see Client-Side Redaction).
  • No diagnostics. The SDK sends none of its own log lines to AgentCat.

Known limits

  • The tokio time driver. A tracked server needs a tokio runtime with the time driver: the SDK times a rebuild of its tool registry with tokio::time::timeout, and tokio panics at such a timer on a runtime without the driver. rmcp uses timers too. #[tokio::main], #[tokio::test] and tokio::runtime::Runtime::new turn the time driver on. A runtime from tokio::runtime::Builder needs enable_time or enable_all.
  • The local feature of rmcp. The SDK does not support it. It spawns the hooks as Send tasks on the tokio runtime of the call.
  • preserve_order of serde_json. The SDK turns on the preserve_order feature of serde_json, so that mcp_session stays the first key of a result. Cargo turns a feature on for the whole build, so every serde_json::Map in your program keeps the order of insertion and does not sort its keys.
  • arbitrary_precision and float_roundtrip. When another crate in your build turns on the arbitrary_precision or the float_roundtrip feature of serde_json, Cargo turns it on for the SDK too. These features change how serde_json reads and writes numbers: the text of some numbers in the events, the token estimates and the size checks can change. The SDK logs a warning that names the feature each time its delivery thread starts.
  • URLs behind nest_service. parameters.extra.requestInfo.url of an event is the URL that the rmcp service sees. axum::Router::nest_service removes the path prefix of the route before that, so the event records the URL without the prefix. route_service keeps the full path.
  • The tool registry. The SDK keeps a registry of what the tool listings tell it, for each handle and each type of server handler, by tool name. It never removes an entry, so a server whose tool names differ per tenant grows the registry with each new name. A hand-written ServerHandler without get_tool depends on that registry (#[tool_handler] writes get_tool for you). On such a server, the listing of one session decides which arguments the SDK removes from the calls of another session.
  • A hook that holds its handle. A hook that holds a clone of its AgentCat handle makes a reference cycle. The handle then never drops, so the drain of the last drop never runs. Let the hook capture only what it needs, or call AgentCat::shutdown before the process ends. A tool reaches its handle through CallContext::agentcat and needs no clone.
  • Redaction hooks have no time limit. The SDK gives the redaction hooks no time limit. A redaction hook that never completes holds one of the 5 delivery slots of its handle for good. Five such hooks stop the delivery of the handle: later events wait in the queue until a shutdown abandons them.
  • The end of the process. The drain of the last drop does not run after std::process::exit, or after a panic with panic = "abort". On a current-thread runtime, call shutdown before the runtime ends (see Current-thread runtimes).