[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-posthog-debugging-mcp-analytics":3,"mdc--49w0ns-key":50,"related-repo-posthog-debugging-mcp-analytics":3125,"related-org-posthog-debugging-mcp-analytics":3224},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":25,"repoUrl":26,"updatedAt":27,"license":28,"forks":29,"topics":30,"repo":45,"sourceUrl":48,"mdContent":49},"debugging-mcp-analytics","debug and build PostHog MCP analytics","Debug, support, and build PostHog MCP Analytics — product analytics for MCP servers (the `@posthog\u002Fmcp` and `posthog.mcp` SDKs plus the mcp_analytics product). Use when MCP analytics data looks wrong or missing (\"events aren't showing\", \"intent clusters are empty\", \"sessions are missing\", \"per-tool numbers look wrong\"), when writing queries over `$mcp_*` events by hand, or when doing feature work on the SDKs, the dashboard and its query runners, the self-instrumented MCP server, the `wizard mcp-analytics` install command, or the in-app onboarding. Covers the repo map, the `$mcp_*` vocabulary and where each property comes from, the rules that silently corrupt metrics when ignored, the end-to-end pipeline and where each stage breaks, and which repo to change. For reading the data rather than fixing it, prefer the `exploring-mcp-*` and `improving-mcp-tools` skills.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"posthog","PostHog","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fposthog.png",[12,16,19,22],{"name":13,"slug":14,"type":15},"Observability","observability","tag",{"name":17,"slug":18,"type":15},"MCP","mcp",{"name":20,"slug":21,"type":15},"Analytics","analytics",{"name":23,"slug":24,"type":15},"Debugging","debugging",35568,"https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog","2026-08-06T06:09:19.392263",null,2977,[31,32,21,33,34,35,36,37,38,39,40,41,42,43,44],"ab-testing","ai-analytics","cdp","data-warehouse","experiments","feature-flags","javascript","product-analytics","python","react","session-replay","surveys","typescript","web-analytics",{"repoUrl":26,"stars":25,"forks":29,"topics":46,"description":47},[31,32,21,33,34,35,36,37,38,39,40,41,42,43,44],"🦔 PostHog is an all-in-one developer platform for building successful products. We offer product analytics, web analytics, session replay, error tracking, feature flags, experimentation, surveys, data warehouse, a CDP, and an AI product assistant to help debug your code, ship features faster, and keep all your usage and customer data in one stack.","https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog\u002Ftree\u002FHEAD\u002Fproducts\u002Fmcp_analytics\u002Fskills\u002Fdebugging-mcp-analytics","---\nname: debugging-mcp-analytics\ndescription: >\n  Debug, support, and build PostHog MCP Analytics — product analytics for MCP\n  servers (the `@posthog\u002Fmcp` and `posthog.mcp` SDKs plus the mcp_analytics\n  product). Use when MCP analytics data looks wrong or missing (\"events aren't\n  showing\", \"intent clusters are empty\", \"sessions are missing\", \"per-tool\n  numbers look wrong\"), when writing queries over `$mcp_*` events by hand, or\n  when doing feature work on the SDKs, the dashboard and its query runners, the\n  self-instrumented MCP server, the `wizard mcp-analytics` install command, or\n  the in-app onboarding. Covers the repo map, the `$mcp_*` vocabulary and where\n  each property comes from, the rules that silently corrupt metrics when\n  ignored, the end-to-end pipeline and where each stage breaks, and which repo\n  to change. For reading the data rather than fixing it, prefer the\n  `exploring-mcp-*` and `improving-mcp-tools` skills.\n---\n\n# Debugging MCP analytics\n\n**Product analytics for MCP servers.** A team ships an MCP server; the `@posthog\u002Fmcp` SDK\nwraps it in one line; every tool call, agent **intent**, and failure lands in PostHog as a\n`$mcp_*` event you can query, chart, alert on, and cluster — plus a dedicated dashboard. The\nMCP-layer sibling of `@posthog\u002Fai`.\n\nThe differentiator is **intent**: not \"ran `query_run` 14 times\" but \"was trying to find a\nchurn cohort\". Explicit non-goal: this does **not** replace LLM analytics \u002F AI observability\n— generation traces, prompt\u002Fresponse, and token cost belong there.\n\nStatus: **beta**, TypeScript and Python SDKs shipped, whole product still behind the\n`mcp-analytics` early-access flag (`products\u002Fmcp_analytics\u002Ffrontend\u002FfeaturePreviewGate.ts`).\nPostHog dogfoods it — its own MCP server instruments itself, and that data drives the\ndashboard. Public tracking: mega-issue **PostHog\u002Fposthog#64016**, which is the live source\nfor roadmap and customer wishlist.\n\n## Repos\n\nGitHub is the source of truth for where the code lives. Paths below are in-repo; for the\nrepos outside this monorepo, resolve a local checkout via\n[references\u002Flocal-repos.md](references\u002Flocal-repos.md) rather than assuming a location.\n\n| Concern                           | Repo                          | Where to look                                                                                                                                              |\n| --------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **Product \u002F dashboard**           | `PostHog\u002Fposthog` (this repo) | `products\u002Fmcp_analytics\u002F` — Django\u002FDRF + HogQL query runners + Temporal, Kea frontend, the `query-mcp-*` tool registry, and the analysis skills            |\n| **Self-instrumented server**      | `PostHog\u002Fposthog` (this repo) | `services\u002Fmcp\u002F` — PostHog's own MCP server (Hono); the dogfood event producer. Also hosts the _generated_ `query-mcp-*` handlers                           |\n| **Shared query reference**        | `PostHog\u002Fposthog` (this repo) | `products\u002Fposthog_ai\u002Fskills\u002Fquerying-posthog-data\u002Freferences\u002Fmodels-mcp.md`                                                                                |\n| **TypeScript SDK** `@posthog\u002Fmcp` | `PostHog\u002Fposthog-js`          | `packages\u002Fmcp\u002F` — the library customers install. Vocabulary source of truth: `src\u002Fextensions\u002Fconstants.ts`. Internals: `docs\u002FARCHITECTURE.md`              |\n| **Python SDK** `posthog.mcp`      | `PostHog\u002Fposthog-python`      | `posthog\u002Fmcp\u002F` — mirrors `posthog.ai`. Ships inside `posthog` (`pip install posthog`); `mcp`\u002F`fastmcp` are lazily-imported peer deps, **no `[mcp]` extra** |\n| **Docs**                          | `PostHog\u002Fposthog.com`         | `contents\u002Fdocs\u002Fmcp-analytics\u002F` (incl. `surfaces\u002F`), plus `src\u002Fhooks\u002FproductData\u002Fmcp_analytics.tsx` and the `mcp_analytics` entry in `src\u002Fdata\u002Ftools.ts`    |\n| **Install codemod**               | `PostHog\u002Fcontext-mill`        | `context\u002Fskills\u002Fmcp-analytics\u002F{config.yaml,description.md}`                                                                                                |\n| **Wizard CLI**                    | `PostHog\u002Fwizard`              | `bin.ts`, `src\u002Fcommands\u002Fmcp-analytics.ts`, `src\u002Flib\u002Fprograms\u002Fmcp-analytics\u002F`                                                                               |\n| **Wizard test harness**           | `PostHog\u002Fwizard-workbench`    | `apps\u002Fmcp-analytics\u002F` fixtures                                                                                                                             |\n\n**Don't conflate:**\n\n- `PostHog\u002Fmcp-analytics` is the **archived prototype** of this SDK — stuck at `0.0.9` with an\n  old `track(server, {...})` API. It published under the same `@posthog\u002Fmcp` name, so grepping\n  that name can land you there. npm `@posthog\u002Fmcp` now resolves to `PostHog\u002Fposthog-js`.\n- `products\u002Fmcp_store\u002F` is the MCP server marketplace \u002F team gateway, not this product. (Older\n  notes also mention a `products\u002Fmcp\u002F` build-tooling directory; it no longer exists — the server\n  and its generation tooling live in `services\u002Fmcp\u002F`.)\n- `wizard mcp add` installs the PostHog **MCP server** into a coding agent. That is NOT\n  `wizard mcp-analytics`, which instruments the user's _own_ server.\n\n> Line numbers drift and this area moves fast — **grep for the symbol**, never trust a\n> remembered line number. Confirm a checkout is on a sane branch before quoting its code.\n\n## Hard rules (break these and the numbers are silently wrong)\n\nThese are the failure modes that produce a plausible-looking answer rather than an error.\n\n1. **Always resolve the effective tool name through `EFFECTIVE_TOOL_SQL`.** The expression\n   lives once, in `products\u002Fmcp_analytics\u002Fbackend\u002Fhogql_queries\u002Fbase.py`:\n   `coalesce(nullIf(toString(properties.$mcp_exec_tool_call_name), ''), toString(properties.$mcp_tool_name))`.\n   It exists because a single-exec server can report the tool two different ways, and the two\n   eras of data coexist. Today `services\u002Fmcp` resolves the inner tool itself and passes it\n   straight in as the tool name (`execToolName()` in `src\u002Fhono\u002Ftool-executor.ts`, which falls\n   back to the literal `exec` when the inner command isn't recognized), so\n   `$mcp_tool_name` usually already holds the real tool. `$mcp_exec_tool_call_name` is\n   registered in `posthog\u002Ftaxonomy\u002Ftaxonomy.py` and coalesced defensively here, but **nothing\n   on master emits it** — treat it as historical rows plus in-flight work, not current\n   producer behaviour. Either way, aggregate through the coalesce: hand-rolling\n   `properties.$mcp_tool_name` alone silently buckets unrecognized exec calls under `exec`,\n   and misses any data that does carry the dedicated property.\n2. **Failures come from `$mcp_is_error` \u002F `$mcp_error_type` \u002F `$mcp_error_status`, never\n   `$exception`.** `$exception` can be disabled, isn't emitted when no error value is passed,\n   and never matched new-SDK events — so querying it returns nothing rather than failing.\n3. **Dash the in-progress bucket.** Every time-bucketed chart zero-fills and marks the final\n   incomplete interval via `products\u002Fmcp_analytics\u002Ffrontend\u002FtimeBuckets.ts` (`resolveWindow`,\n   `normalizeBucket`, `buildBucketKeys`, `lastBucketIsInProgress`). Omit it and a partial\n   period reads as a real decline.\n4. **`harness` is derived, and its logic exists in three places that must move in lockstep:**\n   `products\u002Fmcp_analytics\u002Fbackend\u002Fmcp_harness.py` (source of truth — see its module\n   docstring), `products\u002Fmcp_analytics\u002Ffrontend\u002Fdashboard\u002FharnessRegistry.ts`, and\n   `products\u002Fposthog_ai\u002Fskills\u002Fquerying-posthog-data\u002Freferences\u002Fmodels-mcp.md`.\n5. **Check which SDK version the dogfood server is on before trusting dogfood data.**\n   `services\u002Fmcp` consumes the SDK through an alias in its `package.json` and has historically\n   lagged the published version, so version-dependent properties (typed error types, `$lib`\n   identity, payload redaction) can be absent from PostHog's own data even when documented as\n   current. A query filtering on `$lib = 'posthog-node-mcp'` silently excludes all dogfood\n   traffic if that pin predates SDK 0.7.0. Note too that `services\u002Fmcp` uses the\n   **custom-dispatcher** (`PostHogMCP`) path rather than `instrument()`, so behaviour living\n   only in the `instrument()` path — stable sessions, `$identify` deduplication, `_meta`-based\n   client identity — has never applied to it at any version.\n6. **There are no SQL template files.** Every dashboard and tool-quality query is a typed\n   query runner behind the generic `\u002Fquery\u002F` endpoint. A `backend\u002Ftemplates\u002F*.sql` referenced\n   by older notes no longer exists.\n\n## Event vocabulary\n\nAll data lives on the shared ClickHouse **`events`** table — there is **no dedicated table**.\nEvery metric is an aggregation over `$mcp_tool_call`, usually grouped by `$session_id`.\n\nSource of truth for the SDK-emitted names is `packages\u002Fmcp\u002Fsrc\u002Fextensions\u002Fconstants.ts` in\n`PostHog\u002Fposthog-js`, exported as `PostHogMCPAnalyticsEvent` \u002F `PostHogMCPAnalyticsProperty`\n(import them for typesafe queries). PostHog-side descriptions — including the server-stamped\nand exec-mode properties the SDK does not define — live in `posthog\u002Ftaxonomy\u002Ftaxonomy.py`.\n\n**Events** (all `$`-prefixed; non-`$` names would be treated as customer events):\n`$mcp_tool_call` (primary), `$mcp_tools_list`, `$mcp_initialize`, `$mcp_missing_capability`,\n`$mcp_resource_read` \u002F `$mcp_resources_list`, `$mcp_prompt_get` \u002F `$mcp_prompts_list`,\n`$identify`, `$exception`.\n\n> **`$mcp_initialize` is not a universal session anchor.** The MCP 2026-07-28 stateless\n> revision removes the `initialize` handshake, so clients on that revision never emit it.\n> Anchor on the first `$mcp_tool_call` instead.\n\nFull property tables — split by provenance (SDK-emitted vs stamped by PostHog's own server vs\nexec-mode only), the identifier distinctions, per-version SDK behaviour, and TypeScript\u002FPython\nparity — are in [references\u002Fevent-vocabulary.md](references\u002Fevent-vocabulary.md). Read that\nbefore writing queries or changing what gets captured.\n\n## Reading the data\n\n**Prefer the dedicated analysis skills** over hand-written HogQL; they already encode the\nexec-mode and harness handling that Hard rules 1 and 4 describe:\n\n- `exploring-mcp-tool-usage` — front door \u002F router: takes a broad \"how is my MCP doing\"\n  question and dispatches to the right typed tool or focused skill. Start here.\n- `exploring-mcp-tool-quality` — error rates, latency, reach, failing and slow tools.\n- `exploring-mcp-sessions` — session list, per-session tool calls, intent.\n- `exploring-mcp-intent-clusters` — \"what are people trying to do\" clusters.\n- `improving-mcp-tools` — eval-scored campaign loop: measure, make one bounded fix, re-measure.\n\n**Typed tools** exist for most questions and are preferable to raw SQL: `posthog:query-mcp-tool-stats`,\n`-daily-stats`, `-failures`, `-failure-occurrences`, `-descriptions`, `-neighbors`,\n`-sample-intents`, `-top-users`, and `posthog:query-mcp-harness-breakdown`, plus session tools\n(`posthog:mcp-analytics-sessions-list` \u002F `-tool-calls` \u002F `-generate-intent`) and the intent-cluster\ntools. They are declared in `products\u002Fmcp_analytics\u002Fmcp\u002Ftools.yaml`.\n\n**Harness** is the friendly label for the calling client (Claude Code, Cursor, ChatGPT,\nWindsurf, and ~30 other buckets). It is resolved at query time only, with no stored column:\n`mcp_harness.py::HARNESS_TOKEN_SQL` picks the strongest available signal in priority order\n(`mcp_vendor_client` -> Claude Code user-agent surface -> Grok user-agent -> `$mcp_client_name`\n-> `mcp_session_client_name` -> generic user-agent token -> `$mcp_oauth_client_name`), then\n`harness_label_sql()` buckets it (or `harness_label_or_token_sql()`, which names an\nunrecognized client verbatim instead of collapsing it into \"Other\" — use it for ranked\ntop-N lists, never where labels feed an array or unbounded GROUP BY).\n\n**`$mcp_client_name` is one mid-priority input, not a synonym for harness** — grouping by\nit directly gives a different, messier answer. It rides on the session's `initialize` and\nis absent from the tool calls that follow, so on its own it leaves most traffic\nunattributed; `mcp_session_client_name` is the session-pinned fallback the token chain\nreaches for next.\n\nFor hand-written SQL, `models-mcp.md` (linked in the Repos table) carries the property\nreference and worked query examples.\n\n## The pipeline, and where each stage breaks\n\n1. **Instrument** -> the server emits `$mcp_*` events via the SDK.\n   _Breaks:_ handlers not wrapped (`instrument()` is idempotent and degrades to a silent\n   no-op on failure); a STDIO server writing to stdout with `console.*` (corrupts the\n   protocol stream — wire a `logger`); a disabled or misconfigured posthog-node client.\n   For `services\u002Fmcp` there is a **single emission path**: `src\u002Fhono\u002Fanalytics.ts` +\n   `src\u002Fhono\u002Ftool-executor.ts` -> `getPostHogClient()` (`src\u002Flib\u002Fposthog\u002Fclient.ts`) ->\n   `PostHogMCP`, consumed through the dependency alias `@posthog\u002Fmcp-analytics` (the alias\n   matters when grepping imports). The legacy MCPcat\u002FAgentCat shim and the transition shim\n   that dual-emitted non-`$` `mcp_tool_call` \u002F `mcp_initialize` were both removed and are\n   regression-tested in `services\u002Fmcp\u002Ftests\u002Fhono\u002F`. **`services\u002Fmcp\u002FARCHITECTURE.md` still\n   describes the old multi-emitter design and references a deleted `lib\u002Fmcpcat.ts` — trust\n   the source, not that document.**\n2. **Ingest** -> events land in ClickHouse `events`. _Breaks:_ ordinary ingestion and quota\n   problems; `$session_id` not materialized, which breaks session grouping.\n3. **Session list** -> `backend\u002Flogic.py::list_mcp_sessions` runs HogQL over a **7-day\n   default window** (`DEFAULT_SESSIONS_DATE_FROM`, resolved through `QueryDateRange` with a\n   one-day overlap buffer each side) and caches for 30s (`SESSIONS_CACHE_TTL_SECONDS`).\n   _Breaks:_ anything outside the window simply isn't there; results can be up to 30s stale.\n4. **Charts and tool quality** -> typed `AnalyticsQueryRunner` subclasses in\n   `backend\u002Fhogql_queries\u002F` (`base.py`, `dashboard_series.py`, `harness_breakdown.py`,\n   `tool_quality_tables.py`, `tool_tables.py`), dispatched via the generic `\u002Fquery\u002F` endpoint\n   and enumerated in `backend\u002Ffacade\u002Fqueries.py`, with schemas in `posthog\u002Fschema.py`.\n   Gate: `hogql_queries\u002Fbase.py::validate_mcp_analytics_access` — the feature flag **plus**\n   the `mcp_analytics` RBAC resource. _Breaks:_ flag off, RBAC denies, or Hard rules 1-3\n   ignored.\n5. **Intent generation** (on demand, per session) -> collect `$mcp_intent` values -> an LLM\n   summary of at most two sentences -> Postgres `posthog_mcp_session`. A second,\n   project-level path produces the **intent digest \u002F themes** with structured output, bounded\n   by `MAX_DIGEST_THEMES`; `resolve_themes()` derives every countable field from the corpus\n   so the model cannot invent numbers. Model constants live in `backend\u002Fintent_generation.py`.\n   _Breaks:_ no `$mcp_intent` captured at all (the agent never filled the injected `context`\n   argument and no `intentFallback` was configured), so there is nothing to summarize; LLM\n   key or quota problems.\n6. **Intent clustering** -> embed (cached in `MCPIntentEmbeddingCache`) -> agglomerative\n   clustering (cosine, average linkage, `DEFAULT_DISTANCE_THRESHOLD`) -> JSONB\n   `MCPIntentClusterSnapshot`. **Temporal end-to-end, no Celery.** On-demand recompute\n   (`trigger_intent_cluster_recompute`, serialized with `select_for_update()` and a\n   deterministic per-team workflow id) and the `cluster_mcp_intents` management command both\n   start the workflow; the daily run is a Temporal **Schedule**\n   (`posthog\u002Ftemporal\u002Fmcp_analytics\u002Fintent_clustering\u002Fschedule.py`, behind the\n   `mcp-analytics-clustering-schedule` flag) that triggers\n   `IntentClusteringCoordinatorWorkflow`, which fans out one child workflow per team.\n   Two caps will surprise you: `MAX_SNAPSHOT_CLUSTERS` (snapshots keep only the top clusters\n   by volume, enforced at write and again at read) and `MAX_QUERY_ROWS`.\n   Note the corpus does **not** depend on step 5: `fetch_intent_corpus` takes each session's\n   first `$mcp_intent` straight from ClickHouse and only _overrides_ it with the stored LLM\n   summary where one exists. So a project can cluster with no generated summaries at all.\n   _Breaks:_ empty clusters almost always mean no `$mcp_intent` values in the lookback window\n   (check the corpus before chasing summary generation); schedule flag off; stale embeddings.\n   Also check the allowlist — `intent_clustering\u002Fteam_discovery.py` currently returns a\n   hard-coded `GUARANTEED_TEAM_IDS = [2]`, so the daily schedule covers only PostHog's own\n   project and enabling the flag elsewhere still produces nothing until that changes.\n7. **Serve** -> DRF viewsets at\n   `\u002Fapi\u002Fprojects\u002F{id}\u002Fmcp_analytics\u002F{sessions,intent_clusters,feedback,missing_capabilities}`\n   (router in `backend\u002Fpresentation\u002Furls.py`) plus custom actions\n   (`sessions\u002F{id}\u002Ftool_calls`, `sessions\u002F{id}\u002Fgenerate_intent`, `sessions\u002Fintent_digest`,\n   `sessions\u002Factivity_overview`, `intent_clusters\u002Frecompute`). Parallel surface: step 4's\n   runners, exposed to agents as the `query-mcp-*` tools.\n8. **Frontend** -> Kea scene `MCPAnalyticsScene.tsx`, with tabs enumerated by\n   `MCPAnalyticsTab` in `mcpAnalyticsSceneLogic.ts`: activity, dashboard, sessions,\n   tool quality, intent clustering, notifications. The landing tab is volume-gated by\n   `dashboardStage` in `mcpAnalyticsOnboardingLogic.ts` and applies only to the bare\n   `\u002Fmcp-analytics` redirect — deep links and explicit tab clicks are never overridden.\n   - **Activity** (`earlyData\u002F`): live tool-call feed plus the intent-**themes** card.\n     \"Theme\" (the LLM digest, Activity tab) is **not** \"cluster\" (the embedding clustering,\n     its own tab). Conflating the two is the most common mistake here.\n   - **Tool quality** and the per-tool **tool report** (`MCPAnalyticsToolDetail.tsx`, its own\n     registered scene): shared date filter, failure-occurrence drill-down with copyable error\n     context, and \"create fix task\" straight into `products\u002Ftasks`.\n   - **Dashboard**: quill composable `Metric` tiles and `@posthog\u002Fquill-primitives`, plus\n     **notable sessions** selected by a `NotableRule` — so that table can legitimately be\n     short or empty.\n   - **Notifications**: first-party destinations for MCP events and recurring AI reports\n     (`frontend\u002Fnotifications\u002F`), thin wiring over the generic hog-function destination and\n     subscription machinery.\n\nPostgres models (`backend\u002Fmodels.py`): `MCPSession` (the intent store),\n`MCPIntentClusterSnapshot`, `MCPAnalyticsSubmission` (feedback and missing-capability\nreports), `MCPIntentEmbeddingCache`.\n\n**Seeding local data:** `.\u002Fmanage.py seed_mcp_sessions --team-id N`\n(`backend\u002Fmanagement\u002Fcommands\u002F`), with `--sessions`, `--min-calls`\u002F`--max-calls`, `--days`,\n`--missing-capabilities`, `--seed`, and `--clear`. Seeded events are tagged `$mcp_seeded` so\n`--clear` removes only seeded data.\n\n## Which repo to change\n\n| Change                                          | Repo                                     | Workflow                                                                                                                                                                                                                                                                                                                                                                                 |\n| ----------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| SDK behaviour, events, options, instrumentation | `PostHog\u002Fposthog-js`                     | Work in `packages\u002Fmcp`. Run its unit tests, build, and lint. **Add a changeset.** Ships to npm; then bump the alias in `services\u002Fmcp\u002Fpackage.json` to pick it up.                                                                                                                                                                                                                        |\n| Dashboard, queries, clustering, API             | this repo                                | A new chart means a query runner in `backend\u002Fhogql_queries\u002F` behind `validate_mcp_analytics_access` — never a SQL template. Obey Hard rules 1-3.                                                                                                                                                                                                                                         |\n| A new `query-mcp-*` agent tool                  | this repo (two places)                   | 1) an entry in `products\u002Fmcp_analytics\u002Fmcp\u002Ftools.yaml` with `schema_ref`, `scopes`, `description`, `feature_flag`; 2) the matching `\u003CName>Query` schema and `\u003CName>QueryRunner` in `backend\u002Fhogql_queries\u002F`; 3) regenerate the tool handlers from `services\u002Fmcp` (see its `package.json` scripts). The generic `createQueryWrapper` handles the tool shape — no hand-written TypeScript. |\n| PostHog's own dogfood events                    | this repo                                | `services\u002Fmcp\u002Fsrc\u002Fhono\u002Fanalytics.ts` + `tool-executor.ts`; client in `src\u002Flib\u002Fposthog\u002Fclient.ts`.                                                                                                                                                                                                                                                                                        |\n| Docs                                            | `PostHog\u002Fposthog.com`                    | Keep the event and property tables in `contents\u002Fdocs\u002Fmcp-analytics\u002Fevents.mdx` synced with **both** the TypeScript `constants.ts` and the Python `posthog\u002Fmcp\u002Fconstants.py`.                                                                                                                                                                                                             |\n| The install codemod or the wizard command       | `PostHog\u002Fcontext-mill`, `PostHog\u002Fwizard` | See [references\u002Fwizard-and-onboarding.md](references\u002Fwizard-and-onboarding.md) — in particular the rule about which changes need a wizard release and which do not.                                                                                                                                                                                                                      |\n\n**Rule of thumb:** a change to _what gets captured, or how servers are instrumented_ belongs\nin the SDKs. _How data is shown, aggregated, or clustered_ belongs in this product. _PostHog's\nown dogfood events_ belong in `services\u002Fmcp`. A new customer-facing capability usually spans\nan SDK plus docs, and the product too if it needs a view.\n\nThe wizard install flow, the skill-distribution channels, and the in-app onboarding are all in\n[references\u002Fwizard-and-onboarding.md](references\u002Fwizard-and-onboarding.md).\n\n## Current state\n\nVerified against `master` and the SDK's `main` on 2026-07-31. Treat versions and open threads\nas perishable — re-check `packages\u002Fmcp\u002FCHANGELOG.md`, the pinned alias in\n`services\u002Fmcp\u002Fpackage.json`, and mega-issue #64016 rather than trusting this section.\n\nRecently shipped: structured intent themes, first-party notification destinations and\nrecurring reports, `mcp_analytics` access control, the shared `ProductEmptyState` adoption,\nfailure-occurrence drill-down with \"create fix task\", the migration of every chart to typed\nquery runners, the demo seeder, and exec-mode inner-tool breakout (Hard rule 1).\n\nTwo code-facing facts that shape debugging, both checkable in this repo: the `services\u002Fmcp` SDK\npin can lag the published SDK (Hard rule 5 — read the alias in its `package.json`), and the\nproduct is still behind the `mcp-analytics` flag, so a project without it sees nothing. For\nstatus and planned work, read mega-issue #64016 rather than trusting a snapshot here.\n",{"data":51,"body":52},{"name":4,"description":6},{"type":53,"children":54},"root",[55,63,107,133,168,175,188,642,650,768,784,790,795,1156,1162,1200,1241,1334,1367,1379,1385,1395,1453,1557,1623,1652,1665,1671,2524,2565,2654,2660,2989,3027,3037,3043,3079,3099],{"type":56,"tag":57,"props":58,"children":59},"element","h1",{"id":4},[60],{"type":61,"value":62},"text","Debugging MCP analytics",{"type":56,"tag":64,"props":65,"children":66},"p",{},[67,73,75,82,84,89,91,97,99,105],{"type":56,"tag":68,"props":69,"children":70},"strong",{},[71],{"type":61,"value":72},"Product analytics for MCP servers.",{"type":61,"value":74}," A team ships an MCP server; the ",{"type":56,"tag":76,"props":77,"children":79},"code",{"className":78},[],[80],{"type":61,"value":81},"@posthog\u002Fmcp",{"type":61,"value":83}," SDK\nwraps it in one line; every tool call, agent ",{"type":56,"tag":68,"props":85,"children":86},{},[87],{"type":61,"value":88},"intent",{"type":61,"value":90},", and failure lands in PostHog as a\n",{"type":56,"tag":76,"props":92,"children":94},{"className":93},[],[95],{"type":61,"value":96},"$mcp_*",{"type":61,"value":98}," event you can query, chart, alert on, and cluster — plus a dedicated dashboard. The\nMCP-layer sibling of ",{"type":56,"tag":76,"props":100,"children":102},{"className":101},[],[103],{"type":61,"value":104},"@posthog\u002Fai",{"type":61,"value":106},".",{"type":56,"tag":64,"props":108,"children":109},{},[110,112,116,118,124,126,131],{"type":61,"value":111},"The differentiator is ",{"type":56,"tag":68,"props":113,"children":114},{},[115],{"type":61,"value":88},{"type":61,"value":117},": not \"ran ",{"type":56,"tag":76,"props":119,"children":121},{"className":120},[],[122],{"type":61,"value":123},"query_run",{"type":61,"value":125}," 14 times\" but \"was trying to find a\nchurn cohort\". Explicit non-goal: this does ",{"type":56,"tag":68,"props":127,"children":128},{},[129],{"type":61,"value":130},"not",{"type":61,"value":132}," replace LLM analytics \u002F AI observability\n— generation traces, prompt\u002Fresponse, and token cost belong there.",{"type":56,"tag":64,"props":134,"children":135},{},[136,138,143,145,151,153,159,161,166],{"type":61,"value":137},"Status: ",{"type":56,"tag":68,"props":139,"children":140},{},[141],{"type":61,"value":142},"beta",{"type":61,"value":144},", TypeScript and Python SDKs shipped, whole product still behind the\n",{"type":56,"tag":76,"props":146,"children":148},{"className":147},[],[149],{"type":61,"value":150},"mcp-analytics",{"type":61,"value":152}," early-access flag (",{"type":56,"tag":76,"props":154,"children":156},{"className":155},[],[157],{"type":61,"value":158},"products\u002Fmcp_analytics\u002Ffrontend\u002FfeaturePreviewGate.ts",{"type":61,"value":160},").\nPostHog dogfoods it — its own MCP server instruments itself, and that data drives the\ndashboard. Public tracking: mega-issue ",{"type":56,"tag":68,"props":162,"children":163},{},[164],{"type":61,"value":165},"PostHog\u002Fposthog#64016",{"type":61,"value":167},", which is the live source\nfor roadmap and customer wishlist.",{"type":56,"tag":169,"props":170,"children":172},"h2",{"id":171},"repos",[173],{"type":61,"value":174},"Repos",{"type":56,"tag":64,"props":176,"children":177},{},[178,180,186],{"type":61,"value":179},"GitHub is the source of truth for where the code lives. Paths below are in-repo; for the\nrepos outside this monorepo, resolve a local checkout via\n",{"type":56,"tag":181,"props":182,"children":184},"a",{"href":183},"references\u002Flocal-repos.md",[185],{"type":61,"value":183},{"type":61,"value":187}," rather than assuming a location.",{"type":56,"tag":189,"props":190,"children":191},"table",{},[192,216],{"type":56,"tag":193,"props":194,"children":195},"thead",{},[196],{"type":56,"tag":197,"props":198,"children":199},"tr",{},[200,206,211],{"type":56,"tag":201,"props":202,"children":203},"th",{},[204],{"type":61,"value":205},"Concern",{"type":56,"tag":201,"props":207,"children":208},{},[209],{"type":61,"value":210},"Repo",{"type":56,"tag":201,"props":212,"children":213},{},[214],{"type":61,"value":215},"Where to look",{"type":56,"tag":217,"props":218,"children":219},"tbody",{},[220,262,308,337,388,477,538,567,611],{"type":56,"tag":197,"props":221,"children":222},{},[223,232,243],{"type":56,"tag":224,"props":225,"children":226},"td",{},[227],{"type":56,"tag":68,"props":228,"children":229},{},[230],{"type":61,"value":231},"Product \u002F dashboard",{"type":56,"tag":224,"props":233,"children":234},{},[235,241],{"type":56,"tag":76,"props":236,"children":238},{"className":237},[],[239],{"type":61,"value":240},"PostHog\u002Fposthog",{"type":61,"value":242}," (this repo)",{"type":56,"tag":224,"props":244,"children":245},{},[246,252,254,260],{"type":56,"tag":76,"props":247,"children":249},{"className":248},[],[250],{"type":61,"value":251},"products\u002Fmcp_analytics\u002F",{"type":61,"value":253}," — Django\u002FDRF + HogQL query runners + Temporal, Kea frontend, the ",{"type":56,"tag":76,"props":255,"children":257},{"className":256},[],[258],{"type":61,"value":259},"query-mcp-*",{"type":61,"value":261}," tool registry, and the analysis skills",{"type":56,"tag":197,"props":263,"children":264},{},[265,273,282],{"type":56,"tag":224,"props":266,"children":267},{},[268],{"type":56,"tag":68,"props":269,"children":270},{},[271],{"type":61,"value":272},"Self-instrumented server",{"type":56,"tag":224,"props":274,"children":275},{},[276,281],{"type":56,"tag":76,"props":277,"children":279},{"className":278},[],[280],{"type":61,"value":240},{"type":61,"value":242},{"type":56,"tag":224,"props":283,"children":284},{},[285,291,293,299,301,306],{"type":56,"tag":76,"props":286,"children":288},{"className":287},[],[289],{"type":61,"value":290},"services\u002Fmcp\u002F",{"type":61,"value":292}," — PostHog's own MCP server (Hono); the dogfood event producer. Also hosts the ",{"type":56,"tag":294,"props":295,"children":296},"em",{},[297],{"type":61,"value":298},"generated",{"type":61,"value":300}," ",{"type":56,"tag":76,"props":302,"children":304},{"className":303},[],[305],{"type":61,"value":259},{"type":61,"value":307}," handlers",{"type":56,"tag":197,"props":309,"children":310},{},[311,319,328],{"type":56,"tag":224,"props":312,"children":313},{},[314],{"type":56,"tag":68,"props":315,"children":316},{},[317],{"type":61,"value":318},"Shared query reference",{"type":56,"tag":224,"props":320,"children":321},{},[322,327],{"type":56,"tag":76,"props":323,"children":325},{"className":324},[],[326],{"type":61,"value":240},{"type":61,"value":242},{"type":56,"tag":224,"props":329,"children":330},{},[331],{"type":56,"tag":76,"props":332,"children":334},{"className":333},[],[335],{"type":61,"value":336},"products\u002Fposthog_ai\u002Fskills\u002Fquerying-posthog-data\u002Freferences\u002Fmodels-mcp.md",{"type":56,"tag":197,"props":338,"children":339},{},[340,354,363],{"type":56,"tag":224,"props":341,"children":342},{},[343,348,349],{"type":56,"tag":68,"props":344,"children":345},{},[346],{"type":61,"value":347},"TypeScript SDK",{"type":61,"value":300},{"type":56,"tag":76,"props":350,"children":352},{"className":351},[],[353],{"type":61,"value":81},{"type":56,"tag":224,"props":355,"children":356},{},[357],{"type":56,"tag":76,"props":358,"children":360},{"className":359},[],[361],{"type":61,"value":362},"PostHog\u002Fposthog-js",{"type":56,"tag":224,"props":364,"children":365},{},[366,372,374,380,382],{"type":56,"tag":76,"props":367,"children":369},{"className":368},[],[370],{"type":61,"value":371},"packages\u002Fmcp\u002F",{"type":61,"value":373}," — the library customers install. Vocabulary source of truth: ",{"type":56,"tag":76,"props":375,"children":377},{"className":376},[],[378],{"type":61,"value":379},"src\u002Fextensions\u002Fconstants.ts",{"type":61,"value":381},". Internals: ",{"type":56,"tag":76,"props":383,"children":385},{"className":384},[],[386],{"type":61,"value":387},"docs\u002FARCHITECTURE.md",{"type":56,"tag":197,"props":389,"children":390},{},[391,406,415],{"type":56,"tag":224,"props":392,"children":393},{},[394,399,400],{"type":56,"tag":68,"props":395,"children":396},{},[397],{"type":61,"value":398},"Python SDK",{"type":61,"value":300},{"type":56,"tag":76,"props":401,"children":403},{"className":402},[],[404],{"type":61,"value":405},"posthog.mcp",{"type":56,"tag":224,"props":407,"children":408},{},[409],{"type":56,"tag":76,"props":410,"children":412},{"className":411},[],[413],{"type":61,"value":414},"PostHog\u002Fposthog-python",{"type":56,"tag":224,"props":416,"children":417},{},[418,424,426,432,434,439,441,447,449,454,456,462,464],{"type":56,"tag":76,"props":419,"children":421},{"className":420},[],[422],{"type":61,"value":423},"posthog\u002Fmcp\u002F",{"type":61,"value":425}," — mirrors ",{"type":56,"tag":76,"props":427,"children":429},{"className":428},[],[430],{"type":61,"value":431},"posthog.ai",{"type":61,"value":433},". Ships inside ",{"type":56,"tag":76,"props":435,"children":437},{"className":436},[],[438],{"type":61,"value":8},{"type":61,"value":440}," (",{"type":56,"tag":76,"props":442,"children":444},{"className":443},[],[445],{"type":61,"value":446},"pip install posthog",{"type":61,"value":448},"); ",{"type":56,"tag":76,"props":450,"children":452},{"className":451},[],[453],{"type":61,"value":18},{"type":61,"value":455},"\u002F",{"type":56,"tag":76,"props":457,"children":459},{"className":458},[],[460],{"type":61,"value":461},"fastmcp",{"type":61,"value":463}," are lazily-imported peer deps, ",{"type":56,"tag":68,"props":465,"children":466},{},[467,469,475],{"type":61,"value":468},"no ",{"type":56,"tag":76,"props":470,"children":472},{"className":471},[],[473],{"type":61,"value":474},"[mcp]",{"type":61,"value":476}," extra",{"type":56,"tag":197,"props":478,"children":479},{},[480,488,497],{"type":56,"tag":224,"props":481,"children":482},{},[483],{"type":56,"tag":68,"props":484,"children":485},{},[486],{"type":61,"value":487},"Docs",{"type":56,"tag":224,"props":489,"children":490},{},[491],{"type":56,"tag":76,"props":492,"children":494},{"className":493},[],[495],{"type":61,"value":496},"PostHog\u002Fposthog.com",{"type":56,"tag":224,"props":498,"children":499},{},[500,506,508,514,516,522,524,530,532],{"type":56,"tag":76,"props":501,"children":503},{"className":502},[],[504],{"type":61,"value":505},"contents\u002Fdocs\u002Fmcp-analytics\u002F",{"type":61,"value":507}," (incl. ",{"type":56,"tag":76,"props":509,"children":511},{"className":510},[],[512],{"type":61,"value":513},"surfaces\u002F",{"type":61,"value":515},"), plus ",{"type":56,"tag":76,"props":517,"children":519},{"className":518},[],[520],{"type":61,"value":521},"src\u002Fhooks\u002FproductData\u002Fmcp_analytics.tsx",{"type":61,"value":523}," and the ",{"type":56,"tag":76,"props":525,"children":527},{"className":526},[],[528],{"type":61,"value":529},"mcp_analytics",{"type":61,"value":531}," entry in ",{"type":56,"tag":76,"props":533,"children":535},{"className":534},[],[536],{"type":61,"value":537},"src\u002Fdata\u002Ftools.ts",{"type":56,"tag":197,"props":539,"children":540},{},[541,549,558],{"type":56,"tag":224,"props":542,"children":543},{},[544],{"type":56,"tag":68,"props":545,"children":546},{},[547],{"type":61,"value":548},"Install codemod",{"type":56,"tag":224,"props":550,"children":551},{},[552],{"type":56,"tag":76,"props":553,"children":555},{"className":554},[],[556],{"type":61,"value":557},"PostHog\u002Fcontext-mill",{"type":56,"tag":224,"props":559,"children":560},{},[561],{"type":56,"tag":76,"props":562,"children":564},{"className":563},[],[565],{"type":61,"value":566},"context\u002Fskills\u002Fmcp-analytics\u002F{config.yaml,description.md}",{"type":56,"tag":197,"props":568,"children":569},{},[570,578,587],{"type":56,"tag":224,"props":571,"children":572},{},[573],{"type":56,"tag":68,"props":574,"children":575},{},[576],{"type":61,"value":577},"Wizard CLI",{"type":56,"tag":224,"props":579,"children":580},{},[581],{"type":56,"tag":76,"props":582,"children":584},{"className":583},[],[585],{"type":61,"value":586},"PostHog\u002Fwizard",{"type":56,"tag":224,"props":588,"children":589},{},[590,596,598,604,605],{"type":56,"tag":76,"props":591,"children":593},{"className":592},[],[594],{"type":61,"value":595},"bin.ts",{"type":61,"value":597},", ",{"type":56,"tag":76,"props":599,"children":601},{"className":600},[],[602],{"type":61,"value":603},"src\u002Fcommands\u002Fmcp-analytics.ts",{"type":61,"value":597},{"type":56,"tag":76,"props":606,"children":608},{"className":607},[],[609],{"type":61,"value":610},"src\u002Flib\u002Fprograms\u002Fmcp-analytics\u002F",{"type":56,"tag":197,"props":612,"children":613},{},[614,622,631],{"type":56,"tag":224,"props":615,"children":616},{},[617],{"type":56,"tag":68,"props":618,"children":619},{},[620],{"type":61,"value":621},"Wizard test harness",{"type":56,"tag":224,"props":623,"children":624},{},[625],{"type":56,"tag":76,"props":626,"children":628},{"className":627},[],[629],{"type":61,"value":630},"PostHog\u002Fwizard-workbench",{"type":56,"tag":224,"props":632,"children":633},{},[634,640],{"type":56,"tag":76,"props":635,"children":637},{"className":636},[],[638],{"type":61,"value":639},"apps\u002Fmcp-analytics\u002F",{"type":61,"value":641}," fixtures",{"type":56,"tag":64,"props":643,"children":644},{},[645],{"type":56,"tag":68,"props":646,"children":647},{},[648],{"type":61,"value":649},"Don't conflate:",{"type":56,"tag":651,"props":652,"children":653},"ul",{},[654,709,735],{"type":56,"tag":655,"props":656,"children":657},"li",{},[658,664,666,671,673,679,681,687,689,694,696,701,703,708],{"type":56,"tag":76,"props":659,"children":661},{"className":660},[],[662],{"type":61,"value":663},"PostHog\u002Fmcp-analytics",{"type":61,"value":665}," is the ",{"type":56,"tag":68,"props":667,"children":668},{},[669],{"type":61,"value":670},"archived prototype",{"type":61,"value":672}," of this SDK — stuck at ",{"type":56,"tag":76,"props":674,"children":676},{"className":675},[],[677],{"type":61,"value":678},"0.0.9",{"type":61,"value":680}," with an\nold ",{"type":56,"tag":76,"props":682,"children":684},{"className":683},[],[685],{"type":61,"value":686},"track(server, {...})",{"type":61,"value":688}," API. It published under the same ",{"type":56,"tag":76,"props":690,"children":692},{"className":691},[],[693],{"type":61,"value":81},{"type":61,"value":695}," name, so grepping\nthat name can land you there. npm ",{"type":56,"tag":76,"props":697,"children":699},{"className":698},[],[700],{"type":61,"value":81},{"type":61,"value":702}," now resolves to ",{"type":56,"tag":76,"props":704,"children":706},{"className":705},[],[707],{"type":61,"value":362},{"type":61,"value":106},{"type":56,"tag":655,"props":710,"children":711},{},[712,718,720,726,728,733],{"type":56,"tag":76,"props":713,"children":715},{"className":714},[],[716],{"type":61,"value":717},"products\u002Fmcp_store\u002F",{"type":61,"value":719}," is the MCP server marketplace \u002F team gateway, not this product. (Older\nnotes also mention a ",{"type":56,"tag":76,"props":721,"children":723},{"className":722},[],[724],{"type":61,"value":725},"products\u002Fmcp\u002F",{"type":61,"value":727}," build-tooling directory; it no longer exists — the server\nand its generation tooling live in ",{"type":56,"tag":76,"props":729,"children":731},{"className":730},[],[732],{"type":61,"value":290},{"type":61,"value":734},".)",{"type":56,"tag":655,"props":736,"children":737},{},[738,744,746,751,753,759,761,766],{"type":56,"tag":76,"props":739,"children":741},{"className":740},[],[742],{"type":61,"value":743},"wizard mcp add",{"type":61,"value":745}," installs the PostHog ",{"type":56,"tag":68,"props":747,"children":748},{},[749],{"type":61,"value":750},"MCP server",{"type":61,"value":752}," into a coding agent. That is NOT\n",{"type":56,"tag":76,"props":754,"children":756},{"className":755},[],[757],{"type":61,"value":758},"wizard mcp-analytics",{"type":61,"value":760},", which instruments the user's ",{"type":56,"tag":294,"props":762,"children":763},{},[764],{"type":61,"value":765},"own",{"type":61,"value":767}," server.",{"type":56,"tag":769,"props":770,"children":771},"blockquote",{},[772],{"type":56,"tag":64,"props":773,"children":774},{},[775,777,782],{"type":61,"value":776},"Line numbers drift and this area moves fast — ",{"type":56,"tag":68,"props":778,"children":779},{},[780],{"type":61,"value":781},"grep for the symbol",{"type":61,"value":783},", never trust a\nremembered line number. Confirm a checkout is on a sane branch before quoting its code.",{"type":56,"tag":169,"props":785,"children":787},{"id":786},"hard-rules-break-these-and-the-numbers-are-silently-wrong",[788],{"type":61,"value":789},"Hard rules (break these and the numbers are silently wrong)",{"type":56,"tag":64,"props":791,"children":792},{},[793],{"type":61,"value":794},"These are the failure modes that produce a plausible-looking answer rather than an error.",{"type":56,"tag":796,"props":797,"children":798},"ol",{},[799,910,956,1003,1039,1130],{"type":56,"tag":655,"props":800,"children":801},{},[802,814,816,822,824,830,832,838,840,846,848,854,856,862,864,870,872,878,880,886,888,893,895,901,903,908],{"type":56,"tag":68,"props":803,"children":804},{},[805,807,813],{"type":61,"value":806},"Always resolve the effective tool name through ",{"type":56,"tag":76,"props":808,"children":810},{"className":809},[],[811],{"type":61,"value":812},"EFFECTIVE_TOOL_SQL",{"type":61,"value":106},{"type":61,"value":815}," The expression\nlives once, in ",{"type":56,"tag":76,"props":817,"children":819},{"className":818},[],[820],{"type":61,"value":821},"products\u002Fmcp_analytics\u002Fbackend\u002Fhogql_queries\u002Fbase.py",{"type":61,"value":823},":\n",{"type":56,"tag":76,"props":825,"children":827},{"className":826},[],[828],{"type":61,"value":829},"coalesce(nullIf(toString(properties.$mcp_exec_tool_call_name), ''), toString(properties.$mcp_tool_name))",{"type":61,"value":831},".\nIt exists because a single-exec server can report the tool two different ways, and the two\neras of data coexist. Today ",{"type":56,"tag":76,"props":833,"children":835},{"className":834},[],[836],{"type":61,"value":837},"services\u002Fmcp",{"type":61,"value":839}," resolves the inner tool itself and passes it\nstraight in as the tool name (",{"type":56,"tag":76,"props":841,"children":843},{"className":842},[],[844],{"type":61,"value":845},"execToolName()",{"type":61,"value":847}," in ",{"type":56,"tag":76,"props":849,"children":851},{"className":850},[],[852],{"type":61,"value":853},"src\u002Fhono\u002Ftool-executor.ts",{"type":61,"value":855},", which falls\nback to the literal ",{"type":56,"tag":76,"props":857,"children":859},{"className":858},[],[860],{"type":61,"value":861},"exec",{"type":61,"value":863}," when the inner command isn't recognized), so\n",{"type":56,"tag":76,"props":865,"children":867},{"className":866},[],[868],{"type":61,"value":869},"$mcp_tool_name",{"type":61,"value":871}," usually already holds the real tool. ",{"type":56,"tag":76,"props":873,"children":875},{"className":874},[],[876],{"type":61,"value":877},"$mcp_exec_tool_call_name",{"type":61,"value":879}," is\nregistered in ",{"type":56,"tag":76,"props":881,"children":883},{"className":882},[],[884],{"type":61,"value":885},"posthog\u002Ftaxonomy\u002Ftaxonomy.py",{"type":61,"value":887}," and coalesced defensively here, but ",{"type":56,"tag":68,"props":889,"children":890},{},[891],{"type":61,"value":892},"nothing\non master emits it",{"type":61,"value":894}," — treat it as historical rows plus in-flight work, not current\nproducer behaviour. Either way, aggregate through the coalesce: hand-rolling\n",{"type":56,"tag":76,"props":896,"children":898},{"className":897},[],[899],{"type":61,"value":900},"properties.$mcp_tool_name",{"type":61,"value":902}," alone silently buckets unrecognized exec calls under ",{"type":56,"tag":76,"props":904,"children":906},{"className":905},[],[907],{"type":61,"value":861},{"type":61,"value":909},",\nand misses any data that does carry the dedicated property.",{"type":56,"tag":655,"props":911,"children":912},{},[913,948,949,954],{"type":56,"tag":68,"props":914,"children":915},{},[916,918,924,926,932,933,939,941,947],{"type":61,"value":917},"Failures come from ",{"type":56,"tag":76,"props":919,"children":921},{"className":920},[],[922],{"type":61,"value":923},"$mcp_is_error",{"type":61,"value":925}," \u002F ",{"type":56,"tag":76,"props":927,"children":929},{"className":928},[],[930],{"type":61,"value":931},"$mcp_error_type",{"type":61,"value":925},{"type":56,"tag":76,"props":934,"children":936},{"className":935},[],[937],{"type":61,"value":938},"$mcp_error_status",{"type":61,"value":940},", never\n",{"type":56,"tag":76,"props":942,"children":944},{"className":943},[],[945],{"type":61,"value":946},"$exception",{"type":61,"value":106},{"type":61,"value":300},{"type":56,"tag":76,"props":950,"children":952},{"className":951},[],[953],{"type":61,"value":946},{"type":61,"value":955}," can be disabled, isn't emitted when no error value is passed,\nand never matched new-SDK events — so querying it returns nothing rather than failing.",{"type":56,"tag":655,"props":957,"children":958},{},[959,964,966,972,973,979,981,987,988,994,995,1001],{"type":56,"tag":68,"props":960,"children":961},{},[962],{"type":61,"value":963},"Dash the in-progress bucket.",{"type":61,"value":965}," Every time-bucketed chart zero-fills and marks the final\nincomplete interval via ",{"type":56,"tag":76,"props":967,"children":969},{"className":968},[],[970],{"type":61,"value":971},"products\u002Fmcp_analytics\u002Ffrontend\u002FtimeBuckets.ts",{"type":61,"value":440},{"type":56,"tag":76,"props":974,"children":976},{"className":975},[],[977],{"type":61,"value":978},"resolveWindow",{"type":61,"value":980},",\n",{"type":56,"tag":76,"props":982,"children":984},{"className":983},[],[985],{"type":61,"value":986},"normalizeBucket",{"type":61,"value":597},{"type":56,"tag":76,"props":989,"children":991},{"className":990},[],[992],{"type":61,"value":993},"buildBucketKeys",{"type":61,"value":597},{"type":56,"tag":76,"props":996,"children":998},{"className":997},[],[999],{"type":61,"value":1000},"lastBucketIsInProgress",{"type":61,"value":1002},"). Omit it and a partial\nperiod reads as a real decline.",{"type":56,"tag":655,"props":1004,"children":1005},{},[1006,1017,1023,1025,1031,1033,1038],{"type":56,"tag":68,"props":1007,"children":1008},{},[1009,1015],{"type":56,"tag":76,"props":1010,"children":1012},{"className":1011},[],[1013],{"type":61,"value":1014},"harness",{"type":61,"value":1016}," is derived, and its logic exists in three places that must move in lockstep:",{"type":56,"tag":76,"props":1018,"children":1020},{"className":1019},[],[1021],{"type":61,"value":1022},"products\u002Fmcp_analytics\u002Fbackend\u002Fmcp_harness.py",{"type":61,"value":1024}," (source of truth — see its module\ndocstring), ",{"type":56,"tag":76,"props":1026,"children":1028},{"className":1027},[],[1029],{"type":61,"value":1030},"products\u002Fmcp_analytics\u002Ffrontend\u002Fdashboard\u002FharnessRegistry.ts",{"type":61,"value":1032},", and\n",{"type":56,"tag":76,"props":1034,"children":1036},{"className":1035},[],[1037],{"type":61,"value":336},{"type":61,"value":106},{"type":56,"tag":655,"props":1040,"children":1041},{},[1042,1047,1052,1054,1060,1062,1068,1070,1076,1078,1083,1085,1090,1091,1097,1099,1105,1107,1112,1114,1120,1122,1128],{"type":56,"tag":68,"props":1043,"children":1044},{},[1045],{"type":61,"value":1046},"Check which SDK version the dogfood server is on before trusting dogfood data.",{"type":56,"tag":76,"props":1048,"children":1050},{"className":1049},[],[1051],{"type":61,"value":837},{"type":61,"value":1053}," consumes the SDK through an alias in its ",{"type":56,"tag":76,"props":1055,"children":1057},{"className":1056},[],[1058],{"type":61,"value":1059},"package.json",{"type":61,"value":1061}," and has historically\nlagged the published version, so version-dependent properties (typed error types, ",{"type":56,"tag":76,"props":1063,"children":1065},{"className":1064},[],[1066],{"type":61,"value":1067},"$lib",{"type":61,"value":1069},"\nidentity, payload redaction) can be absent from PostHog's own data even when documented as\ncurrent. A query filtering on ",{"type":56,"tag":76,"props":1071,"children":1073},{"className":1072},[],[1074],{"type":61,"value":1075},"$lib = 'posthog-node-mcp'",{"type":61,"value":1077}," silently excludes all dogfood\ntraffic if that pin predates SDK 0.7.0. Note too that ",{"type":56,"tag":76,"props":1079,"children":1081},{"className":1080},[],[1082],{"type":61,"value":837},{"type":61,"value":1084}," uses the\n",{"type":56,"tag":68,"props":1086,"children":1087},{},[1088],{"type":61,"value":1089},"custom-dispatcher",{"type":61,"value":440},{"type":56,"tag":76,"props":1092,"children":1094},{"className":1093},[],[1095],{"type":61,"value":1096},"PostHogMCP",{"type":61,"value":1098},") path rather than ",{"type":56,"tag":76,"props":1100,"children":1102},{"className":1101},[],[1103],{"type":61,"value":1104},"instrument()",{"type":61,"value":1106},", so behaviour living\nonly in the ",{"type":56,"tag":76,"props":1108,"children":1110},{"className":1109},[],[1111],{"type":61,"value":1104},{"type":61,"value":1113}," path — stable sessions, ",{"type":56,"tag":76,"props":1115,"children":1117},{"className":1116},[],[1118],{"type":61,"value":1119},"$identify",{"type":61,"value":1121}," deduplication, ",{"type":56,"tag":76,"props":1123,"children":1125},{"className":1124},[],[1126],{"type":61,"value":1127},"_meta",{"type":61,"value":1129},"-based\nclient identity — has never applied to it at any version.",{"type":56,"tag":655,"props":1131,"children":1132},{},[1133,1138,1140,1146,1148,1154],{"type":56,"tag":68,"props":1134,"children":1135},{},[1136],{"type":61,"value":1137},"There are no SQL template files.",{"type":61,"value":1139}," Every dashboard and tool-quality query is a typed\nquery runner behind the generic ",{"type":56,"tag":76,"props":1141,"children":1143},{"className":1142},[],[1144],{"type":61,"value":1145},"\u002Fquery\u002F",{"type":61,"value":1147}," endpoint. A ",{"type":56,"tag":76,"props":1149,"children":1151},{"className":1150},[],[1152],{"type":61,"value":1153},"backend\u002Ftemplates\u002F*.sql",{"type":61,"value":1155}," referenced\nby older notes no longer exists.",{"type":56,"tag":169,"props":1157,"children":1159},{"id":1158},"event-vocabulary",[1160],{"type":61,"value":1161},"Event vocabulary",{"type":56,"tag":64,"props":1163,"children":1164},{},[1165,1167,1176,1178,1183,1185,1191,1193,1199],{"type":61,"value":1166},"All data lives on the shared ClickHouse ",{"type":56,"tag":68,"props":1168,"children":1169},{},[1170],{"type":56,"tag":76,"props":1171,"children":1173},{"className":1172},[],[1174],{"type":61,"value":1175},"events",{"type":61,"value":1177}," table — there is ",{"type":56,"tag":68,"props":1179,"children":1180},{},[1181],{"type":61,"value":1182},"no dedicated table",{"type":61,"value":1184},".\nEvery metric is an aggregation over ",{"type":56,"tag":76,"props":1186,"children":1188},{"className":1187},[],[1189],{"type":61,"value":1190},"$mcp_tool_call",{"type":61,"value":1192},", usually grouped by ",{"type":56,"tag":76,"props":1194,"children":1196},{"className":1195},[],[1197],{"type":61,"value":1198},"$session_id",{"type":61,"value":106},{"type":56,"tag":64,"props":1201,"children":1202},{},[1203,1205,1211,1213,1218,1220,1226,1227,1233,1235,1240],{"type":61,"value":1204},"Source of truth for the SDK-emitted names is ",{"type":56,"tag":76,"props":1206,"children":1208},{"className":1207},[],[1209],{"type":61,"value":1210},"packages\u002Fmcp\u002Fsrc\u002Fextensions\u002Fconstants.ts",{"type":61,"value":1212}," in\n",{"type":56,"tag":76,"props":1214,"children":1216},{"className":1215},[],[1217],{"type":61,"value":362},{"type":61,"value":1219},", exported as ",{"type":56,"tag":76,"props":1221,"children":1223},{"className":1222},[],[1224],{"type":61,"value":1225},"PostHogMCPAnalyticsEvent",{"type":61,"value":925},{"type":56,"tag":76,"props":1228,"children":1230},{"className":1229},[],[1231],{"type":61,"value":1232},"PostHogMCPAnalyticsProperty",{"type":61,"value":1234},"\n(import them for typesafe queries). PostHog-side descriptions — including the server-stamped\nand exec-mode properties the SDK does not define — live in ",{"type":56,"tag":76,"props":1236,"children":1238},{"className":1237},[],[1239],{"type":61,"value":885},{"type":61,"value":106},{"type":56,"tag":64,"props":1242,"children":1243},{},[1244,1249,1251,1257,1259,1264,1266,1271,1273,1279,1280,1286,1287,1293,1294,1300,1301,1307,1308,1314,1315,1321,1322,1327,1328,1333],{"type":56,"tag":68,"props":1245,"children":1246},{},[1247],{"type":61,"value":1248},"Events",{"type":61,"value":1250}," (all ",{"type":56,"tag":76,"props":1252,"children":1254},{"className":1253},[],[1255],{"type":61,"value":1256},"$",{"type":61,"value":1258},"-prefixed; non-",{"type":56,"tag":76,"props":1260,"children":1262},{"className":1261},[],[1263],{"type":61,"value":1256},{"type":61,"value":1265}," names would be treated as customer events):\n",{"type":56,"tag":76,"props":1267,"children":1269},{"className":1268},[],[1270],{"type":61,"value":1190},{"type":61,"value":1272}," (primary), ",{"type":56,"tag":76,"props":1274,"children":1276},{"className":1275},[],[1277],{"type":61,"value":1278},"$mcp_tools_list",{"type":61,"value":597},{"type":56,"tag":76,"props":1281,"children":1283},{"className":1282},[],[1284],{"type":61,"value":1285},"$mcp_initialize",{"type":61,"value":597},{"type":56,"tag":76,"props":1288,"children":1290},{"className":1289},[],[1291],{"type":61,"value":1292},"$mcp_missing_capability",{"type":61,"value":980},{"type":56,"tag":76,"props":1295,"children":1297},{"className":1296},[],[1298],{"type":61,"value":1299},"$mcp_resource_read",{"type":61,"value":925},{"type":56,"tag":76,"props":1302,"children":1304},{"className":1303},[],[1305],{"type":61,"value":1306},"$mcp_resources_list",{"type":61,"value":597},{"type":56,"tag":76,"props":1309,"children":1311},{"className":1310},[],[1312],{"type":61,"value":1313},"$mcp_prompt_get",{"type":61,"value":925},{"type":56,"tag":76,"props":1316,"children":1318},{"className":1317},[],[1319],{"type":61,"value":1320},"$mcp_prompts_list",{"type":61,"value":980},{"type":56,"tag":76,"props":1323,"children":1325},{"className":1324},[],[1326],{"type":61,"value":1119},{"type":61,"value":597},{"type":56,"tag":76,"props":1329,"children":1331},{"className":1330},[],[1332],{"type":61,"value":946},{"type":61,"value":106},{"type":56,"tag":769,"props":1335,"children":1336},{},[1337],{"type":56,"tag":64,"props":1338,"children":1339},{},[1340,1350,1352,1358,1360,1365],{"type":56,"tag":68,"props":1341,"children":1342},{},[1343,1348],{"type":56,"tag":76,"props":1344,"children":1346},{"className":1345},[],[1347],{"type":61,"value":1285},{"type":61,"value":1349}," is not a universal session anchor.",{"type":61,"value":1351}," The MCP 2026-07-28 stateless\nrevision removes the ",{"type":56,"tag":76,"props":1353,"children":1355},{"className":1354},[],[1356],{"type":61,"value":1357},"initialize",{"type":61,"value":1359}," handshake, so clients on that revision never emit it.\nAnchor on the first ",{"type":56,"tag":76,"props":1361,"children":1363},{"className":1362},[],[1364],{"type":61,"value":1190},{"type":61,"value":1366}," instead.",{"type":56,"tag":64,"props":1368,"children":1369},{},[1370,1372,1377],{"type":61,"value":1371},"Full property tables — split by provenance (SDK-emitted vs stamped by PostHog's own server vs\nexec-mode only), the identifier distinctions, per-version SDK behaviour, and TypeScript\u002FPython\nparity — are in ",{"type":56,"tag":181,"props":1373,"children":1375},{"href":1374},"references\u002Fevent-vocabulary.md",[1376],{"type":61,"value":1374},{"type":61,"value":1378},". Read that\nbefore writing queries or changing what gets captured.",{"type":56,"tag":169,"props":1380,"children":1382},{"id":1381},"reading-the-data",[1383],{"type":61,"value":1384},"Reading the data",{"type":56,"tag":64,"props":1386,"children":1387},{},[1388,1393],{"type":56,"tag":68,"props":1389,"children":1390},{},[1391],{"type":61,"value":1392},"Prefer the dedicated analysis skills",{"type":61,"value":1394}," over hand-written HogQL; they already encode the\nexec-mode and harness handling that Hard rules 1 and 4 describe:",{"type":56,"tag":651,"props":1396,"children":1397},{},[1398,1409,1420,1431,1442],{"type":56,"tag":655,"props":1399,"children":1400},{},[1401,1407],{"type":56,"tag":76,"props":1402,"children":1404},{"className":1403},[],[1405],{"type":61,"value":1406},"exploring-mcp-tool-usage",{"type":61,"value":1408}," — front door \u002F router: takes a broad \"how is my MCP doing\"\nquestion and dispatches to the right typed tool or focused skill. Start here.",{"type":56,"tag":655,"props":1410,"children":1411},{},[1412,1418],{"type":56,"tag":76,"props":1413,"children":1415},{"className":1414},[],[1416],{"type":61,"value":1417},"exploring-mcp-tool-quality",{"type":61,"value":1419}," — error rates, latency, reach, failing and slow tools.",{"type":56,"tag":655,"props":1421,"children":1422},{},[1423,1429],{"type":56,"tag":76,"props":1424,"children":1426},{"className":1425},[],[1427],{"type":61,"value":1428},"exploring-mcp-sessions",{"type":61,"value":1430}," — session list, per-session tool calls, intent.",{"type":56,"tag":655,"props":1432,"children":1433},{},[1434,1440],{"type":56,"tag":76,"props":1435,"children":1437},{"className":1436},[],[1438],{"type":61,"value":1439},"exploring-mcp-intent-clusters",{"type":61,"value":1441}," — \"what are people trying to do\" clusters.",{"type":56,"tag":655,"props":1443,"children":1444},{},[1445,1451],{"type":56,"tag":76,"props":1446,"children":1448},{"className":1447},[],[1449],{"type":61,"value":1450},"improving-mcp-tools",{"type":61,"value":1452}," — eval-scored campaign loop: measure, make one bounded fix, re-measure.",{"type":56,"tag":64,"props":1454,"children":1455},{},[1456,1461,1463,1469,1470,1476,1477,1483,1484,1490,1491,1497,1498,1504,1505,1511,1512,1518,1520,1526,1528,1534,1535,1541,1542,1548,1550,1556],{"type":56,"tag":68,"props":1457,"children":1458},{},[1459],{"type":61,"value":1460},"Typed tools",{"type":61,"value":1462}," exist for most questions and are preferable to raw SQL: ",{"type":56,"tag":76,"props":1464,"children":1466},{"className":1465},[],[1467],{"type":61,"value":1468},"posthog:query-mcp-tool-stats",{"type":61,"value":980},{"type":56,"tag":76,"props":1471,"children":1473},{"className":1472},[],[1474],{"type":61,"value":1475},"-daily-stats",{"type":61,"value":597},{"type":56,"tag":76,"props":1478,"children":1480},{"className":1479},[],[1481],{"type":61,"value":1482},"-failures",{"type":61,"value":597},{"type":56,"tag":76,"props":1485,"children":1487},{"className":1486},[],[1488],{"type":61,"value":1489},"-failure-occurrences",{"type":61,"value":597},{"type":56,"tag":76,"props":1492,"children":1494},{"className":1493},[],[1495],{"type":61,"value":1496},"-descriptions",{"type":61,"value":597},{"type":56,"tag":76,"props":1499,"children":1501},{"className":1500},[],[1502],{"type":61,"value":1503},"-neighbors",{"type":61,"value":980},{"type":56,"tag":76,"props":1506,"children":1508},{"className":1507},[],[1509],{"type":61,"value":1510},"-sample-intents",{"type":61,"value":597},{"type":56,"tag":76,"props":1513,"children":1515},{"className":1514},[],[1516],{"type":61,"value":1517},"-top-users",{"type":61,"value":1519},", and ",{"type":56,"tag":76,"props":1521,"children":1523},{"className":1522},[],[1524],{"type":61,"value":1525},"posthog:query-mcp-harness-breakdown",{"type":61,"value":1527},", plus session tools\n(",{"type":56,"tag":76,"props":1529,"children":1531},{"className":1530},[],[1532],{"type":61,"value":1533},"posthog:mcp-analytics-sessions-list",{"type":61,"value":925},{"type":56,"tag":76,"props":1536,"children":1538},{"className":1537},[],[1539],{"type":61,"value":1540},"-tool-calls",{"type":61,"value":925},{"type":56,"tag":76,"props":1543,"children":1545},{"className":1544},[],[1546],{"type":61,"value":1547},"-generate-intent",{"type":61,"value":1549},") and the intent-cluster\ntools. They are declared in ",{"type":56,"tag":76,"props":1551,"children":1553},{"className":1552},[],[1554],{"type":61,"value":1555},"products\u002Fmcp_analytics\u002Fmcp\u002Ftools.yaml",{"type":61,"value":106},{"type":56,"tag":64,"props":1558,"children":1559},{},[1560,1565,1567,1573,1575,1581,1583,1589,1591,1597,1599,1605,1607,1613,1615,1621],{"type":56,"tag":68,"props":1561,"children":1562},{},[1563],{"type":61,"value":1564},"Harness",{"type":61,"value":1566}," is the friendly label for the calling client (Claude Code, Cursor, ChatGPT,\nWindsurf, and ~30 other buckets). It is resolved at query time only, with no stored column:\n",{"type":56,"tag":76,"props":1568,"children":1570},{"className":1569},[],[1571],{"type":61,"value":1572},"mcp_harness.py::HARNESS_TOKEN_SQL",{"type":61,"value":1574}," picks the strongest available signal in priority order\n(",{"type":56,"tag":76,"props":1576,"children":1578},{"className":1577},[],[1579],{"type":61,"value":1580},"mcp_vendor_client",{"type":61,"value":1582}," -> Claude Code user-agent surface -> Grok user-agent -> ",{"type":56,"tag":76,"props":1584,"children":1586},{"className":1585},[],[1587],{"type":61,"value":1588},"$mcp_client_name",{"type":61,"value":1590},"\n-> ",{"type":56,"tag":76,"props":1592,"children":1594},{"className":1593},[],[1595],{"type":61,"value":1596},"mcp_session_client_name",{"type":61,"value":1598}," -> generic user-agent token -> ",{"type":56,"tag":76,"props":1600,"children":1602},{"className":1601},[],[1603],{"type":61,"value":1604},"$mcp_oauth_client_name",{"type":61,"value":1606},"), then\n",{"type":56,"tag":76,"props":1608,"children":1610},{"className":1609},[],[1611],{"type":61,"value":1612},"harness_label_sql()",{"type":61,"value":1614}," buckets it (or ",{"type":56,"tag":76,"props":1616,"children":1618},{"className":1617},[],[1619],{"type":61,"value":1620},"harness_label_or_token_sql()",{"type":61,"value":1622},", which names an\nunrecognized client verbatim instead of collapsing it into \"Other\" — use it for ranked\ntop-N lists, never where labels feed an array or unbounded GROUP BY).",{"type":56,"tag":64,"props":1624,"children":1625},{},[1626,1636,1638,1643,1645,1650],{"type":56,"tag":68,"props":1627,"children":1628},{},[1629,1634],{"type":56,"tag":76,"props":1630,"children":1632},{"className":1631},[],[1633],{"type":61,"value":1588},{"type":61,"value":1635}," is one mid-priority input, not a synonym for harness",{"type":61,"value":1637}," — grouping by\nit directly gives a different, messier answer. It rides on the session's ",{"type":56,"tag":76,"props":1639,"children":1641},{"className":1640},[],[1642],{"type":61,"value":1357},{"type":61,"value":1644}," and\nis absent from the tool calls that follow, so on its own it leaves most traffic\nunattributed; ",{"type":56,"tag":76,"props":1646,"children":1648},{"className":1647},[],[1649],{"type":61,"value":1596},{"type":61,"value":1651}," is the session-pinned fallback the token chain\nreaches for next.",{"type":56,"tag":64,"props":1653,"children":1654},{},[1655,1657,1663],{"type":61,"value":1656},"For hand-written SQL, ",{"type":56,"tag":76,"props":1658,"children":1660},{"className":1659},[],[1661],{"type":61,"value":1662},"models-mcp.md",{"type":61,"value":1664}," (linked in the Repos table) carries the property\nreference and worked query examples.",{"type":56,"tag":169,"props":1666,"children":1668},{"id":1667},"the-pipeline-and-where-each-stage-breaks",[1669],{"type":61,"value":1670},"The pipeline, and where each stage breaks",{"type":56,"tag":796,"props":1672,"children":1673},{},[1674,1828,1857,1910,2022,2108,2276,2345],{"type":56,"tag":655,"props":1675,"children":1676},{},[1677,1682,1684,1689,1691,1696,1698,1703,1705,1711,1713,1719,1721,1726,1728,1733,1735,1741,1743,1748,1750,1756,1757,1763,1765,1770,1772,1778,1780,1785,1786,1792,1793,1799,1801,1807,1809],{"type":56,"tag":68,"props":1678,"children":1679},{},[1680],{"type":61,"value":1681},"Instrument",{"type":61,"value":1683}," -> the server emits ",{"type":56,"tag":76,"props":1685,"children":1687},{"className":1686},[],[1688],{"type":61,"value":96},{"type":61,"value":1690}," events via the SDK.\n",{"type":56,"tag":294,"props":1692,"children":1693},{},[1694],{"type":61,"value":1695},"Breaks:",{"type":61,"value":1697}," handlers not wrapped (",{"type":56,"tag":76,"props":1699,"children":1701},{"className":1700},[],[1702],{"type":61,"value":1104},{"type":61,"value":1704}," is idempotent and degrades to a silent\nno-op on failure); a STDIO server writing to stdout with ",{"type":56,"tag":76,"props":1706,"children":1708},{"className":1707},[],[1709],{"type":61,"value":1710},"console.*",{"type":61,"value":1712}," (corrupts the\nprotocol stream — wire a ",{"type":56,"tag":76,"props":1714,"children":1716},{"className":1715},[],[1717],{"type":61,"value":1718},"logger",{"type":61,"value":1720},"); a disabled or misconfigured posthog-node client.\nFor ",{"type":56,"tag":76,"props":1722,"children":1724},{"className":1723},[],[1725],{"type":61,"value":837},{"type":61,"value":1727}," there is a ",{"type":56,"tag":68,"props":1729,"children":1730},{},[1731],{"type":61,"value":1732},"single emission path",{"type":61,"value":1734},": ",{"type":56,"tag":76,"props":1736,"children":1738},{"className":1737},[],[1739],{"type":61,"value":1740},"src\u002Fhono\u002Fanalytics.ts",{"type":61,"value":1742}," +\n",{"type":56,"tag":76,"props":1744,"children":1746},{"className":1745},[],[1747],{"type":61,"value":853},{"type":61,"value":1749}," -> ",{"type":56,"tag":76,"props":1751,"children":1753},{"className":1752},[],[1754],{"type":61,"value":1755},"getPostHogClient()",{"type":61,"value":440},{"type":56,"tag":76,"props":1758,"children":1760},{"className":1759},[],[1761],{"type":61,"value":1762},"src\u002Flib\u002Fposthog\u002Fclient.ts",{"type":61,"value":1764},") ->\n",{"type":56,"tag":76,"props":1766,"children":1768},{"className":1767},[],[1769],{"type":61,"value":1096},{"type":61,"value":1771},", consumed through the dependency alias ",{"type":56,"tag":76,"props":1773,"children":1775},{"className":1774},[],[1776],{"type":61,"value":1777},"@posthog\u002Fmcp-analytics",{"type":61,"value":1779}," (the alias\nmatters when grepping imports). The legacy MCPcat\u002FAgentCat shim and the transition shim\nthat dual-emitted non-",{"type":56,"tag":76,"props":1781,"children":1783},{"className":1782},[],[1784],{"type":61,"value":1256},{"type":61,"value":300},{"type":56,"tag":76,"props":1787,"children":1789},{"className":1788},[],[1790],{"type":61,"value":1791},"mcp_tool_call",{"type":61,"value":925},{"type":56,"tag":76,"props":1794,"children":1796},{"className":1795},[],[1797],{"type":61,"value":1798},"mcp_initialize",{"type":61,"value":1800}," were both removed and are\nregression-tested in ",{"type":56,"tag":76,"props":1802,"children":1804},{"className":1803},[],[1805],{"type":61,"value":1806},"services\u002Fmcp\u002Ftests\u002Fhono\u002F",{"type":61,"value":1808},". ",{"type":56,"tag":68,"props":1810,"children":1811},{},[1812,1818,1820,1826],{"type":56,"tag":76,"props":1813,"children":1815},{"className":1814},[],[1816],{"type":61,"value":1817},"services\u002Fmcp\u002FARCHITECTURE.md",{"type":61,"value":1819}," still\ndescribes the old multi-emitter design and references a deleted ",{"type":56,"tag":76,"props":1821,"children":1823},{"className":1822},[],[1824],{"type":61,"value":1825},"lib\u002Fmcpcat.ts",{"type":61,"value":1827}," — trust\nthe source, not that document.",{"type":56,"tag":655,"props":1829,"children":1830},{},[1831,1836,1838,1843,1844,1848,1850,1855],{"type":56,"tag":68,"props":1832,"children":1833},{},[1834],{"type":61,"value":1835},"Ingest",{"type":61,"value":1837}," -> events land in ClickHouse ",{"type":56,"tag":76,"props":1839,"children":1841},{"className":1840},[],[1842],{"type":61,"value":1175},{"type":61,"value":1808},{"type":56,"tag":294,"props":1845,"children":1846},{},[1847],{"type":61,"value":1695},{"type":61,"value":1849}," ordinary ingestion and quota\nproblems; ",{"type":56,"tag":76,"props":1851,"children":1853},{"className":1852},[],[1854],{"type":61,"value":1198},{"type":61,"value":1856}," not materialized, which breaks session grouping.",{"type":56,"tag":655,"props":1858,"children":1859},{},[1860,1865,1866,1872,1874,1879,1880,1886,1888,1894,1896,1902,1904,1908],{"type":56,"tag":68,"props":1861,"children":1862},{},[1863],{"type":61,"value":1864},"Session list",{"type":61,"value":1749},{"type":56,"tag":76,"props":1867,"children":1869},{"className":1868},[],[1870],{"type":61,"value":1871},"backend\u002Flogic.py::list_mcp_sessions",{"type":61,"value":1873}," runs HogQL over a ",{"type":56,"tag":68,"props":1875,"children":1876},{},[1877],{"type":61,"value":1878},"7-day\ndefault window",{"type":61,"value":440},{"type":56,"tag":76,"props":1881,"children":1883},{"className":1882},[],[1884],{"type":61,"value":1885},"DEFAULT_SESSIONS_DATE_FROM",{"type":61,"value":1887},", resolved through ",{"type":56,"tag":76,"props":1889,"children":1891},{"className":1890},[],[1892],{"type":61,"value":1893},"QueryDateRange",{"type":61,"value":1895}," with a\none-day overlap buffer each side) and caches for 30s (",{"type":56,"tag":76,"props":1897,"children":1899},{"className":1898},[],[1900],{"type":61,"value":1901},"SESSIONS_CACHE_TTL_SECONDS",{"type":61,"value":1903},").\n",{"type":56,"tag":294,"props":1905,"children":1906},{},[1907],{"type":61,"value":1695},{"type":61,"value":1909}," anything outside the window simply isn't there; results can be up to 30s stale.",{"type":56,"tag":655,"props":1911,"children":1912},{},[1913,1918,1920,1926,1928,1934,1935,1941,1942,1948,1949,1955,1956,1962,1963,1969,1971,1976,1978,1984,1986,1992,1994,2000,2002,2007,2009,2014,2016,2020],{"type":56,"tag":68,"props":1914,"children":1915},{},[1916],{"type":61,"value":1917},"Charts and tool quality",{"type":61,"value":1919}," -> typed ",{"type":56,"tag":76,"props":1921,"children":1923},{"className":1922},[],[1924],{"type":61,"value":1925},"AnalyticsQueryRunner",{"type":61,"value":1927}," subclasses in\n",{"type":56,"tag":76,"props":1929,"children":1931},{"className":1930},[],[1932],{"type":61,"value":1933},"backend\u002Fhogql_queries\u002F",{"type":61,"value":440},{"type":56,"tag":76,"props":1936,"children":1938},{"className":1937},[],[1939],{"type":61,"value":1940},"base.py",{"type":61,"value":597},{"type":56,"tag":76,"props":1943,"children":1945},{"className":1944},[],[1946],{"type":61,"value":1947},"dashboard_series.py",{"type":61,"value":597},{"type":56,"tag":76,"props":1950,"children":1952},{"className":1951},[],[1953],{"type":61,"value":1954},"harness_breakdown.py",{"type":61,"value":980},{"type":56,"tag":76,"props":1957,"children":1959},{"className":1958},[],[1960],{"type":61,"value":1961},"tool_quality_tables.py",{"type":61,"value":597},{"type":56,"tag":76,"props":1964,"children":1966},{"className":1965},[],[1967],{"type":61,"value":1968},"tool_tables.py",{"type":61,"value":1970},"), dispatched via the generic ",{"type":56,"tag":76,"props":1972,"children":1974},{"className":1973},[],[1975],{"type":61,"value":1145},{"type":61,"value":1977}," endpoint\nand enumerated in ",{"type":56,"tag":76,"props":1979,"children":1981},{"className":1980},[],[1982],{"type":61,"value":1983},"backend\u002Ffacade\u002Fqueries.py",{"type":61,"value":1985},", with schemas in ",{"type":56,"tag":76,"props":1987,"children":1989},{"className":1988},[],[1990],{"type":61,"value":1991},"posthog\u002Fschema.py",{"type":61,"value":1993},".\nGate: ",{"type":56,"tag":76,"props":1995,"children":1997},{"className":1996},[],[1998],{"type":61,"value":1999},"hogql_queries\u002Fbase.py::validate_mcp_analytics_access",{"type":61,"value":2001}," — the feature flag ",{"type":56,"tag":68,"props":2003,"children":2004},{},[2005],{"type":61,"value":2006},"plus",{"type":61,"value":2008},"\nthe ",{"type":56,"tag":76,"props":2010,"children":2012},{"className":2011},[],[2013],{"type":61,"value":529},{"type":61,"value":2015}," RBAC resource. ",{"type":56,"tag":294,"props":2017,"children":2018},{},[2019],{"type":61,"value":1695},{"type":61,"value":2021}," flag off, RBAC denies, or Hard rules 1-3\nignored.",{"type":56,"tag":655,"props":2023,"children":2024},{},[2025,2030,2032,2038,2040,2046,2048,2053,2055,2061,2063,2069,2071,2077,2079,2083,2085,2090,2092,2098,2100,2106],{"type":56,"tag":68,"props":2026,"children":2027},{},[2028],{"type":61,"value":2029},"Intent generation",{"type":61,"value":2031}," (on demand, per session) -> collect ",{"type":56,"tag":76,"props":2033,"children":2035},{"className":2034},[],[2036],{"type":61,"value":2037},"$mcp_intent",{"type":61,"value":2039}," values -> an LLM\nsummary of at most two sentences -> Postgres ",{"type":56,"tag":76,"props":2041,"children":2043},{"className":2042},[],[2044],{"type":61,"value":2045},"posthog_mcp_session",{"type":61,"value":2047},". A second,\nproject-level path produces the ",{"type":56,"tag":68,"props":2049,"children":2050},{},[2051],{"type":61,"value":2052},"intent digest \u002F themes",{"type":61,"value":2054}," with structured output, bounded\nby ",{"type":56,"tag":76,"props":2056,"children":2058},{"className":2057},[],[2059],{"type":61,"value":2060},"MAX_DIGEST_THEMES",{"type":61,"value":2062},"; ",{"type":56,"tag":76,"props":2064,"children":2066},{"className":2065},[],[2067],{"type":61,"value":2068},"resolve_themes()",{"type":61,"value":2070}," derives every countable field from the corpus\nso the model cannot invent numbers. Model constants live in ",{"type":56,"tag":76,"props":2072,"children":2074},{"className":2073},[],[2075],{"type":61,"value":2076},"backend\u002Fintent_generation.py",{"type":61,"value":2078},".\n",{"type":56,"tag":294,"props":2080,"children":2081},{},[2082],{"type":61,"value":1695},{"type":61,"value":2084}," no ",{"type":56,"tag":76,"props":2086,"children":2088},{"className":2087},[],[2089],{"type":61,"value":2037},{"type":61,"value":2091}," captured at all (the agent never filled the injected ",{"type":56,"tag":76,"props":2093,"children":2095},{"className":2094},[],[2096],{"type":61,"value":2097},"context",{"type":61,"value":2099},"\nargument and no ",{"type":56,"tag":76,"props":2101,"children":2103},{"className":2102},[],[2104],{"type":61,"value":2105},"intentFallback",{"type":61,"value":2107}," was configured), so there is nothing to summarize; LLM\nkey or quota problems.",{"type":56,"tag":655,"props":2109,"children":2110},{},[2111,2116,2118,2124,2126,2132,2134,2140,2141,2146,2148,2154,2156,2162,2164,2170,2172,2177,2179,2185,2187,2193,2195,2201,2203,2209,2211,2217,2219,2223,2225,2231,2233,2238,2240,2245,2247,2251,2253,2258,2260,2266,2268,2274],{"type":56,"tag":68,"props":2112,"children":2113},{},[2114],{"type":61,"value":2115},"Intent clustering",{"type":61,"value":2117}," -> embed (cached in ",{"type":56,"tag":76,"props":2119,"children":2121},{"className":2120},[],[2122],{"type":61,"value":2123},"MCPIntentEmbeddingCache",{"type":61,"value":2125},") -> agglomerative\nclustering (cosine, average linkage, ",{"type":56,"tag":76,"props":2127,"children":2129},{"className":2128},[],[2130],{"type":61,"value":2131},"DEFAULT_DISTANCE_THRESHOLD",{"type":61,"value":2133},") -> JSONB\n",{"type":56,"tag":76,"props":2135,"children":2137},{"className":2136},[],[2138],{"type":61,"value":2139},"MCPIntentClusterSnapshot",{"type":61,"value":1808},{"type":56,"tag":68,"props":2142,"children":2143},{},[2144],{"type":61,"value":2145},"Temporal end-to-end, no Celery.",{"type":61,"value":2147}," On-demand recompute\n(",{"type":56,"tag":76,"props":2149,"children":2151},{"className":2150},[],[2152],{"type":61,"value":2153},"trigger_intent_cluster_recompute",{"type":61,"value":2155},", serialized with ",{"type":56,"tag":76,"props":2157,"children":2159},{"className":2158},[],[2160],{"type":61,"value":2161},"select_for_update()",{"type":61,"value":2163}," and a\ndeterministic per-team workflow id) and the ",{"type":56,"tag":76,"props":2165,"children":2167},{"className":2166},[],[2168],{"type":61,"value":2169},"cluster_mcp_intents",{"type":61,"value":2171}," management command both\nstart the workflow; the daily run is a Temporal ",{"type":56,"tag":68,"props":2173,"children":2174},{},[2175],{"type":61,"value":2176},"Schedule",{"type":61,"value":2178},"\n(",{"type":56,"tag":76,"props":2180,"children":2182},{"className":2181},[],[2183],{"type":61,"value":2184},"posthog\u002Ftemporal\u002Fmcp_analytics\u002Fintent_clustering\u002Fschedule.py",{"type":61,"value":2186},", behind the\n",{"type":56,"tag":76,"props":2188,"children":2190},{"className":2189},[],[2191],{"type":61,"value":2192},"mcp-analytics-clustering-schedule",{"type":61,"value":2194}," flag) that triggers\n",{"type":56,"tag":76,"props":2196,"children":2198},{"className":2197},[],[2199],{"type":61,"value":2200},"IntentClusteringCoordinatorWorkflow",{"type":61,"value":2202},", which fans out one child workflow per team.\nTwo caps will surprise you: ",{"type":56,"tag":76,"props":2204,"children":2206},{"className":2205},[],[2207],{"type":61,"value":2208},"MAX_SNAPSHOT_CLUSTERS",{"type":61,"value":2210}," (snapshots keep only the top clusters\nby volume, enforced at write and again at read) and ",{"type":56,"tag":76,"props":2212,"children":2214},{"className":2213},[],[2215],{"type":61,"value":2216},"MAX_QUERY_ROWS",{"type":61,"value":2218},".\nNote the corpus does ",{"type":56,"tag":68,"props":2220,"children":2221},{},[2222],{"type":61,"value":130},{"type":61,"value":2224}," depend on step 5: ",{"type":56,"tag":76,"props":2226,"children":2228},{"className":2227},[],[2229],{"type":61,"value":2230},"fetch_intent_corpus",{"type":61,"value":2232}," takes each session's\nfirst ",{"type":56,"tag":76,"props":2234,"children":2236},{"className":2235},[],[2237],{"type":61,"value":2037},{"type":61,"value":2239}," straight from ClickHouse and only ",{"type":56,"tag":294,"props":2241,"children":2242},{},[2243],{"type":61,"value":2244},"overrides",{"type":61,"value":2246}," it with the stored LLM\nsummary where one exists. So a project can cluster with no generated summaries at all.\n",{"type":56,"tag":294,"props":2248,"children":2249},{},[2250],{"type":61,"value":1695},{"type":61,"value":2252}," empty clusters almost always mean no ",{"type":56,"tag":76,"props":2254,"children":2256},{"className":2255},[],[2257],{"type":61,"value":2037},{"type":61,"value":2259}," values in the lookback window\n(check the corpus before chasing summary generation); schedule flag off; stale embeddings.\nAlso check the allowlist — ",{"type":56,"tag":76,"props":2261,"children":2263},{"className":2262},[],[2264],{"type":61,"value":2265},"intent_clustering\u002Fteam_discovery.py",{"type":61,"value":2267}," currently returns a\nhard-coded ",{"type":56,"tag":76,"props":2269,"children":2271},{"className":2270},[],[2272],{"type":61,"value":2273},"GUARANTEED_TEAM_IDS = [2]",{"type":61,"value":2275},", so the daily schedule covers only PostHog's own\nproject and enabling the flag elsewhere still produces nothing until that changes.",{"type":56,"tag":655,"props":2277,"children":2278},{},[2279,2284,2286,2292,2294,2300,2302,2308,2309,2315,2316,2322,2323,2329,2330,2336,2338,2343],{"type":56,"tag":68,"props":2280,"children":2281},{},[2282],{"type":61,"value":2283},"Serve",{"type":61,"value":2285}," -> DRF viewsets at\n",{"type":56,"tag":76,"props":2287,"children":2289},{"className":2288},[],[2290],{"type":61,"value":2291},"\u002Fapi\u002Fprojects\u002F{id}\u002Fmcp_analytics\u002F{sessions,intent_clusters,feedback,missing_capabilities}",{"type":61,"value":2293},"\n(router in ",{"type":56,"tag":76,"props":2295,"children":2297},{"className":2296},[],[2298],{"type":61,"value":2299},"backend\u002Fpresentation\u002Furls.py",{"type":61,"value":2301},") plus custom actions\n(",{"type":56,"tag":76,"props":2303,"children":2305},{"className":2304},[],[2306],{"type":61,"value":2307},"sessions\u002F{id}\u002Ftool_calls",{"type":61,"value":597},{"type":56,"tag":76,"props":2310,"children":2312},{"className":2311},[],[2313],{"type":61,"value":2314},"sessions\u002F{id}\u002Fgenerate_intent",{"type":61,"value":597},{"type":56,"tag":76,"props":2317,"children":2319},{"className":2318},[],[2320],{"type":61,"value":2321},"sessions\u002Fintent_digest",{"type":61,"value":980},{"type":56,"tag":76,"props":2324,"children":2326},{"className":2325},[],[2327],{"type":61,"value":2328},"sessions\u002Factivity_overview",{"type":61,"value":597},{"type":56,"tag":76,"props":2331,"children":2333},{"className":2332},[],[2334],{"type":61,"value":2335},"intent_clusters\u002Frecompute",{"type":61,"value":2337},"). Parallel surface: step 4's\nrunners, exposed to agents as the ",{"type":56,"tag":76,"props":2339,"children":2341},{"className":2340},[],[2342],{"type":61,"value":259},{"type":61,"value":2344}," tools.",{"type":56,"tag":655,"props":2346,"children":2347},{},[2348,2353,2355,2361,2363,2369,2370,2376,2378,2384,2385,2391,2393,2399,2401],{"type":56,"tag":68,"props":2349,"children":2350},{},[2351],{"type":61,"value":2352},"Frontend",{"type":61,"value":2354}," -> Kea scene ",{"type":56,"tag":76,"props":2356,"children":2358},{"className":2357},[],[2359],{"type":61,"value":2360},"MCPAnalyticsScene.tsx",{"type":61,"value":2362},", with tabs enumerated by\n",{"type":56,"tag":76,"props":2364,"children":2366},{"className":2365},[],[2367],{"type":61,"value":2368},"MCPAnalyticsTab",{"type":61,"value":847},{"type":56,"tag":76,"props":2371,"children":2373},{"className":2372},[],[2374],{"type":61,"value":2375},"mcpAnalyticsSceneLogic.ts",{"type":61,"value":2377},": activity, dashboard, sessions,\ntool quality, intent clustering, notifications. The landing tab is volume-gated by\n",{"type":56,"tag":76,"props":2379,"children":2381},{"className":2380},[],[2382],{"type":61,"value":2383},"dashboardStage",{"type":61,"value":847},{"type":56,"tag":76,"props":2386,"children":2388},{"className":2387},[],[2389],{"type":61,"value":2390},"mcpAnalyticsOnboardingLogic.ts",{"type":61,"value":2392}," and applies only to the bare\n",{"type":56,"tag":76,"props":2394,"children":2396},{"className":2395},[],[2397],{"type":61,"value":2398},"\u002Fmcp-analytics",{"type":61,"value":2400}," redirect — deep links and explicit tab clicks are never overridden.\n",{"type":56,"tag":651,"props":2402,"children":2403},{},[2404,2434,2465,2506],{"type":56,"tag":655,"props":2405,"children":2406},{},[2407,2412,2413,2419,2421,2426,2428,2432],{"type":56,"tag":68,"props":2408,"children":2409},{},[2410],{"type":61,"value":2411},"Activity",{"type":61,"value":440},{"type":56,"tag":76,"props":2414,"children":2416},{"className":2415},[],[2417],{"type":61,"value":2418},"earlyData\u002F",{"type":61,"value":2420},"): live tool-call feed plus the intent-",{"type":56,"tag":68,"props":2422,"children":2423},{},[2424],{"type":61,"value":2425},"themes",{"type":61,"value":2427}," card.\n\"Theme\" (the LLM digest, Activity tab) is ",{"type":56,"tag":68,"props":2429,"children":2430},{},[2431],{"type":61,"value":130},{"type":61,"value":2433}," \"cluster\" (the embedding clustering,\nits own tab). Conflating the two is the most common mistake here.",{"type":56,"tag":655,"props":2435,"children":2436},{},[2437,2442,2444,2449,2450,2456,2458,2464],{"type":56,"tag":68,"props":2438,"children":2439},{},[2440],{"type":61,"value":2441},"Tool quality",{"type":61,"value":2443}," and the per-tool ",{"type":56,"tag":68,"props":2445,"children":2446},{},[2447],{"type":61,"value":2448},"tool report",{"type":61,"value":440},{"type":56,"tag":76,"props":2451,"children":2453},{"className":2452},[],[2454],{"type":61,"value":2455},"MCPAnalyticsToolDetail.tsx",{"type":61,"value":2457},", its own\nregistered scene): shared date filter, failure-occurrence drill-down with copyable error\ncontext, and \"create fix task\" straight into ",{"type":56,"tag":76,"props":2459,"children":2461},{"className":2460},[],[2462],{"type":61,"value":2463},"products\u002Ftasks",{"type":61,"value":106},{"type":56,"tag":655,"props":2466,"children":2467},{},[2468,2473,2475,2481,2483,2489,2491,2496,2498,2504],{"type":56,"tag":68,"props":2469,"children":2470},{},[2471],{"type":61,"value":2472},"Dashboard",{"type":61,"value":2474},": quill composable ",{"type":56,"tag":76,"props":2476,"children":2478},{"className":2477},[],[2479],{"type":61,"value":2480},"Metric",{"type":61,"value":2482}," tiles and ",{"type":56,"tag":76,"props":2484,"children":2486},{"className":2485},[],[2487],{"type":61,"value":2488},"@posthog\u002Fquill-primitives",{"type":61,"value":2490},", plus\n",{"type":56,"tag":68,"props":2492,"children":2493},{},[2494],{"type":61,"value":2495},"notable sessions",{"type":61,"value":2497}," selected by a ",{"type":56,"tag":76,"props":2499,"children":2501},{"className":2500},[],[2502],{"type":61,"value":2503},"NotableRule",{"type":61,"value":2505}," — so that table can legitimately be\nshort or empty.",{"type":56,"tag":655,"props":2507,"children":2508},{},[2509,2514,2516,2522],{"type":56,"tag":68,"props":2510,"children":2511},{},[2512],{"type":61,"value":2513},"Notifications",{"type":61,"value":2515},": first-party destinations for MCP events and recurring AI reports\n(",{"type":56,"tag":76,"props":2517,"children":2519},{"className":2518},[],[2520],{"type":61,"value":2521},"frontend\u002Fnotifications\u002F",{"type":61,"value":2523},"), thin wiring over the generic hog-function destination and\nsubscription machinery.",{"type":56,"tag":64,"props":2525,"children":2526},{},[2527,2529,2535,2537,2543,2545,2550,2551,2557,2559,2564],{"type":61,"value":2528},"Postgres models (",{"type":56,"tag":76,"props":2530,"children":2532},{"className":2531},[],[2533],{"type":61,"value":2534},"backend\u002Fmodels.py",{"type":61,"value":2536},"): ",{"type":56,"tag":76,"props":2538,"children":2540},{"className":2539},[],[2541],{"type":61,"value":2542},"MCPSession",{"type":61,"value":2544}," (the intent store),\n",{"type":56,"tag":76,"props":2546,"children":2548},{"className":2547},[],[2549],{"type":61,"value":2139},{"type":61,"value":597},{"type":56,"tag":76,"props":2552,"children":2554},{"className":2553},[],[2555],{"type":61,"value":2556},"MCPAnalyticsSubmission",{"type":61,"value":2558}," (feedback and missing-capability\nreports), ",{"type":56,"tag":76,"props":2560,"children":2562},{"className":2561},[],[2563],{"type":61,"value":2123},{"type":61,"value":106},{"type":56,"tag":64,"props":2566,"children":2567},{},[2568,2573,2574,2580,2581,2587,2589,2595,2596,2602,2603,2609,2610,2616,2617,2623,2624,2630,2631,2637,2639,2645,2647,2652],{"type":56,"tag":68,"props":2569,"children":2570},{},[2571],{"type":61,"value":2572},"Seeding local data:",{"type":61,"value":300},{"type":56,"tag":76,"props":2575,"children":2577},{"className":2576},[],[2578],{"type":61,"value":2579},".\u002Fmanage.py seed_mcp_sessions --team-id N",{"type":61,"value":2178},{"type":56,"tag":76,"props":2582,"children":2584},{"className":2583},[],[2585],{"type":61,"value":2586},"backend\u002Fmanagement\u002Fcommands\u002F",{"type":61,"value":2588},"), with ",{"type":56,"tag":76,"props":2590,"children":2592},{"className":2591},[],[2593],{"type":61,"value":2594},"--sessions",{"type":61,"value":597},{"type":56,"tag":76,"props":2597,"children":2599},{"className":2598},[],[2600],{"type":61,"value":2601},"--min-calls",{"type":61,"value":455},{"type":56,"tag":76,"props":2604,"children":2606},{"className":2605},[],[2607],{"type":61,"value":2608},"--max-calls",{"type":61,"value":597},{"type":56,"tag":76,"props":2611,"children":2613},{"className":2612},[],[2614],{"type":61,"value":2615},"--days",{"type":61,"value":980},{"type":56,"tag":76,"props":2618,"children":2620},{"className":2619},[],[2621],{"type":61,"value":2622},"--missing-capabilities",{"type":61,"value":597},{"type":56,"tag":76,"props":2625,"children":2627},{"className":2626},[],[2628],{"type":61,"value":2629},"--seed",{"type":61,"value":1519},{"type":56,"tag":76,"props":2632,"children":2634},{"className":2633},[],[2635],{"type":61,"value":2636},"--clear",{"type":61,"value":2638},". Seeded events are tagged ",{"type":56,"tag":76,"props":2640,"children":2642},{"className":2641},[],[2643],{"type":61,"value":2644},"$mcp_seeded",{"type":61,"value":2646}," so\n",{"type":56,"tag":76,"props":2648,"children":2650},{"className":2649},[],[2651],{"type":61,"value":2636},{"type":61,"value":2653}," removes only seeded data.",{"type":56,"tag":169,"props":2655,"children":2657},{"id":2656},"which-repo-to-change",[2658],{"type":61,"value":2659},"Which repo to change",{"type":56,"tag":189,"props":2661,"children":2662},{},[2663,2683],{"type":56,"tag":193,"props":2664,"children":2665},{},[2666],{"type":56,"tag":197,"props":2667,"children":2668},{},[2669,2674,2678],{"type":56,"tag":201,"props":2670,"children":2671},{},[2672],{"type":61,"value":2673},"Change",{"type":56,"tag":201,"props":2675,"children":2676},{},[2677],{"type":61,"value":210},{"type":56,"tag":201,"props":2679,"children":2680},{},[2681],{"type":61,"value":2682},"Workflow",{"type":56,"tag":217,"props":2684,"children":2685},{},[2686,2730,2763,2868,2905,2955],{"type":56,"tag":197,"props":2687,"children":2688},{},[2689,2694,2702],{"type":56,"tag":224,"props":2690,"children":2691},{},[2692],{"type":61,"value":2693},"SDK behaviour, events, options, instrumentation",{"type":56,"tag":224,"props":2695,"children":2696},{},[2697],{"type":56,"tag":76,"props":2698,"children":2700},{"className":2699},[],[2701],{"type":61,"value":362},{"type":56,"tag":224,"props":2703,"children":2704},{},[2705,2707,2713,2715,2720,2722,2728],{"type":61,"value":2706},"Work in ",{"type":56,"tag":76,"props":2708,"children":2710},{"className":2709},[],[2711],{"type":61,"value":2712},"packages\u002Fmcp",{"type":61,"value":2714},". Run its unit tests, build, and lint. ",{"type":56,"tag":68,"props":2716,"children":2717},{},[2718],{"type":61,"value":2719},"Add a changeset.",{"type":61,"value":2721}," Ships to npm; then bump the alias in ",{"type":56,"tag":76,"props":2723,"children":2725},{"className":2724},[],[2726],{"type":61,"value":2727},"services\u002Fmcp\u002Fpackage.json",{"type":61,"value":2729}," to pick it up.",{"type":56,"tag":197,"props":2731,"children":2732},{},[2733,2738,2743],{"type":56,"tag":224,"props":2734,"children":2735},{},[2736],{"type":61,"value":2737},"Dashboard, queries, clustering, API",{"type":56,"tag":224,"props":2739,"children":2740},{},[2741],{"type":61,"value":2742},"this repo",{"type":56,"tag":224,"props":2744,"children":2745},{},[2746,2748,2753,2755,2761],{"type":61,"value":2747},"A new chart means a query runner in ",{"type":56,"tag":76,"props":2749,"children":2751},{"className":2750},[],[2752],{"type":61,"value":1933},{"type":61,"value":2754}," behind ",{"type":56,"tag":76,"props":2756,"children":2758},{"className":2757},[],[2759],{"type":61,"value":2760},"validate_mcp_analytics_access",{"type":61,"value":2762}," — never a SQL template. Obey Hard rules 1-3.",{"type":56,"tag":197,"props":2764,"children":2765},{},[2766,2778,2783],{"type":56,"tag":224,"props":2767,"children":2768},{},[2769,2771,2776],{"type":61,"value":2770},"A new ",{"type":56,"tag":76,"props":2772,"children":2774},{"className":2773},[],[2775],{"type":61,"value":259},{"type":61,"value":2777}," agent tool",{"type":56,"tag":224,"props":2779,"children":2780},{},[2781],{"type":61,"value":2782},"this repo (two places)",{"type":56,"tag":224,"props":2784,"children":2785},{},[2786,2788,2793,2795,2801,2802,2808,2809,2815,2816,2822,2824,2830,2832,2838,2839,2844,2846,2851,2853,2858,2860,2866],{"type":61,"value":2787},"1) an entry in ",{"type":56,"tag":76,"props":2789,"children":2791},{"className":2790},[],[2792],{"type":61,"value":1555},{"type":61,"value":2794}," with ",{"type":56,"tag":76,"props":2796,"children":2798},{"className":2797},[],[2799],{"type":61,"value":2800},"schema_ref",{"type":61,"value":597},{"type":56,"tag":76,"props":2803,"children":2805},{"className":2804},[],[2806],{"type":61,"value":2807},"scopes",{"type":61,"value":597},{"type":56,"tag":76,"props":2810,"children":2812},{"className":2811},[],[2813],{"type":61,"value":2814},"description",{"type":61,"value":597},{"type":56,"tag":76,"props":2817,"children":2819},{"className":2818},[],[2820],{"type":61,"value":2821},"feature_flag",{"type":61,"value":2823},"; 2) the matching ",{"type":56,"tag":76,"props":2825,"children":2827},{"className":2826},[],[2828],{"type":61,"value":2829},"\u003CName>Query",{"type":61,"value":2831}," schema and ",{"type":56,"tag":76,"props":2833,"children":2835},{"className":2834},[],[2836],{"type":61,"value":2837},"\u003CName>QueryRunner",{"type":61,"value":847},{"type":56,"tag":76,"props":2840,"children":2842},{"className":2841},[],[2843],{"type":61,"value":1933},{"type":61,"value":2845},"; 3) regenerate the tool handlers from ",{"type":56,"tag":76,"props":2847,"children":2849},{"className":2848},[],[2850],{"type":61,"value":837},{"type":61,"value":2852}," (see its ",{"type":56,"tag":76,"props":2854,"children":2856},{"className":2855},[],[2857],{"type":61,"value":1059},{"type":61,"value":2859}," scripts). The generic ",{"type":56,"tag":76,"props":2861,"children":2863},{"className":2862},[],[2864],{"type":61,"value":2865},"createQueryWrapper",{"type":61,"value":2867}," handles the tool shape — no hand-written TypeScript.",{"type":56,"tag":197,"props":2869,"children":2870},{},[2871,2876,2880],{"type":56,"tag":224,"props":2872,"children":2873},{},[2874],{"type":61,"value":2875},"PostHog's own dogfood events",{"type":56,"tag":224,"props":2877,"children":2878},{},[2879],{"type":61,"value":2742},{"type":56,"tag":224,"props":2881,"children":2882},{},[2883,2889,2891,2897,2899,2904],{"type":56,"tag":76,"props":2884,"children":2886},{"className":2885},[],[2887],{"type":61,"value":2888},"services\u002Fmcp\u002Fsrc\u002Fhono\u002Fanalytics.ts",{"type":61,"value":2890}," + ",{"type":56,"tag":76,"props":2892,"children":2894},{"className":2893},[],[2895],{"type":61,"value":2896},"tool-executor.ts",{"type":61,"value":2898},"; client in ",{"type":56,"tag":76,"props":2900,"children":2902},{"className":2901},[],[2903],{"type":61,"value":1762},{"type":61,"value":106},{"type":56,"tag":197,"props":2906,"children":2907},{},[2908,2912,2920],{"type":56,"tag":224,"props":2909,"children":2910},{},[2911],{"type":61,"value":487},{"type":56,"tag":224,"props":2913,"children":2914},{},[2915],{"type":56,"tag":76,"props":2916,"children":2918},{"className":2917},[],[2919],{"type":61,"value":496},{"type":56,"tag":224,"props":2921,"children":2922},{},[2923,2925,2931,2933,2938,2940,2946,2948,2954],{"type":61,"value":2924},"Keep the event and property tables in ",{"type":56,"tag":76,"props":2926,"children":2928},{"className":2927},[],[2929],{"type":61,"value":2930},"contents\u002Fdocs\u002Fmcp-analytics\u002Fevents.mdx",{"type":61,"value":2932}," synced with ",{"type":56,"tag":68,"props":2934,"children":2935},{},[2936],{"type":61,"value":2937},"both",{"type":61,"value":2939}," the TypeScript ",{"type":56,"tag":76,"props":2941,"children":2943},{"className":2942},[],[2944],{"type":61,"value":2945},"constants.ts",{"type":61,"value":2947}," and the Python ",{"type":56,"tag":76,"props":2949,"children":2951},{"className":2950},[],[2952],{"type":61,"value":2953},"posthog\u002Fmcp\u002Fconstants.py",{"type":61,"value":106},{"type":56,"tag":197,"props":2956,"children":2957},{},[2958,2963,2977],{"type":56,"tag":224,"props":2959,"children":2960},{},[2961],{"type":61,"value":2962},"The install codemod or the wizard command",{"type":56,"tag":224,"props":2964,"children":2965},{},[2966,2971,2972],{"type":56,"tag":76,"props":2967,"children":2969},{"className":2968},[],[2970],{"type":61,"value":557},{"type":61,"value":597},{"type":56,"tag":76,"props":2973,"children":2975},{"className":2974},[],[2976],{"type":61,"value":586},{"type":56,"tag":224,"props":2978,"children":2979},{},[2980,2982,2987],{"type":61,"value":2981},"See ",{"type":56,"tag":181,"props":2983,"children":2985},{"href":2984},"references\u002Fwizard-and-onboarding.md",[2986],{"type":61,"value":2984},{"type":61,"value":2988}," — in particular the rule about which changes need a wizard release and which do not.",{"type":56,"tag":64,"props":2990,"children":2991},{},[2992,2997,2999,3004,3006,3011,3013,3018,3020,3025],{"type":56,"tag":68,"props":2993,"children":2994},{},[2995],{"type":61,"value":2996},"Rule of thumb:",{"type":61,"value":2998}," a change to ",{"type":56,"tag":294,"props":3000,"children":3001},{},[3002],{"type":61,"value":3003},"what gets captured, or how servers are instrumented",{"type":61,"value":3005}," belongs\nin the SDKs. ",{"type":56,"tag":294,"props":3007,"children":3008},{},[3009],{"type":61,"value":3010},"How data is shown, aggregated, or clustered",{"type":61,"value":3012}," belongs in this product. ",{"type":56,"tag":294,"props":3014,"children":3015},{},[3016],{"type":61,"value":3017},"PostHog's\nown dogfood events",{"type":61,"value":3019}," belong in ",{"type":56,"tag":76,"props":3021,"children":3023},{"className":3022},[],[3024],{"type":61,"value":837},{"type":61,"value":3026},". A new customer-facing capability usually spans\nan SDK plus docs, and the product too if it needs a view.",{"type":56,"tag":64,"props":3028,"children":3029},{},[3030,3032,3036],{"type":61,"value":3031},"The wizard install flow, the skill-distribution channels, and the in-app onboarding are all in\n",{"type":56,"tag":181,"props":3033,"children":3034},{"href":2984},[3035],{"type":61,"value":2984},{"type":61,"value":106},{"type":56,"tag":169,"props":3038,"children":3040},{"id":3039},"current-state",[3041],{"type":61,"value":3042},"Current state",{"type":56,"tag":64,"props":3044,"children":3045},{},[3046,3048,3054,3056,3062,3064,3070,3072,3077],{"type":61,"value":3047},"Verified against ",{"type":56,"tag":76,"props":3049,"children":3051},{"className":3050},[],[3052],{"type":61,"value":3053},"master",{"type":61,"value":3055}," and the SDK's ",{"type":56,"tag":76,"props":3057,"children":3059},{"className":3058},[],[3060],{"type":61,"value":3061},"main",{"type":61,"value":3063}," on 2026-07-31. Treat versions and open threads\nas perishable — re-check ",{"type":56,"tag":76,"props":3065,"children":3067},{"className":3066},[],[3068],{"type":61,"value":3069},"packages\u002Fmcp\u002FCHANGELOG.md",{"type":61,"value":3071},", the pinned alias in\n",{"type":56,"tag":76,"props":3073,"children":3075},{"className":3074},[],[3076],{"type":61,"value":2727},{"type":61,"value":3078},", and mega-issue #64016 rather than trusting this section.",{"type":56,"tag":64,"props":3080,"children":3081},{},[3082,3084,3089,3091,3097],{"type":61,"value":3083},"Recently shipped: structured intent themes, first-party notification destinations and\nrecurring reports, ",{"type":56,"tag":76,"props":3085,"children":3087},{"className":3086},[],[3088],{"type":61,"value":529},{"type":61,"value":3090}," access control, the shared ",{"type":56,"tag":76,"props":3092,"children":3094},{"className":3093},[],[3095],{"type":61,"value":3096},"ProductEmptyState",{"type":61,"value":3098}," adoption,\nfailure-occurrence drill-down with \"create fix task\", the migration of every chart to typed\nquery runners, the demo seeder, and exec-mode inner-tool breakout (Hard rule 1).",{"type":56,"tag":64,"props":3100,"children":3101},{},[3102,3104,3109,3111,3116,3118,3123],{"type":61,"value":3103},"Two code-facing facts that shape debugging, both checkable in this repo: the ",{"type":56,"tag":76,"props":3105,"children":3107},{"className":3106},[],[3108],{"type":61,"value":837},{"type":61,"value":3110}," SDK\npin can lag the published SDK (Hard rule 5 — read the alias in its ",{"type":56,"tag":76,"props":3112,"children":3114},{"className":3113},[],[3115],{"type":61,"value":1059},{"type":61,"value":3117},"), and the\nproduct is still behind the ",{"type":56,"tag":76,"props":3119,"children":3121},{"className":3120},[],[3122],{"type":61,"value":150},{"type":61,"value":3124}," flag, so a project without it sees nothing. For\nstatus and planned work, read mega-issue #64016 rather than trusting a snapshot here.",{"items":3126,"total":3223},[3127,3140,3152,3164,3177,3190,3206],{"slug":3128,"name":3128,"fn":3129,"description":3130,"org":3131,"tags":3132,"stars":25,"repoUrl":26,"updatedAt":3139},"analyzing-expensive-users","analyze expensive users in AI observability","Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user LLM cost, user-level cost drivers, or patterns behind high AI observability spend.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3133,3134,3137,3138],{"name":20,"slug":21,"type":15},{"name":3135,"slug":3136,"type":15},"Cost Optimization","cost-optimization",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-07-28T05:34:11.117757",{"slug":3141,"name":3141,"fn":3142,"description":3143,"org":3144,"tags":3145,"stars":25,"repoUrl":26,"updatedAt":3151},"auditing-endpoints","audit PostHog project endpoints","Audit every endpoint in a PostHog project for staleness, failed materialisations, and unused materialised versions. Use when the user asks \"what endpoints can I clean up?\", \"are any of my endpoints broken?\", \"which materialised versions are still being called?\", or wants a one-shot cleanup pass over the Endpoints product. Produces a prioritised report grouped by issue type, with recommended actions but does not modify anything without explicit confirmation.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3146,3147,3150],{"name":20,"slug":21,"type":15},{"name":3148,"slug":3149,"type":15},"Audit","audit",{"name":9,"slug":8,"type":15},"2026-06-08T08:08:33.693989",{"slug":3153,"name":3153,"fn":3154,"description":3155,"org":3156,"tags":3157,"stars":25,"repoUrl":26,"updatedAt":3163},"auditing-warehouse-source-health","audit PostHog data warehouse source health","Audit the health of a PostHog project's data warehouse sources and syncs — find every broken or degraded source connection, sync schema, and webhook channel. Use when the user asks \"why are my imports failing?\", \"what's broken with my sources?\", \"why is my warehouse data stale?\", or wants a one-shot triage of source\u002Fsync health before deciding where to dig in. Produces a prioritized report grouped by severity, with recommended next steps. For materialized-view health use `auditing-warehouse-view-health`; for a single failing sync use `diagnosing-failed-warehouse-syncs`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3158,3159,3161,3162],{"name":3148,"slug":3149,"type":15},{"name":3160,"slug":34,"type":15},"Data Warehouse",{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-06-18T08:22:57.67984",{"slug":3165,"name":3165,"fn":3166,"description":3167,"org":3168,"tags":3169,"stars":25,"repoUrl":26,"updatedAt":3176},"auditing-warehouse-view-health","audit PostHog materialized view health","Audit the health of a PostHog project's materialized views (saved queries) — find every failed materialization and flag unused or stale materialized views that cost storage and compute. Use when the user asks \"which of my views are broken?\", \"why is this materialized view failing?\", \"are any of my views wasting compute?\", or wants a one-shot triage of view health. For source\u002Fsync health use `auditing-warehouse-source-health`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3170,3171,3172,3175],{"name":3148,"slug":3149,"type":15},{"name":3160,"slug":34,"type":15},{"name":3173,"slug":3174,"type":15},"Performance","performance",{"name":9,"slug":8,"type":15},"2026-06-18T08:25:10.936787",{"slug":3178,"name":3178,"fn":3179,"description":3180,"org":3181,"tags":3182,"stars":25,"repoUrl":26,"updatedAt":3189},"authoring-error-tracking-alerts","author PostHog error tracking alerts","Author error tracking alerts that fire when an issue is created, reopened, or starts spiking. Use when the user asks to set up error notifications, route exceptions to Slack\u002Fwebhook\u002FLinear, or evaluate which error events are worth alerting on. Covers trigger-event selection, integration choice, dedup against existing alerts, and shipping with the canonical message body shape.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3183,3186,3187,3188],{"name":3184,"slug":3185,"type":15},"Alerting","alerting",{"name":23,"slug":24,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-06-18T08:24:40.318583",{"slug":3191,"name":3191,"fn":3192,"description":3193,"org":3194,"tags":3195,"stars":25,"repoUrl":26,"updatedAt":3205},"authoring-log-alerts","author log alerts in PostHog","Author useful, low-noise log alerts on services in a PostHog project. Use when the user asks to set up alerts for their logs, suggest alerts they should add, or evaluate whether a service is worth monitoring. Covers service triage, baseline characterisation, threshold drafting, back-testing via simulate, and shipping with a notification destination.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3196,3197,3200,3201,3204],{"name":20,"slug":21,"type":15},{"name":3198,"slug":3199,"type":15},"Monitoring","monitoring",{"name":13,"slug":14,"type":15},{"name":3202,"slug":3203,"type":15},"Operations","operations",{"name":9,"slug":8,"type":15},"2026-07-18T05:10:54.430898",{"slug":3207,"name":3207,"fn":3208,"description":3209,"org":3210,"tags":3211,"stars":25,"repoUrl":26,"updatedAt":3222},"building-canvases","create and edit PostHog canvases","Create or edit a PostHog canvas — a sandboxed browser application (data board, document, form, small tool, graphics experiment) stored in PostHog and rendered by the desktop\u002Fweb app. Use when a task asks to build, generate, update, or fix a canvas, or when a canvas id is given as the publish target. Covers resolving or creating the target canvas, choosing an implementation approach (React + Quill vs plain HTML\u002Fbrowser APIs), the read → edit → validate → publish → build loop, and which companion canvas skills to load for the details.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3212,3215,3218,3219],{"name":3213,"slug":3214,"type":15},"Automation","automation",{"name":3216,"slug":3217,"type":15},"Design","design",{"name":9,"slug":8,"type":15},{"name":3220,"slug":3221,"type":15},"Prototyping","prototyping","2026-08-06T06:09:29.946969",74,{"items":3225,"total":3348},[3226,3233,3239,3246,3253,3260,3268,3275,3293,3308,3321,3333],{"slug":3128,"name":3128,"fn":3129,"description":3130,"org":3227,"tags":3228,"stars":25,"repoUrl":26,"updatedAt":3139},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3229,3230,3231,3232],{"name":20,"slug":21,"type":15},{"name":3135,"slug":3136,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":3141,"name":3141,"fn":3142,"description":3143,"org":3234,"tags":3235,"stars":25,"repoUrl":26,"updatedAt":3151},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3236,3237,3238],{"name":20,"slug":21,"type":15},{"name":3148,"slug":3149,"type":15},{"name":9,"slug":8,"type":15},{"slug":3153,"name":3153,"fn":3154,"description":3155,"org":3240,"tags":3241,"stars":25,"repoUrl":26,"updatedAt":3163},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3242,3243,3244,3245],{"name":3148,"slug":3149,"type":15},{"name":3160,"slug":34,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":3165,"name":3165,"fn":3166,"description":3167,"org":3247,"tags":3248,"stars":25,"repoUrl":26,"updatedAt":3176},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3249,3250,3251,3252],{"name":3148,"slug":3149,"type":15},{"name":3160,"slug":34,"type":15},{"name":3173,"slug":3174,"type":15},{"name":9,"slug":8,"type":15},{"slug":3178,"name":3178,"fn":3179,"description":3180,"org":3254,"tags":3255,"stars":25,"repoUrl":26,"updatedAt":3189},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3256,3257,3258,3259],{"name":3184,"slug":3185,"type":15},{"name":23,"slug":24,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"slug":3191,"name":3191,"fn":3192,"description":3193,"org":3261,"tags":3262,"stars":25,"repoUrl":26,"updatedAt":3205},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3263,3264,3265,3266,3267],{"name":20,"slug":21,"type":15},{"name":3198,"slug":3199,"type":15},{"name":13,"slug":14,"type":15},{"name":3202,"slug":3203,"type":15},{"name":9,"slug":8,"type":15},{"slug":3207,"name":3207,"fn":3208,"description":3209,"org":3269,"tags":3270,"stars":25,"repoUrl":26,"updatedAt":3222},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3271,3272,3273,3274],{"name":3213,"slug":3214,"type":15},{"name":3216,"slug":3217,"type":15},{"name":9,"slug":8,"type":15},{"name":3220,"slug":3221,"type":15},{"slug":3276,"name":3276,"fn":3277,"description":3278,"org":3279,"tags":3280,"stars":25,"repoUrl":26,"updatedAt":3292},"building-html-canvases","author HTML and CSS PostHog canvases","Author a PostHog canvas with semantic HTML, CSS, and direct browser APIs — documents, articles, generative graphics, 2D canvas and WebGL experiences, and focused experiments where React components add no useful structure. Use after building-canvases has routed a canvas request to a plain-HTML\u002Fbrowser-API implementation. Covers the thin component wrapper the current runtime requires, styling and theming without Quill, drawing surfaces, and animation\u002Fcleanup patterns.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3281,3284,3285,3288,3291],{"name":3282,"slug":3283,"type":15},"CSS","css",{"name":3216,"slug":3217,"type":15},{"name":3286,"slug":3287,"type":15},"Graphics","graphics",{"name":3289,"slug":3290,"type":15},"HTML","html",{"name":9,"slug":8,"type":15},"2026-08-06T06:09:30.313848",{"slug":3294,"name":3294,"fn":3295,"description":3296,"org":3297,"tags":3298,"stars":25,"repoUrl":26,"updatedAt":3307},"building-react-quill-canvases","build React and Quill canvases","Author the React + Quill implementation of a PostHog canvas: the single-component contract, the allowed imports, Quill (PostHog's design system) component and composition rules, theme-aware design tokens, loading skeletons, and the in-canvas date picker. Use after building-canvases has routed a canvas request to a React implementation — dashboards, data boards, forms, tools, or any canvas that should look native to PostHog.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3299,3300,3302,3304],{"name":3216,"slug":3217,"type":15},{"name":2352,"slug":3301,"type":15},"frontend",{"name":3303,"slug":40,"type":15},"React",{"name":3305,"slug":3306,"type":15},"UI Components","ui-components","2026-08-06T06:09:18.633724",{"slug":3309,"name":3309,"fn":3310,"description":3311,"org":3312,"tags":3313,"stars":25,"repoUrl":26,"updatedAt":3320},"building-workflows","build and edit PostHog workflows","Build, edit, test, enable, and monitor PostHog workflows over MCP. Author the action\u002Fedge graph so it runs and opens cleanly in the visual editor, then change drafts surgically with patch operations. Use when asked to build, set up, automate, change, fix, or debug a workflow, campaign, broadcast, drip sequence, or event-triggered automation in the workflows product.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3314,3315,3316,3317],{"name":3213,"slug":3214,"type":15},{"name":17,"slug":18,"type":15},{"name":9,"slug":8,"type":15},{"name":3318,"slug":3319,"type":15},"Workflow Automation","workflow-automation","2026-08-06T05:36:26.504811",{"slug":3322,"name":3322,"fn":3323,"description":3324,"org":3325,"tags":3326,"stars":25,"repoUrl":26,"updatedAt":3332},"check-posthog-loading","inspect PostHog SDK loading across URLs","Inspect how the PostHog JavaScript SDK is loaded across a list of URLs. Use to confirm consistent installation across pages, find pages missing the snippet, detect mismatched API keys or hosts between pages, and verify the load method (head snippet vs deferred vs array.js).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3327,3328,3329,3330,3331],{"name":20,"slug":21,"type":15},{"name":23,"slug":24,"type":15},{"name":2352,"slug":3301,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},"2026-05-07T05:56:19.828048",{"slug":3334,"name":3334,"fn":3335,"description":3336,"org":3337,"tags":3338,"stars":25,"repoUrl":26,"updatedAt":3347},"consuming-endpoints-from-client-code","integrate PostHog endpoints into client applications","Wire a PostHog endpoint into a client app or SDK. Covers fetching the OpenAPI spec, generating a typed client with openapi-generator or @hey-api\u002Fopenapi-ts, sending the right auth header, shaping the variables payload (HogQL code_name vs insight breakdown property), handling rate-limit and materialised-endpoint error responses. Use when the user says \"how do I call my endpoint\", \"generate a client for this\", or \"what auth header do I use\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3339,3342,3343,3344],{"name":3340,"slug":3341,"type":15},"API Development","api-development",{"name":2352,"slug":3301,"type":15},{"name":9,"slug":8,"type":15},{"name":3345,"slug":3346,"type":15},"SDK","sdk","2026-06-08T08:08:34.929454",243]