AgentCat v2.0.0 β explicit handles for sessionless MCP, and MCP Python SDK v2 support
AgentCat v2 rebuilds task correlation for the sessionless MCP era β and adds full support for MCP Python SDK v2.
Why v2
The MCP 2026-07-28 specification removed protocol-level sessions. SEP-2567 eliminated the initialize handshake and the Mcp-Session-Id header β every request is now self-contained. Sessions were the built-in thread tying related tool calls together; without them, a stateless deployment sees each call in isolation.
The MCP core team's guidance for cross-call state is explicit: mint an explicit handle from a tool and have the model pass it back as an argument. AgentCat v2 rebuilds correlation on exactly this pattern. track() mints an explicit session_id handle and delivers it to the agent, which threads it back on every subsequent call β correlation that holds across stateless HTTP, load balancers, and per-request server instances, where transport-session inference gives you nothing at all.
What it costs you: session_id adds 323 tokens to a tool's schema β 0.03% of a 1M-token context window. Tokens scale with the tools loaded into a given request, not with the size of your catalog.
What's new
Task correlation via explicit handles
session_idis injected into every tracked tool's input schema. Agents echo it back on each call, grouping related calls into one task β even across stateless HTTP, load-balanced deployments, and per-request server instances.- Issued IDs are delivered via
_mcp_instructionsand, for tools declaring an output schema, mirrored intostructuredContentso clients that only read structured results still receive them. - Injected parameters are stripped before your handler runs β your tool code never sees them β and mint-back instructions never appear in published events.
- Session IDs land in the same
sessionIdevent field with the sameses_prefix, so your existing dashboards, queries, and exporter pipelines keep working untouched. - Already track your own correlation IDs? Pass a
resolve_session_idhook and AgentCat derives its session from your identifier instead of injectingsession_idat all.
Agent attribution (opt-in)
agent_idβ enable withenable_agent_tracking=True. Each agent self-generates amodel|harness|nonceID, so parallel agents collaborating on one task stay individually attributable. Off by default; no server-side minting.
MCP Python SDK v2 support
track()now supports both SDK v1 and v2 servers through a unified engine with per-object SDK detection β the official high-level facades (FastMCPon v1,MCPServeron v2) and low-levelServeron both majors, plus community FastMCP 3.x and 4.x.- Full 2026-07-28 protocol support: envelope-first client identity, the protocol version ladder, fully-qualified reserved keys, and MRTR tagging.
- Per-request serving is first-class: call
track()inside your server factory; queues, exporters, and diagnostics initialize once and are shared across instances. get_more_toolsis annotated read-only via MCP tool annotations.
Fault containment
An adversarial audit of every failure path between AgentCat and the host server hardened v2 around one guarantee: an AgentCat failure never takes your server down with it. Each fix landed with a reproducing test.
- A failure while decorating or recording a completed tool call can no longer replace your tool's response: exception capture is never-raise with per-step guards, so a hostile
__str__, a deleted working directory, or a poisoned cause chain forfeits that call's analytics instead of your result on the wire. - A failed on-demand schema rebuild can no longer strip customer-declared parameters: the fallback is shape- and config-aware, so a
session_id/agent_id/contextparameter you declared yourself rides through to your handler untouched. - Customer hooks β
identify,resolve_session_id,event_tags,event_propertiesβ now run contained: sync hooks offload to a worker thread so your event loop never stalls, everything is capped at 5 seconds, and nothing a hook does β including raisingSystemExitβ reaches your request path. A slow, throwing, or even permanently hanging hook costs analytics data for that one event, never your server. - The SDK never touches your process lifecycle: no
SIGINT/SIGTERMhandlers, noos._exit, no exit-time event drain β every worker is a daemon thread and shutdown is entirely yours. The one bounded exit hook stops the publish worker before interpreter finalization, closing a CPython β€ 3.13 daemon-threadSIGABRTon Linux. import agentcatis side-effect free, thread-safe, and survives metadata-less installs; the event queue is bounded, and publish HTTP calls carry a 10-second timeout.
Known limitation, accepted for 2.0.0: telemetry still queued when the process exits is dropped β the deliberate price of never delaying or hijacking your shutdown.
Reliability
- Full Python exception detail on tool errors β stack frames, exception type, context lines, chained causes β is recovered on every era through a per-call inner tap, isolated by
ContextVarso parallel calls can never read each other's exception. - Opt-in real-HTTP e2e matrix across four deployment topologies, behavior-parity suites twinning all four server flavors, and a 25-way concurrency proof per flavor.
Breaking changes
- Session-id machinery, identity caches, and identify events are removed. Correlation now flows through explicit
session_idhandles. - Agent tracking is opt-in β
enable_agent_trackingdefaults toFalse. identify,event_tags,event_properties, andresolve_session_idnow receive the tool call's request params, not the enclosing request. This one fails silently if you skip it.publish_custom_eventtakes verbatim session ids;CustomEventData.session_idreplaces session references.- Community FastMCP 2.x is no longer supported β pin
agentcat<2if you need it.
Most integrations upgrade with a version bump and no code changes β track() and its options are purely additive in 2.0.0. The migration guide covers the schema changes your MCP clients will see, the cases that do need a code change, and how to bring your own session IDs.
Compatibility
| MCP Python SDK 1.x | MCP Python SDK 2.x | |
|---|---|---|
Low-level Server |
β | β |
| Official facade | β
mcp.server.fastmcp |
β
mcp.server.mcpserver |
| Community FastMCP | β 3.x | β 4.x |
| Stateless 2026-07-28 transports | β | β |
| Python 3.10 / 3.11 / 3.12 | β | β |
| Community FastMCP 2.x | β | β |
Also since v1.0.0
- 1.0.1 β restored context/intent capture for community FastMCP 3.x tools that hold non-copyable runtime state (OpenAPI-generated tools and friends): injection now copies only the parameter schema, never the whole tool (#38)
- 1.0.2 β events with non-JSON-serializable payloads are no longer silently dropped:
tools/listresponses are captured in canonical MCP shape and every payload is sanitized before publish (#40)
Install
pip install agentcatMigrating from mcpcat? Same team, same product, new name β see the migration guide.
Full changelog: v1.0.0...v2.0.0