Skip to content

AgentCat v2.0.0 β€” explicit handles for sessionless MCP, and MCP Python SDK v2 support

Choose a tag to compare

@naji247 naji247 released this 05 Aug 03:12
· 6 commits to main since this release
21df778

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_id is 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_instructions and, for tools declaring an output schema, mirrored into structuredContent so 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 sessionId event field with the same ses_ prefix, so your existing dashboards, queries, and exporter pipelines keep working untouched.
  • Already track your own correlation IDs? Pass a resolve_session_id hook and AgentCat derives its session from your identifier instead of injecting session_id at all.

Agent attribution (opt-in)

  • agent_id β€” enable with enable_agent_tracking=True. Each agent self-generates a model|harness|nonce ID, 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 (FastMCP on v1, MCPServer on v2) and low-level Server on 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_tools is 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 / context parameter 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 raising SystemExit β€” 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/SIGTERM handlers, no os._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-thread SIGABRT on Linux.
  • import agentcat is 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 ContextVar so 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_id handles.
  • Agent tracking is opt-in β€” enable_agent_tracking defaults to False.
  • identify, event_tags, event_properties, and resolve_session_id now receive the tool call's request params, not the enclosing request. This one fails silently if you skip it.
  • publish_custom_event takes verbatim session ids; CustomEventData.session_id replaces session references.
  • Community FastMCP 2.x is no longer supported β€” pin agentcat<2 if 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/list responses are captured in canonical MCP shape and every payload is sanitized before publish (#40)

Install

pip install agentcat

Migrating from mcpcat? Same team, same product, new name β€” see the migration guide.

Full changelog: v1.0.0...v2.0.0