Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 96 additions & 11 deletions skills/setup-metabase-instance/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ description: Set up and run a local Metabase instance. Downloads the JAR (if Jav

# Set Up a Local Metabase Instance

**Read this entire skill file end-to-end before taking any action.** Do not skim, do not stop at the first matching step, do not act on the summary alone. Prerequisite checks, launch sections, init gates, and post-setup handoff rules are scattered through the document; skipping ahead has repeatedly produced broken flows. Load the full text into context first, then start executing.

**Follow these instructions exactly as written.** Do not make assumptions, do not "be helpful" by overstepping, do not silently substitute "equivalent" actions for the ones specified. Every step, every verbatim message, every gate, and every prohibition is here because skipping or improvising on it has produced a known regression. If a step says "send this verbatim", send exactly that. If a step says "stop and wait", stop and wait. If a step says "do not call endpoint X", do not call X — even if the user asks you to. When in doubt, do less, not more.

---

This skill helps users run a local Metabase instance for development, testing, or exploration.

## Important: Network Access Required
Expand Down Expand Up @@ -285,24 +291,103 @@ Once healthy, tell the user:

The user must drive setup in the browser. You only run the read-only verification curls below. Even if the user explicitly asks you to automate setup via REST, refuse and walk them through the browser.

### Gate 1 — First-run wizard is complete (programmatic)
### Gate 1 — First-run wizard is complete (background poll)

Run this **first**, before anything else, before telling the user "Metabase is ready":
This gate is **passive**: the server is the source of truth, not the user. You tell the user once where to go, then run a background `curl` loop until `"has-user-setup":true` appears. **Do not ask the user to confirm.** Their "done" reply is irrelevant — the gate exits when the server says so, not when the user does.

```bash
curl -s http://localhost:$PORT/api/session/properties | grep -o '"has-user-setup":[a-z]*'
```
1. **Initial probe:**

```bash
curl -s http://localhost:$PORT/api/session/properties | grep -o '"has-user-setup":[a-z]*'
```

- `"has-user-setup":true` → gate passes, continue to Gate 2.
- `"has-user-setup":false` → continue to step 2.

2. **Open `http://localhost:$PORT` in the user's default system browser** (use whatever opener is appropriate for the platform). Then tell the user verbatim and immediately move to step 3 — do **not** wait for a reply:

> I opened the Metabase first-run wizard in your default browser. Complete it there — I'll detect automatically when you're done.

3. **Start the background poll** (max 2 minutes, 5-second interval). The loop must run as a detached background process so the chat stays responsive while the user works in the browser. Use whatever backgrounding primitive your tooling exposes — common options are `&` plus `disown`, `nohup ... &`, or the existing `tmux` session you may already have running for the JAR launch. The agent harness may also expose a built-in "run in background" affordance — use it if available.

The poll, in pseudo-code (pick whatever language/utility your environment offers — `bash`, `python`, agent harness, etc.):

```
deadline = now + 120 seconds
loop:
resp = GET http://localhost:$PORT/api/session/properties
if resp contains '"has-user-setup":true':
report success and exit
if now >= deadline:
report timeout and exit
sleep 5 seconds
```

Surface two distinct outcomes to step 4 (e.g. exit code `0` vs `1`, return value, or a status flag — whatever your runner uses).

4. **Wait for the loop to exit:**

- **Exit code 0** (server flipped to `true`) → gate passes. Advance to Gate 2.
- **Exit code 1** (2-minute timeout) → fall through to step 5 (user-driven mode).

5. **Timeout fallback — user-driven re-check.** Once 2 minutes have passed without the server flipping, stop polling automatically. Send the user verbatim:

> It's been 2 minutes and I haven't seen the wizard complete on the Metabase side. Take your time — just tell me once you've finished setup and I'll verify.

Then wait for any user reply. When they reply, run one explicit `curl`:

```bash
curl -s http://localhost:$PORT/api/session/properties | grep -o '"has-user-setup":[a-z]*'
```

- `true` → gate passes, advance to Gate 2.
- `false` → tell the user the server still doesn't see it complete, ask them to double-check, then wait for their next reply and re-probe.

While the background loop (step 3) is running:

- If the user asks you a question, answer it — but **do not** stop the loop and **do not** advance to Gate 2 on their word alone.
- If the user says "done" / "ready" / "I finished", respect them and **run an explicit probe right away** (don't wait for the next 5-second tick):

```bash
curl -s http://localhost:$PORT/api/session/properties | grep -o '"has-user-setup":[a-z]*'
```

- `true` → great, kill the background loop and advance to Gate 2.
- `false` → reply briefly: "The server doesn't show the wizard complete yet — double-check the last step in the browser." Keep the background loop running; it will pick up the flip on its own once the wizard really completes.

### Gate 2 — Offer the user a chance to connect their own database (mandatory ask)

**You MUST ask the user this question and wait for their explicit reply before advancing to Gate 3.** Do not skip this gate "to be helpful". Do not infer the answer from prior context. Do not proceed on silence. A fresh Metabase only has the Sample Database; the user almost always wants their own data, and not asking is one of the most common UX regressions in this skill.

1. **Send the user this message verbatim** (do not paraphrase, do not summarise, do not assume the user already wants to skip):

> Metabase is set up. By default it only knows about its Sample Database. Want to connect your own database now so you can ask Codex questions about your data? Reply **yes** to open the "Add database" page in Metabase, or **no** / **skip** to continue with just the Sample Database (you can always add one later from Admin → Databases).

2. **Stop generating and wait for a reply.** Do not advance to step 3 or to Gate 3 until you have an explicit user message addressing this question.

3. **Branch on the reply:**

- User says **yes** (or equivalent like "sure", "add it", "let's do it") → continue to the "If the user says yes" sub-section below.
- User says **no** / **skip** (or equivalent like "later", "not now", "just the sample") → continue to Gate 3.
- User replies with something unrelated → re-send the verbatim message and wait again. Do not abandon the gate.

#### If the user says yes

Open `http://localhost:$PORT/admin/databases/create` in the user's default system browser, then send them verbatim:

> I opened the "Add database" page in your browser. Fill in the connection details for your database (host, port, credentials, etc.), test the connection, and save it. Tell me once you've saved it successfully.

Do **not** automate the form submission — connection credentials must come from the user via Metabase's UI, never via chat. Opening the URL is fine; entering the credentials for them is not.

- `"has-user-setup":true` → first-run is done, continue to Gate 2.
- `"has-user-setup":false` → first-run is **NOT** done. Stop. Send this to the user verbatim and wait:
This gate completes on the user's confirmation when they reply "done" / "added" / "saved".

> Open `http://localhost:$PORT` in your browser and complete the Metabase first-run wizard — create an admin account, then either connect a database or click "I'll add my data later". Tell me once you're on the Metabase home page.
#### If the user says no / skip

After the user confirms, **re-run Gate 1**. Loop until it returns `true`. Do not skip this loop. Do not advance on the user's word alone — verify with curl every time.
Continue immediately to Gate 3.

### Gate 2 — Hand back to MCP setup
### Gate 3 — Hand back to MCP setup

Only after Gate 1 passes, resume the `setup-metabase-mcp` skill with `http://localhost:$PORT` as the instance URL. Do not ask the user for the URL again, you already know it. That skill validates the URL (version + MCP endpoint) and handles the plugin-side configuration (`.mcp.json`, OAuth login, asking the user to start a new chat). Do not duplicate those checks here.
Only after Gates 1 and 2 are both resolved, resume the `setup-metabase-mcp` skill with `http://localhost:$PORT` as the instance URL. Do not ask the user for the URL again, you already know it. That skill validates the URL (version + MCP endpoint) and handles the plugin-side configuration (`.mcp.json`, OAuth login, asking the user to start a new chat). Do not duplicate those checks here.

---

Expand Down
25 changes: 18 additions & 7 deletions skills/setup-metabase-mcp/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ name: setup-metabase-mcp
description: Read these instructions before using Metabase MCP tools. Setup is needed to connect to Metabase instances via the built-in MCP server.
---

**Read this entire skill file end-to-end before taking any action.** Do not skim, do not stop at the first matching step, do not act on the summary alone. The gates, failure modes, prohibitions, and post-setup rules are scattered through the document; skipping ahead has repeatedly produced broken flows. Load the full text into context first, then start executing from step 1.

**Follow these instructions exactly as written.** Do not make assumptions, do not "be helpful" by overstepping, do not silently substitute "equivalent" actions for the ones specified. Every step, every verbatim message, every gate, and every prohibition is here because skipping or improvising on it has produced a known regression. If a step says "send this verbatim", send exactly that. If a step says "stop and wait", stop and wait. If a step says "do not call endpoint X", do not call X — even if the user asks you to. When in doubt, do less, not more.

---

Configure the Metabase MCP plugin to point at the user's Metabase instance and finish OAuth. This skill assumes the instance itself is already set up and has the MCP feature enabled — that is the job of the `setup-metabase-instance` skill, not this one. Never mention `{METABASE_INSTANCE_PLACEHOLDER}` or any internal placeholder name to the user — just say the MCP needs their Metabase URL.

## Valid Instance URL Formats
Expand All @@ -22,20 +28,25 @@ Configure the Metabase MCP plugin to point at the user's Metabase instance and f
- **If they provide a URL**: continue with step 3.
- **If they don't have one and want to set up a local instance**: invoke the `setup-metabase-instance` skill. That skill spins up Metabase, walks the user through first-run setup and enabling the MCP feature, and returns with a ready URL (typically `http://localhost:3000`). Continue here with that URL.

3. Sanity-check that the URL points at a Metabase instance with MCP enabled. Run **both**:
3. Sanity-check that the URL points at a **ready-to-use** Metabase instance. Run all three probes:

```bash
curl -s <INSTANCE_URL>/api/session/properties | grep -o '"tag":"[^"]*"'
curl -s <INSTANCE_URL>/api/session/properties | grep -o '"has-user-setup":[a-z]*'
curl -s -o /dev/null -w "%{http_code}\n" <INSTANCE_URL>/api/mcp
```

Required:
- The version tag's major version is **≥ 60**.
- The `/api/mcp` response code is **`401`** (endpoint live, OAuth required).
All three must pass:
- Version tag's major version is **≥ 60**.
- `"has-user-setup":true` — instance has an admin account and is past the first-run wizard.
- `/api/mcp` response code is **`401`** — endpoint live, OAuth required.

If any fails, **stop**. Do not modify `.mcp.json`, do not run `codex mcp login`. Failure modes:

If either fails, **stop**. Do not modify `.mcp.json`, do not run `codex mcp login`. Tell the user:
- For a local URL that came from `setup-metabase-instance`: that skill should have made the instance ready — re-run it and check what failed.
- For a self-hosted or Cloud URL the user supplied: ask them to confirm their Metabase is on version 60+. The MCP feature is on by default in 60+ and does not require a toggle, so a `404` typically means the version is too old or the URL is wrong.
- **`has-user-setup:false`** — the instance is running but has never been initialized. This frequently happens when an agent loads both skills, finds Metabase already up, and jumps straight here. If this is the local instance you launched through this workflow, **forward to the `setup-metabase-instance` skill** so its Gate 1 walks the user through the first-run wizard; once that returns, re-run step 3 here. If this is a user-supplied Cloud or self-hosted URL, tell the user to open `<INSTANCE_URL>` in their browser, complete the first-run wizard there, and then come back so you can re-run step 3 here. Do not "just run OAuth and hope" — the OAuth flow will land on the wizard page instead of an authorize page and will hang.
- **Version < 60** — tell the user to upgrade Metabase, then stop.
- **`/api/mcp` returns `404`** — MCP is on by default in 60+ and has no toggle, so this usually means the version is older than reported or the URL is wrong. Ask the user to confirm.
- **Other HTTP codes** — surface the code to the user and stop.

**Never call `POST /api/setup`, `POST /api/session`, or any other authenticated Metabase REST endpoint.** Those bypass the OAuth flow this skill depends on. If the user asks you to, refuse.

Expand Down