Conversation IDs
Contents
A PostHog $session_id normally follows the MCP protocol session. The handshake-free 2026-07-28 revision has no protocol session, so each request gets a new session unless you add another correlation signal.
$mcp_conversation_id groups those calls by conversation. The SDK also derives $session_id from an accepted conversation handle, so PostHog session queries group the same calls.
Conversation IDs are enabled by default. Calls stay correlated when the agent echoes the handle returned in tool results.
Enabling
No extra configuration is needed in either SDK:
The SDK does three things:
- Injects an optional
conversation_idargument into compatible tool schemas, with a description telling the agent to reuse the value the server returns. - Creates a handle when needed and returns it on eligible tool responses as a
{"conversation_id":"…"}text block. - Captures the handle as
$mcp_conversation_id. When the agent echoes a valid handle, the SDK derives a stable$session_idfrom it. Until then, existing protocol sessions remain in use.
The SDK reuses an echoed UUIDv7 that matches the handles it creates. It replaces missing or arbitrary values with a new handle to avoid merging unrelated conversations.
Event properties
A new request or connection made by the same agent reusing the same conversation_id shares both $mcp_conversation_id and $session_id. You can group by the conversation property in HogQL:
Caveats
The SDK cannot add conversation_id to schemas that use oneOf, allOf, anyOf, or $ref. It also skips tools without an input schema. It logs a warning and returns no handle for these tools. Use identify to group their calls by user.
A client with a stale cached tool listing does not know about the new parameter. The ttlMs setting on tools/list can extend this period.
The SDK returns the handle as a {"conversation_id":"…"} text block. Clients that display raw tool results also display this JSON. The block contains data rather than an instruction because hardened clients can treat instructions in tool results as prompt injection.
The SDK preserves structured output and result metadata. Clients that only consume structured output may never see the text block, so they may not echo the handle.
The SDK only reuses UUIDv7 values that match the shape of handles it can create. It replaces other values with a new handle. A client can still reuse a valid-looking handle across users, so don't use $mcp_conversation_id as a security boundary.
PostHog's session-level joins use $session_id. When conversation IDs are enabled, the SDK hashes the accepted conversation_id into a deterministic $session_id. Separate server instances derive the same value without shared storage.
When to skip this
If your MCP server runs over a long-lived 2025-11-25 connection that already matches your conversation boundaries, you can disable conversation IDs. Set enableConversationId: false in TypeScript or MCPAnalyticsOptions(enable_conversation_id=False) in Python to omit the injected argument and response block.
Keep it enabled when:
- The same logical conversation crosses connections (HTTP/SSE clients that reconnect).
- Your server handles the
2026-07-28revision and you want more than one request in each PostHog session.