---
title: MCP Analytics event reference
description: "Every event the Amplitude MCP Analytics SDK sends, when each one fires, and the properties it carries."
product: general
lang: en
last_updated: 2026-11-12
token_estimate: 4348
---
# MCP Analytics event reference

The Amplitude MCP Analytics SDK sends six events to your Amplitude project. This page lists when each one fires and the properties it carries. For what MCP Analytics does and how to set it up, go to [MCP Analytics](https://amplitude.com/docs/amplitude-ai/mcp-analytics).

> For AI agents: a documentation index is available at [/docs/llms.txt](/docs/llms.txt). Append `.md` to any page URL for markdown, or send `Accept: text/markdown`.

Every default event name and every SDK-derived property carries the `[MCP]` prefix. The prefix prevents collisions with events and properties that other Amplitude SDKs send to the same project. The events arrive through the standard Amplitude client, so they behave like any other event in your project.

## Events the SDK sends

| Event | Fires when | Toggle |
| --- | --- | --- |
| `[MCP] Session Initialized` | The `initialize` handshake completes. | `autocapture.serverEvents` |
| `[MCP] Session Ended` | A connection that outlived one request closes, after an initialized session. | `autocapture.serverEvents` |
| `[MCP] Tools Listed` | The server serves a `tools/list` request. | `autocapture.serverEvents` |
| `[MCP] Tool Call Response` | An instrumented tool call settles. | `autocapture.toolCalls` |
| `[MCP] Tool Call Rejected` | A `tools/call` request fails before any tool callback runs. | `autocapture.toolCalls` |
| `[MCP] Feedback Submitted` | An agent calls the opt-in `submit_feedback` tool. | Registering the tool is the opt-in |

The autocaptured events need the SDK bound to your server before you connect the server. If you wrap a tool on an unbound server, the wrapper is a no-op passthrough: the handler runs untouched, and the SDK emits nothing and logs a one-time warning.

The SDK is best-effort and never throws. It catches and logs its own failures, so an SDK failure can't break a handler, a `tools/list` response, or a connection. When a handler throws, the SDK emits the failure event first and then re-throws to the MCP SDK.

Session events depend on the transport. On protocol revision `2025-11-25` and earlier, a stateless Streamable HTTP server still performs the handshake, so `[MCP] Session Initialized` fires with a `[MCP] Session ID` of `no-session`. Protocol revision `2026-07-28` removes the handshake, so neither session event fires there. `[MCP] Session Ended` never fires for a transport built per request, because the connection starts and ends inside one request. The other four events fire on every transport and every revision.

## Identity on every event

Alongside `event_properties`, every event carries the standard Amplitude identity fields. The SDK resolves those fields per request through a fixed chain, and the first match wins.

| Order | Source |
| --- | --- |
| 1 | An explicit identity set during the request. |
| 2 | A per-tool resolver callback that returns a non-empty result from the request's verified auth info. |
| 3 | The static identity passed when you bound the server. |
| 4 | The correlation anchor: process, session id, or trace. |
| 5 | The anonymous per-request floor. |

At level 4, `user_id` is the synthetic key `<anchor type>:<anchor value>`. At level 5, it's `anonymous:<device id>`. When you supply a `user_id` without a `device_id`, the SDK derives a stable `device_id` from the anchor so calls in the same session, process, or trace correlate.

The SDK sends a tenant to Amplitude `groups`, not to an event property.

The SDK drops an event when the identity resolved to the anonymous floor and the event carries no tenant, rather than emitting noise. In practice, this rule affects only stateless Streamable HTTP requests with no identity configured and no trace context propagated.

### Correlation anchor

The anchor is the per-request correlation key the SDK derives from the transport. It feeds `[MCP] Anchor Type`, `[MCP] Session ID`, and the synthetic identity floor. The SDK never fabricates a session id.

| Transport | `[MCP] Anchor Type` | `[MCP] Session ID` |
| --- | --- | --- |
| stdio | `process` | `no-session` |
| Streamable HTTP with a session id | `session-id` | The session id |
| Stateless Streamable HTTP with a W3C `traceparent` | `trace` | `no-session` |
| Stateless Streamable HTTP with no trace context | `anonymous` | `no-session` |

## Shared properties

These SDK-derived properties appear on every event, including the custom events you send through the SDK.

| Property | Type | Present | Value |
| --- | --- | --- | --- |
| `[MCP] Session ID` | string | Always | The protocol session id, or `no-session`. |
| `[MCP] Client Name` | string | Always | The MCP client name, or `unknown` when unavailable. |
| `[MCP] Client Version` | string | When known | The MCP client version. |
| `[MCP] OAuth Client ID` | string | When authenticated | The OAuth `client_id` for the request. Identifies a client registration, not a product. |
| `[MCP] User Agent` | string | Always | The raw HTTP `User-Agent` header on Streamable HTTP, and `unknown` on stdio. |
| `[MCP] Server Name` | string | Always | The server name you configured. |
| `[MCP] Server Version` | string | When set | The server version you configured. |
| `[MCP] Server Type` | string | When set | Your server classification, on a manually built context only. |
| `[MCP] Transport` | string | Always | `stdio` or `streamable-http`, auto-detected. |
| `[MCP] Anchor Type` | string | Always | `session-id`, `trace`, `process`, or `anonymous`. |
| `[MCP] Protocol Version` | string | When carried | The negotiated MCP protocol revision, read per request. Absent on stdio and on the session events. |
| `[MCP] Auth Type` | string | When configured | The auth type you passed when you bound the server, such as `oauth`. |

Enrichment values you attach at server scope appear on every event. Values you attach at tool scope appear on the tool-scope events.

## `[MCP] Session Initialized`

`[MCP] Session Initialized` marks the start of a protocol session. It fires when the MCP `initialize` request succeeds. At that moment, the SDK also captures the client's identifying information.

This event carries the shared properties and your server-scope enrichment values. It has no event-specific properties.

## `[MCP] Session Ended`

`[MCP] Session Ended` marks the end of a protocol session. It fires when the transport closes, but only under two conditions: `[MCP] Session Initialized` fired for that connection first, and the transport outlived the request that opened it.

| Property | Type | Present | Value |
| --- | --- | --- | --- |
| `[MCP] Session Duration` | number | When known | Milliseconds from the `initialize` handshake to transport close, rounded. |

## `[MCP] Tools Listed`

`[MCP] Tools Listed` reports each `tools/list` request the server serves, with the live tool set at call time. It fires when the handler returns or throws, and the handler's own behavior passes through untouched.

| Property | Type | Present | Value |
| --- | --- | --- | --- |
| `[MCP] Is Error` | boolean | Always | `true` when the handler threw. |
| `[MCP] Tool Count` | number | Always | The true total number of tools returned, even when the SDK truncates the name list. `0` on failure. |
| `[MCP] Tool Names` | string\[\] | When at least one tool | The returned tool names, capped at 100 entries. |
| `[MCP] Tool Names Truncated` | boolean | Only when capped | `true` when the list exceeded 100 names. |
| `[MCP] Response Duration` | number | Always | Milliseconds the handler took. |
| `[MCP] Response Size` | number | On success, when serializable | Serialized byte size of the full result. |
| `[MCP] Error Message` | string | On failure | The message of the classified error. |
| `[MCP] Error Code` | string | On failure, when known | A machine-readable error identifier. |
| `[MCP] Error Type` | string | On failure | The error category. |

## `[MCP] Tool Call Response`

`[MCP] Tool Call Response` is the default tool-execution event, one per call of an instrumented handler. It fires when the handler settles: returns, throws, or rejects. On failure, the SDK emits the event before it re-throws the error.

A call counts as a failure when the handler throws or rejects, or when it returns an in-band error result.

| Property | Type | Present | Value |
| --- | --- | --- | --- |
| `[MCP] Tool Name` | string | Always | The tool name from the tool metadata. |
| `[MCP] Tool Owner` | string | When set | The owner from the tool metadata. |
| `[MCP] Tool Tags` | string\[\] | When set | The tags from the tool metadata. |
| `[MCP] Tool Category` | string | When set | The category from the tool metadata. |
| `[MCP] Conversation ID` | string | When the request supplies it | The host conversation or thread identifier. |
| `[MCP] Run ID` | string | When the request supplies it | The agent run or batch job identifier. |
| `[MCP] Turn ID` | string | When the request supplies it | The turn identifier or normalized turn number. |
| `[MCP] Subject ID` | string | When ChatGPT sends it | The anonymized ChatGPT user id. It isn't a `user_id` and isn't an episode boundary. |
| `[MCP] Episode Anchor Type` | string | Always | `conversation-id`, `run-id`, `transport-session`, `trace`, or `inferred`. |
| `[MCP] Episode Anchor Confidence` | string | Always | `high`, `medium`, or `low`. |
| `[MCP] Is Error` | boolean | Always | `true` on a thrown exception or an in-band error result. |
| `[MCP] Response Duration` | number | Always | Milliseconds the handler took, rounded. |
| `[MCP] Request Size` | number | Schema-taking handlers, when serializable | Serialized byte size of the tool's arguments. |
| `[MCP] Response Size` | number | When the handler returned, and serializable | Serialized byte size of the returned result. Absent when the handler threw. |
| `[MCP] Param Keys` | string\[\] | Schema-taking handlers, unless shape capture is off | Sorted top-level parameter keys, capped at 32. |
| `[MCP] Param Count` | number | Schema-taking handlers, unless shape capture is off | The uncapped count of supplied top-level keys, after exclusions. |
| `[MCP] Param Shape` | string | Schema-taking handlers, unless shape capture is off | A deterministic shallow shape, capped at 1,024 characters. |
| `[MCP] Param Fingerprint` | string | Schema-taking handlers, unless shape capture is off | The first 12 hexadecimal characters of a SHA-256 hash over the emitted shape. |
| `[MCP] Param: <key>` | string, number, or boolean | When the tool declares a derived fact | Tool-authored derived metadata. |
| `[MCP] Error Message` | string | On failure | The message of the classified error. |
| `[MCP] Error Code` | string | On failure, when known | A machine-readable error identifier. |
| `[MCP] Error Type` | string | On failure | The error category. |

`[MCP] Param Count` is uncapped, and the SDK caps `[MCP] Param Keys` at 32. A count higher than the number of keys means the SDK omitted some keys.

## `[MCP] Tool Call Rejected`

`[MCP] Tool Call Rejected` reports each `tools/call` request that fails before any tool callback runs. A request can fail before dispatch because the requested tool doesn't exist, because the tool is disabled, or because the arguments fail input-schema validation. No handler executes, so these calls would otherwise go unrecorded.

The attempted name is unvalidated caller input, so the SDK sends it as `[MCP] Attempted Tool Name` and never as `[MCP] Tool Name`, the key that per-tool dashboards slice on. Parameter capture doesn't run for this event, because rejected arguments are unvalidated.

One request never produces both this event and `[MCP] Tool Call Response`. A call that reached a tool callback reports on `[MCP] Tool Call Response` instead, even when the protocol layer fails after dispatch.

| Property | Type | Present | Value |
| --- | --- | --- | --- |
| `[MCP] Attempted Tool Name` | string | Always | The tool name the client sent, capped at 200 characters. |
| `[MCP] Rejection Reason` | string | Always | `unknown_tool`, `disabled_tool`, `schema_validation`, or `unrecognized`. |
| `[MCP] Is Error` | boolean | Always | Always `true`. |
| `[MCP] Error Message` | string | Unless redaction drops it | The message as the client saw it, after built-in PII redaction. |
| `[MCP] Error Code` | string | When recoverable | The JSON-RPC error code the client received, such as `-32602`. |
| `[MCP] Error Type` | string | Always | Always `protocol_error`. |
| `[MCP] Response Duration` | number | Always | Milliseconds the `tools/call` handler took. |
| `[MCP] Response Size` | number | When serializable | Serialized byte size of the response the client received. |
| `[MCP] Response HTTP Status` | number | Streamable HTTP only | `200`. Protocol-level rejections answer HTTP 200 with the error in the JSON-RPC body. |

The MCP SDK raises the same error for every pre-dispatch failure, so all three causes arrive with the same error code and type. `[MCP] Rejection Reason` carries the cause structurally instead. It contains no caller data, so redaction never affects it. `unrecognized` is the deliberate fallback value for a cause the SDK can't establish. If `unrecognized` becomes more frequent after you upgrade the MCP SDK, check what changed upstream.

## `[MCP] Feedback Submitted`

`[MCP] Feedback Submitted` fires when an agent calls the `submit_feedback` tool, which you register explicitly. It's the direct "did this help" signal: the agent reports what the user expressed, and the SDK doesn't infer feedback from any other tool's result.

This event doesn't pair with `[MCP] Tool Call Response`, and `autocapture.toolCalls: false` doesn't suppress the event. The event carries no conversation content.

| Property | Type | Present | Value |
| --- | --- | --- | --- |
| `[MCP] Tool Name` | string | Always | The registered name, `submit_feedback` by default. |
| `[MCP] Feedback Helpful` | boolean | Always | The `helpful` argument. |
| `[MCP] Feedback Reason` | string | When the agent sent a known reason | `wrong_result`, `incomplete`, `too_slow`, `wrong_tool`, `missing_capability`, or `other`. The SDK drops any other value. |
| `[MCP] Feedback Solicited` | boolean | When the agent sent a boolean | `true` when the agent asked, `false` when the user volunteered it. |
| `[MCP] Feedback Tool Names` | string\[\] | When at least one name matched the registry | Up to 8 deduplicated names, in the order given. |
| `[MCP] Feedback Has Comment` | boolean | Always | `true` when comment capture is on and the user supplied a non-empty comment. |
| `[MCP] Feedback Comment` | string | When comment capture is on and the text survived redaction | The comment, capped at 500 characters and then redacted. |

Comment capture is off by default. Until you turn comment capture on, the field is absent from the tool schema, so the schema never requests free text from the agent.

## Error classification

`[MCP] Error Type` is a closed set that the SDK assigns. Hosts never pick the value. The property appears on `[MCP] Tool Call Response`, `[MCP] Tools Listed`, and `[MCP] Tool Call Rejected`.

| Value | Meaning |
| --- | --- |
| `returned_error` | The tool returned an in-band error result. |
| `thrown_exception` | The handler threw an error that matches no more specific rule. |
| `timeout` | The handler threw an abort error. |
| `transport_error` | The thrown error carried a network error code, such as `ECONNREFUSED` or `ETIMEDOUT`. |
| `rate_limited` | An otherwise-unclassified thrown error carried HTTP status 429. |
| `protocol_error` | A `tools/call` failed before dispatch. Always the type on `[MCP] Tool Call Rejected`. |
| `unknown` | The handler threw a value that isn't an error. |

`[MCP] Error Code` is the finer-grained companion to `[MCP] Error Type`. The SDK emits the code only when a specific identifier is known: a code you supplied, a system error code, or a JSON-RPC code. The SDK omits the code for a bare thrown exception rather than echoing the type, so its presence means a specific known reason exists.

To attach a machine-readable code to an in-band error result and control the result's message, build the result with the SDK's tool-error helper. Describe the specific failure through that free-form code, not through the error type. The SDK emits the code as `[MCP] Error Code`.

## Parameter capture

Shape capture is on by default. It reads only the handler's parsed, schema-validated argument object. It represents parameter values only by types, collection counts, and bucketed string lengths. Shape capture never walks nested content, and it never records parameter values.

The global exclusion list defaults to `rationale` and `context`. If you replace that list, include those names again when you still want them omitted.

Servers can opt in to richer capture for an individual tool:

- **Route values**: A declared route key contributes a prefix to the shape, but only for a small schema enum. Don't declare a route key on a high-cardinality id field.
- **Derived facts**: A tool can emit up to eight scalar `[MCP] Param: <key>` facts. The SDK drops string values longer than 256 characters, values containing `@`, quotes, or newlines, and non-finite numbers. A callback that throws or returns the wrong shape emits no facts and can't affect the handler.

Capture doesn't run on an unbound server, which preserves the no-op passthrough for a wrapped tool.

