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

# TypeScript

> Set up AgentCat in a TypeScript 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/typescript.md to set up AgentCat in this MCP server. Follow its Guidance for AI agents.
> ```

## Supported MCP SDKs

| MCP library | Versions | Transports | Runtime |
| - | - | - | - |
| `@modelcontextprotocol/server` (MCP SDK 2.x) | 2.0.0 and later 2.x | stdio, streamable HTTP, stateless HTTP | Node.js 20 or later, Cloudflare Workers |
| `@modelcontextprotocol/sdk` (MCP SDK 1.x) | 1.11 and later 1.x | stdio, streamable HTTP, stateless HTTP | Node.js 20 or later |

For a new server, we recommend `@modelcontextprotocol/server` 2.x, because it implements the stateless MCP protocol of 2026-07-28. One `agentcat` package supports both, and `track()` finds the MCP SDK version by itself.

## Installation

```bash theme={null}
npm install agentcat
```

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. The SDK does not read it by itself, so the snippets pass it to `track()`.

## Adding AgentCat to your server

`agentcat.track()` adds AgentCat to an `McpServer`, in the place where your code creates it:

```typescript MCP SDK 2.x theme={null}
import { createMcpHandler, McpServer } from "@modelcontextprotocol/server";
import * as agentcat from "agentcat";

const handler = createMcpHandler(() => {
  const server = new McpServer({ name: "my-server", version: "1.0.0" });
  // server.registerTool(...)
  return agentcat.track(server, process.env.AGENTCAT_PROJECT_ID!);
});
```

```typescript MCP SDK 1.x theme={null}
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import * as agentcat from "agentcat";

const server = new McpServer({ name: "my-server", version: "1.0.0" });
// server.registerTool(...)
agentcat.track(server, process.env.AGENTCAT_PROJECT_ID!);
```

A stateless server creates a new `McpServer` for each request (`createMcpHandler`) or each connection (`serveStdio`). Each `track()` call tracks one instance, so the call goes inside that factory, as the 2.x tab shows.

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

### Full identity (recommended)

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

```typescript MCP SDK 2.x theme={null}
// Inside the createMcpHandler factory
return agentcat.track(server, process.env.AGENTCAT_PROJECT_ID!, {
  identify: async (request, ctx) => {
    const token = ctx?.http?.req?.headers.get("authorization")?.replace("Bearer ", "");
    if (!token) return null;
    const user = await getUserByToken(token); // your own lookup
    if (!user) return null;
    return { userId: user.id, userName: user.name };
  },
});
```

```typescript MCP SDK 1.x theme={null}
agentcat.track(server, process.env.AGENTCAT_PROJECT_ID!, {
  identify: async (request, extra) => {
    const token = String(extra?.requestInfo?.headers?.authorization ?? "").replace("Bearer ", "");
    if (!token) return null;
    const user = await getUserByToken(token); // your own lookup
    if (!user) return null;
    return { userId: user.id, userName: user.name };
  },
});
```

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

```typescript MCP SDK 2.x theme={null}
import { createHash } from "node:crypto";

// Inside the createMcpHandler factory
return agentcat.track(server, process.env.AGENTCAT_PROJECT_ID!, {
  identify: async (request, ctx) => {
    const token = ctx?.http?.req?.headers.get("authorization")?.replace("Bearer ", "");
    if (!token) return null;
    const hash = createHash("sha256").update(token).digest("hex");
    return { userId: `anon-${hash.slice(0, 16)}` };
  },
});
```

```typescript MCP SDK 1.x theme={null}
import { createHash } from "node:crypto";

agentcat.track(server, process.env.AGENTCAT_PROJECT_ID!, {
  identify: async (request, extra) => {
    const token = String(extra?.requestInfo?.headers?.authorization ?? "").replace("Bearer ", "");
    if (!token) return null;
    const hash = createHash("sha256").update(token).digest("hex");
    return { userId: `anon-${hash.slice(0, 16)}` };
  },
});
```

With MCP auth, the checked token is in `ctx.http.authInfo.token` (2.x) or `extra.authInfo.token` (1.x). A stdio server has no HTTP headers, so the hook can read the key that your server already uses, for example from `process.env`. If the hook throws or takes more than 30 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 different view of how agents use your server:

* **Intent** (`enableToolCallContext`): agents tell you why they call each tool, which powers session goals.
* **Agent feedback** (`enableReportMissing`): agents can report tools that they looked for and did not find, through the `get_more_tools` tool.
* **Sessions** (`enableTracing`): AgentCat records each tool call and groups the calls of one task into one session, so you can replay it.
* **Diagnostics** (`disableDiagnostics` 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/typescript/reference.md#options) explains each option.

## Testing your setup

The TypeScript SDK always writes its log to `~/agentcat.log`, so it needs no debug option. The log shows the setup and each event that AgentCat sends.

1. Watch the log:

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

2. Start your real server with `AGENTCAT_PROJECT_ID` set, as you start it in production.
3. Call one tool with an MCP client, for example the MCP Inspector CLI:

```bash theme={null}
npx @modelcontextprotocol/inspector --cli http://localhost:3000/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 from `identify`.

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. On Cloudflare Workers, the log goes to the console instead.

## 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. Keep raw tokens, API keys, and passwords out of `userId`, `userName`, and `userData`, because AgentCat stores and shows them.
4. Leave `enableToolCallContext`, `enableReportMissing`, and `enableTracing` at their defaults, because each one feeds a part of the dashboard.
5. Read the project ID from `AGENTCAT_PROJECT_ID`, so that it stays out of committed code.
6. Call `track()` once per server instance, and inside the factory on a stateless server, because the factory makes a new instance each time.
7. Run `npm view agentcat version` before you pin a version, because a version from memory can be old.
8. Test through the real server start, because a separate script can skip the `track()` call.

## Next steps

> [card] [TypeScript reference](https://docs.agentcat.com/languages/typescript/reference.md)
>
> Options, runtimes, shutdown, 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, Sentry, or PostHog


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