diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/SKILL.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/SKILL.md new file mode 100644 index 0000000..740c0c8 --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/SKILL.md @@ -0,0 +1,128 @@ +--- +name: manage-boards +description: > + Full lifecycle dashboard management for Mixpanel — create, template, clone, clean up, + inventory, and update dashboards across projects and teams. ALWAYS use when a user asks + to: create a dashboard, build a board, template or clone a dashboard, clean up stale + dashboards, audit dashboards, list all dashboards, inventory boards, update or rename a + dashboard, delete a dashboard, or standardize boards across projects. Also trigger on + "duplicate board", "stale dashboards", "empty boards", "board management", or when + dashboards are mentioned with "governance", "cleanup", "template", "onboarding", or + "standardize". Do NOT use for A/B experiments (use `manage-experiment`), feature-flag + rollouts (use `manage-feature-flags`), or Lexicon/event-and-property metadata cleanup (use + `manage-lexicon`). Requires Mixpanel MCP. +compatibility: "Requires Mixpanel MCP (mcp.mixpanel.com or regional variants). No other connectors required." +--- + +# Manage Boards + +Top-level router: validate project → route command → handle return. + +This skill uses the **Mixpanel MCP only**. No other connectors are required or referenced. + +--- + +## Execution Philosophy + +**Silent execution.** Do not narrate steps, announce phases, or explain what you are about to do. Run the work, process results, present only final output. The user sees: +- Command menu (when needed) +- Confirmation prompts before destructive operations (delete, bulk cleanup) +- Progress indicators during batch operations +- Error messages +- Final output + +Nothing else. No "Starting X...", no "I'll now fetch Y...", no "Let me analyze Z...". Just do the work and show the result. + +--- + +## Global Rules + +1. **Silent execution** — see the Execution Philosophy section above. +2. **Project ID immutable.** All work uses the confirmed `project_id` unless explicitly cross-project (template command). +3. **Surface MCP failures explicitly.** Never silently skip. +4. **Confirm before destructive ops.** Always preview + explicit user confirmation before: deleting a dashboard, bulk cleanup, or overwriting dashboard content. +5. **'exit' always valid.** Stop, discard uncommitted, return to menu. +6. **No per-command "what next" menus.** Commands return control here. The router shows the menu. +7. **Cross-project operations.** The template command is the only one that works across projects. It validates both source and target project IDs and reconstructs the board in the target project (see `commands/template-dashboard.md`). +8. **Validate every write before reporting success.** After any operation that mutates a board — create, update, duplicate, or a template rebuild — re-read the affected board *including its full layout* and confirm the result matches intent (expected row count, report/text cell counts, title/description). If the readback diverges, do NOT report `✅` — surface what landed vs. what was requested. Layout cells use opaque server-generated IDs, so a write can partially succeed silently; the readback is the only reliable confirmation. Refresh `dashboard_layout_cache` from this readback. +9. **Fetching the dashboard set.** Default to the sortable entity-search capability when listing dashboards — it returns richer metadata and supports sorting. Fall back to the plain dashboard-list capability only if search is unavailable. Cache the result in `dashboard_list_cache` and reuse it across commands rather than re-fetching. +10. **Shared constraints.** Layout limits, the text-card HTML whitelist, and other API gotchas live once in `references/mcp-tool-reference.md`. Command files point to it by name rather than restating. + +--- + +## Session Context + +Persist across commands within a session. **Cross-command reuse is mandatory** — never re-fetch what exists in session. + +| Variable | Description | +|----------|-------------| +| `project_id` | Immutable after Step 0. | +| `project_name` | Display name. | +| `projects_list` | All accessible projects. | +| `dashboard_list_cache` | `dashboard_id → {title, description, last_modified, ...}` map. Report counts are NOT returned by the list operation — populate them from `dashboard_layout_cache` after reading a board's full layout. | +| `dashboard_layout_cache` | `dashboard_id → {layout, report_count, text_count, row_count}` map (populated on-demand). | + +--- + +## Step 0 — Project Validation + +**Direct routing:** If the user's message contains a project ID AND a clear command intent (e.g. "create a dashboard in project 12345", "clean up dashboards in project 67890"), extract both, validate, and route directly — skip the menu. + +**Project ID without command:** Validate and show menu. + +**No project ID:** Ask which project. On 'list' → retrieve the accessible projects and show them in a table. + +**Validation:** +1. Retrieve the list of accessible projects and match the ID. If found → `✅ [Project Name] ([project_id])`, proceed. +2. Not found → error, ask to re-enter or 'list'. + +**MCP check:** If the project lookup fails because no Mixpanel capability is available → tell the user to connect the Mixpanel MCP, then stop. + +--- + +## Command Menu + +Show only when no direct command was inferred: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + Manage Boards — [Project Name] ([project_id]) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + 1. Create Dashboard — Build a new board from description + 2. Template Dashboard — Clone a reference board to a new project + 3. Cleanup Dashboards — Audit & remove stale/empty boards + 4. Dashboard Inventory — Catalog all boards with metadata + 5. Duplicate Dashboard — Copy a board within the same project + 6. Update Dashboard — Modify metadata, rows, or layout + 7. Exit +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +| Choice | Action | +|--------|--------| +| **1** | Read `commands/create-dashboard.md`, execute | +| **2** | Read `commands/template-dashboard.md`, execute | +| **3** | Read `commands/cleanup-dashboards.md`, execute | +| **4** | Read `commands/dashboard-inventory.md`, execute | +| **5** | Read `commands/duplicate-dashboard.md`, execute | +| **6** | Read `commands/update-dashboard.md`, execute | +| **7** | Exit | + +**Routing matrix** — when the user's phrasing doesn't map to a menu number, route on intent rather than showing the menu: + +| User intent (examples) | Route to | +|------------------------|----------| +| "build / make / set up a board", "new dashboard for X" | Create | +| "copy this board to [other project]", "standardize boards across projects" | Template | +| "clean up / audit / find stale / empty / duplicate boards" | Cleanup | +| "list / catalog / inventory all boards", "what boards exist" | Inventory | +| "copy / duplicate this board here", "clone within this project" | Duplicate | +| "rename / edit / add a row / change the layout of a board" | Update | +| "delete [board]" | Cleanup (single-board delete path) | +| Ambiguous or matches multiple commands | Show the menu — do not guess | + +--- + +## Return Handler + +When a command completes → `✅ Done.` → re-display command menu. No re-validation. diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/cleanup-dashboards.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/cleanup-dashboards.md new file mode 100644 index 0000000..96930b1 --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/cleanup-dashboards.md @@ -0,0 +1,142 @@ +# Command: Cleanup Dashboards + +Audits the dashboard estate in a project: identifies **stale** (not touched in a long time), duplicate, empty, and sparse boards. Recommends archive or delete. + +Staleness is a first-class signal here — a board with many reports that nobody has touched in months is still a cleanup candidate. Do not equate "has reports" with "healthy." + +--- + +## Contents + +- Phase 1 — Fetch all dashboards (with recency) +- Phase 2 — Deep inspection +- Phase 3 — Classification (structural + recency flags, duplicates) +- Phase 4 — Report +- Phase 5 — Action (interactive delete paths) +- Output +- Error Handling + +--- + +## Execution + +### Phase 1 — Fetch all dashboards (with recency) + +1. Fetch the dashboard set per the **Fetching the dashboard set** rule (sortable entity-search preferred, + sorting on the most recent timestamp the API exposes; plain list as fallback). +2. For each dashboard, extract whatever the response provides: + - `id`, `title`, `description` + - `last_modified` (a.k.a. modified/updated), `last_viewed` (if present), `created_at` + - `creator` / `owner` (if available) +3. Cache in `dashboard_list_cache`. + +**Recency field discovery (do this once, silently):** Scan the result set — not just the first object — to determine which timestamp fields the API populates, since field coverage can vary board to board. Choose the preferred field by coverage across boards, in priority order: `last_viewed` → `last_modified`/`updated_at` → `created_at`. Per board, if the chosen field is missing, fall back down the same order for that board and label its recency basis accordingly. Record the field(s) used so the report can label the column accurately. If NO board exposes any timestamp field, skip the Stale classification entirely and tell the user in the report header: "Recency data not available from the API — staleness not assessed; showing structural flags only." + +### Phase 2 — Deep inspection + +For each dashboard from Phase 1, read its full layout. Fire in parallel (batches of 5 to avoid rate limits). Skip any dashboard already in `dashboard_layout_cache`. + +From the layout, derive and cache: +- **Report count:** number of report cells +- **Text-only count:** number of text cells +- **Total cells:** sum of all cells +- **Row count:** number of rows + +### Phase 3 — Classification + +Compute `days_since` from the chosen recency timestamp (today minus that date). Then classify. **Staleness and structure are independent axes** — evaluate both; a board may carry a structural flag *and* a stale flag. + +> **Use the bundled helper for staleness and duplicate math.** Run `scripts/dashboard_utils.py` rather than re-deriving title normalization or recency arithmetic by hand each run — it is the single source of truth for `days_since(...)`, `normalize_title(...)`, and `is_probable_duplicate(...)`. This keeps results deterministic across runs. + +**Structural flags** (from layout): + +| Category | Criteria | Flag | +|----------|----------|------| +| **Empty** | 0 report cells AND 0 text cells (or only a single default text card) | 🟡 Empty | +| **Text-only** | 0 report cells but has text cards | 🟡 Text-only | +| **Sparse** | 1-2 report cells only | 🔵 Sparse | +| **Potential duplicate** | `is_probable_duplicate()` returns true vs. another board | 🟠 Possible dup | +| **Healthy** | 3+ report cells | ✅ Active | + +**Recency flag** (from `days_since`, only if a timestamp was found): + +| Category | Criteria | Flag | +|----------|----------|------| +| **Stale** | `days_since` ≥ 90 | 🔴 Stale ([N]d) | +| **Aging** | 60 ≤ `days_since` < 90 | 🟤 Aging ([N]d) | +| **Recent** | `days_since` < 60 | (no flag) | + +> Default threshold is 90 days (a skill-chosen heuristic). If the user names a different window ("anything untouched for 6 months", "stale = 30 days"), use theirs. State the threshold in the report header. + +**Cleanup priority** — order the action list by: 🔴 Stale **and** (Empty/Text-only/Sparse) first → 🔴 Stale + Active → 🟠 duplicates → 🟡 structural-only. The worst offenders are old *and* thin. + +**Duplicate detection** — delegated to `scripts/dashboard_utils.py`. Run `is_probable_duplicate(a, b)` pairwise across the board list; flag both members of any matching pair. (It matches on normalized-title similarity ≥ 0.80 or one normalized title contained in the other — the module is the source of truth for the exact rule.) + +### Phase 4 — Report + +Present the audit as a table. Include the recency column and label it with the actual field used. + +``` +Dashboard Audit — [Project Name] ([project_id]) +Recency basis: Last modified | Stale threshold: 90 days +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +ID | Title | Reports | Last modified | Status +---------|---------------------------|---------|---------------|------------------ +1234567 | Onboarding Funnel | 6 | 5d ago | ✅ Active +1234568 | Onboarding Funnel (Copy) | 6 | 142d ago | 🔴 Stale · 🟠 dup +1234569 | Test Board | 0 | 311d ago | 🔴 Stale · 🟡 Empty +1234570 | Notes | 0 | 18d ago | 🟡 Text-only +1234571 | Quick Metrics | 1 | 96d ago | 🔴 Stale · 🔵 Sparse +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Summary: 15 dashboards | 4 stale | 3 empty | 2 possible duplicates | 1 sparse | 8 active +Top cleanup candidates: #1234569 (stale + empty), #1234568 (stale + dup), #1234571 (stale + sparse) +``` + +If recency data was unavailable, drop the "Last modified" column and the stale flags, and note it in the header. + +### Phase 5 — Action (interactive) + +After showing the audit, ask what the user wants to do: + +**Option A: Delete selected boards** — user provides IDs (comma-separated or range). Show confirmation with titles: "Delete these 3 dashboards? [Title A], [Title B], [Title C]". On confirm, delete each sequentially, showing progress: `Deleted 2/3...` + +**Option B: Delete all top cleanup candidates** — list all boards flagged 🔴 Stale **and** structurally thin (Empty / Text-only / Sparse) — the safest bulk target. Require explicit confirmation with count: "Delete all 4 stale + thin dashboards?" Then execute. + +**Option C: Delete all flagged-empty boards** — list all 🟡 Empty + 🟡 Text-only boards (regardless of age). Require explicit confirmation with count, then execute. + +**Option D: Skip — just wanted the audit** — return control to router. + +**Never auto-delete.** Every deletion path requires explicit user confirmation — no exceptions. + +**Protect high-value stale boards.** Never propose deleting a 🔴 Stale board that still has 3+ reports without flagging that it may be a seasonal/quarterly board worth archiving rather than deleting. + +**Verify deletions.** After running deletions, re-fetch the dashboard list (or attempt to read each deleted ID and expect a not-found) to confirm each target is actually gone before reporting the count. Report any ID that still resolves as a failed deletion rather than a success. + +--- + +## Output + +After deletions (if any): + +``` +✅ Cleanup complete + Deleted: [N] dashboards + Remaining: [M] dashboards + Freed: [list of deleted titles] +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Entity-search unavailable | Fall back to the plain dashboard list (no sort); recency still parsed if present | +| No timestamp field in response | Skip Stale/Aging classification, note in header, show structural flags only | +| Fetch returns empty | "No dashboards found in this project." Return. | +| Layout read fails for one board | Mark as "⚠️ Could not inspect", continue with others | +| A deletion fails | Note the failure, continue with remaining deletions | +| User cancels deletion | "No dashboards deleted." Return. | diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/create-dashboard.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/create-dashboard.md new file mode 100644 index 0000000..d1d4c03 --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/create-dashboard.md @@ -0,0 +1,90 @@ +# Command: Create Dashboard + +Creates a new dashboard from a natural language description. + +--- + +## Intake + +The user provides either: +- **A description** — e.g. "create a dashboard tracking onboarding funnel metrics" +- **A structured spec** — title, description, specific reports to include + +Extract: +1. **Title** (required) — infer from description if not stated +2. **Description** (optional) — a 1-2 line summary +3. **Report intent** (optional) — what charts/reports the user wants on the board +4. **Visibility** — private or shared (default: shared) +5. **Time filter** — if the user mentions a date range, set it; otherwise omit + +--- + +## Execution + +### Path A: Empty Dashboard (no reports specified or no query_ids available) + +If the user just wants a board created without pre-built reports: + +1. Create the dashboard with the session `project_id`, the extracted title and + description, the chosen visibility, and at minimum one row holding a single + text card, e.g. `
Description here. Add reports to populate.
`. +2. Return the dashboard ID and confirm. + +### Path B: Dashboard with Reports + +If the user wants specific charts, each report needs a `query_id` minted first. +The flow: + +1. For each desired report, run its query with results skipped to mint a + `query_id`. Read the query schema first if unsure about available + events/properties. Fire queries in parallel where possible. +2. Assemble the rows, observing the layout limits and grouping rules in + `references/mcp-tool-reference.md`. Group related reports in the same row; + use text cards as section headers between logical groups. +3. Create the dashboard with the assembled rows. +4. Return the dashboard ID, title, and a summary of what was created. + +### Path C: Dashboard from a description (AI-inferred layout) + +When the user gives a loose description like "build me a product health dashboard": + +1. Infer 4-8 logical report categories from the description. +2. Create the dashboard with text-card section headers for each category and a + placeholder description. +3. Tell the user: "Created [Title] with section scaffolding. Reports need to be + added manually or by minting queries — want me to populate any sections?" + +--- + +## Time Filter + +If the user specifies a date range, set a time filter. Common mappings: +- "last 7 days" → last 7 days +- "last month" → last 1 month +- "last quarter" → last 3 months +- Specific range → a "between" range with `from`/`to` dates (YYYY-MM-DD) + +--- + +## Output + +``` +✅ Dashboard created + ID: [dashboard_id] + Title: [title] + Reports: [N reports] | Empty (scaffold only) + Access: Shared | Private +``` + +Then re-read the board to confirm the write landed (see the **Validate every +write** rule) before reporting `✅`. Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| A report's query fails to mint | Skip that report, note in output, continue with others | +| Dashboard creation fails | Surface full error to user | +| User description too vague | Create scaffold with text-card sections, explain next steps | diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/dashboard-inventory.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/dashboard-inventory.md new file mode 100644 index 0000000..607af6f --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/dashboard-inventory.md @@ -0,0 +1,69 @@ +# Command: Dashboard Inventory + +Lists all dashboards in a project with report counts, ownership, and metadata. Produces a governance-ready catalog. Read-only. + +--- + +## Execution + +### Phase 1 — Fetch all dashboards + +Fetch the dashboard set per the **Fetching the dashboard set** rule, reusing `dashboard_list_cache` if it +is already populated (e.g. from a prior cleanup command). Only re-fetch if the +cache is empty. + +### Phase 2 — Enrich with layout data + +For each dashboard, read its full layout. Fire in parallel (batches of 5). + +Extract per dashboard: +- **Report count:** number of report cells +- **Report names:** the name of each report cell +- **Text card count:** number of text cells +- **Row count** +- **Total cells** + +Cache layouts in `dashboard_layout_cache`. + +### Phase 3 — Build catalog + +Present as a structured table: + +``` +Dashboard Inventory — [Project Name] ([project_id]) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +ID | Title | Reports | Rows | Description +---------|---------------------------|---------|------|------------------ +1234567 | Onboarding Funnel | 6 | 4 | Tracks new user... +1234568 | Product Health | 8 | 5 | Core KPIs for... +1234569 | Engagement Weekly | 4 | 3 | Weekly active... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Total: 12 dashboards | 54 reports | Avg 4.5 reports/board +``` + +### Phase 4 — Optional detail drill-down + +After showing the catalog, if the user asks about a specific dashboard, show +full details: all report names, description, text card contents. This data is +already in `dashboard_layout_cache` — no additional calls needed. + +### Phase 5 — Optional export + +If the user wants a downloadable version, offer to produce a Markdown or CSV file with the full catalog. + +--- + +## Output + +The catalog table above, plus the summary line. Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Fetch returns empty | "No dashboards in this project." Return. | +| Layout read fails for one board | Show row with "⚠️ Could not inspect" in Reports column | +| Large project (50+ dashboards) | Process in batches of 5, show progress: "Inspecting 15/52..." | diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/duplicate-dashboard.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/duplicate-dashboard.md new file mode 100644 index 0000000..0fce964 --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/duplicate-dashboard.md @@ -0,0 +1,64 @@ +# Command: Duplicate Dashboard + +Creates a copy of an existing dashboard within the same project. Optionally renames and updates the description. + +--- + +## Intake + +Required: +1. **Dashboard ID** — the board to copy (accept by name or ID; match by ID first, then case-insensitive name) + +Optional: +2. **New title** — defaults to "[Original Title] (Copy)" +3. **New description** — defaults to original description + +If the user doesn't provide a dashboard, help them find it: +- If `dashboard_list_cache` is populated → show a quick picker from cache +- Otherwise → fetch the dashboard set (per the **Fetching the dashboard set** rule), show a table, let user pick + +--- + +## Execution + +1. **Preview source.** Read the source board's full layout to show the user what + they're copying: + ``` + Source: [Title] (ID: [dashboard_id]) + Reports: [N] | Rows: [M] | Description: [first 100 chars...] + ``` + +2. **Confirm.** "Duplicate this dashboard?" (skip confirmation if the user already stated intent clearly) + +3. **Duplicate** the source board within the session project, applying the new + title/description if provided. (Duplication is same-project only — see + `references/mcp-tool-reference.md`.) + +4. **Post-duplicate metadata update.** If the duplicate operation doesn't apply + the title/description overrides cleanly, follow up with a metadata update on + the new board to set them. + +5. **Verify** the new board per the **Validate every write** rule before reporting `✅`. + +--- + +## Output + +``` +✅ Dashboard duplicated + Source: [original_title] (ID: [source_id]) + Copy: [new_title] (ID: [new_id]) + Reports: [N] carried over +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Source dashboard not found | Error, help user find correct ID | +| Duplicate operation fails | Surface error, suggest retry | +| User cancels | "No changes made." Return. | diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/template-dashboard.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/template-dashboard.md new file mode 100644 index 0000000..d2adab0 --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/template-dashboard.md @@ -0,0 +1,145 @@ +# Command: Template Dashboard + +Reproduces a reference dashboard in another project, renames it, and optionally updates the description. This is the core enabler for standardized onboarding dashboard templates across accounts. + +**Key API fact:** duplication only copies *within the source project* — it has no target-project parameter. So genuine cross-project templating cannot be done by duplicating. It is done by **reconstructing** the board in the target project: read the source layout, re-mint each report's query in the target project, then create the board there. This command does that. + +--- + +## Contents + +- Intake +- Routing: same project vs. cross project +- Path A — Same-project copy +- Path B — Cross-project reconstruction (read → portability check → re-mint → build → verify) +- Batch template (multiple target projects) +- Output +- Error Handling + +--- + +## Intake + +Required: +1. **Source dashboard ID** — the reference board to clone +2. **Source project ID** — where the reference lives (may differ from session `project_id`) +3. **Target project ID(s)** — where the clone(s) should land + +Optional: +4. **New title** — defaults to "[Original Title]" +5. **New description** — defaults to original description with a "[Templated from [source]]" note appended +6. **Batch mode** — template to multiple target projects at once + +If the user doesn't provide source/target explicitly, ask. Use the session's projects list to help them pick. Accept projects and boards by name or ID. + +--- + +## Routing: same project vs. cross project + +- **Target project == source project** → this is a plain copy. Use Path A. Fast, exact, preserves everything. +- **Target project != source project** → use the reconstruction flow (Path B). Duplication cannot reach another project. + +--- + +## Path A — Same-project copy + +1. **Validate source.** Read its full layout; preview title, description, report count, row count. If not found → error, stop. +2. **Duplicate** within the source project, applying `title`/`description` overrides if provided. +3. Verify (per the **Validate every write** rule) and report the new dashboard ID. Done. + +--- + +## Path B — Cross-project reconstruction (the real templating path) + +### Step 1 — Read the source + +1. Read the source board's full layout (from the source project). + - For each **report** cell, capture its report/query reference and name, plus the cell's description if present. + - For each **text** cell, capture its HTML content. + - Preserve row grouping and cell order so the rebuilt board matches the original layout. +2. Preview to the user: title, description, report count, text-card count, row count. + +### Step 2 — Portability pre-check (important) + +A report only renders in the target project if the events, properties, and cohorts it references **exist there**. Templating an onboarding board into a brand-new project where nothing is instrumented yet will produce empty charts. + +- Identify the events/properties each source report depends on (from each report's query definition). +- Check they exist in the target project (inspect the target project's schema — its events and properties). +- Classify each report: **portable** (all dependencies present in target) vs **at-risk** (missing events/props). +- Show the user the at-risk list before building: + ``` + 3 of 7 reports reference events not found in [Target Project]: + - "Activation Funnel" → missing: signup_completed, first_value_event + - "Feature Adoption" → missing: feature_used + Proceed and create them anyway (they may stay empty until instrumented), skip them, or cancel? + ``` +- Default to asking. For a fresh-onboarding template this is expected — the user often wants the scaffold in place ahead of instrumentation, so "proceed anyway" is a valid, informed choice. + +### Step 3 — Re-mint queries in the target project + +For each report to carry over, its query must be re-run **against the target project** to produce a target-valid `query_id` (a source project's `query_id` is not valid elsewhere — see `references/mcp-tool-reference.md`): + +1. Reconstruct the query from the source report/query definition. +2. Run it against the target project with results skipped to obtain a fresh `query_id`. +3. Fire in parallel where possible. If a query fails (e.g. unsupported by missing schema), mark that report skipped and continue. + +### Step 4 — Build the board in the target project + +1. Assemble the rows preserving the source's grouping — report cells referencing + their fresh target `query_id` and original name/description, text cells carrying + their original HTML. Observe the layout limits and content rules in + `references/mcp-tool-reference.md`. +2. Create the board in the target project with the new title, the new description + plus a templated-from note, and the assembled rows (carry over the source's + time filter if it had one). +3. Capture the new dashboard ID. + +### Step 5 — Verify + +Re-read the new board's full layout in the target project and confirm report/row counts match expectations (minus any reports the user chose to skip). See the **Validate every write** rule. + +--- + +## Batch template (multiple target projects) + +1. Read + portability-check the source once. +2. For each target project, run Path B Steps 3–5 (re-mint queries per target — they cannot be shared across projects). +3. Show progress: `Templated 3/7...` +4. Final summary table: + +``` +Template Results — "[Source Dashboard Title]" +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Project | Status | New ID | Reports carried / skipped +[Project A] | ✅ | 12345 | 7 / 0 +[Project B] | ⚠️ partial | 12346 | 4 / 3 (missing events) +[Project C] | ❌ Error | — | Query timeout +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +--- + +## Output (single, cross-project) + +``` +✅ Dashboard templated + Source: [source_title] (ID: [source_id], Project: [source_project]) + Clone: [new_title] (ID: [new_id], Project: [target_project]) + Reports: [N carried over] | [M skipped — missing dependencies] + Method: Reconstructed (queries re-run in target project) +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Source dashboard not found | Error, ask user to re-check ID | +| Target project not accessible | Error, list available projects | +| Same source & target project | Use Path A instead | +| Report depends on events/props missing in target | Flag in portability pre-check; let user proceed / skip / cancel | +| A query fails to mint in target | Skip that report, note in output, continue with the rest | +| Board creation fails | Surface full error, suggest retry | diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/update-dashboard.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/update-dashboard.md new file mode 100644 index 0000000..ab2144c --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/commands/update-dashboard.md @@ -0,0 +1,120 @@ +# Command: Update Dashboard + +Modifies an existing dashboard's metadata, rows, or cell layout. The most flexible command — it handles renames, description edits, adding/removing rows, reordering rows, and updating cell content. + +--- + +## Contents + +- Intake +- Execution (read layout → apply updates → confirm → execute & verify) +- Output +- Error Handling + +--- + +## Intake + +Required: +1. **Dashboard ID** — the board to update (accept by name or ID) + +The user's intent determines the update path: +- **Rename** → title only +- **Update description** → description only +- **Add a section/row** → row + cell creation +- **Remove a row** → row deletion +- **Reorder rows** → row-order update +- **Update a report cell** → cell update with a new `query_id` +- **Update a text card** → cell update with new HTML +- **Bulk restructure** → a combination of the above + +If the user doesn't specify a dashboard, help them find it using `dashboard_list_cache` or by fetching the set (per the **Fetching the dashboard set** rule). + +--- + +## Execution + +### Step 1 — Read current layout + +Always start by reading the board's full layout, then show the user a structural +summary so they can point at real rows/cells: + +``` +Dashboard: [Title] (ID: [dashboard_id]) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Row 1: [Report: "DAU Trend"] [Report: "WAU Trend"] +Row 2: [Text: "Engagement Section"] +Row 3: [Report: "Session Length"] [Report: "Retention"] +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +Layout cell/row IDs are opaque server-generated strings — read the real IDs from +this layout; use temporary placeholder IDs only for newly-added rows/cells (see +`references/mcp-tool-reference.md`). + +### Step 2 — Apply updates + +Submit a single update to the board carrying the operations the user's intent +requires. Work at the level of intent — consult the update tool's own schema for +the exact operand order and payload shape. + +| Intent | What to submit | +|--------|----------------| +| Rename / edit description | Set the board's title and/or description. | +| Add a new row | One add-row operation. | +| Add a text card | An add-row operation plus a create-cell operation of type `text` carrying the card's HTML. | +| Add a report cell | First mint a `query_id` (run its query with results skipped), then an add-row op plus a create-cell op of type `report` referencing that `query_id`. | +| Delete a row or cell | A delete operation targeting the **real** server ID (read it from the layout first). | +| Update a text or report cell | An update operation targeting the real cell ID with the new HTML or new `query_id`. | +| Reorder rows | A set-row-order operation listing the real row IDs in the desired order. | + +New rows/cells use temporary placeholder IDs; the server assigns the real ones on +write. Text-card HTML must obey the tag whitelist and no-newline rule in +`references/mcp-tool-reference.md`. + +### Step 3 — Confirm before applying + +For destructive operations (deleting rows/cells, major restructures), show a before/after preview: + +``` +Changes to apply: + - Title: "Old Title" → "New Title" + - Delete Row 3: [Report: "Unused Chart"] + - Add Row: [Text: "New Section Header"] + +Proceed? +``` + +For simple renames or description updates, skip confirmation unless the user seems uncertain. + +### Step 4 — Execute and verify + +Apply the update, then re-read the board's full layout to confirm the change took +effect (per the **Validate every write** rule) and show the updated structure. If +the readback diverges from intent, surface what landed vs. what was requested +rather than reporting `✅`. + +--- + +## Output + +``` +✅ Dashboard updated + ID: [dashboard_id] + Title: [title] + Changes: [summary of what changed] +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Dashboard not found | Error, help user find correct ID | +| Invalid row/cell ID | Re-read layout, map correct IDs | +| Update fails | Surface error with details | +| User cancels | "No changes made." Return. | +| A report's query fails to mint | Skip that report, note in output | diff --git a/plugins/mixpanel-mcp-eu/skills/manage-boards/references/mcp-tool-reference.md b/plugins/mixpanel-mcp-eu/skills/manage-boards/references/mcp-tool-reference.md new file mode 100644 index 0000000..85ba26a --- /dev/null +++ b/plugins/mixpanel-mcp-eu/skills/manage-boards/references/mcp-tool-reference.md @@ -0,0 +1,47 @@ +# Dashboard API — Gotchas & Constraints + +Non-obvious behaviour the tool descriptions don't make clear. For tool +parameters and response shapes, rely on the tool descriptions themselves — +this file is only the knowledge those descriptions leave out. + +## Contents + +- Layout & structure limits +- Content rules for text cards +- Cross-project & duplication constraints +- Reading layout for updates + +--- + +## Layout & structure limits + +- A dashboard holds at most **30 rows**, and each row at most **4 cells** + (report or text). *(verify current — API-enforced.)* +- Every row needs at least one cell. +- Report cells require a `query_id` minted by a prior query run (run the + query with results skipped). You cannot place a report without one. + +## Content rules for text cards + +- Only these HTML tags survive; everything else is stripped: + `a, blockquote, br, code, em, h1, h2, h3, hr, li, mark, ol, p, s, + strong, u, ul`. No `div`, `span`, `img`, or `table`. *(verify current.)* +- No newlines in the HTML — each element implicitly line-breaks. Use + `Description here. Add reports to populate.
`. +2. Return the dashboard ID and confirm. + +### Path B: Dashboard with Reports + +If the user wants specific charts, each report needs a `query_id` minted first. +The flow: + +1. For each desired report, run its query with results skipped to mint a + `query_id`. Read the query schema first if unsure about available + events/properties. Fire queries in parallel where possible. +2. Assemble the rows, observing the layout limits and grouping rules in + `references/mcp-tool-reference.md`. Group related reports in the same row; + use text cards as section headers between logical groups. +3. Create the dashboard with the assembled rows. +4. Return the dashboard ID, title, and a summary of what was created. + +### Path C: Dashboard from a description (AI-inferred layout) + +When the user gives a loose description like "build me a product health dashboard": + +1. Infer 4-8 logical report categories from the description. +2. Create the dashboard with text-card section headers for each category and a + placeholder description. +3. Tell the user: "Created [Title] with section scaffolding. Reports need to be + added manually or by minting queries — want me to populate any sections?" + +--- + +## Time Filter + +If the user specifies a date range, set a time filter. Common mappings: +- "last 7 days" → last 7 days +- "last month" → last 1 month +- "last quarter" → last 3 months +- Specific range → a "between" range with `from`/`to` dates (YYYY-MM-DD) + +--- + +## Output + +``` +✅ Dashboard created + ID: [dashboard_id] + Title: [title] + Reports: [N reports] | Empty (scaffold only) + Access: Shared | Private +``` + +Then re-read the board to confirm the write landed (see the **Validate every +write** rule) before reporting `✅`. Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| A report's query fails to mint | Skip that report, note in output, continue with others | +| Dashboard creation fails | Surface full error to user | +| User description too vague | Create scaffold with text-card sections, explain next steps | diff --git a/plugins/mixpanel-mcp-in/skills/manage-boards/commands/dashboard-inventory.md b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/dashboard-inventory.md new file mode 100644 index 0000000..607af6f --- /dev/null +++ b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/dashboard-inventory.md @@ -0,0 +1,69 @@ +# Command: Dashboard Inventory + +Lists all dashboards in a project with report counts, ownership, and metadata. Produces a governance-ready catalog. Read-only. + +--- + +## Execution + +### Phase 1 — Fetch all dashboards + +Fetch the dashboard set per the **Fetching the dashboard set** rule, reusing `dashboard_list_cache` if it +is already populated (e.g. from a prior cleanup command). Only re-fetch if the +cache is empty. + +### Phase 2 — Enrich with layout data + +For each dashboard, read its full layout. Fire in parallel (batches of 5). + +Extract per dashboard: +- **Report count:** number of report cells +- **Report names:** the name of each report cell +- **Text card count:** number of text cells +- **Row count** +- **Total cells** + +Cache layouts in `dashboard_layout_cache`. + +### Phase 3 — Build catalog + +Present as a structured table: + +``` +Dashboard Inventory — [Project Name] ([project_id]) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +ID | Title | Reports | Rows | Description +---------|---------------------------|---------|------|------------------ +1234567 | Onboarding Funnel | 6 | 4 | Tracks new user... +1234568 | Product Health | 8 | 5 | Core KPIs for... +1234569 | Engagement Weekly | 4 | 3 | Weekly active... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Total: 12 dashboards | 54 reports | Avg 4.5 reports/board +``` + +### Phase 4 — Optional detail drill-down + +After showing the catalog, if the user asks about a specific dashboard, show +full details: all report names, description, text card contents. This data is +already in `dashboard_layout_cache` — no additional calls needed. + +### Phase 5 — Optional export + +If the user wants a downloadable version, offer to produce a Markdown or CSV file with the full catalog. + +--- + +## Output + +The catalog table above, plus the summary line. Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Fetch returns empty | "No dashboards in this project." Return. | +| Layout read fails for one board | Show row with "⚠️ Could not inspect" in Reports column | +| Large project (50+ dashboards) | Process in batches of 5, show progress: "Inspecting 15/52..." | diff --git a/plugins/mixpanel-mcp-in/skills/manage-boards/commands/duplicate-dashboard.md b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/duplicate-dashboard.md new file mode 100644 index 0000000..0fce964 --- /dev/null +++ b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/duplicate-dashboard.md @@ -0,0 +1,64 @@ +# Command: Duplicate Dashboard + +Creates a copy of an existing dashboard within the same project. Optionally renames and updates the description. + +--- + +## Intake + +Required: +1. **Dashboard ID** — the board to copy (accept by name or ID; match by ID first, then case-insensitive name) + +Optional: +2. **New title** — defaults to "[Original Title] (Copy)" +3. **New description** — defaults to original description + +If the user doesn't provide a dashboard, help them find it: +- If `dashboard_list_cache` is populated → show a quick picker from cache +- Otherwise → fetch the dashboard set (per the **Fetching the dashboard set** rule), show a table, let user pick + +--- + +## Execution + +1. **Preview source.** Read the source board's full layout to show the user what + they're copying: + ``` + Source: [Title] (ID: [dashboard_id]) + Reports: [N] | Rows: [M] | Description: [first 100 chars...] + ``` + +2. **Confirm.** "Duplicate this dashboard?" (skip confirmation if the user already stated intent clearly) + +3. **Duplicate** the source board within the session project, applying the new + title/description if provided. (Duplication is same-project only — see + `references/mcp-tool-reference.md`.) + +4. **Post-duplicate metadata update.** If the duplicate operation doesn't apply + the title/description overrides cleanly, follow up with a metadata update on + the new board to set them. + +5. **Verify** the new board per the **Validate every write** rule before reporting `✅`. + +--- + +## Output + +``` +✅ Dashboard duplicated + Source: [original_title] (ID: [source_id]) + Copy: [new_title] (ID: [new_id]) + Reports: [N] carried over +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Source dashboard not found | Error, help user find correct ID | +| Duplicate operation fails | Surface error, suggest retry | +| User cancels | "No changes made." Return. | diff --git a/plugins/mixpanel-mcp-in/skills/manage-boards/commands/template-dashboard.md b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/template-dashboard.md new file mode 100644 index 0000000..d2adab0 --- /dev/null +++ b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/template-dashboard.md @@ -0,0 +1,145 @@ +# Command: Template Dashboard + +Reproduces a reference dashboard in another project, renames it, and optionally updates the description. This is the core enabler for standardized onboarding dashboard templates across accounts. + +**Key API fact:** duplication only copies *within the source project* — it has no target-project parameter. So genuine cross-project templating cannot be done by duplicating. It is done by **reconstructing** the board in the target project: read the source layout, re-mint each report's query in the target project, then create the board there. This command does that. + +--- + +## Contents + +- Intake +- Routing: same project vs. cross project +- Path A — Same-project copy +- Path B — Cross-project reconstruction (read → portability check → re-mint → build → verify) +- Batch template (multiple target projects) +- Output +- Error Handling + +--- + +## Intake + +Required: +1. **Source dashboard ID** — the reference board to clone +2. **Source project ID** — where the reference lives (may differ from session `project_id`) +3. **Target project ID(s)** — where the clone(s) should land + +Optional: +4. **New title** — defaults to "[Original Title]" +5. **New description** — defaults to original description with a "[Templated from [source]]" note appended +6. **Batch mode** — template to multiple target projects at once + +If the user doesn't provide source/target explicitly, ask. Use the session's projects list to help them pick. Accept projects and boards by name or ID. + +--- + +## Routing: same project vs. cross project + +- **Target project == source project** → this is a plain copy. Use Path A. Fast, exact, preserves everything. +- **Target project != source project** → use the reconstruction flow (Path B). Duplication cannot reach another project. + +--- + +## Path A — Same-project copy + +1. **Validate source.** Read its full layout; preview title, description, report count, row count. If not found → error, stop. +2. **Duplicate** within the source project, applying `title`/`description` overrides if provided. +3. Verify (per the **Validate every write** rule) and report the new dashboard ID. Done. + +--- + +## Path B — Cross-project reconstruction (the real templating path) + +### Step 1 — Read the source + +1. Read the source board's full layout (from the source project). + - For each **report** cell, capture its report/query reference and name, plus the cell's description if present. + - For each **text** cell, capture its HTML content. + - Preserve row grouping and cell order so the rebuilt board matches the original layout. +2. Preview to the user: title, description, report count, text-card count, row count. + +### Step 2 — Portability pre-check (important) + +A report only renders in the target project if the events, properties, and cohorts it references **exist there**. Templating an onboarding board into a brand-new project where nothing is instrumented yet will produce empty charts. + +- Identify the events/properties each source report depends on (from each report's query definition). +- Check they exist in the target project (inspect the target project's schema — its events and properties). +- Classify each report: **portable** (all dependencies present in target) vs **at-risk** (missing events/props). +- Show the user the at-risk list before building: + ``` + 3 of 7 reports reference events not found in [Target Project]: + - "Activation Funnel" → missing: signup_completed, first_value_event + - "Feature Adoption" → missing: feature_used + Proceed and create them anyway (they may stay empty until instrumented), skip them, or cancel? + ``` +- Default to asking. For a fresh-onboarding template this is expected — the user often wants the scaffold in place ahead of instrumentation, so "proceed anyway" is a valid, informed choice. + +### Step 3 — Re-mint queries in the target project + +For each report to carry over, its query must be re-run **against the target project** to produce a target-valid `query_id` (a source project's `query_id` is not valid elsewhere — see `references/mcp-tool-reference.md`): + +1. Reconstruct the query from the source report/query definition. +2. Run it against the target project with results skipped to obtain a fresh `query_id`. +3. Fire in parallel where possible. If a query fails (e.g. unsupported by missing schema), mark that report skipped and continue. + +### Step 4 — Build the board in the target project + +1. Assemble the rows preserving the source's grouping — report cells referencing + their fresh target `query_id` and original name/description, text cells carrying + their original HTML. Observe the layout limits and content rules in + `references/mcp-tool-reference.md`. +2. Create the board in the target project with the new title, the new description + plus a templated-from note, and the assembled rows (carry over the source's + time filter if it had one). +3. Capture the new dashboard ID. + +### Step 5 — Verify + +Re-read the new board's full layout in the target project and confirm report/row counts match expectations (minus any reports the user chose to skip). See the **Validate every write** rule. + +--- + +## Batch template (multiple target projects) + +1. Read + portability-check the source once. +2. For each target project, run Path B Steps 3–5 (re-mint queries per target — they cannot be shared across projects). +3. Show progress: `Templated 3/7...` +4. Final summary table: + +``` +Template Results — "[Source Dashboard Title]" +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Project | Status | New ID | Reports carried / skipped +[Project A] | ✅ | 12345 | 7 / 0 +[Project B] | ⚠️ partial | 12346 | 4 / 3 (missing events) +[Project C] | ❌ Error | — | Query timeout +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +--- + +## Output (single, cross-project) + +``` +✅ Dashboard templated + Source: [source_title] (ID: [source_id], Project: [source_project]) + Clone: [new_title] (ID: [new_id], Project: [target_project]) + Reports: [N carried over] | [M skipped — missing dependencies] + Method: Reconstructed (queries re-run in target project) +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Source dashboard not found | Error, ask user to re-check ID | +| Target project not accessible | Error, list available projects | +| Same source & target project | Use Path A instead | +| Report depends on events/props missing in target | Flag in portability pre-check; let user proceed / skip / cancel | +| A query fails to mint in target | Skip that report, note in output, continue with the rest | +| Board creation fails | Surface full error, suggest retry | diff --git a/plugins/mixpanel-mcp-in/skills/manage-boards/commands/update-dashboard.md b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/update-dashboard.md new file mode 100644 index 0000000..ab2144c --- /dev/null +++ b/plugins/mixpanel-mcp-in/skills/manage-boards/commands/update-dashboard.md @@ -0,0 +1,120 @@ +# Command: Update Dashboard + +Modifies an existing dashboard's metadata, rows, or cell layout. The most flexible command — it handles renames, description edits, adding/removing rows, reordering rows, and updating cell content. + +--- + +## Contents + +- Intake +- Execution (read layout → apply updates → confirm → execute & verify) +- Output +- Error Handling + +--- + +## Intake + +Required: +1. **Dashboard ID** — the board to update (accept by name or ID) + +The user's intent determines the update path: +- **Rename** → title only +- **Update description** → description only +- **Add a section/row** → row + cell creation +- **Remove a row** → row deletion +- **Reorder rows** → row-order update +- **Update a report cell** → cell update with a new `query_id` +- **Update a text card** → cell update with new HTML +- **Bulk restructure** → a combination of the above + +If the user doesn't specify a dashboard, help them find it using `dashboard_list_cache` or by fetching the set (per the **Fetching the dashboard set** rule). + +--- + +## Execution + +### Step 1 — Read current layout + +Always start by reading the board's full layout, then show the user a structural +summary so they can point at real rows/cells: + +``` +Dashboard: [Title] (ID: [dashboard_id]) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Row 1: [Report: "DAU Trend"] [Report: "WAU Trend"] +Row 2: [Text: "Engagement Section"] +Row 3: [Report: "Session Length"] [Report: "Retention"] +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +Layout cell/row IDs are opaque server-generated strings — read the real IDs from +this layout; use temporary placeholder IDs only for newly-added rows/cells (see +`references/mcp-tool-reference.md`). + +### Step 2 — Apply updates + +Submit a single update to the board carrying the operations the user's intent +requires. Work at the level of intent — consult the update tool's own schema for +the exact operand order and payload shape. + +| Intent | What to submit | +|--------|----------------| +| Rename / edit description | Set the board's title and/or description. | +| Add a new row | One add-row operation. | +| Add a text card | An add-row operation plus a create-cell operation of type `text` carrying the card's HTML. | +| Add a report cell | First mint a `query_id` (run its query with results skipped), then an add-row op plus a create-cell op of type `report` referencing that `query_id`. | +| Delete a row or cell | A delete operation targeting the **real** server ID (read it from the layout first). | +| Update a text or report cell | An update operation targeting the real cell ID with the new HTML or new `query_id`. | +| Reorder rows | A set-row-order operation listing the real row IDs in the desired order. | + +New rows/cells use temporary placeholder IDs; the server assigns the real ones on +write. Text-card HTML must obey the tag whitelist and no-newline rule in +`references/mcp-tool-reference.md`. + +### Step 3 — Confirm before applying + +For destructive operations (deleting rows/cells, major restructures), show a before/after preview: + +``` +Changes to apply: + - Title: "Old Title" → "New Title" + - Delete Row 3: [Report: "Unused Chart"] + - Add Row: [Text: "New Section Header"] + +Proceed? +``` + +For simple renames or description updates, skip confirmation unless the user seems uncertain. + +### Step 4 — Execute and verify + +Apply the update, then re-read the board's full layout to confirm the change took +effect (per the **Validate every write** rule) and show the updated structure. If +the readback diverges from intent, surface what landed vs. what was requested +rather than reporting `✅`. + +--- + +## Output + +``` +✅ Dashboard updated + ID: [dashboard_id] + Title: [title] + Changes: [summary of what changed] +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Dashboard not found | Error, help user find correct ID | +| Invalid row/cell ID | Re-read layout, map correct IDs | +| Update fails | Surface error with details | +| User cancels | "No changes made." Return. | +| A report's query fails to mint | Skip that report, note in output | diff --git a/plugins/mixpanel-mcp-in/skills/manage-boards/references/mcp-tool-reference.md b/plugins/mixpanel-mcp-in/skills/manage-boards/references/mcp-tool-reference.md new file mode 100644 index 0000000..85ba26a --- /dev/null +++ b/plugins/mixpanel-mcp-in/skills/manage-boards/references/mcp-tool-reference.md @@ -0,0 +1,47 @@ +# Dashboard API — Gotchas & Constraints + +Non-obvious behaviour the tool descriptions don't make clear. For tool +parameters and response shapes, rely on the tool descriptions themselves — +this file is only the knowledge those descriptions leave out. + +## Contents + +- Layout & structure limits +- Content rules for text cards +- Cross-project & duplication constraints +- Reading layout for updates + +--- + +## Layout & structure limits + +- A dashboard holds at most **30 rows**, and each row at most **4 cells** + (report or text). *(verify current — API-enforced.)* +- Every row needs at least one cell. +- Report cells require a `query_id` minted by a prior query run (run the + query with results skipped). You cannot place a report without one. + +## Content rules for text cards + +- Only these HTML tags survive; everything else is stripped: + `a, blockquote, br, code, em, h1, h2, h3, hr, li, mark, ol, p, s, + strong, u, ul`. No `div`, `span`, `img`, or `table`. *(verify current.)* +- No newlines in the HTML — each element implicitly line-breaks. Use + `Description here. Add reports to populate.
`. +2. Return the dashboard ID and confirm. + +### Path B: Dashboard with Reports + +If the user wants specific charts, each report needs a `query_id` minted first. +The flow: + +1. For each desired report, run its query with results skipped to mint a + `query_id`. Read the query schema first if unsure about available + events/properties. Fire queries in parallel where possible. +2. Assemble the rows, observing the layout limits and grouping rules in + `references/mcp-tool-reference.md`. Group related reports in the same row; + use text cards as section headers between logical groups. +3. Create the dashboard with the assembled rows. +4. Return the dashboard ID, title, and a summary of what was created. + +### Path C: Dashboard from a description (AI-inferred layout) + +When the user gives a loose description like "build me a product health dashboard": + +1. Infer 4-8 logical report categories from the description. +2. Create the dashboard with text-card section headers for each category and a + placeholder description. +3. Tell the user: "Created [Title] with section scaffolding. Reports need to be + added manually or by minting queries — want me to populate any sections?" + +--- + +## Time Filter + +If the user specifies a date range, set a time filter. Common mappings: +- "last 7 days" → last 7 days +- "last month" → last 1 month +- "last quarter" → last 3 months +- Specific range → a "between" range with `from`/`to` dates (YYYY-MM-DD) + +--- + +## Output + +``` +✅ Dashboard created + ID: [dashboard_id] + Title: [title] + Reports: [N reports] | Empty (scaffold only) + Access: Shared | Private +``` + +Then re-read the board to confirm the write landed (see the **Validate every +write** rule) before reporting `✅`. Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| A report's query fails to mint | Skip that report, note in output, continue with others | +| Dashboard creation fails | Surface full error to user | +| User description too vague | Create scaffold with text-card sections, explain next steps | diff --git a/plugins/mixpanel-mcp/skills/manage-boards/commands/dashboard-inventory.md b/plugins/mixpanel-mcp/skills/manage-boards/commands/dashboard-inventory.md new file mode 100644 index 0000000..607af6f --- /dev/null +++ b/plugins/mixpanel-mcp/skills/manage-boards/commands/dashboard-inventory.md @@ -0,0 +1,69 @@ +# Command: Dashboard Inventory + +Lists all dashboards in a project with report counts, ownership, and metadata. Produces a governance-ready catalog. Read-only. + +--- + +## Execution + +### Phase 1 — Fetch all dashboards + +Fetch the dashboard set per the **Fetching the dashboard set** rule, reusing `dashboard_list_cache` if it +is already populated (e.g. from a prior cleanup command). Only re-fetch if the +cache is empty. + +### Phase 2 — Enrich with layout data + +For each dashboard, read its full layout. Fire in parallel (batches of 5). + +Extract per dashboard: +- **Report count:** number of report cells +- **Report names:** the name of each report cell +- **Text card count:** number of text cells +- **Row count** +- **Total cells** + +Cache layouts in `dashboard_layout_cache`. + +### Phase 3 — Build catalog + +Present as a structured table: + +``` +Dashboard Inventory — [Project Name] ([project_id]) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +ID | Title | Reports | Rows | Description +---------|---------------------------|---------|------|------------------ +1234567 | Onboarding Funnel | 6 | 4 | Tracks new user... +1234568 | Product Health | 8 | 5 | Core KPIs for... +1234569 | Engagement Weekly | 4 | 3 | Weekly active... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +Total: 12 dashboards | 54 reports | Avg 4.5 reports/board +``` + +### Phase 4 — Optional detail drill-down + +After showing the catalog, if the user asks about a specific dashboard, show +full details: all report names, description, text card contents. This data is +already in `dashboard_layout_cache` — no additional calls needed. + +### Phase 5 — Optional export + +If the user wants a downloadable version, offer to produce a Markdown or CSV file with the full catalog. + +--- + +## Output + +The catalog table above, plus the summary line. Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Fetch returns empty | "No dashboards in this project." Return. | +| Layout read fails for one board | Show row with "⚠️ Could not inspect" in Reports column | +| Large project (50+ dashboards) | Process in batches of 5, show progress: "Inspecting 15/52..." | diff --git a/plugins/mixpanel-mcp/skills/manage-boards/commands/duplicate-dashboard.md b/plugins/mixpanel-mcp/skills/manage-boards/commands/duplicate-dashboard.md new file mode 100644 index 0000000..0fce964 --- /dev/null +++ b/plugins/mixpanel-mcp/skills/manage-boards/commands/duplicate-dashboard.md @@ -0,0 +1,64 @@ +# Command: Duplicate Dashboard + +Creates a copy of an existing dashboard within the same project. Optionally renames and updates the description. + +--- + +## Intake + +Required: +1. **Dashboard ID** — the board to copy (accept by name or ID; match by ID first, then case-insensitive name) + +Optional: +2. **New title** — defaults to "[Original Title] (Copy)" +3. **New description** — defaults to original description + +If the user doesn't provide a dashboard, help them find it: +- If `dashboard_list_cache` is populated → show a quick picker from cache +- Otherwise → fetch the dashboard set (per the **Fetching the dashboard set** rule), show a table, let user pick + +--- + +## Execution + +1. **Preview source.** Read the source board's full layout to show the user what + they're copying: + ``` + Source: [Title] (ID: [dashboard_id]) + Reports: [N] | Rows: [M] | Description: [first 100 chars...] + ``` + +2. **Confirm.** "Duplicate this dashboard?" (skip confirmation if the user already stated intent clearly) + +3. **Duplicate** the source board within the session project, applying the new + title/description if provided. (Duplication is same-project only — see + `references/mcp-tool-reference.md`.) + +4. **Post-duplicate metadata update.** If the duplicate operation doesn't apply + the title/description overrides cleanly, follow up with a metadata update on + the new board to set them. + +5. **Verify** the new board per the **Validate every write** rule before reporting `✅`. + +--- + +## Output + +``` +✅ Dashboard duplicated + Source: [original_title] (ID: [source_id]) + Copy: [new_title] (ID: [new_id]) + Reports: [N] carried over +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Source dashboard not found | Error, help user find correct ID | +| Duplicate operation fails | Surface error, suggest retry | +| User cancels | "No changes made." Return. | diff --git a/plugins/mixpanel-mcp/skills/manage-boards/commands/template-dashboard.md b/plugins/mixpanel-mcp/skills/manage-boards/commands/template-dashboard.md new file mode 100644 index 0000000..d2adab0 --- /dev/null +++ b/plugins/mixpanel-mcp/skills/manage-boards/commands/template-dashboard.md @@ -0,0 +1,145 @@ +# Command: Template Dashboard + +Reproduces a reference dashboard in another project, renames it, and optionally updates the description. This is the core enabler for standardized onboarding dashboard templates across accounts. + +**Key API fact:** duplication only copies *within the source project* — it has no target-project parameter. So genuine cross-project templating cannot be done by duplicating. It is done by **reconstructing** the board in the target project: read the source layout, re-mint each report's query in the target project, then create the board there. This command does that. + +--- + +## Contents + +- Intake +- Routing: same project vs. cross project +- Path A — Same-project copy +- Path B — Cross-project reconstruction (read → portability check → re-mint → build → verify) +- Batch template (multiple target projects) +- Output +- Error Handling + +--- + +## Intake + +Required: +1. **Source dashboard ID** — the reference board to clone +2. **Source project ID** — where the reference lives (may differ from session `project_id`) +3. **Target project ID(s)** — where the clone(s) should land + +Optional: +4. **New title** — defaults to "[Original Title]" +5. **New description** — defaults to original description with a "[Templated from [source]]" note appended +6. **Batch mode** — template to multiple target projects at once + +If the user doesn't provide source/target explicitly, ask. Use the session's projects list to help them pick. Accept projects and boards by name or ID. + +--- + +## Routing: same project vs. cross project + +- **Target project == source project** → this is a plain copy. Use Path A. Fast, exact, preserves everything. +- **Target project != source project** → use the reconstruction flow (Path B). Duplication cannot reach another project. + +--- + +## Path A — Same-project copy + +1. **Validate source.** Read its full layout; preview title, description, report count, row count. If not found → error, stop. +2. **Duplicate** within the source project, applying `title`/`description` overrides if provided. +3. Verify (per the **Validate every write** rule) and report the new dashboard ID. Done. + +--- + +## Path B — Cross-project reconstruction (the real templating path) + +### Step 1 — Read the source + +1. Read the source board's full layout (from the source project). + - For each **report** cell, capture its report/query reference and name, plus the cell's description if present. + - For each **text** cell, capture its HTML content. + - Preserve row grouping and cell order so the rebuilt board matches the original layout. +2. Preview to the user: title, description, report count, text-card count, row count. + +### Step 2 — Portability pre-check (important) + +A report only renders in the target project if the events, properties, and cohorts it references **exist there**. Templating an onboarding board into a brand-new project where nothing is instrumented yet will produce empty charts. + +- Identify the events/properties each source report depends on (from each report's query definition). +- Check they exist in the target project (inspect the target project's schema — its events and properties). +- Classify each report: **portable** (all dependencies present in target) vs **at-risk** (missing events/props). +- Show the user the at-risk list before building: + ``` + 3 of 7 reports reference events not found in [Target Project]: + - "Activation Funnel" → missing: signup_completed, first_value_event + - "Feature Adoption" → missing: feature_used + Proceed and create them anyway (they may stay empty until instrumented), skip them, or cancel? + ``` +- Default to asking. For a fresh-onboarding template this is expected — the user often wants the scaffold in place ahead of instrumentation, so "proceed anyway" is a valid, informed choice. + +### Step 3 — Re-mint queries in the target project + +For each report to carry over, its query must be re-run **against the target project** to produce a target-valid `query_id` (a source project's `query_id` is not valid elsewhere — see `references/mcp-tool-reference.md`): + +1. Reconstruct the query from the source report/query definition. +2. Run it against the target project with results skipped to obtain a fresh `query_id`. +3. Fire in parallel where possible. If a query fails (e.g. unsupported by missing schema), mark that report skipped and continue. + +### Step 4 — Build the board in the target project + +1. Assemble the rows preserving the source's grouping — report cells referencing + their fresh target `query_id` and original name/description, text cells carrying + their original HTML. Observe the layout limits and content rules in + `references/mcp-tool-reference.md`. +2. Create the board in the target project with the new title, the new description + plus a templated-from note, and the assembled rows (carry over the source's + time filter if it had one). +3. Capture the new dashboard ID. + +### Step 5 — Verify + +Re-read the new board's full layout in the target project and confirm report/row counts match expectations (minus any reports the user chose to skip). See the **Validate every write** rule. + +--- + +## Batch template (multiple target projects) + +1. Read + portability-check the source once. +2. For each target project, run Path B Steps 3–5 (re-mint queries per target — they cannot be shared across projects). +3. Show progress: `Templated 3/7...` +4. Final summary table: + +``` +Template Results — "[Source Dashboard Title]" +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Project | Status | New ID | Reports carried / skipped +[Project A] | ✅ | 12345 | 7 / 0 +[Project B] | ⚠️ partial | 12346 | 4 / 3 (missing events) +[Project C] | ❌ Error | — | Query timeout +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +--- + +## Output (single, cross-project) + +``` +✅ Dashboard templated + Source: [source_title] (ID: [source_id], Project: [source_project]) + Clone: [new_title] (ID: [new_id], Project: [target_project]) + Reports: [N carried over] | [M skipped — missing dependencies] + Method: Reconstructed (queries re-run in target project) +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Source dashboard not found | Error, ask user to re-check ID | +| Target project not accessible | Error, list available projects | +| Same source & target project | Use Path A instead | +| Report depends on events/props missing in target | Flag in portability pre-check; let user proceed / skip / cancel | +| A query fails to mint in target | Skip that report, note in output, continue with the rest | +| Board creation fails | Surface full error, suggest retry | diff --git a/plugins/mixpanel-mcp/skills/manage-boards/commands/update-dashboard.md b/plugins/mixpanel-mcp/skills/manage-boards/commands/update-dashboard.md new file mode 100644 index 0000000..ab2144c --- /dev/null +++ b/plugins/mixpanel-mcp/skills/manage-boards/commands/update-dashboard.md @@ -0,0 +1,120 @@ +# Command: Update Dashboard + +Modifies an existing dashboard's metadata, rows, or cell layout. The most flexible command — it handles renames, description edits, adding/removing rows, reordering rows, and updating cell content. + +--- + +## Contents + +- Intake +- Execution (read layout → apply updates → confirm → execute & verify) +- Output +- Error Handling + +--- + +## Intake + +Required: +1. **Dashboard ID** — the board to update (accept by name or ID) + +The user's intent determines the update path: +- **Rename** → title only +- **Update description** → description only +- **Add a section/row** → row + cell creation +- **Remove a row** → row deletion +- **Reorder rows** → row-order update +- **Update a report cell** → cell update with a new `query_id` +- **Update a text card** → cell update with new HTML +- **Bulk restructure** → a combination of the above + +If the user doesn't specify a dashboard, help them find it using `dashboard_list_cache` or by fetching the set (per the **Fetching the dashboard set** rule). + +--- + +## Execution + +### Step 1 — Read current layout + +Always start by reading the board's full layout, then show the user a structural +summary so they can point at real rows/cells: + +``` +Dashboard: [Title] (ID: [dashboard_id]) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Row 1: [Report: "DAU Trend"] [Report: "WAU Trend"] +Row 2: [Text: "Engagement Section"] +Row 3: [Report: "Session Length"] [Report: "Retention"] +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +Layout cell/row IDs are opaque server-generated strings — read the real IDs from +this layout; use temporary placeholder IDs only for newly-added rows/cells (see +`references/mcp-tool-reference.md`). + +### Step 2 — Apply updates + +Submit a single update to the board carrying the operations the user's intent +requires. Work at the level of intent — consult the update tool's own schema for +the exact operand order and payload shape. + +| Intent | What to submit | +|--------|----------------| +| Rename / edit description | Set the board's title and/or description. | +| Add a new row | One add-row operation. | +| Add a text card | An add-row operation plus a create-cell operation of type `text` carrying the card's HTML. | +| Add a report cell | First mint a `query_id` (run its query with results skipped), then an add-row op plus a create-cell op of type `report` referencing that `query_id`. | +| Delete a row or cell | A delete operation targeting the **real** server ID (read it from the layout first). | +| Update a text or report cell | An update operation targeting the real cell ID with the new HTML or new `query_id`. | +| Reorder rows | A set-row-order operation listing the real row IDs in the desired order. | + +New rows/cells use temporary placeholder IDs; the server assigns the real ones on +write. Text-card HTML must obey the tag whitelist and no-newline rule in +`references/mcp-tool-reference.md`. + +### Step 3 — Confirm before applying + +For destructive operations (deleting rows/cells, major restructures), show a before/after preview: + +``` +Changes to apply: + - Title: "Old Title" → "New Title" + - Delete Row 3: [Report: "Unused Chart"] + - Add Row: [Text: "New Section Header"] + +Proceed? +``` + +For simple renames or description updates, skip confirmation unless the user seems uncertain. + +### Step 4 — Execute and verify + +Apply the update, then re-read the board's full layout to confirm the change took +effect (per the **Validate every write** rule) and show the updated structure. If +the readback diverges from intent, surface what landed vs. what was requested +rather than reporting `✅`. + +--- + +## Output + +``` +✅ Dashboard updated + ID: [dashboard_id] + Title: [title] + Changes: [summary of what changed] +``` + +Return control to router. + +--- + +## Error Handling + +| Situation | Action | +|-----------|--------| +| Dashboard not found | Error, help user find correct ID | +| Invalid row/cell ID | Re-read layout, map correct IDs | +| Update fails | Surface error with details | +| User cancels | "No changes made." Return. | +| A report's query fails to mint | Skip that report, note in output | diff --git a/plugins/mixpanel-mcp/skills/manage-boards/references/mcp-tool-reference.md b/plugins/mixpanel-mcp/skills/manage-boards/references/mcp-tool-reference.md new file mode 100644 index 0000000..85ba26a --- /dev/null +++ b/plugins/mixpanel-mcp/skills/manage-boards/references/mcp-tool-reference.md @@ -0,0 +1,47 @@ +# Dashboard API — Gotchas & Constraints + +Non-obvious behaviour the tool descriptions don't make clear. For tool +parameters and response shapes, rely on the tool descriptions themselves — +this file is only the knowledge those descriptions leave out. + +## Contents + +- Layout & structure limits +- Content rules for text cards +- Cross-project & duplication constraints +- Reading layout for updates + +--- + +## Layout & structure limits + +- A dashboard holds at most **30 rows**, and each row at most **4 cells** + (report or text). *(verify current — API-enforced.)* +- Every row needs at least one cell. +- Report cells require a `query_id` minted by a prior query run (run the + query with results skipped). You cannot place a report without one. + +## Content rules for text cards + +- Only these HTML tags survive; everything else is stripped: + `a, blockquote, br, code, em, h1, h2, h3, hr, li, mark, ol, p, s, + strong, u, ul`. No `div`, `span`, `img`, or `table`. *(verify current.)* +- No newlines in the HTML — each element implicitly line-breaks. Use + `