feat(kilo-mcp): add server-side PostHog analytics to the MCP worker (part 1/1) - #6066
feat(kilo-mcp): add server-side PostHog analytics to the MCP worker (part 1/1)#6066iscekic wants to merge 4 commits into
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryThe incremental fix at HEAD 6c42d90 gates the OAuth failure emit on the winning pending → denied / expired transition and persists upstream expiry as a terminal record, so each pairing emits at most one failure event; no new issues found. Files Reviewed (11 files)
Previous Review Summaries (2 snapshots, latest commit 028ff55)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 028ff55)Status: No Issues Found | Recommendation: Merge Executive SummaryThe two prior findings are resolved at HEAD 028ff55: caller-supplied tool names are normalized to Files Reviewed (4 files)
Previous review (commit 60a8653)Status: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (13 files)
Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0 Review guidance: REVIEW.md from base branch |
60a8653 to
028ff55
Compare
- the denied poll emits kilo_mcp_oauth_sign_in_failed only when this request wins the pending -> denied transition, so concurrent polls do not double-count. - an upstream expired answer is persisted as a terminal code status (pending -> expired) and emitted once; later polls answer expired from the record. The org picker rejects the expired state too.
…o kwf/add-posthog-analytics-to-the-dcd5-l1
…o kwf/add-posthog-analytics-to-the-dcd5-l1
Changelog for users
unknown, the resolved catalog path, success or failure, the error class, and the latency.Changelog for maintainers
services/kilo-mcp/src/index.ts:331— accepted:tools/callaccepts any string asname, so the recorded value was caller-controlled. Analytics now records only the published names (search,call) and reports every other value asunknown; thepath-is-a-real-catalog-key guard is unchanged.services/kilo-mcp/src/oauth-pages/authorize-page.ts:179— accepted: the terminaldeniedbranch re-emitted the sign-in failure on every poll.denyCodeonly transitions pending → denied at the branch that already emits once, so polling a denied record now answers denied without re-emitting.services/kilo-mcp/src/analytics.ts: a direct capture POST with a 5 second timeout, no SDK, and no new dependency.[kilo-mcp] analytics <event> <json>, gates onNEXT_PUBLIC_POSTHOG_KEY, and schedules throughwaitUntil; the emitter cannot throw.auth/authorize.ts(started, failed),auth/token.ts(succeeded andinvalid_grant), andoauth-pages/authorize-page.ts(denied, expired).wrangler.jsoncaddsNEXT_PUBLIC_POSTHOG_KEYas a worker var; it is absent fromenv.dev, so local runs do not send.worker-configuration.d.tsis regenerated with unrelated workerd runtime-type churn — review the generated diff.vitest.config.tsnow uses the verbose reporter. Confirm this is intended.E2E proof
Stack-wide proof from the stack tip. The injection-name and denial-poll checks replace the earlier claims that a tool call records the raw caller name and that every poll of a denied pairing emits a failure.
kilo_mcp_tool_calledwith the published tool name, success=true, the resolved path, and a latency.kilo_mcp_search_performedhit_count=0 empty=true; a search with hits emits hit_count>0 empty=false.kilo_mcp_tool_calledsuccess=false with error_classunknown_pathorschema_invalid, plus a rejection event.kilo_mcp_call_rejectedreason=auth_failure with distinct_idkilo-mcp-anonymousand no userId.kilo_mcp_tool_calledsuccess=false error_class=upstream_unreachable while the MCP response is unchanged.kilo_mcp_session_startedwith protocol_version and client_name.kilo_mcp_oauth_sign_in_startedwith client_id and no user identity.kilo_mcp_oauth_sign_in_succeededbound to userId and organizationId.kilo_mcp_oauth_sign_in_failedwith reason expired or invalid_grant; a denied pairing emits once at the transition, as the denial-poll check below shows.tools/callwhoseparams.nameis an injection-shaped string logskilo_mcp_tool_calledwithtool=unknownanderrorClass=unknown_tool; the raw name is absent from the log line and any captured payload.GET /authorize/statuseach answer{"status":"denied"}and exactly onekilo_mcp_oauth_sign_in_failedwith reason=denied is logged across all polls.tools/callforsearchand forcallstill logstool=searchandtool=callinkilo_mcp_tool_called.[kilo-mcp] analytics kilo_mcp_call_rejectedfor a POST /mcp without Authorization.Owner request for the stack