You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Status: In Progress Author: David Elgut (PM, Security AI) Date: 2026-05-29 Epic Link:(to be filled when published as a GitHub issue) Target Release: Rolling — instrumentation shipped; analytics pipeline next
Background
The Elastic Security MCP App puts Security workflows — alert triage, attack discovery, case management, detection rules, threat hunting, and sample-data generation — directly inside an MCP host such as Claude Desktop. Until recently we had no visibility into which of these surfaces customers actually use once the app is installed in the wild. We could not answer basic adoption questions: which views get opened, which tools get invoked, whether a feature is dead weight or load-bearing.
PR #29 (merged May 26, 2026) closed that gap. It wires the MCP App into Elastic's V3 analytics shipper (@elastic/ebt) and emits two closed-schema, anonymised events — mcp_tool_called and view_rendered — that respect the user's existing Kibana telemetry opt-in. The implementation is deliberately privacy-conservative: no PII, no free-form text, no cluster_name, and a fail-closed opt-in model.
Data is already flowing. Events are visible today in the stack-telemetry securitysolution view. This epic captures that completed instrumentation work as a record, and scopes the next phase: turning the raw event stream into PM-grade insight by correlating cluster identity to customers, sourcing the data from the forthcoming golden table, and surfacing it in a dedicated tab of the Security AI telemetry dashboard.
User Story / Problem Statement
As a Security AI Product Manager, I want to see anonymised MCP App usage telemetry — which views are rendered and which tools are called, by how many clusters — surfaced in the PM telemetry dashboard, so that I can measure adoption, prioritize investment toward the surfaces customers actually use, and tell a data-backed story about MCP App traction.
Raw events are not yet PM-consumable. The data now lands in stack-telemetry, but it is anonymised at the cluster_uuid level with no link to a named customer or user, and it is not yet surfaced anywhere a PM looks day-to-day.
No customer correlation. A cluster_uuid alone cannot answer "is this a strategic account?" or "how many distinct customers are exercising attack discovery?" — the questions that actually drive prioritization.
The Solution
Two phases. Phase 1 (shipped — Explore) instruments the MCP App and ships anonymised usage events under the user's Kibana opt-in. Phase 2 (next — Expand) builds the analytics path: render an "MCP App" tab in the sec-pm-telemetry-dashboard and correlate cluster identity to customers, sourced from the golden table when it lands.
To avoid dangling multi-phase work, Phase 2 is sequenced so value lands early: a v0 tab on anonymised, cluster-level metrics (view renders, tool-call volume and success rate, active clusters) can ship from currently queryable data without waiting on the golden table or identity enrichment. Customer-level breakdowns layer in once WS2 (identity) and WS3 (golden table) complete.
UX: Before
A PM asking "how is the MCP App being used?" had nowhere to look. No dashboard, no query, no event stream. The answer was anecdote.
UX: After
Usage events ship automatically from every opted-in install (shipped).
A PM opens the Security AI telemetry dashboard, selects the MCP App tab, and sees view-render counts, tool-call volume and success rates, active clusters, and — once identity enrichment lands — active customers and account-level breakdowns over a selectable date range.
The V3 shipper requires cluster_uuid to ship at all; events without cluster context are dropped (fail-closed).
Identity enrichment (dotted edge) is an open design question — the join source is not yet decided (see Open Questions).
The dashboard consumes data through its existing pattern: a BigQuery refresher registered in registry.ts, cached behind /api/metrics, rendered by a tab component wired into App.tsx.
Goals & Non-Goals
Goals
Visibility into which MCP views are rendered and which tools are called, by volume and success rate (shipped).
Respect the user's Kibana telemetry opt-in, fail-closed (shipped).
Correlate cluster_uuid to the associated customer/account so PMs can reason about adoption per customer.
Source the data from the golden table once available, and surface it in a dedicated dashboard tab.
Non-Goals
No PII or free-form capture. Schemas are closed (Zod + EBT); no user identifiers, no alert/case/rule bodies, no ES|QL query text.
No per-keystroke event volume. High-frequency emitters (e.g. live-validation) must not flood the stream (see execute-esql decision below).
No cluster_name collection. It is user-controlled and frequently leaks company/environment identifiers, undermining the anonymised framing.
No per-install segmentation in v1. Two installs on the same cluster share cluster_uuid and are indistinguishable; acceptable for now.
Work Streams
Work Stream 1: Telemetry instrumentation (DONE — shipped in PR #29)
Wire the MCP App into Elastic's V3 analytics shipper via @elastic/ebt
Emit mcp_tool_called (server-side: tool_id, duration_ms, success) for every tracked tool handler
Emit view_rendered (client-side: view_id enum of 6 views) once per top-level view mount
Add the registerTrackedAppTool wrapper so new tools get instrumented automatically
Mirror the Kibana telemetry opt-in (GET /api/telemetry/v2/config) once at startup, fail-closed when optIn is false/null or the fetch errors
Attach anonymised context to every event: cluster_uuid, cluster_version, license_id/status/type, mcp_app_version (deliberately omit cluster_name)
Enforce closed schemas end-to-end (Zod on the client→server tool boundary, EBT schema server-side)
Document the event catalog, opt-out story, and codebase map in docs/telemetry.md
Add unit tests + typecheck coverage for the analytics client, context loader, and telemetry service
Add MCP_APP_TELEMETRY_ENV=staging developer override to route events to telemetry-staging.elastic.co
Fix the execute-esql over-emission (~7k events/session from Monaco live-validation) and the related threat-hunt UI bug
Work Stream 2: Identity enrichment — cluster → customer/user (NEXT)
Decide the join source for mapping cluster_uuid (and/or license_id) to an account/org and its associated users — open design question (golden table vs. existing BigQuery identity tables)
Anonymised mcp_tool_called and view_rendered events ship under the Kibana opt-in
Events visible in the stack-telemetry securitysolution view
cluster_uuid reliably maps to a customer/account via an approved join source
Golden table access secured and schema validated
"MCP App" tab live in sec-pm-telemetry-dashboard with passing typecheck/build/tests
Technical Requirements
Performance: Telemetry must not block tool handlers; events queue in-memory and ship asynchronously. Dashboard queries follow the repo's cost-capped BigQuery governance.
Security & Privacy: Closed schemas only; no PII; license_id usage gated on sign-off; honor the Kibana opt-in fail-closed.
Compatibility:@elastic/ebt@^1.4.1 (adds ~+560 KB raw / +113 KB gzipped to the bundle — one-time .mcpb download cost).
Observability: Opt-in resolution, batching, and shipping decisions are logged to stderr under the telemetry scope.
Testing: Unit + typecheck on the analytics path (shipped); typecheck/build/test gate on the dashboard tab (WS4).
Related Epics
MCP App Security — Vision (work_docs/prd/mcp-app-security-vision.md) — parent vision for the Security MCP App; this epic delivers its usage-measurement pillar.
PR #29 — the merged implementation this epic records and extends.
[Epic] MCP App Usage Telemetry: Account level view
Background
The Elastic Security MCP App puts Security workflows — alert triage, attack discovery, case management, detection rules, threat hunting, and sample-data generation — directly inside an MCP host such as Claude Desktop. Until recently we had no visibility into which of these surfaces customers actually use once the app is installed in the wild. We could not answer basic adoption questions: which views get opened, which tools get invoked, whether a feature is dead weight or load-bearing.
PR #29 (merged May 26, 2026) closed that gap. It wires the MCP App into Elastic's V3 analytics shipper (
@elastic/ebt) and emits two closed-schema, anonymised events —mcp_tool_calledandview_rendered— that respect the user's existing Kibana telemetry opt-in. The implementation is deliberately privacy-conservative: no PII, no free-form text, nocluster_name, and a fail-closed opt-in model.Data is already flowing. Events are visible today in the stack-telemetry securitysolution view. This epic captures that completed instrumentation work as a record, and scopes the next phase: turning the raw event stream into PM-grade insight by correlating cluster identity to customers, sourcing the data from the forthcoming golden table, and surfacing it in a dedicated tab of the Security AI telemetry dashboard.
User Story / Problem Statement
As a Security AI Product Manager,
I want to see anonymised MCP App usage telemetry — which views are rendered and which tools are called, by how many clusters — surfaced in the PM telemetry dashboard,
so that I can measure adoption, prioritize investment toward the surfaces customers actually use, and tell a data-backed story about MCP App traction.
Problem Details
cluster_uuidlevel with no link to a named customer or user, and it is not yet surfaced anywhere a PM looks day-to-day.cluster_uuidalone cannot answer "is this a strategic account?" or "how many distinct customers are exercising attack discovery?" — the questions that actually drive prioritization.The Solution
Two phases. Phase 1 (shipped — Explore) instruments the MCP App and ships anonymised usage events under the user's Kibana opt-in. Phase 2 (next — Expand) builds the analytics path: render an "MCP App" tab in the sec-pm-telemetry-dashboard and correlate cluster identity to customers, sourced from the golden table when it lands.
To avoid dangling multi-phase work, Phase 2 is sequenced so value lands early: a v0 tab on anonymised, cluster-level metrics (view renders, tool-call volume and success rate, active clusters) can ship from currently queryable data without waiting on the golden table or identity enrichment. Customer-level breakdowns layer in once WS2 (identity) and WS3 (golden table) complete.
UX: Before
A PM asking "how is the MCP App being used?" had nowhere to look. No dashboard, no query, no event stream. The answer was anecdote.
UX: After
Architecture
graph TD subgraph app [MCP App - shipped in PR 29] Views["React views (view_rendered)"] Tools["Tracked MCP tools (mcp_tool_called)"] OptIn["Kibana opt-in mirror (GET /api/telemetry/v2/config)"] Ctx["Anonymised context: cluster_uuid, version, license, app_version"] end Views --> Shipper["@elastic/ebt V3 shipper"] Tools --> Shipper OptIn -->|"gates shipping (fail-closed)"| Shipper Ctx --> Shipper Shipper -->|"opt-in only"| Telemetry["telemetry.elastic.co"] Telemetry --> Golden["Golden table (forthcoming)"] Golden --> BQ["BigQuery refresher (sec-pm-telemetry-dashboard)"] Identity["Identity mapping: cluster_uuid -> account/user"] -.->|"enrichment (open design)"| BQ BQ --> Tab["MCP App dashboard tab"]Notes:
cluster_uuidto ship at all; events without cluster context are dropped (fail-closed)./api/metrics, rendered by a tab component wired into App.tsx.Goals & Non-Goals
Goals
cluster_uuidto the associated customer/account so PMs can reason about adoption per customer.Non-Goals
execute-esqldecision below).cluster_namecollection. It is user-controlled and frequently leaks company/environment identifiers, undermining the anonymised framing.cluster_uuidand are indistinguishable; acceptable for now.Work Streams
Work Stream 1: Telemetry instrumentation (DONE — shipped in PR #29)
@elastic/ebtmcp_tool_called(server-side:tool_id,duration_ms,success) for every tracked tool handlerview_rendered(client-side:view_idenum of 6 views) once per top-level view mountregisterTrackedAppToolwrapper so new tools get instrumented automaticallyGET /api/telemetry/v2/config) once at startup, fail-closed whenoptInis false/null or the fetch errorscluster_uuid,cluster_version,license_id/status/type,mcp_app_version(deliberately omitcluster_name)docs/telemetry.mdMCP_APP_TELEMETRY_ENV=stagingdeveloper override to route events totelemetry-staging.elastic.coexecute-esqlover-emission (~7k events/session from Monaco live-validation) and the related threat-hunt UI bugWork Stream 2: Identity enrichment — cluster → customer/user (NEXT)
cluster_uuid(and/orlicense_id) to an account/org and its associated users — open design question (golden table vs. existing BigQuery identity tables)license_idas a customer-linkable key (open thread from PR feat(analytics): add anonymised usage telemetry via @elastic/ebt #29 review)Work Stream 3: Golden table access (NEXT)
Work Stream 4: Dashboard tab in sec-pm-telemetry-dashboard (NEXT)
src/server/queries/mcp-app-usage.ts) returning aCategoryMetricspayloadsrc/server/queries/registry.tssrc/client/hooks/expected-categories.ts(and its snapshot test) with the new categoryMcpAppUsageDashboard.tsx) reusingMetricCard,TrendChart,MonthlyBarChartNAVarray and render switch insrc/client/App.tsxnpm run typecheck && npm run build && npm testChild Issues
license_idas a customer-linkable keyKey Design Decisions
cluster_name, noinstall_idin v1license_idin contextexecute-esqllive validation)Success Criteria
Metrics
Acceptance Checklist
mcp_tool_calledandview_renderedevents ship under the Kibana opt-incluster_uuidreliably maps to a customer/account via an approved join sourceTechnical Requirements
license_idusage gated on sign-off; honor the Kibana opt-in fail-closed.@elastic/ebt@^1.4.1(adds ~+560 KB raw / +113 KB gzipped to the bundle — one-time.mcpbdownload cost).telemetryscope.Related Epics
work_docs/prd/mcp-app-security-vision.md) — parent vision for the Security MCP App; this epic delivers its usage-measurement pillar.Stakeholders