> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentcat.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python reference

> Options, transports, delivery, logging, and limits of the AgentCat Python SDK.

This page describes the `agentcat` PyPI package, version 2.x. For the first setup, see [Python setup](https://docs.agentcat.com/languages/python.md).

## Options

`agentcat.track(server, project_id, options)` takes an `AgentCatOptions` object. Every field is optional.

| Option | Default | What it does |
| - | - | - |
| `identify` | `None` | `(request, extra) -> UserIdentity \| None`, sync or async. Runs on every tool call and names the user of that call. See [Identifying users](https://docs.agentcat.com/languages/python.md#identifying-users). |
| `enable_tool_call_context` | `True` | Adds the `context` parameter to each tool. The agent explains in it why it calls the tool. This is the source of intent data. |
| `custom_context_description` | built-in text | Replaces the description of the `context` parameter, for example with domain-specific guidance. Works only when `enable_tool_call_context` is `True`. |
| `enable_report_missing` | `True` | Adds the `get_more_tools` tool, so agents can report the tools that they looked for and did not find. |
| `enable_tracing` | `True` | Records tool calls and injects the `session_id` parameter. |
| `enable_agent_tracking` | `False` | Adds an `agent_id` parameter to each tool, in its `required` list. Each agent makes its own ID and sends it on every call. AgentCat puts it on the event as a tag. A strict client refuses to send a call without `agent_id`, so this option is off by default. |
| `resolve_session_id` | `None` | `(request, extra) -> str \| None`, sync or async. Gives your own task ID for each request. AgentCat then injects no `session_id` parameter. It combines your value with the project ID into one fixed `ses_` ID. A `None` result makes a new session that the agent never learns. |
| `redact_sensitive_information` | `None` | `(text) -> str`, sync or async. Changes every text value before the event leaves your server. |
| `redact_event` | `None` | `(event) -> Event \| None`, sync or async. Gets the full event before `redact_sensitive_information`. Change the event you receive and return it, or return `None` to drop it. The returned event replaces the original, so a new or partial `Event` loses the fields that it leaves out. If the hook raises, AgentCat drops the event. |
| `event_tags` | `None` | `(request, extra) -> dict[str, str] \| None`, sync or async. Adds tags that you can filter on. Keys: 32 characters or fewer, from `[a-zA-Z0-9$_.:\- ]`. Values: strings of 200 characters or fewer, with no newlines. At most 50 tags. AgentCat drops invalid entries and logs a warning in debug mode. |
| `event_properties` | `None` | `(request, extra) -> dict[str, Any] \| None`, sync or async. Adds JSON data to each event. Values must be JSON-serializable. |
| `exporters` | `None` | Sends events to `otlp`, `datadog`, or `sentry` too. See [Integrations](https://docs.agentcat.com/integrations.md). |
| `debug_mode` | `None` | `True` writes the log to `~/agentcat.log`. `None` follows the `AGENTCAT_DEBUG_MODE` environment variable. A value that you set wins over the variable. |
| `api_base_url` | `https://api.agentcat.com` | The address that receives events. If not set, the SDK reads `AGENTCAT_API_URL`, then `MCPCAT_API_URL`. |
| `disable_diagnostics` | `False` | Stops the anonymous error reports that the SDK sends to AgentCat. These reports never contain tool calls, responses, or user data. |

> [!NOTE]
>
> 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 records nothing.

`UserIdentity` is a dataclass with three fields and no defaults: `user_id` (a string), `user_name` (a string or `None`), and `user_data` (a dict of strings or `None`).

A `project_id` of `None` turns on telemetry-only mode: events go to your `exporters` and not to AgentCat. With no project ID and no exporters, the SDK sends nothing and writes a warning to the log.

The SDK reads these environment variables:

| Variable | What it does |
| - | - |
| `AGENTCAT_DEBUG_MODE` | `true`, `1`, `yes`, or `on` turns on the log file, when `debug_mode` is not set. |
| `AGENTCAT_API_URL` | The address that receives events, when `api_base_url` is not set. `MCPCAT_API_URL` is the old name. |
| `DISABLE_DIAGNOSTICS` | Stops the anonymous error reports, the same as `disable_diagnostics`. |
| `DIAGNOSTICS_ENDPOINT`, `DIAGNOSTICS_TOKEN` | The address and token for a self-hosted diagnostics collector. |

The SDK does not read `AGENTCAT_PROJECT_ID`. The setup page passes it to `track()` in your code.

## Framework and transport details

### Official `mcp` 2.x

* `track()` accepts `MCPServer` from `mcp.server.mcpserver` and the low-level server of `mcp` 2.x.
* A server that you build for each worker or tenant calls `track()` inside its factory. All objects share one event queue, one set of exporters, and one diagnostics client. AgentCat builds them on the first `track()` call, so a call for each object is cheap.
* `server.run(transport="streamable-http", stateless_http=True)` serves each request with a new transport. Calls still join one session, because the `session_id` value travels with the agent.

### Official `mcp` 1.x

`track()` accepts `FastMCP` from `mcp.server.fastmcp` and the low-level `Server`. FastMCP 1.x sets host, port, and `stateless_http` in its constructor (`FastMCP("my-server", stateless_http=True)`), and `run()` takes only the transport. A FastMCP 1.x server reports no version.

### Community `fastmcp`

`track()` adds an AgentCat middleware to `FastMCP` 3.x and 4.x, and it needs `pip install "agentcat[community]"`. For stateless HTTP, pass `stateless_http=True` to `run(transport="http", ...)`. `fastmcp` 2.x is not supported: `track()` returns the server untracked and writes a warning that names the 2.x line.

### What `track()` changes in your server

* Each tool schema gets `session_id` and `context` (and `agent_id` with `enable_agent_tracking`), listed in `required`. AgentCat removes these values before your handler runs.
* AgentCat removes `additionalProperties: false` from the input schemas that it changes.
* On the first call of a task, the result carries a new `ses_` session ID for the agent. For a tool with an output schema, the ID goes in `structuredContent` under `mcp_session`. Otherwise it is a text block.
* If your tool already declares `session_id`, 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 schema with `oneOf`, `allOf`, or `anyOf` at the top level gets no `session_id` or `agent_id`. The log names the tool.
* Tools that you register after `track()` are tracked too.
* `track()` returns the server and never raises.

## Runtimes, delivery, and shutdown

The `identify`, `resolve_session_id`, `event_tags`, and `event_properties` hooks run in the request path, before your tool handler. A sync hook runs on a worker thread, so it does not block the event loop of your server. Each hook has 5 seconds, then AgentCat sends the event without that value. A slow hook delays the response of that call, so we recommend a cheap lookup, with your own cache when it calls a database or an API.

AgentCat puts each event in a queue in the process. One background thread sends the events, with a 10-second limit for each attempt, and tries 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. The thread starts at the first event, so `import agentcat` starts nothing.

At exit, AgentCat stops the sending thread and does not drain the queue. A short script can end before it sends its last events. A long-lived server is not affected. There is no handle to flush or close.

## Logging and debug mode

With debug mode on, the SDK writes its log to `~/agentcat.log`, and never to stdout, because stdout carries JSON-RPC on a stdio server. With debug mode off, the SDK writes no log file. Every line ends with a stamp of the `agentcat`, Python, `mcp`, and `fastmcp` versions, which helps when you share an excerpt.

Useful log lines:

* `AgentCat setup complete | project ... | tracing=True context=True report_missing=True ...`: `track()` worked.
* `Successfully sent event ... | mcp:tools/call | session ... | ... | <user>`: an event reached AgentCat. The value after the duration is the user ID from `identify`.
* `Warning: Failed to track server - Unrecognized MCP server shape`: the server shape is not supported. `track()` returns the server untracked.

## Testing

When `PYTEST_CURRENT_TEST` or `PYTEST_VERSION` is set, the SDK turns off diagnostics. It still sends events when it has a project ID. If you prefer that tests send no events, you can leave `AGENTCAT_PROJECT_ID` unset in the test environment, or pass `project_id=None`.

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.
* Each event carries the request context, with the HTTP headers. The `redact_event` hook can remove a header before the event leaves your server.
* AgentCat cuts each string to 10 KB and each event to 100 KB. Objects keep at most 5 levels and 500 keys or items for each level.
* `event_properties` values must be JSON-serializable, which is stricter than the TypeScript SDK.
* `publish_custom_event(server, project_id, data)` sends an event with no session, unless `data["session_id"]` gives one. See [Custom events](https://docs.agentcat.com/sdk/custom-events.md).
* Exporters: `otlp`, `datadog`, and `sentry`. The Python SDK has no PostHog exporter.
* The old package name is `mcpcat`. It still works, but new features go to `agentcat`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.