agentcat gem, version 1.x, which tracks servers built on the official mcp gem. For the first setup, see Ruby setup.
Options
AgentCat.track(server, project_id, options) takes an AgentCat::Options object as options. Every option is optional, and you pass options as keyword arguments to AgentCat::Options.new.
We recommend that you keep the defaults of
enable_tool_call_context, enable_report_missing, enable_tracing, and disable_diagnostics, because each one feeds a part of the dashboard or helps us fix a broken install. With enable_tool_call_context: false, the dashboard has no intent data. With enable_report_missing: false, agents cannot report missing tools. With enable_tracing: false, AgentCat sends no events and injects no session_id.project_id of nil turns on telemetry-only mode: events go to your exporters and not to AgentCat.
AgentCat::UserIdentity has three fields: user_id (a string), user_name (optional), and user_data (an optional hash).
The SDK reads these environment variables:
The SDK does not read
AGENTCAT_PROJECT_ID.
Framework and transport details
The mcp gem
The SDK supports MCP::Server from the mcp gem, 0.23.0 and later. The CI tests every minor release from 0.23.0 each night. The mcp gem has no login of its own: it can check bearer tokens when you pass token_verifier: to the HTTP transport, and your app can put its own data in the server’s server_context:. Hooks see that context as tool_call.server_context. AgentCat sends the auth_info: entry with each event only when it is a hash that your app put in server_context: (such as {"clientId" => ..., "scopes" => [...]}), so keep raw tokens out of it. With token_verifier:, the gem stores an MCP::Server::OAuth::AccessToken object under auth_info instead, and AgentCat does not send that object.
Stateless HTTP
StreamableHTTPTransport.new(server, stateless: true) serves each request on its own, and a per-request server needs one track call inside the factory. The event queue, exporters, and diagnostics start once and all instances share them. AgentCat holds each server weakly, so a server that you build for one request is freed with it.
Long-lived HTTP and stdio
A long-lived server needs onetrack call, at start. Tools that you register after track are tracked too. The mcp gem keeps session state of the streamable HTTP transport in memory, so the gem’s documentation advises one process.
What track changes in your server
- Each tool schema gets
session_idandcontext(andagent_idwithenable_agent_tracking). 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 instructuredContentasmcp_session. - AgentCat checks the
session_idvalue: it rejects an ID that it did not issue and tells the agent to send the one that it got. - Calls that the
mcpgem rejects before a tool runs (an unknown tool, a missing argument, or arguments that fail the input schema) become events too. - A second
trackon the same server does nothing.AgentCat.tracked?(server)tells you if a server is tracked. tracknever raises into your setup code. If setup fails, it logs an error and returns your server untracked.
Runtimes, delivery, and shutdown
The hooks run on their own thread with a time limit, after AgentCat builds a frozenAgentCat::ToolCall. They never delay the tool call, and changing the arguments inside a hook raises FrozenError without any effect on your tool.
AgentCat puts each event in a queue in the process and sends it in the background. It retries a failed send 3 times. When the queue is full, AgentCat drops the oldest event. The queue restarts in a forked child, which covers Puma cluster mode, Unicorn, and Passenger.
AgentCat registers an at_exit hook that waits up to 5 seconds for the queue to empty. In a container or another short-lived process, we recommend that you also call AgentCat.flush(timeout: 5) on shutdown, because at_exit is best effort. It returns true when the queue emptied in time.
Logging and debug mode
By default, the SDK writes WARN and ERROR lines to$stderr through AgentCat.logger, and the lines never contain your payload values. Repeated lines are held back for a minute. You can set your own logger, for example AgentCat.logger = Rails.logger.
AgentCat.debug = true also writes setup and diagnostics lines to ~/agentcat.log, and never to stdout, because stdout carries JSON-RPC on a stdio server. If the process has no home directory, the SDK writes no file. The file does not list each sent event. Useful lines:
AgentCat setup started | project ...:trackran.AgentCat setup skipped | no adapter for ...: the server shape is not supported.trackreturns the server untracked.AgentCat runtime error | event publish failed after ... attempts: events could not reach AgentCat.
Testing
In a test environment,AgentCat.track returns your server untouched and sends no events. AgentCat treats a process as a test environment when Minitest or RSpec is loaded, or when RAILS_ENV, RACK_ENV, or APP_ENV is test. AGENTCAT_ENABLED=true turns it on in tests.
To check what your server tracks, you call AgentCat.fake before AgentCat.track. The fake keeps every event in memory and sends nothing:
session_id and context after your own parameters.
Differences and known limits
identifyruns on every tool call, and AgentCat keeps no identity cache. A hook has 1 second by default, where the TypeScript SDK waits 30 seconds, so we recommend your own cache for slow lookups.- The SDK does not write a log line for each sent event. The dashboard or the AgentCat MCP server can confirm an event.
- 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. Invalid UTF-8 becomes U+FFFD.
AgentCat.publish_custom_event(server, project_id, resource_name: ..., ...)sends anagentcat:customevent with no session, unless you passsession_id:. See Custom events.- If a release of the
mcpgem removes an internal that AgentCat uses, AgentCat logs one error and turns off only the feature that needs it. - The gem was never published under the old
mcpcatname, so there is nothing to migrate.