Skip to content

AgentCat v2.0.0 β€” explicit handles for sessionless MCP, for both Go MCP libraries

Choose a tag to compare

@naji247 naji247 released this 05 Aug 03:16
· 8 commits to main since this release
4aeb63f

AgentCat v2 rebuilds task correlation for the sessionless MCP era β€” for both Go MCP libraries.

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. The injected copy is byte-identical across every AgentCat SDK and pinned by a golden test, so the number is the same wherever you integrate. 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 each tracked tool's input schema. Agents echo it back on every call, grouping related calls into one task β€” even across stateless HTTP, load-balanced deployments, and per-request server instances.
  • Issued IDs are delivered via a trailing [MCP INSTRUCTIONS] text block and, for tools declaring an output schema, mirrored into structuredContent as _mcp_instructions, 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: every event carries your raw request and your original, undecorated response.
  • 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? Set ResolveSessionID and AgentCat derives its session deterministically from your identifier β€” the same input produces the same session across processes and languages β€” and injects no session_id parameter at all.

Handles are validated

  • AgentCat trusts only a session_id it issued β€” the ses_ prefix plus a 27-character KSUID. Event.SessionId is exempt from both redaction hooks, so a value adopted there could never be scrubbed afterwards; anything AgentCat did not mint is never adopted.
  • A handle this server did not mint publishes without a session, and the agent is told to re-send the ID it was given rather than handed a new one.
  • A tool that declares its own session_id is never read from: your parameter reaches your handler untouched, those calls publish sessionless, and you get one actionable error per tool naming the fix.
  • Every event carries an agentcat_session_id_source tag: minted, supplied, hook, invalid, or foreign.

Agent attribution (opt-in)

  • agent_id β€” enable with EnableAgentTracking: 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.

Both Go MCP libraries

  • One feature set behind identical Options on both adapters: go.agentcat.com/sdk/mcpgo/v2 for mark3labs/mcp-go and go.agentcat.com/sdk/officialsdk/v2 for modelcontextprotocol/go-sdk. You import only the adapter matching your library.
  • Per-request serving is first-class: call Track() inside your server factory. Queues, exporters, and diagnostics initialize once and are shared across instances; per-server state is released when the server object is garbage collected.
  • mcp-go strict validation is supported: AgentCat declares its parameters on your registered tool schemas as optional properties only β€” your required list and your additionalProperties setting are never changed β€” so servers using WithInputSchemaValidation, WithStrictInputSchemaDefault, or WithOutputSchemaValidation accept exactly the calls AgentCat's advertised schemas invite.
  • 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 regression test that fails on the commit before it.

  • officialsdk no longer round-trips your arguments through float64 when stripping injected parameters: every surviving literal re-marshals verbatim, so integers above 2^53 reach your handler β€” and your published events β€” exactly as sent.
  • Per-request factory topologies no longer leak: neither adapter holds a strong reference from AgentCat's process-lifetime state back to your server, so every per-request server instance is released when it dies. This includes a customer-owned *server.Hooks value shared across mcp-go servers β€” it is instrumented exactly once, with closures that resolve the live server from the request context instead of capturing it.
  • Injection is best-effort and never fails a tools/list: a tool that already declares a parameter keeps its own, and composed (oneOf/allOf/anyOf), unreadable, or absent input schemas are advertised untouched.
  • Every customer callback β€” Identify, EventTags, EventProperties, RedactEvent, RedactSensitiveInformation, ResolveSessionID β€” is panic-guarded; a failure costs that call's analytics, never the call.
  • When the log file can't be created (containers without a resolvable home directory), logging goes silent instead of falling back to stdout β€” on stdio transports, stdout is the JSON-RPC wire.

Known limitations, accepted for 2.0.0 and tracked for a follow-up: the event queue is bounded by count (10,000) but not bytes, and events are truncated after dequeue, so a long AgentCat API outage combined with very large tool results can hold significant memory; and debug-log writes are synchronous, so with Debug enabled an unresponsive network-mounted home directory would stall the process.

Reliability

  • Real-transport e2e suites over stdio and streamable HTTP for both adapters, plus a per-request factory topology lane.
  • Every version in both supported MCP-library ranges is tested with -race on each push by dedicated compatibility workflows.

Breaking changes

  • Transport-session machinery, identity caches, and identify events are removed. Correlation now flows through explicit session_id handles.
  • Module paths move to /v2: go.agentcat.com/sdk/v2, go.agentcat.com/sdk/mcpgo/v2, go.agentcat.com/sdk/officialsdk/v2. v1 paths keep resolving untouched, so you can adopt v2 one service at a time.
  • v2 publishes only two event types β€” mcp:tools/call and agentcat:custom. mcp:initialize, mcp:tools/list, agentcat:identify, and all resource/prompt events are gone.
  • Identify now runs on every tool call and stamps only that call's event. There is no identity cache β€” keep the hook cheap.
  • Agent tracking is opt-in β€” EnableAgentTracking defaults to false.
  • PublishCustomEvent takes verbatim session IDs; CustomEventData.SessionID replaces session references.
  • A hand-written session_id no longer correlates, and tools with composed, opaque, or malformed input schemas now publish sessionless.

For most integrations the upgrade is the /v2 import path and go mod tidy β€” code changes only where a removed API was used. The migration guide covers the schema changes your MCP clients will see, the removed APIs, and how to bring your own session IDs.

Compatibility

mark3labs/mcp-go modelcontextprotocol/go-sdk
Supported versions v0.53.0 – v0.57.0 v1.4.1 – v1.7.0
Installs with v0.57.0 v1.7.0
Stateless 2026-07-28 transports βœ… βœ…
stdio / streamable HTTP βœ… βœ…
Per-request server factories βœ… βœ…
MRTR tagging β€” (not in mcp-go) v1.7.0+
Go 1.25+ 1.25+

You do not have to upgrade your MCP library to adopt v2. go.mod pins the newest version, so a fresh go get is unchanged β€” but if your project pins an older release in the supported range, the adapter compiles and tracks against it. The one exception is mcp-go below v0.53.0: v2 installs its middleware through MCPServer.Use, so bump mcp-go when you move to v2.

Also since v1.0.0

Everything merged between v1.0.0 and v2.0.0 makes its first stable-tag appearance here:

  • Telemetry exporters β€” otlp, datadog, sentry, and posthog backends with per-exporter fault isolation, plus a telemetry-only mode (empty project ID with at least one exporter configured).
  • EventTags / EventProperties β€” per-event tags (validated client-side) and arbitrary JSON properties from your own callbacks.
  • PublishCustomEvent β€” publish your own agentcat:custom events alongside captured tool calls.
  • RedactEvent hook β€” event-level redaction that sees the full event with context and can rewrite or drop it entirely, running before the string-level RedactSensitiveInformation.
  • Hardened capture pipeline β€” send retries with backoff, binary/base64 sanitization, per-field and whole-event truncation budgets.

Install

go get go.agentcat.com/sdk/mcpgo/v2        # mark3labs/mcp-go
go get go.agentcat.com/sdk/officialsdk/v2  # official modelcontextprotocol/go-sdk

Submodules are tagged alongside the root: mcpgo/v2.0.0, officialsdk/v2.0.0.

Migrating from v1 or from mcpcat? See the migration guide.

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