> ## 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

> Set up AgentCat in a Python MCP server, with identity and every feature on.

> [!TIP]
>
> Your coding agent can do the setup for you with this prompt:
>
> ```text theme={null}
> Read and follow https://docs.agentcat.com/languages/python.md to set up AgentCat in this MCP server. Follow its Guidance for AI agents.
> ```

## Supported MCP SDKs

| MCP library | Versions | Transports | Runtime |
| - | - | - | - |
| Official `mcp` 2.x (`MCPServer` in `mcp.server.mcpserver`) | 2.0.0 and later 2.x | stdio, streamable HTTP, stateless HTTP | Python 3.10 or later |
| Official `mcp` 1.x (`FastMCP` in `mcp.server.fastmcp`) | 1.2 and later 1.x | stdio; streamable and stateless HTTP from 1.8 | Python 3.10 or later |
| Community `fastmcp` (`FastMCP` in `fastmcp`) | 3.0 and later, below 5 | stdio, streamable HTTP, stateless HTTP | Python 3.10 or later |

For a new server, we recommend `mcp` 2.x, because it implements the stateless MCP protocol of 2026-07-28. One `agentcat` package supports all three, and `track()` finds the library by itself.

## Installation

```bash mcp 2.x theme={null}
pip install agentcat
```

```bash mcp 1.x theme={null}
pip install agentcat "mcp<2"
```

```bash fastmcp theme={null}
pip install "agentcat[community]"
```

The SDK needs your project ID, which you can find in the [AgentCat dashboard](https://agentcat.com/app/settings/projects/). We recommend the `AGENTCAT_PROJECT_ID` environment variable, which keeps the ID out of your code.

## Adding AgentCat to your server

`agentcat.track()` adds AgentCat to the server object where your code creates it:

```python mcp 2.x theme={null}
import os

import agentcat
from mcp.server.mcpserver import MCPServer

def create_server() -> MCPServer:
    server = MCPServer("my-server", version="1.0.0")
    # @server.tool() ...
    agentcat.track(server, os.environ["AGENTCAT_PROJECT_ID"])
    return server

server = create_server()
server.run(transport="streamable-http", stateless_http=True)
```

```python mcp 1.x theme={null}
import os

import agentcat
from mcp.server.fastmcp import FastMCP

server = FastMCP("my-server")
# @server.tool() ...
agentcat.track(server, os.environ["AGENTCAT_PROJECT_ID"])

server.run(transport="streamable-http")
```

```python fastmcp theme={null}
import os

import agentcat
from fastmcp import FastMCP

server = FastMCP("my-server", version="1.0.0")
# @server.tool ...
agentcat.track(server, os.environ["AGENTCAT_PROJECT_ID"])

server.run(transport="http")
```

A stateless HTTP server serves every request from one server object. A factory that builds one object for each worker or tenant, as in the 2.x tab, needs `track()` inside it.

## Identifying users

> [!NOTE]
>
> We strongly recommend that you identify your users. Without identity, the dashboard cannot show who uses your server, and each session stays anonymous.

The `identify` hook tells AgentCat which user made each tool call. We recommend the first of these two levels that your server can give. The hook is the same on all three libraries.

### Full identity (recommended)

Full identity gives each session a real user ID and name, read from the request:

```python theme={null}
from agentcat import AgentCatOptions, UserIdentity

async def identify(request, extra):
    http = getattr(extra, "request", None)
    token = http.headers.get("authorization", "").removeprefix("Bearer ") if http else ""
    if not token:
        return None
    user = await get_user_by_token(token)  # your own lookup
    if not user:
        return None
    return UserIdentity(user_id=user.id, user_name=user.name, user_data=None)

agentcat.track(server, os.environ["AGENTCAT_PROJECT_ID"], AgentCatOptions(identify=identify))
```

### Anonymized identity (the minimum)

If you prefer not to send user details, a stable ID works too, for example a hash of the token or API key. The same user always gets the same ID:

```python theme={null}
import hashlib

from agentcat import AgentCatOptions, UserIdentity

async def identify(request, extra):
    http = getattr(extra, "request", None)
    token = http.headers.get("authorization", "").removeprefix("Bearer ") if http else ""
    if not token:
        return None
    digest = hashlib.sha256(token.encode()).hexdigest()
    return UserIdentity(user_id=f"anon-{digest[:16]}", user_name=None, user_data=None)

agentcat.track(server, os.environ["AGENTCAT_PROJECT_ID"], AgentCatOptions(identify=identify))
```

With MCP auth, `get_access_token()` from `mcp.server.auth.middleware.auth_context` returns the checked token. A stdio server has no HTTP headers, so the hook can read the key that your server already uses, for example from `os.environ`. If the hook fails or takes more than 5 seconds, the event still goes out, without identity. Without an `identify` hook, AgentCat still works, but every user is anonymous.

## Recommended settings

AgentCat turns on every feature by default, and we recommend that you keep them that way. Each one adds a view of how agents use your server:

* **Intent** (`enable_tool_call_context`): agents tell you why they call each tool, which powers session goals.
* **Agent feedback** (`enable_report_missing`): agents can report tools that they looked for and did not find.
* **Sessions** (`enable_tracing`): AgentCat groups the calls of one task into one session, so you can replay it.
* **Diagnostics** (`disable_diagnostics` turns it off): anonymous error reports help us fix a broken install faster.

If you need to turn one off, the [reference page](https://docs.agentcat.com/languages/python/reference.md#options) explains each option.

## Testing your setup

With debug mode on (`AGENTCAT_DEBUG_MODE=true` or `AgentCatOptions(debug_mode=True)`), the Python SDK writes its log to `~/agentcat.log`.

1. Watch the log:

```bash theme={null}
tail -f ~/agentcat.log
```

2. Start your real server with debug mode on, as you start it in production:

```bash theme={null}
AGENTCAT_DEBUG_MODE=true AGENTCAT_PROJECT_ID=<project-id> python server.py
```

3. Call one tool with an MCP client, for example the MCP Inspector CLI:

```bash theme={null}
npx @modelcontextprotocol/inspector --cli http://localhost:8000/mcp --transport http \
  --header "Authorization: Bearer <token>" \
  --method tools/call --tool-name <tool> --tool-arg <name>=<value> \
  --tool-arg session_id=start --tool-arg "context=Testing that AgentCat records this tool call."
```

For a stdio server, you can replace the URL and `--transport http` with the command that starts your server, and leave out `--header`.

4. Look for `Successfully sent event ... | mcp:tools/call | ...` in the log. The line ends with the user ID from `identify`, or `anonymous`. In [Sessions](https://agentcat.com/app/sessions/), the new session shows the user name.

A coding agent can confirm the event with the [AgentCat MCP server](https://docs.agentcat.com/agent/connect.md). If no event arrives, the log shows whether `track()` worked and whether a send failed.

## Guidance for AI agents

1. Keep `identify` in place, because without it every user is anonymous; if the developer does not want to send user details, offer the anonymized ID.
2. Return the same ID for the same user on every call, because a random value or a timestamp splits one user into many.
3. Pass all three fields to `UserIdentity`, with `None` for unused ones, because the constructor has no defaults.
4. Keep raw tokens, API keys, and passwords out of `user_id`, `user_name`, and `user_data`, because AgentCat stores and shows them.
5. Leave `enable_tool_call_context`, `enable_report_missing`, and `enable_tracing` at their defaults, because each one feeds a part of the dashboard.
6. Read the project ID from `AGENTCAT_PROJECT_ID`, so that it stays out of committed code.
7. Call `track()` once per server object, and inside the factory when one builds the objects, because the factory makes a new object each time.
8. Run `pip index versions agentcat` before you pin a version, because a remembered version can be old.
9. Test through the real server start with debug mode on, because a separate script can skip the `track()` call.

## Next steps

> [card] [Python reference](https://docs.agentcat.com/languages/python/reference.md)
>
> Options, transports, delivery, and limits

> [card] [Custom events](https://docs.agentcat.com/sdk/custom-events.md)
>
> Send your own events

> [card] [Tags and properties](https://docs.agentcat.com/sdk/event-tags-properties.md)
>
> Add data that you can filter on

> [card] [Redaction](https://docs.agentcat.com/privacy-security/client-side-redaction.md)
>
> Remove sensitive data in your server

> [card] [Exporters](https://docs.agentcat.com/integrations.md)
>
> Copies of events for OpenTelemetry, Datadog, or Sentry


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