Repository navigation
feat(mcp): add a send_initialize_event option - #1115
Conversation
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 4571911: 1 Should fix.
This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
MCPAnalyticsOptions(capture_initialize=False) stops $mcp_initialize. The option is on by default. Many clients reconnect before every few tool calls, so the handshake event can outnumber $mcp_tool_call. With the option off, record_initialize and the first-request fallback return early. Nothing else changes: the middleware still mints the session token, so tool calls keep their sessions and client names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4571911 to
dca253f
Compare
posthog-python Compliance ReportDate: 2026-10-28T09:55:24.902541+00:00 ✅ All Tests Passed!121/121 tests passed Capture_V1 Tests✅ 95/95 tests passed View Details
Capture_Ai Tests✅ 5/5 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
Feature_Flags_Local_Evaluation Tests✅ 4/4 tests passed View Details
|
record_initialize returned before handle_identify when the option was off. An identify callback that resolves the user only from the initialize request then left the session anonymous, so later tool calls lost the user. Identify now runs first, and the option stops only the event. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@PostHog review |
|
@gesh PostHog Review is reviewing this pull request. |
There was a problem hiding this comment.
Not approved — this change needs a human reviewer.
Re-adding the stamphog label gives the same result unless the changed files change.
stamphog can't approve this pull request, because two gates refused it. The deny-list gate matched public_api: the change adds capture_initialize to MCPAnalyticsOptions in posthog/mcp/types.py and updates references/public_api_snapshot.txt. The tier gate classified the change as T2-never (108 lines across 6 files, cross-cutting, a feature), so it always needs a human reviewer. The size gate passed, so splitting the PR won't change this outcome. The next step is to ask a human maintainer to review it, ideally one who owns the public API surface of the MCP module.
- posthog[bot] reviewed the current head.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: public_api |
| size | ✓ | 14L, 2F substantive, 108L/6F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (108L, 6F, cross-cutting, feat) |
| stamphog 2.6.1 | .stamphog/policy.yml @ unknown · reviewed head 7e1f2f7 |
lucasheriques
left a comment
There was a problem hiding this comment.
LGTM, approving. One naming question worth settling before merge, plus an optional docs note.
| resolve_original_tool: Optional[Callable[[str], Any]] = None | ||
| # Send `$mcp_initialize` for each `initialize` handshake. On by default. | ||
| # False sends no `$mcp_initialize`. Nothing else changes. | ||
| capture_initialize: bool = True |
There was a problem hiding this comment.
These option names collide with the manual capture methods: PostHogMCP.capture_initialize(...) / capture_tools_list(...) already exist. Reading MCPAnalyticsOptions(capture_initialize=False) next to ph.capture_initialize(...) is confusing, and this is public API we'd have to deprecate in two SDKs to change later.
Could we pick names that don't overload the method? A few options:
send_initialize_event/send_tools_list_eventinitialize_event=False/tools_list_event=False- one
disabled_events=["$mcp_initialize", "$mcp_tools_list"]list, which also covers the next event we want to make optional
Not a strong preference on which one, just want it decided before we ship it. If you'd rather keep the names, fine, but let's do it on purpose. (Same applies to capture_tools_list in #1116, and should match whatever we pick in posthog-js#5401.)
There was a problem hiding this comment.
| serves one client, so this misses only a client that never sends a request. | ||
|
|
||
| Set `capture_initialize=False` to stop sending `$mcp_initialize`. Many clients reconnect before | ||
| every few tool calls, so this event can outnumber `$mcp_tool_call`. Nothing else changes: tool |
There was a problem hiding this comment.
optional: "Nothing else changes" is true for the SDK, but the dashboard template's users/sessions tiles and the onboarding waiting state both read $mcp_initialize. Maybe "Nothing else changes in what the SDK sends" or a short note? Fine to skip if we're moving those off initialize soon anyway.
There was a problem hiding this comment.
Added in 56a712f: "Nothing else changes in what the SDK sends", plus a note that onboarding and the dashboard's users and sessions tiles read $mcp_initialize.
PostHogMCP already has a capture_initialize() method that sends the event by hand. An option with the same name next to that method makes readers link the two. The new name says what the option controls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MCP onboarding and the users and sessions tiles of the default MCP dashboard read $mcp_initialize. The README now says that they show no data while send_initialize_event is off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
💡 Motivation and Context
$mcp_initializecan outnumber$mcp_tool_call.Part of one change across three repos: PostHog/posthog-js#5401 (
@posthog/mcp) and PostHog/sdk-specs#141 (the spec).Follow-up, stacked on this PR: #1116 adds the same option for
$mcp_tools_list.Changes
MCPAnalyticsOptions(send_initialize_event=False). It is on by default, so nothing changes unless a host sets it.capture_initialize, becausePostHogMCP.capture_initialize()is already a method that sends the event by hand.record_initializereturns afteridentifyand before the event. The first-request fallback returns early. These are the only places that send the event.identifystill runs in the handshake, so a user known only frominitializestays on later tool calls.$mcp_initialize. The README says that they show no data while the option is off.minorchangeset.💚 How did you test it?
test_send_initialize_event_off_sends_no_initialize_and_keeps_sessionsdrives two round-robin pods over HTTP, for the SDK high-level server, standalone fastmcp, and a low-levelServer, on both SDK majors. It asserts no$mcp_initialize, a minted token, each connection's tool calls in that token's session, and the client name on every pod.test_send_initialize_event_off_keeps_the_handshake_identityuses anidentifycallback that returns a user only forinitialize. The later tool call keeps that user.test_send_initialize_event_off_also_gates_the_first_request_fallbackcovers SDK 1.x without HTTP, as on stdio, with the option on and off.📝 Checklist
If releasing new changes
sampo addto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
claude-opus-5-5).🤖 Generated with Claude Code