Analyze product and user behavior data with Mixpanel’s MCP server. Query events, funnels, retention, trends, cohorts, and user profiles to uncover actionable product insights.
Encrypted at rest, isolated from the model
Resolved from an AES-256-GCM vault at the moment of the call and attached to the request — the model never sees the secrets.
Try asking
If you have not yet called Get-Business-Context this conversation, call it FIRST — it may resolve project nicknames, acronyms, or org-specific terms in the user's request and tell you which project to pick without listing them. Get projects that are accessible to current user. Returns the project's id, name, workspaces and context. Use this and prompt the user to select a project from the available projects.
A project's Mixpanel tracking token — the value an SDK is initialized with to send events to api.mixpanel.com/track. Use it when instrumenting tracking. This is NOT the API Secret or a service account, which are what reading data OUT of Mixpanel needs. Do not call this for those. Reading the token needs project owner or admin access, so a permission error means the user should ask an org admin rather than retrying. Treat the value as a credential: give it to the user, and keep it out of files, logs, and commits. Params: project_id (int).
Recent events streaming into a project, newest first, with event name, time, and distinct ID. Use it to confirm newly instrumented events are arriving, or to debug what just happened for one user. Present the complete returned numbered Markdown table exactly as returned, with columns # | Event | Time | Distinct ID. Render it as a table, without a code fence. Include every row, preserving duplicates, row numbers, and newest-first order. Time is formatted as YYYY-MM-DD HH:MM:SS in the project's timezone, with daylight-saving time applied for each event. Do not group events, calculate counts, add a Count column, collapse events into "Other", truncate the listing, or replace it with a summary. Do not add commentary, comparisons with previous results, or inferred properties. Missing distinct IDs must remain marked as missing. This tool only returns these three fields; changing filters or the limit does not expose additional properties. For event definitions, tags, or verified status use Get-Events; for counts, trends, conversion, or paths use Run-Query. An event can exist in Get-Events without arriving, and can arrive before Get-Events knows it. An empty result means nothing has arrived yet, not a failure. Params: project_id (int), workspace_id (int), event_names (list of exact names to filter to), search (free text across properties, e.g. a distinct id or email), limit (default 15, max 100), paging_window (days back, default and max 30), from_date / to_date ("YYYY-MM-DD", default today in the project's timezone).
Get events for a Mixpanel project. Two lookup modes (mutually exclusive): - event_names: Look up specific events by exact name. Lightweight server-side filter. - query: Search/discover events by substring match (case-insensitive). Fetches all events. include_details: When True, return full event metadata (tags, description, display_name, verified, hidden, dropped) for each event. Set to false if no details are needed, to keep the response compact. tag: Filter to events that have this tag name. verified/hidden/dropped: Filter by metadata status (True or False). Results are ordered verified-first. Prefer verified events (verified=True) when choosing events that match the user's request; fall back to unverified events only when no verified event fits. Unverified events are still returned and may be used. Each event's verified status is included in the response (set include_details=True for full metadata).
Use contact_emails or team_contact_names for ownership. Set verified=True to verify/approve events, hidden=True to hide from UI, dropped=True to deprecate.
Edit multiple events at once. Supports two modes: 1. Uniform fields (applied to ALL events): hidden, verified, dropped, tags, contact_emails, team_contact_names. 2. Per-event fields (on individual events in the events list): description, display_name. Both modes can be combined in a single call. Maximum 50 events per call.
List properties for a Mixpanel project. Returns name and type by default. Two lookup modes (mutually exclusive): - names: Look up specific properties by exact name (max 100). - query: Search/discover properties by substring match (case-insensitive). resource_type: 'Event' for event properties, 'User' for user properties, or omit for both. events: Scope to one or more events' properties (only valid with resource_type='Event' or omitted). attributes: Extra attributes to include in the response. Valid values: description, display_name, hidden, dropped, sensitive, example_value, merged, tags, events. The 'events' attribute is only allowed when 'names' is provided — it requires a specific set of properties to look up event associations for. It is also expensive for large projects, so only request it when needed. tag: Filter to properties that have this tag name. hidden/dropped/sensitive: Filter by metadata status (True or False).
Get values for one or more properties, returned as a table. properties: one or more property names. With a single property the result is a one-column table of its distinct values. With multiple Event properties the result has one column per property so you can see which values co-occur on the same events. Prefer this over the deprecated single-string 'property' alias. property: DEPRECATED alias for a single-element 'properties'. Use 'properties' instead. Passing both 'property' and 'properties' with conflicting values is an error. result_mode (Event properties only): - 'grouped' (default): deduped combinations of the property values with a 'count' column, sorted by count descending. - 'expanded': one row per event occurrence, with a 'time' column, sorted by time. Use this to inspect raw, high-cardinality values (e.g. free-text) alongside their co-occurring properties. limit: maximum rows to return (default 100, max 1000). When results are truncated a trailing note row makes the cap explicit. from_date / to_date (YYYY-MM-DD): query window for the returned values. For the multi-property and expanded paths this defaults to the trailing ~30 days; for the single-property distinct-values path, omitting it falls back to the server's default trailing window. For Event properties, the 'event' parameter is required. User properties support only a single property in grouped mode.
Set sensitive=True for PII data classification. Set example_value to populate the example shown in Lexicon.
Edit multiple properties at once. Supports two modes: 1. Uniform fields (applied to ALL properties): hidden, dropped, sensitive, tags. 2. Per-property fields (on individual entries in the properties list): description, display_name, example_value. Both modes can be combined in a single call. All properties must share the same resource_type ("Event" or "User"). Maximum 50 properties per call.
Create a formula-based custom property (a computed event or user property) in a project. Define it with a `display_formula` expression that references named `composed_properties` variables (_A, _B, ...). Every property used in the formula must be mapped in `composed_properties` — use List-Properties to find the properties to compose. `resource_type` is 'events' or 'people'. The created property appears in Lexicon and is usable in reports.
Update an existing formula-based custom property. Partial update: pass only the fields you want to change (`name`, `description`, `display_formula`, `composed_properties`); omitted fields keep their current value. When changing `display_formula` you must also pass the complete `composed_properties` mapping for it. `resource_type` is immutable. Use Get-Custom-Property first to see the current definition.
Get a custom property by id, including its full definition (behavior or display_formula + composed_properties). Use this before Update-Custom-Property to see the current definition. Custom property ids come from List-Properties (custom properties are named '$custom_property:<id>').
Read a lookup table by id or name, or list all lookup tables. Provide `data_group_id` or `name` to get one table's schema (columns), row count, and a capped preview of its rows. Omit both to list every lookup table in the project (metadata only) — useful for discovering table names/ids. The `id` returned for each table is the `data_group_id` you pass back to this tool or to Update-Lookup-Table. The preview is capped by `preview_limit` (default 100) and may be smaller than `row_count` — it is a sample, not the full table. Use it to inspect the schema and existing values; to change rows, send only the rows you want to add/overwrite (`upsert_rows`) or remove (`delete_keys`) to Update-Lookup-Table, which applies the delta to the full table for you.
Create a lookup table from rows. Pass `rows` as a list of {column: value} objects; one column is the primary key (`primary_key_column`, default "Primary Key") used to join the table to event/user data. The table appears in Lexicon and can then be mapped to a property in the UI.
Update a lookup table with a row delta and/or edit name/description. Send only the cells you want to change — you do NOT need to read or resend the whole table: - `upsert_rows`: a list of {column: value} objects to add or patch. When a row's `primary_key_column` matches an existing row, only the columns you send are updated and the row's other columns are kept; an unmatched key is added as a new row. Set a column to "" to blank it; to replace all of a row's columns, `delete_keys` it and upsert it in the same call. - `delete_keys`: a list of primary-key values whose rows to remove. Keys not in the table are ignored (reported back under `not_found`). The server reads the current table, applies the delta, and re-imports the full result, so a shrink is an explicit `delete_keys` rather than an omission. The response includes an `update_summary` ({added, updated, deleted, not_found}) so you can confirm what landed. Pass `name`/`description` to edit metadata. Provide at least one field.
Create a tag for organizing events and properties in Lexicon.
Get all data quality issues for a Mixpanel project. Returns rich context with human-readable descriptions, event/property names, timestamps, and variance details. Filter by event name, property name, issue type, status, date range, or search by description.
Dismiss data quality issues matching natural criteria - no need to look up IDs first. Specify what to dismiss using event names, property names, dates, and issue types. Example: dismiss issues for the 'signup' event from November 15th, or dismiss all type drift issues for the 'user_id' property. IMPORTANT: If multiple issues match your criteria, you must set dismiss_all_matching=True as a safety measure. To dismiss a single issue, provide enough criteria to uniquely identify it (event + date, or property + date).
Rename an existing tag in a Mixpanel project. The new name must be unique within the project (max 175 characters). This updates all events and properties currently using this tag.
Delete a tag from a Mixpanel project. This removes the tag from all associated events and properties. Use with caution as this operation cannot be undone.
Return a Mixpanel Lexicon transformations detail URL for an event or property. Provide either event or property along with project_id. If workspace_id is omitted, the tool will choose the 'All project data' workspace. Use this when the user wants to change event/property metadata such as display name and description.
Get session replays information. Provide either a distinct_id (with from_date and to_date) to find all replays for a user, OR a list of specific replay_ids (up to 20) to analyze directly. Optionally include event_properties (up to 5) to fetch specific property values for each event. Each replay includes a replay_url when available. When linking to a replay, always use replay_url verbatim — NEVER construct, guess, or modify replay URLs yourself. If replay_url is absent, state that no direct link is available instead of fabricating one.
Get the full instructions and JSON schema for building a full Mixpanel query. Call this to learn all available fields and options for the 'report' parameter in Run-Query. report_type: 'insights', 'funnels', 'flows', or 'retention'.
Retrieve a saved report's metadata from a Mixpanel project. Optionally include the report results if it's a queryable report type. Returns report metadata (id, name, type, creator info, timestamps) but NOT the query definition. To build a similar query, call Get-Query-Schema for the report type, then Run-Query.
Run a single analytics query and return its results directly. Use this whenever the user requests a chart, a report, a metric, explore a behavior or root cause, or asks to "create a report". Returns results to chain queries iteratively. Only use skip_results=true when building a dashboard or you won't use the results. Report types: - insights: Basic report, supports different chart types, trends, and metric aggregations. - funnels: Conversion rates between sequential events within a time window. Requires at least 2 steps. - flows: Most frequent user paths to or from events. Shows steps before/after/between events as a sankey or paths chart. - retention: User engagement over time. Requires exactly 2 events: an initial action and a retention action. For very simple insights queries, use this schema as the `report` parameter: { "name": "string", "metrics": [ { "eventName": "string", "measurement": { "type": "basic", "math": "total | unique" } } ], "chartType": "table | line | bar", "unit": "hour | day | week | month", "dateRange": { "type": "relative", "range": { "unit": "day | week | month", "value": "integer" } } } Event names must match the project exactly; an unrecognized name returns zeros, not an error. Pass the literal "$all_events" (insights) or "$mp_anything_event" (retention), never their UI labels "All Events"/"Any event". Funnel steps, flow steps, and behavioral breakdowns each need a specific event. Profile sources ("All User Profiles", "All <group name>(s)") are not events and cannot be queried here. Breakdowns split results by a property. Each breakdown's property fields must be nested under a `metric` object (do NOT place `type`/`propertyName` at the breakdown's top level). For example, to split "$all_events" into individual events by the "Event Name" property: "breakdowns": [ {"metric": {"type": "property", "propertyName": "Event Name", "resource": "event"}} ] For more elaborated queries, with multiple events, filters, breakdowns, formulas or advanced measurements you must call Get-Query-Schema(report_type: 'insights'|'funnels'|'flows'|'retention') first to see the full schema for the `report` parameter. Keep responses compact: prefer short date ranges (7-30 days) or coarser granularity (week/month), and avoid combining many breakdowns with fine-grained time series.
Display the interactive chart widget for a previously-run query. Takes a query_id returned by Run-Query and render results in the MCP App visualization widget.
Create a Mixpanel dashboard that combines multiple reports and text into a single view. Use when the user asks for a "dashboard," "board", or requests to save several reports grouped together. For a single report request, prefer Run-Query. Requires query_id(s) from prior Run-Query calls (use skip_results=true to chain multiple queries). Max 30 rows per dashboard. Each row can contain up to 4 items (text cards or reports). Row schema: {'$defs': {'ReportContent': {'additionalProperties': False, 'description': 'Report content for a dashboard row.', 'properties': {'type': {'const': 'report', 'default': 'report', 'title': 'Type', 'type': 'string'}, 'query_id': {'description': 'query_id from Run-Query', 'title': 'Query Id', 'type': 'string'}, 'name': {'maxLength': 255, 'title': 'Name', 'type': 'string'}, 'description': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'title': 'Description'}}, 'required': ['query_id', 'name'], 'title': 'ReportContent', 'type': 'object'}, 'TextContent': {'additionalProperties': False, 'description': 'Text content for a dashboard cell.', 'properties': {'type': {'const': 'text', 'default': 'text', 'title': 'Type', 'type': 'string'}, 'html_content': {'description': 'HTML content for the text card. Allowed tags: a, blockquote, br, code, em, h1, h2, h3, hr, li, mark, ol, p, s, strong, u, ul. Other tags are stripped. Do not include newlines; Each html element means a new line.', 'maxLength': 2000, 'title': 'Html Content', 'type': 'string'}}, 'required': ['html_content'], 'title': 'TextContent', 'type': 'object'}}, 'description': 'A row to add to a dashboard.', 'properties': {'contents': {'items': {'discriminator': {'mapping': {'report': '#/$defs/ReportContent', 'text': '#/$defs/TextContent'}, 'propertyName': 'type'}, 'oneOf': [{'$ref': '#/$defs/TextContent'}, {'$ref': '#/$defs/ReportContent'}]}, 'maxItems': 4, 'minItems': 1, 'title': 'Contents', 'type': 'array'}}, 'required': ['contents'], 'title': 'DashboardRow', 'type': 'object'} Time filter schema: {'$defs': {'DateRange': {'description': 'Date range specification for dashboard time filter.', 'properties': {'type': {'description': 'Type of date range', 'enum': ['since', 'between', 'in the last'], 'title': 'Type', 'type': 'string'}, 'from': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "Start date (YYYY-MM-DD) for 'since' or 'between'", 'title': 'From'}, 'to': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': "End date (YYYY-MM-DD) for 'between'", 'title': 'To'}, 'window': {'anyOf': [{'$ref': '#/$defs/TimeWindow'}, {'type': 'null'}], 'default': None, 'description': "Time window for 'in the last'"}}, 'required': ['type'], 'title': 'DateRange', 'type': 'object'}, 'TimeWindow': {'description': 'Time window for relative date ranges.', 'properties': {'unit': {'description': 'Time unit', 'enum': ['day', 'week', 'month'], 'title': 'Unit', 'type': 'string'}, 'value': {'description': 'Number of units', 'minimum': 1, 'title': 'Value', 'type': 'integer'}}, 'required': ['unit', 'value'], 'title': 'TimeWindow', 'type': 'object'}}, 'description': 'Dashboard time filter.', 'properties': {'dateRange': {'$ref': '#/$defs/DateRange', 'description': 'Date range configuration'}, 'displayText': {'description': "Human-readable display text, e.g. 'Last 30 days'", 'title': 'Displaytext', 'type': 'string'}}, 'required': ['dateRange', 'displayText'], 'title': 'DashboardTimeFilter', 'type': 'object'}
Prefer Search-Entities with entity_types=['dashboard'] instead, it offers more flexibility and efficiency. Returns a list of all the dashboards in the project. Use query to filter by title (case-insensitive substring match).
Set include_layout=True to get full layout with cell/row IDs (needed for Update-Dashboard). Layout format: [[row_id, [[cell_id, type, extra], ...]], ...].
Call Get-Dashboard with include_layout=True first to get cell/row IDs. - To update a report cell query_id, call Run-Query first. - To add rows or cells, use any temporary string ID (e.g. "temp-row-1"). - To add cell in a new row, use the row temp id in the cell definition. - For updates and deletes, use real row and cell ids from Get-Dashboard. rows: ['<row_id>', 'add'] | ['<row_id>', 'delete'] Content: {type: 'text', html_content: 'string'} | {type: 'report', query_id: 'string', name: 'string', description: 'string'} cells: ['<cell_id>', 'create', 'text' | 'report', {row_id: 'string', ...Content}] | ['<cell_id>', 'update', 'text' | 'report', {...Content}] | ['<cell_id>', 'delete']
Create a copy of an existing dashboard with all its contents. Optionally override the title and description of the new dashboard.
Delete a dashboard. Always confirm with the user before proceeding. Use List-Dashboards or Get-Dashboard to find the dashboard ID.
List and search feature flags in a project. Filter by status, key, name, creator, or creation date. Use Get-Feature-Flag for full configuration.
Get full configuration for a specific feature flag. Returns metadata, variants, rollout rules, experiment link, and UI URL. For listing flags, use List-Feature-Flags.
Create a feature flag in the current project. `project_id` and `workspace_id` are auto-injected from the caller's session — pass any int and the values you supply will be replaced before the call reaches the server. Do not ask the user for them. For routing (Feature Gate vs Dynamic Config vs Experiment), input gathering, naming/keying conventions, and per-flagType variant rules, call `Get-Feature-Flag-Setup-Guidance` first. Mechanics: flag key is auto-derived from name when omitted; flag starts disabled (use Update-Feature-Flag to enable, or call Get-Feature-Flag-Lifecycle-Guidance for rollout decisions); rolloutPercentage defaults to 1.0 (100% of targeted traffic). Configure cohort targeting in the Mixpanel UI via the URL in the response.
Update flag configuration, status, or archive state. For rollout / kill-switch / archival decisions — including the staged-rollout cadence, when to use status vs rolloutPercentage, and archive-vs-restore semantics — call `Get-Feature-Flag-Lifecycle-Guidance` first. All fields on `flag` are optional but at least one is required. To configure cohort targeting or advanced rollout rules, use the Mixpanel UI via the flag's URL (returned by Get-Feature-Flag).
Returns best-practice guidance for creating and configuring a Mixpanel feature flag. Call this when the user is creating, configuring, or troubleshooting a feature-flag setup — including choosing the flag type (Feature Gate vs Dynamic Config vs Experiment-backed), naming the flag, defining variants, or deciding on initial rollout. The response is the canonical setup guidance document; follow it when proposing or validating feature-flag configuration. No input parameters. Equivalent to reading the `guidance://feature-flags/setup` MCP resource — provided as a tool for clients that don't read resources directly.
Returns best-practice guidance for managing a Mixpanel feature flag after creation — staged rollout, kill-switch, hygiene/cleanup, archival, exposure tracking, and experiment linkage. Call this when the user is rolling out, monitoring, killing, archiving, or cleaning up an existing feature flag, or asking about exposure tracking or flag-to-experiment links. The response is the canonical lifecycle guidance document; follow it when reasoning about post-creation flag operations. No input parameters. Equivalent to reading the `guidance://feature-flags/lifecycle` MCP resource — provided as a tool for clients that don't read resources directly.
List and search experiments in a project. Filter by status, name (case-insensitive substring match), creator, creation date, or tags. Use Get-Experiment for full configuration.
Get full experiment configuration and (optionally) fresh live results. Returns metadata, variants, metrics (with IDs, type, and direction), cached data, and UI URL. Metric IDs are included; use List-Metrics to find saved metrics. Set ``compute_exposures=true`` to refresh live exposure counts and SRM analysis (``live_srm_analysis``); set ``compute_metrics=true`` to refresh per-metric lift/CI/p-value/significance (``live_metrics``) and the retro A/A health-check verdict (``live_retro_aa``). These fields are the same source of truth the in-app banner reads. Either flag persists the refreshed cache server-side and may trigger an auto-conclude transition. Non-fatal compute errors surface in ``live_results_errors`` (``[]`` when compute was requested but nothing failed; ``None`` when compute wasn't requested). Setting either flag requires a workspace; the wrapper auto-resolves the project's global workspace when ``workspace_id`` is omitted. To turn these fields into a ship/no-ship verdict (SRM and retro A/A thresholds, per-metric significance, and the guardrail-regression hard gate), call ``Get-Experiment-Results-Interpretation-Guidance``.
Create an experiment (in DRAFT status) in the current project. For setup decisions (hypothesis writing, metric selection, sample sizing, testing model, end condition, advanced features like CUPED/Winsorization/ multiple testing correction) call Get-Experiment-Setup-Guidance first — it is the single source of truth for what makes a sound experiment. `project_id` and `experiment.workspaceId` are auto-injected from the caller's session — pass any int (or omit workspaceId) and the values you supply will be replaced before the call reaches the server. Do not ask the user for them or call other tools to discover them. Mechanics (NOT best-practice advice — see setup guidance for that): - For duration-based experiments, set endCondition="days" and endAfterDays; for sample-size-based, set endCondition="sample_size" and sampleSize. - Metrics: pass saved metrics via primaryMetricIds/guardrailMetricIds/ secondaryMetricIds (find IDs with List-Metrics), or define inline via the metrics array with eventName and metricType. - Optional `variants` array — only include when the user explicitly states variant keys/values/splits. Otherwise the system creates a default 50/50 control/treatment flag. - The server always runs the seven deterministic pre-launch pitfall checks before creation, deriving most inputs (arm count, sample size, metric counts, stats toggles) from the experiment itself. Optional `validationContext` supplies the few externals it can't derive (baseline rate, MDE, expected exposures, cohort size, primary-metric measurement types). Blocker pitfalls (under-half-required exposures, cohort too small) short-circuit the create and are surfaced as an actionable error; warnings and fyi findings ride along on the created experiment as `validationFindings`. After creation, use Update-Experiment with action="launch" to start the experiment.
Update experiment configuration or manage its lifecycle. Lifecycle actions (set action param): - "launch": DRAFT→ACTIVE. Enables linked flag. - "conclude": ACTIVE→CONCLUDED. Disables linked flag. - "decide": CONCLUDED→SUCCESS/FAIL. See "decide" below. - "archive" / "restore": soft delete / undelete. For action="decide", pick by settings.collectionMethod (call Get-Experiment first if unknown). shipMode rolls the linked flag as part of decide; omit it on exposure-events experiments (returns UnsupportedCollectionMethod). feature_flag experiments: ship variant X → shipMode="ship_variant", variant=X keep control → shipMode="do_not_ship" (auto: success=true) abandon flag → shipMode="abandon" (auto: success=false, variant="abandoned") record only → success=true|false, variant=<key> (omit shipMode) exposure_events experiments (always omit shipMode): ship variant X → success=true, variant=X keep control → success=true, variant=<control_key> abandon → success=false, variant="abandoned" keepCohortTargeting (only with shipMode=ship_variant|do_not_ship): preserve existing cohort restrictions instead of serving the chosen variant to 100%. Config updates (all optional): name, description, hypothesis, metrics, settings, tags. Metrics: Use List-Metrics to find saved metric IDs, then pass them via primaryMetricIds/guardrailMetricIds/secondaryMetricIds. Alternatively, define inline with the metrics array using eventName and metricType. Field edits and launches run the seven deterministic pre-launch pitfall checks over the *resulting* configuration (the server merges this patch onto the stored experiment and derives most inputs from it). Optional `validationContext` supplies the externals it can't derive (baseline rate, MDE, expected exposures, cohort size, primary-metric measurement types). Blockers short-circuit the update (actionable error); warnings/fyi ride along as `validationFindings` on the updated experiment.
Explain why an experiment's health check is firing — or confirm it isn't — and recommend a next action. Supports two checks: - `health_check_kind="srm"` — Sample Ratio Mismatch (traffic split deviates from configured allocation). Call Get-Experiment with compute_exposures=true first, then pass: - p_value: liveSrmAnalysis.p_value (null when SRM can't be computed yet — pass it as-is and the tool returns a clear "SRM unavailable" message instead of erroring) - live_exposures: liveExposures (variant → count); webapp emits percentages (e.g. {control: 50}), the tool accepts either fractions or percentages - target_allocations: experiment.settings.srm.targetAllocations - `health_check_kind="retro_a_a"` — pre-experiment bias (per-metric A/B z-tests on the pre-experiment window, Bonferroni-corrected). Call Get-Experiment with compute_metrics=true first (null when retro A/A hasn't been computed — typical right after an experiment starts), then pass: - retro_aa_verdict: the `liveRetroAa` block from Get-Experiment; carries `any_failing`, `acknowledged`, and per-metric `results` - metric_names: map of metric_id → display name built from `experiment.metrics`; the summary names the affected metrics instead of surfacing raw ids Returns a HealthCheckDiagnosis. For SRM: signed per-variant deviation, likely causes in most-probable-first order, recommended action (pause / investigate exposures / restart with bot filtering / continue). For retro A/A: list of biased metrics, retro-A/A- specific causes (randomization bug, context mismatch, insufficient pre-period, natural variance), recommended action (enable CUPED / restart with longer pre-period / acknowledge / pause). The Kohavi (SRM) or Twyman's-Law (retro A/A) trustworthiness principle is cited in the failing case.
Returns best-practice guidance for designing a Mixpanel experiment before launch. Call this when the user is creating, configuring, or troubleshooting an experiment setup — including writing a hypothesis, picking metrics, sizing the experiment, or choosing a testing model. The response is the canonical setup guidance document; follow it when proposing or validating experiment configuration. No input parameters. Equivalent to reading the `guidance://experiments/setup` MCP resource — provided as a tool for clients that don't read resources directly.
Returns best-practice guidance for interpreting Mixpanel experiment results and making ship/iterate/kill decisions. Call this when the user is analyzing, interpreting, or making a decision based on experiment results — including reviewing a concluded experiment, asking about p-values, lift, SRM, or whether to ship. The response is the canonical results interpretation document; follow it when reasoning about results. No input parameters. Equivalent to reading the `guidance://experiments/results-interpretation` MCP resource — provided as a tool for clients that don't read resources directly.
Cross-references a draft experiment's configuration against a canonical list of pre-launch pitfalls and returns a structured PitfallReport. Call this at the **config-summary-for-approval** step before launching an experiment — once the user has chosen their primary metrics, baseline rate, MDE, cohort, etc. and the agent is summarizing the configuration for sign-off. Pitfall kinds (every one of these may appear in the returned report): - `pre_experiment_bias_likely` — retro A/A is enabled and a continuous-ish metric (continuous, retention, funnel) is configured but CUPED is off. - `high_variance_no_winsorization` — a continuous-ish metric is configured but Winsorization is off. - `multiple_primaries_no_bonferroni` — two or more primaries with no Bonferroni multiple-testing correction. - `underpowered_duration_insufficient` — expected exposures are less than half of the per-arm sample size required for the configured baseline rate and MDE. Severity: blocker. - `underpowered_duration_marginal` — expected exposures are between half and one full per-arm required sample size. - `cohort_too_small` — configured cohort cannot supply enough eligible users (per-arm target × `num_arms`) for every arm to hit its target. Pass `num_arms` for non-A/B experiments; defaults to 2. Severity: blocker. - `missing_guardrails` — no guardrail metrics configured. - `hypothesis_metric_mismatch` — the hypothesis mentions an outcome (signup, conversion, retention, revenue, etc.) that isn't represented in any configured primary metric name. - `primary_lacks_leading_indicator` — a retention-type primary is configured but no conversion- or funnel-type secondary metric is configured. Retention is lagging by construction; without a leading-indicator secondary, the agent has no earlier evidence to reason from while the experiment runs. Pass `secondary_metric_types` / `secondary_metric_count` so this pitfall can evaluate; with no secondary info supplied it silently abstains. Each pitfall carries a `severity` (`blocker` / `warning` / `fyi`) and an optional `fix_action` discriminated union (`extend_duration`, `enable_cuped`, `enable_winsorization`, `enable_bonferroni`, `add_guardrail`, `resize_cohort_or_sample`, `review_metric_alignment`) — the renderer pre-fills a corresponding `Update-Experiment` call from the fix_action so the user can accept a remediation with a single confirmation. **Blocker prevention is a form-layer concern, not Spark's.** This tool reports blockers so the agent can surface them prominently in the summary, but the experiment-creation form is what actually stops a launch when a blocker is unresolved. Don't pretend to gate the launch yourself — quote the blocker and the recommended fix_action, then defer to the form. Pitfalls are returned sorted by (severity, declaration order): blockers first, then warnings, then fyi; within a severity, the ordering above wins so data-trust risks (pre-experiment bias, variance inflation) surface before configuration nudges. All inputs other than `target_sample_size` are optional — the tool silently skips any pitfall whose inputs aren't supplied, so the agent can call it iteratively as the user fills out fields.
Search the project's experiments store for prior tests on the same feature, metric, or hypothesis. Returns up to ``max_matches`` ranked matches with similarity reasons. Pass the ``metric_ids``, ``flag_key``, and ``hypothesis`` you are considering for the experiment you're setting up; the tool checks whether a similar experiment has already been run so you can surface what was learned. Provide whichever of these you have — any one is enough to get matches, and supplying more sharpens the ranking. Three deterministic signals are combined: metric_id overlap (Jaccard), flag-key similarity (exact / case-insensitive / substring / shared-token), and hypothesis-token overlap. Each match carries ``similarity_reasons`` so the agent can quote *why* a prior experiment is relevant. Pass ``exclude_experiment_id`` when ranking against an in-progress draft already saved in the store to prevent the draft trivially matching itself. ``include_archived=true`` to include archived experiments in the candidate pool.
Return the schema for the `definition` parameter accepted by Create-Cohort and Update-Cohort. Call this before authoring a cohort definition for the first time in a session so you know which fields are required for the grouped vs. selector format. The result has three keys: - `definition`: the CohortDefinition JSON schema (grouped/selector union). - `grouped_filter_types`: per-type schemas + worked examples for the grouped format's `groups[].filters[]` entries (property / behavioral / cohort_membership), which the base schema leaves opaque. - `notes`: gotchas worth reading before authoring a definition.
Create a new Mixpanel cohort. A cohort is a saved group of users matching a set of criteria. Pass a `definition` dict matching the CohortDefinition schema (grouped or selector format). Call Describe-Cohort-Schema first to retrieve the full JSON schema, including the required fields per format (grouped uses a `groups[]` filters grammar; selector uses the lower-level `behaviors{}` + compound `selector` AST for cohorts that embed funnel or retention report behaviors). For the grouped format, each group's `event` is the anchor cohort the filters narrow down — almost always `{"resourceType": "cohort", "value": "$all_users"}`. To anchor on members of an existing cohort instead, pass that cohort's integer id as `value`. `workspace_id` is required (unlike List-Cohorts, which lists project-wide when it is omitted).
Retrieve a Mixpanel cohort by ID. Returns the cohort's metadata (name, description, count, is_visible, verified, creator, updated_at) and its definition in the AI-typed format (CohortDefinition). Only `updated_at` (last edited) is tracked — there is no creation timestamp. If the wire-format definition contains unmodeled clause kinds, the `definition` field will be None, `unmodeled_clause_kinds` will list the unsupported shapes, and `definition_raw` will contain the wire-format dict so callers can still inspect the cohort's structure. `workspace_id` is required (unlike List-Cohorts, which lists project-wide when it is omitted).
List all cohorts in a Mixpanel project. Returns a lightweight list of cohort headers (id, name, description, count, verified). Use the optional `query` parameter to filter by name (case-insensitive substring match). Results are ordered verified-first. Prefer verified cohorts (verified=True) when choosing a cohort that matches the user's request; fall back to unverified cohorts only when no verified cohort fits. Unverified cohorts are still returned and may be used. `workspace_id` is optional here: omit it to list across the whole project, or pass one to scope to a single workspace. Note: `count` is frequently `null` in this list. The backend suppresses cached member counts in non-global workspaces and in projects with sensitive/classified properties for callers without sensitive-data access. Call Get-Cohort for an authoritative count. For full cohort definitions, call Get-Cohort on individual cohort IDs.
Update an existing Mixpanel cohort. All fields (name, description, definition, is_visible) are optional. Only the provided fields will be updated; omitted fields remain unchanged. `is_visible` toggles whether the cohort is hidden in the Mixpanel UI. Note that the `is_visible` value in the response is derived from entity sharing/visibility (a shared webapp serialization path) and may not reflect the value you just set — do not rely on the returned value to confirm a hide/unhide. To update the cohort's filter criteria, pass a new `definition` dict matching the CohortDefinition schema (same as Create-Cohort). Call Describe-Cohort-Schema for the full JSON schema if you don't already have it. `workspace_id` is required (unlike List-Cohorts, which lists project-wide when it is omitted).
Delete a Mixpanel cohort. WARNING: This action is destructive and cannot be undone. Always confirm with the user before deleting a cohort. The webapp will prevent deletion if the cohort is used in active reports or other dependencies, returning an actionable error message. `workspace_id` is required (unlike List-Cohorts, which lists project-wide when it is omitted).
List all saved metrics in a project. Returns metric IDs, names, types, descriptions, and verified status. Use before creating experiments to find reusable metrics. For full definition: Get-Metric. To use in experiment: reference by ID. Results are ordered verified-first. Prefer verified metrics (verified=True) when choosing a metric that matches the user's request; fall back to unverified metrics only when no verified metric fits. Unverified metrics are still returned and may be used.
Get full definition for a saved metric. Returns complete metric structure (events, formulas, filters, aggregation). Use to inspect, copy, or verify metric configuration.
Create a saved metric (behavior or formula) for reuse across experiments. Types: - "metric": Single event behavior (count, unique users, DAU, etc.) - "formula": Combines multiple metrics with mathematical expressions Definition schema: { "displayOptions": { "chartType": "line | bar" }, "sections": { "events": [ { "event": "string", "math": "unique | total | session | dau | wau | mau", "filters": [ [ { "type": "string", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "equals | contains | does not equal | does not contain", "value": "string" }, { "type": "string", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "is set | is not set" }, { "type": "number_array", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "is between", "value": [ "number" ] }, { "type": "number", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "is at least | is equal to | is not equal to | is greater than | is less than | is at most", "value": "number" }, { "type": "boolean", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "true | false", "value": "boolean" }, { "type": "datetime", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "was on | was before | was since", "value": "string" }, { "type": "list-of-objects", "propertyName": "string", "resource": "event | user", "listItemFilters": [ [ { "type": "string", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "equals | contains | does not equal | does not contain", "value": "string" }, { "type": "string", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "is set | is not set" }, { "type": "number_array", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "is between", "value": [ "number" ] }, { "type": "number", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "is at least | is equal to | is not equal to | is greater than | is less than | is at most", "value": "number" }, { "type": "boolean", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "true | false", "value": "boolean" }, { "type": "datetime", "propertyName": "string", "propertyType": "string | number | boolean | datetime | list", "resource": "event | user", "operator": "was on | was before | was since", "value": "string" } ] ], "listQuantifier": "any | all", "listInclusion": "all | matching", "propertyObjectKey": [ "string" ] } ] ] } ] } } Returns metric with ID for use in Create-Experiment with primaryMetricIds. For complex definitions, use Get-Metric on existing metrics as templates.
Update saved metric's name, definition, or description. At least one field required. Warning: affects all experiments using this metric. Consider creating new metric to preserve original. Use Get-Metric first.
Search entities in a Mixpanel project: dashboards, reports, experiments, feature flags, metric trees, playlists, and heat maps. query: can be empty to browse by sort order. entity_types: set to include specific entity types. Values: insights, funnels, flows, retention, dashboard, launch-analysis, experiments, feature-flags, metric-trees, playlists, heat-maps. - Use Get-Report to fetch full details for insights, funnels, flows, and retention types. - Use Get-Dashboard to fetch full details for dashboards.
Call this FIRST, before any other Mixpanel tool whenever ANY of these are true: 1. It is the first substantive turn of the conversation about this org or project. 2. The user references a name, acronym, product, team, project nickname, event, property, or concept whose org-specific meaning you cannot verify just from the tool list. Examples that should trigger this: "show me MCP data", "how is ingest doing?", "the onboarding funnel", "Project Atlas". 3. You are about to guess which project_id, event name, or property to use based on a name in the user's request. Example: User: "what project has sales data?" ❌ Wrong: jump to Get-Projects and pattern-match against project names. ✅ Right: call Get-Business-Context first, the org likely defines what "sales data" refers to (a product area, an internal acronym, a specific project). Once you have called this in the current conversation for a given organization (and project, if applicable), do NOT call it again. The result is stable for the session; reuse the previously returned context on every subsequent turn — including follow-ups, drill-downs, refinements, and new questions about the same project. Re-call ONLY if: - The user asks about a different project_id whose context you have not yet fetched this conversation. - The user explicitly asks you to refresh or reload business context. - You called Update-Business-Context this conversation and need the new content. What you get back: - Specialized instructions on how to query data in this org - How projects, events, and other entities are organized and named - Business vocabulary and definitions (acronyms, internal product names, etc.) Params: - project_id (int, optional): If provided, returns context for the project AND its organization. organization_id is not required in this case — the org is derived from the project. - organization_id (int, optional): Required when project_id is NOT provided. Call List-Organizations FIRST to obtain it. If List-Organizations returns exactly one org, use its id directly; if it returns more than one, ASK the user which org they mean before calling this tool.
Update the business context at the project or organization level. This is a full replace — the new content overwrites whatever exists; there is no merge or partial update. Other users may have authored the current context, so ALWAYS ask the user for explicit confirmation before calling this tool. Content should be minimal and focused: short, structured markdown notes that capture essential domain knowledge. Params: - context (str, required): The new context content. Pass an empty string to clear. - level (str, required): Either the literal string "project" or "organization". Must be passed explicitly so the level is never inferred. - project_id (int, required when level="project"): The project to update. - organization_id (int, required when level="organization"): The org to update. Call List-Organizations FIRST to obtain it. If List-Organizations returns exactly one org, use its id directly; if it returns more than one, ASK the user which org they mean before calling this tool.
Returns the organizations the current user belongs to.
Find groups of duplicate or near-duplicate names in a Mixpanel project — both events and event properties. Returns clusters a user might want to merge in Lexicon (e.g. 'Add to Cart', 'add_to_cart', 'addToCart'; or 'from_date', 'from-date'). Returns a FormattedTable with Columns: - suggested_name: the most-popular variant in the cluster — use this as the merge target. - entity_names: every variant in the group, in popularity order (includes suggested_name as the first entry). - entity_type: 'events' or 'event_properties'. Pass this value back to Merge-Group / Dismiss-Duplicate-Group. Groups already merged or dismissed by the user are filtered out by the server. Empty `rows` means there is nothing actionable.
Merge a group of duplicate names into one canonical entity in a Mixpanel project's Lexicon. Works for events and event properties. DESTRUCTIVE: source entities are remapped to the canonical entity and their historical data is unified. Confirm with the user before calling. However, the merge can be undone in the Mixpanel UI with a single button click, so it's not a permanent action. Use with Find-Duplicate-Groups: pass its suggested_name as canonical_name, the remaining entity_names as source_names, and the group's entity_type as entity_type. canonical_name is filtered out of source_names automatically. entity_type must be 'events' or 'event_properties'. excluded: names from the suggested cluster the user does NOT want to merge. Pass them here (not in source_names) — they are left untouched but are still required to locate the suggestion, so include every name the cluster originally had across canonical + source + excluded. Server-side restrictions (rejected with an error): Mixpanel default entities, custom entities, dropped entities, entities already merged into another, and names that do not exist in the project.
Dismiss a duplicate-group suggestion so it no longer appears in Find-Duplicate-Groups results. Works for events and event properties. Does not modify any entity data — only hides the suggestion. There is no un-dismiss, so confirm with the user before calling. Pass the full entity_names list of the group exactly as returned by Find-Duplicate-Groups (order does not matter; the group is keyed by the set of names), plus the group's entity_type. entity_type must be 'events' or 'event_properties'.
Use AI to fill in missing event metadata for a Mixpanel project. For every event that is missing a display name and/or description, this generates one and applies it in bulk to the project's Lexicon. GAP-FILL ONLY: events that already have both a display name and a description are left untouched — this never overwrites existing metadata. DESTRUCTIVE: it writes metadata to the project's events. Always confirm with the user before calling. Returns the number of events whose metadata was filled in.
One endpoint, the same key, whichever client you use.
~/Library/Application Support/Claude/claude_desktop_config.json (Mac) · %APPDATA%\Claude\claude_desktop_config.json (Windows)
Replace API_KEY with your own key.
Already have an "mcpServers" section in your config? Just add the server entry inside it.
Discovery, routing, credentials, tool scoping and execution logs all happen at the gateway→connections stay ACTIVE with no work from you
Mixpanel MCP runs through a gateway that holds the credentials, scopes the access and records every call.
Managed auth, hosted MCP servers, and every Gmail tool your agent needs.
Free to start.