Skip to main content
This page describes the AgentCat Go SDK, version 2.x (go.agentcat.com/sdk/mcpgo/v2 and go.agentcat.com/sdk/officialsdk/v2). For the first setup, see Go setup.

Options

agentcat.Track(server, projectID, options) takes an *agentcat.Options. Passing nil uses the defaults. Every field is optional, and both modules have the same fields, except where the table says otherwise. The names that start with Disable turn a feature off, so the zero value keeps it on.
We recommend that you keep the defaults of DisableToolCallContext, DisableReportMissing, DisableTracing, and DisableDiagnostics, because each one feeds a part of the dashboard or helps us fix a broken install. With DisableToolCallContext: true, the dashboard has no intent data. With DisableReportMissing: true, agents cannot report missing tools. With DisableTracing: true, AgentCat publishes no events.
UserIdentity has three fields: UserID (a string), UserName (optional), and UserData (an optional map[string]any). An empty projectID is valid only with at least one exporter. That is telemetry-only mode: events go to your Exporters and not to AgentCat. With no project ID and no exporters, Track() returns agentcat.ErrEmptyProjectID. The SDK reads these environment variables: The SDK does not read AGENTCAT_PROJECT_ID. The example programs in the SDK repository read MCPCAT_PROJECT_ID, which is only a convention of those examples.

Framework and transport details

mark3labs/mcp-go

  • Track() takes a *server.MCPServer. It installs a tool-call middleware through MCPServer.Use, and composes with your own hooks through GetHooks().
  • server.NewStreamableHTTPServer(s) and server.ServeStdio(s) both work. server.WithStateLess(true) also works, and it still uses one MCPServer, so one Track() call is enough. ServeStdio stops on SIGINT and SIGTERM, and then returns, so a deferred shutdown runs.
  • On HTTP, the request headers are in req.Header. On stdio, req.Header is empty.
  • AgentCat also declares its parameters on the registered schemas of your tools, as optional properties, so WithInputSchemaValidation and WithOutputSchemaValidation accept the calls and results. Your required list does not change. After that, MCPServer.ListTools() returns RawInputSchema for the tool and not the structured fields.

Official go-sdk

  • Track() takes a *mcp.Server and installs receiving middleware.
  • mcp.NewStreamableHTTPHandler(factory, &mcp.StreamableHTTPOptions{Stateless: true}) calls the factory for each request, so Track() goes inside it. The go-sdk accepts requests at protocol version 2026-07-28 only with Stateless: true. Per-server state is released when the garbage collector frees the server, so a factory does not leak memory.
  • A server that you create once runs with server.Run(ctx, &mcp.StdioTransport{}), or behind a handler that returns the same server. It needs one Track() call.
  • On HTTP, the headers are in req.Extra.Header, and the checked bearer token is in req.Extra.TokenInfo. Both are empty on stdio.
  • AgentCat reads the server name and version from a private field of mcp.Server. If a go-sdk release changes that field, events carry no server name until AgentCat ships an update.

What Track() changes in your server

  • Each tool schema gets session_id and context (and agent_id with EnableAgentTracking). AgentCat removes these values before your handler runs.
  • On the first call of a task, the result starts with a text block that gives the agent its new session_id. For a tool with an output schema, AgentCat also puts the ID in structuredContent.
  • If your tool already declares session_id, agent_id, or context, AgentCat leaves that parameter alone and writes a line to the log. A tool with its own session_id sends its events with no session. A tool with a oneOf, allOf, or anyOf input schema gets no parameters.
  • A session_id that AgentCat did not issue does not join a session. The event is published without one.
  • Tools that you register after Track() are tracked too.
  • A second Track() on the same server does nothing, and the first configuration stands.

Runtimes, delivery, and shutdown

Identify, ResolveSessionID, EventTags, and EventProperties run inline, on the goroutine of the tool call, so a slow hook adds time to that call. We recommend that they read the request and make no network calls. The ctx is the live request context, so it is already done when the client cancelled the call. A lookup that uses this ctx then fails, and the event goes out without that value. AgentCat puts each event in a queue in the process and sends it in the background. Five workers send at the same time. Each attempt times out after 10 seconds, and a failed send is tried again 3 times (after 1, 2, and 4 seconds). The queue holds up to 10,000 events. When the queue is full, AgentCat drops the new event and writes a warning to the log. The SDK does not listen for signals. The queue goes out at exit when your code calls the shutdown function from Track(), or agentcat.Shutdown(ctx), which is the same for the whole process. Both wait up to 5 seconds when ctx has no deadline. The setup page shows the pattern: the HTTP server stops first, then the queue goes out. When you give the queue its own deadline, a slow client cannot use up the time for sending. shutdown is safe to call more than once, but it stops the process-wide publisher, so we recommend one call at exit. log.Fatal and os.Exit skip deferred calls.

Logging and debug mode

The log is off until you set Debug: true. Then the SDK writes to ~/agentcat.log, and never to stdout, because stdout carries JSON-RPC on a stdio server. The log is shared by every AgentCat SDK on the machine, and each Go line starts with [AgentCat] and ends with the SDK, Go, and MCP library versions. If the process has no home directory, the SDK writes no log. Useful log lines:
  • AgentCat setup complete | project ... | context=true report_missing=true exporters=0: Track() worked.
  • Event evt_... enqueued for publishing, then Worker N successfully published event evt_...: an event reached AgentCat.
  • AgentCat setup failed | ...: Track() returned an error, for example for an empty project ID.
  • inject: tool "..." already declares a "session_id" parameter: that tool is published without a session.

Testing

The SDK has no test mode. It sends events whenever it has a project ID. If you prefer that tests send no events, you can leave AGENTCAT_PROJECT_ID empty in the test environment, and Track() then returns an error that your test setup can ignore. Another choice is to point APIBaseURL at a local test server. AgentCat changes your tool schemas. If your tests compare exact schemas, they see session_id and context after your own parameters.

Differences and known limits

  • Identify runs on every tool call. AgentCat keeps no identity cache, and there is no separate identify event.
  • The SDK publishes mcp:tools/call and custom events. It does not publish initialize or tools/list events.
  • The agentcat_mrtr tag, which marks multi-round tool calls, needs go-sdk v1.7.0 or later. mcp-go has no multi-round support, so the tag never appears there.
  • Integers above 2^53 keep their exact value in events only on mcp-go v0.56.0 or later.
  • AgentCat cuts each string to 32 KB, each event to 100 KB, and the intent text to 2,048 characters. Objects keep at most 10 levels and 100 keys or items for each level.
  • PublishCustomEvent(server, projectID, data) sends an event with no session, unless data.SessionID gives one. See Custom events.
  • The old module is github.com/mcpcat/mcpcat-go-sdk. It keeps working, but new features go to go.agentcat.com/sdk. The migration guide shows the steps.