@mushi-mushi/mcp 0.24.3 → 0.24.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,52 +7,22 @@
7
7
  [![Try the demo — no signup](https://img.shields.io/badge/Try%20the%20demo-no%20signup-E34234)](https://kensaur.us/mushi-mushi/docs/connect)
8
8
  [![npm](https://img.shields.io/npm/v/@mushi-mushi/mcp?color=cb3837)](https://www.npmjs.com/package/@mushi-mushi/mcp)
9
9
 
10
- [Model Context Protocol](https://spec.modelcontextprotocol.io/) server that wires Mushi into Cursor, Claude Code, and any MCP client. Pull fix context, review bugs, and dispatch fixes without a second LLM vendor key.
10
+ The [Model Context Protocol](https://modelcontextprotocol.io/) server for [Mushi Mushi](https://github.com/kensaurus/mushi-mushi). It lets Cursor, Claude Code, VS Code or any MCP client read your app's bug reports, get a plain-English diagnosis with a fix to start from, and dispatch or merge fixes. Your editor's own model does the work, so you need no second LLM key.
11
11
 
12
- Wire it into Cursor, Claude Code, or any MCP client in one command:
13
-
14
- ```bash
15
- npx mushi-mushi setup --ide cursor
16
- # or: npx mushi-mushi setup --ide claude
12
+ ```mermaid
13
+ flowchart LR
14
+ A["Bug reports<br/>in Mushi"] --> B["This MCP server"] --> C["Your editor<br/>'what's broken in prod?'"] --> D["Fix: you, or a<br/>draft PR from an agent"]
17
15
  ```
18
16
 
19
- That command reads CLI config at **`~/.config/mushi/config.json`** (legacy `~/.mushirc` auto-migrates), writes `.cursor/mcp.json` with the `mushi-<slug>` server block, and prints "Done; restart Cursor and ask: `list mushi tools`". No copy-pasting environment variables.
20
-
21
- > **What this is, and what it isn't**
22
- >
23
- > - **This package** (`@mushi-mushi/mcp`) is the MCP **server**; runs locally next to your editor, talks to the Mushi API, and presents bug reports as MCP tools/resources to your coding agent. Always install it by its scoped name (`npx -y @mushi-mushi/mcp@latest`); the bare `mushi-mcp` name was never published to npm.
24
- > - **`@mushi-mushi/agents`** ships the MCP **client adapter**; used by the autofix orchestrator when your project's `autofix_agent = 'mcp'`. See `packages/agents/src/adapters/mcp.ts`.
25
- > - The `generic_mcp` adapter shipped before V5.3 was a misnomer (it spoke plain REST). It is now `RestFixWorkerAgent`; the old export is kept as a deprecated alias for one more minor.
26
-
27
17
  ## Quick start
28
18
 
29
- ### 0. One-click: "Add to Cursor" deeplink
30
-
31
- The Mushi admin console (**Admin → MCP → Setup tab**) generates a one-click deeplink that opens Cursor's "Install MCP server?" dialog with your project ID and a freshly-minted `mcp:write` key already embedded:
32
-
33
- ```
34
- cursor://anysphere.cursor-deeplink/mcp/install?name=mushi-<project>&config=<base64>
35
- ```
36
-
37
- Click **"⚡ Add to Cursor"** (or **"Add to VS Code"**); Cursor prompts you to confirm, then writes the server block into your global `mcp.json` automatically. No copy-pasting.
38
-
39
- > **Security note:** The deeplink mints a dedicated `mcp:write` key (or `mcp:read` for read-only), separate from your app's SDK key. Your SDK key (the `report:write`-scoped key your app sends bug reports with) should never carry `mcp:write`; it would expose admin-level triage and fix dispatch to anyone who extracted it from your browser bundle. The deeplink mint enforces this separation automatically. See [API key scopes](#api-key-scopes) below.
40
-
41
- ### 1. One-liner CLI (recommended for first-time setup)
42
-
43
19
  ```bash
44
- # First: make sure you've logged in
45
- npx mushi-mushi login --api-key mushi_xxx --endpoint https://<ref>.supabase.co/functions/v1/api
46
-
47
- # Then wire your IDE
48
- npx mushi-mushi setup --ide cursor # Cursor
49
- npx mushi-mushi setup --ide claude # Claude Code / Claude Desktop
50
- npx mushi-mushi setup --ide cursor --with-rules # also write .cursorrules
20
+ npx mushi-mushi setup --ide cursor # or: claude, continue, zed
51
21
  ```
52
22
 
53
- ### 2. With Claude Desktop (manual)
23
+ Restart the editor and ask *"what's broken in prod?"*. For Cursor and Claude, `setup` writes the hosted server entry: the editor opens a browser sign-in on first use, and no API key is stored on disk. Pass `--stdio` for a local server, or `--with-rules` to also write the lesson-library rules file. You can also use the one-click **Add to Cursor** button on the [connect page](https://kensaur.us/mushi-mushi/docs/connect).
54
24
 
55
- Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
25
+ ### Manual setup (any MCP client)
56
26
 
57
27
  ```json
58
28
  {
@@ -62,436 +32,68 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
62
32
  "args": ["-y", "@mushi-mushi/mcp@latest"],
63
33
  "env": {
64
34
  "MUSHI_API_KEY": "mushi_xxxxxxxxxxxxxxxxxxxx",
65
- "MUSHI_PROJECT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
66
- "MUSHI_API_ENDPOINT": "https://<your-ref>.supabase.co/functions/v1/api"
35
+ "MUSHI_PROJECT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
67
36
  }
68
37
  }
69
38
  }
70
39
  }
71
40
  ```
72
41
 
73
- Restart Claude Desktop. You should see a hammer icon in the chat input; click it to see the Mushi Mushi tools.
74
-
75
- > **Where do I find these values?**
76
- > - **`MUSHI_API_KEY`**: [Admin → Connect](https://kensaur.us/mushi-mushi/admin/connect) or **MCP** setup; mint an `mcp:read` / `mcp:write` key. This is **not** the SDK ingest key from **Setup → Verify** (`report:write`) and **not** a BYOK key from **Settings → API Keys**.
77
- > - **`MUSHI_PROJECT_ID`**: [Admin console](https://kensaur.us/mushi-mushi/projects) → click your project → copy the UUID below the project name (e.g. `542b34e0-019e-41fe-b900-7b637717bb86`)
78
- > - **`MUSHI_API_ENDPOINT`**: Shown when you mint the MCP key, or use your project's API base (`https://<ref>.supabase.co/functions/v1/api`)
79
- >
80
- > Or visit **Admin → MCP** in the console for a one-click pre-filled config snippet.
81
-
82
- ### 3. With Cursor (manual)
83
-
84
- In Cursor settings, open **MCP** → **Add new MCP server** and paste:
85
-
86
- ```bash
87
- npx -y @mushi-mushi/mcp@latest
88
- ```
89
-
90
- Then set the same three environment variables:
91
-
92
42
  | Variable | Where to find it |
93
- |---|---|
94
- | `MUSHI_API_KEY` | **Connect** or **MCP** tab: mint `mcp:read` / `mcp:write` (not Setup → Verify ingest key; not Settings → BYOK) |
95
- | `MUSHI_PROJECT_ID` | Admin console → Projects → click project → UUID below the name |
96
- | `MUSHI_API_ENDPOINT` | Shown at key mint, or your Supabase `.../functions/v1/api` base |
97
-
98
- Without `MUSHI_PROJECT_ID` the server starts but scoped tools return an empty result with a message pointing you here.
99
-
100
- ### 4. From the command line
101
-
102
- ```bash
103
- MUSHI_API_KEY=mushi_xxxxxxxxxxxxxxxxxxxx \
104
- MUSHI_PROJECT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
105
- npx -y @mushi-mushi/mcp@latest
106
- ```
107
-
108
- The server speaks stdio MCP transport by default; your client launches it as a subprocess.
109
-
110
- ### 5. Hosted Streamable HTTP (no subprocess)
111
-
112
- The Mushi backend now exposes the same tool catalog over the **Streamable HTTP** transport (dual-era: MCP 2024-11-05 … 2025-11-25 legacy and the current 2026-07-28 revision) at `/functions/v1/mcp`. Use this when you want to skip the local subprocess; typical for OpenAI Agents SDK, ChatGPT Agent, hosted CrewAI, or any orchestrator that talks remote MCP:
113
-
114
- ```jsonc
115
- // .cursor/mcp.json — example (hosted HTTP)
116
- {
117
- "mcpServers": {
118
- "mushi-mushi-hosted": {
119
- "type": "http",
120
- "url": "https://<your-ref>.supabase.co/functions/v1/mcp",
121
- "headers": {
122
- "Authorization": "Bearer mushi_xxxxxxxxxxxxxxxxxxxx",
123
- "X-Mushi-Api-Key": "mushi_xxxxxxxxxxxxxxxxxxxx",
124
- "X-Mushi-Project-Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
125
- }
126
- }
127
- }
128
- }
129
- ```
130
-
131
- > **Cursor icon:** HTTP MCP URLs on `*.supabase.co` often show the **Supabase favicon** in Cursor settings; not a Mushi bug. Use **stdio** (`command` + `npx @mushi-mushi/mcp`) for the red 虫 stamp, or set `"icon": "https://kensaur.us/mushi-mushi/docs/integrations/mushi-mark-512.png"` in your server block. The hosted endpoint also emits MCP `serverInfo.icons` and serves inline SVG at `?icon=1`.
132
-
133
- ### Feature groups (`?features=` / `MUSHI_FEATURES`)
134
-
135
- Full catalog is **117 tools** (stdio / `MUSHI_FEATURES=all`). The hosted HTTP
136
- endpoint exposes a leaner subset filtered by feature groups (see
137
- `mcp-hosted-tool-manifest.json`). New installs now default to the lean
138
- `triage,fixes,inventory,setup,docs` set automatically (stdio: when
139
- `MUSHI_FEATURES` is unset; HTTP: pass the same `?features=` on the URL). To
140
- change the surface:
141
-
142
- - **Stdio:** `MUSHI_FEATURES=all` for the full catalog, or a CSV like `MUSHI_FEATURES=triage,qa,skills`
143
- - **HTTP:** `?features=all` or `?features=triage,qa,skills` on the MCP URL
144
-
145
- Renamed tools (`inventory_get` → `get_inventory`, `inventory_diff` →
146
- `diff_inventory`, `inventory_findings` → `list_gate_findings`, `fix_suggest` →
147
- `suggest_fix`, `graph_neighborhood` → `get_graph_neighborhood`,
148
- `graph_node_status` → `get_graph_node`) and the consolidated setup tooling
149
- (`setup_check` / `ingest_setup_check` / `diagnose_connection` → `diagnose_setup`;
150
- `get_activation_status` → `activation_status`; `get_reporter_thread` →
151
- `get_report_timeline`) are documented in the changelog; update calls to the new
152
- names.
153
-
154
- New unified tools: `diagnose_setup` (replaces the setup trilogy), `search_mushi_docs` (keyword doc search).
155
-
156
- Append `?read_only=1` to the URL to hide write tools (Supabase-parity mode).
157
-
158
- ## Programmatic imports
159
-
160
- For custom MCP hosts or tests:
161
-
162
- | Subpath | Exports |
163
43
  | --- | --- |
164
- | `@mushi-mushi/mcp/catalog` | `TOOL_CATALOG`, scopes, tool specs |
165
- | `@mushi-mushi/mcp/server` | `createMushiServer()` |
166
- | `@mushi-mushi/mcp/branding` | Icons and server metadata |
167
- | `@mushi-mushi/mcp/feature-groups` | `MUSHI_FEATURES` filtering |
168
-
169
- ## Cursor config hygiene
170
-
171
- 1. **One global MCP config**; keep `mushi` in `~/.cursor/mcp.json` only. Do **not** duplicate `mushi` / `mushi-stdio` in per-project `.cursor/mcp.json` (prevents connection storms). Project repos may ship `{}` or a comment pointing to the global file.
172
- 2. **Windows paths**; use forward slashes in JSON (`C:/Users/...`) or escaped backslashes (`C:\\Users\\...`). Raw `\f`, `\n`, `\t` in paths corrupt JSON.
173
- 3. **Multi-project**; either one HTTP server per project (distinct server name + `X-Mushi-Project-Id`) or one stdio server and pass `projectId` on each tool call.
174
-
175
- Tool parameters are camelCase (`projectId`, `reportId`, `includeRaw`). The snake_case spelling of any of them (`project_id`) is accepted too, on both transports, so older prompts and configs keep working.
176
- 4. **After editing global config**; fully restart Cursor (MCP panel must reload).
177
-
178
- | Header | Role |
179
- |--------|------|
180
- | `Authorization: Bearer <key>` | Auth (optional duplicate of API key) |
181
- | `X-Mushi-Api-Key` | Auth (preferred for MCP clients) |
182
- | `X-Mushi-Project-Id` | **Project scope**: required for API-key callers |
183
-
184
- ~~`X-Mushi-Project`~~ is deprecated for project UUID (collision with legacy slug header).
185
-
186
- The endpoint accepts JSON-RPC 2.0 over POST (returns `application/json` or `text/event-stream` per content negotiation), opens an SSE stream on GET for server-pushed notifications, and accepts DELETE for session termination. Auth is the same dual-mode API-key / JWT used everywhere else on `/v1/admin/*`.
187
-
188
- ## Tools
189
-
190
- ### Read
191
-
192
- | Tool | What it does |
193
- |---|---|
194
- | `get_recent_reports` | Fetch the N most recent reports, with optional `status` / `category` / `severity` filters |
195
- | `get_report_detail` | Full payload for a single report: description, console logs, network requests, screenshot URL, classification result, fix history |
196
- | `search_reports` | Semantic + keyword search (server-side pgvector; falls back to keyword match when embeddings aren't available) |
197
- | `get_similar_bugs` | Embedding-nearest neighbours for a component, page, or description |
198
- | `get_fix_context` | One-shot brief for a coding agent: report + repro + root-cause + ontology tags |
199
- | `get_fix_timeline` | Ordered timeline of a fix attempt (dispatched → started → branch → commit → PR → CI → completed/failed) |
200
- | `get_blast_radius` | Graph traversal showing other components a bug group touches |
201
- | `get_knowledge_graph` | Traverse the knowledge graph from a seed component or page |
202
- | `diagnose_setup` | Setup health in one call: `mode=full` (default) runs ingest + dispatch preflight, `mode=ingest` / `mode=dispatch` narrow it. Returns the single best next action. Run first when a user says setup is broken |
203
- | `check_sdk_version` | Compare a published `@mushi-mushi/*` pin to `GET /v1/sdk/latest-version`. Returns `{ package, current, latest, outdated }` and, when outdated, Sentry-style `suggestedActions` (max 1). Does not bump the pin. |
204
- | `activation_status` | Unified activation posture for the active project: required steps, SDK heartbeat, dispatch preflight, and the next best action |
205
- | `query_funnel` | Ordered funnel over `Mushi.track()` events (2–8 steps, per-step window, optional breakdown). Answers "where do users drop off?" from `GET /v1/admin/events/funnel` |
206
- | `get_product_events_summary` | Event names, counts, distinct users and daily volume for the trailing window — call first to discover event names |
207
- | `get_user_paths` | Most common events users fired right after a given event ("what did they do next?") from `GET /v1/admin/events/paths` |
208
- | `get_report_timeline` | Ordered report timeline: the reporter/admin comment thread (including verify/reopen signals) plus fix, QA, and status lanes. Use when triaging whether an end user still sees a bug as unfixed |
209
- | `list_projects` | Discover all Mushi projects accessible to this API key. Returns project id, name, and created date |
210
- | `get_project_context` | Rich context snapshot: SDK heartbeat, ingest status, autofix readiness, and open report counts |
211
- | `get_pipeline_logs` | Recent log entries from fix-worker, pipeline, and QA story runner: filterable by service, level, time, and limit |
212
- | `get_report_evidence` | Focused evidence package for a report: screenshot URL, console logs, network excerpts, environment, and user comments (lighter than `get_report_detail`) |
213
- | `triage_issue` | **Primary triage entry point**: combines report detail, evidence, similar bugs, fix context, blast radius, pipeline logs, and recommended next actions in one packet |
214
- | `query_lessons` | Token-budget retrieval of relevant learning rules for a code diff |
215
- | `list_lessons` | List promoted learning rules (lessons) for the current project |
216
-
217
- ### Write / agentic
218
-
219
- | Tool | What it does |
220
- |---|---|
221
- | `submit_fix_result` | Record a fix outcome (branch, PR, files, lines) from an external agent |
222
- | `dispatch_fix` | Kick off the agentic fix orchestrator for a report: returns a `fix_attempt` id |
223
- | `trigger_judge` | Run the Sonnet-as-Judge over a batch of classified reports |
224
- | `transition_status` | Move a report between workflow states (enforces the same rules as the UI) |
225
- | `run_nl_query` | Natural-language → read-only SQL against your project data (60/hour rate-limited) |
226
-
227
- ### Codebase (indexed repos)
228
-
229
- When codebase indexing is enabled on a project, these tools ground on `project_codebase_files` (+ wiki chunks when configured):
230
-
231
- | Tool | Scope | Purpose |
232
- |------|-------|---------|
233
- | `ask_codebase` | write | Plain-English Q&A with file:line citations |
234
- | `get_file_summary` | read | Lazy plain-English file/symbol summary |
235
- | `get_codebase_tour` | read | Dependency-ordered onboarding tour |
236
- | `search_codebase` | read | Semantic (or scoped) embedding search |
237
- | `get_codebase_domains` | read | Business domain / flow map |
238
- | `analyze_codebase_impact` | read | Diff impact (paths, last push, compare, fix PR) |
239
- | `analyze_wiki_knowledge` | read | Wiki/docs knowledge graph |
240
- | `get_repo_digest` | read | Paste-ready repo digest (tree + files) at a pinned commit, scoped to a folder or a bug; default feature set, no index needed |
241
-
242
- > Need a tool that isn't here? Open an issue at [github.com/kensaurus/mushi-mushi/issues](https://github.com/kensaurus/mushi-mushi/issues) and tag it `mcp`.
243
-
244
- ### Tool annotations (what clients see before invoking)
245
-
246
- Every tool is registered via `server.registerTool()` with MCP 2025-10 **tool annotations** so clients (Cursor, Claude Desktop, Continue, Cline, Zed) can render a proper "is this safe to auto-invoke?" UI without calling the tool first. The annotations come from a single source of truth; `src/catalog.ts`; mirrored into the admin console (`apps/admin/src/lib/mcpCatalog.ts`) and guarded against drift by `scripts/check-mcp-catalog-sync.mjs`.
247
-
248
- | Annotation | Meaning | Example |
249
- |---|---|---|
250
- | `readOnlyHint: true` | Safe to loop on: never mutates state | `get_recent_reports`, every `project://` resource |
251
- | `destructiveHint: true` | Mutates project state; client should confirm | `dispatch_fix`, `transition_status` |
252
- | `idempotentHint: true` | Repeated calls produce the same effect | `transition_status`, `submit_fix_result` |
253
- | `openWorldHint: true` | Reaches out to your Mushi deployment (not a pure local function) | Every tool in this server |
254
-
255
- The same catalog entries power the `/mcp` beginner console in the admin app; so the tool catalog the agent sees and the tool catalog the human operator reads can never disagree.
256
-
257
- ### Progress notifications on long-running tools
258
-
259
- `dispatch_fix` emits an MCP `notifications/progress` event the moment the orchestrator accepts the request, so clients that support progress (Cursor, Claude Desktop) can render a live "Dispatching fix…" indicator instead of freezing until the HTTP round-trip returns. The notification mirrors the `ProgressToken` the client passed in `_meta.progressToken`; clients that don't pass one get the normal non-streaming response, unchanged.
260
-
261
- ## Resources
44
+ | `MUSHI_API_KEY` | Console → **Connect** or **MCP**: mint an `mcp:read` or `mcp:write` key. Not the SDK key from Setup → Verify, and not an AI key from Settings |
45
+ | `MUSHI_PROJECT_ID` | Console → Projects → the UUID under your project's name |
46
+ | `MUSHI_API_ENDPOINT` | Optional. Only for self-hosting, e.g. `http://localhost:54321/functions/v1/api` |
47
+ | `MUSHI_FEATURES` | Optional. Tool groups to expose (see below) |
262
48
 
263
- Full list (8). See also the generated catalog at
264
- [kensaur.us/mushi-mushi/docs/sdks/mcp-tools](https://kensaur.us/mushi-mushi/docs/sdks/mcp-tools).
49
+ Claude Desktop does not expand `${VAR}` references in this file; Cursor and VS Code expand `${env:MUSHI_API_KEY}` and Claude Code expands `${MUSHI_API_KEY}`. Keep the key out of any `mcp.json` you commit.
265
50
 
266
- | URI | Returns |
267
- |---|---|
268
- | `project://stats` | Counts of new / classified / fixed reports + last 7-day trend |
269
- | `project://settings` | Project config: autofix agent, plugins enabled, ontology, LLM budgets |
270
- | `project://dashboard` | PDCA health snapshot: stage counts, bottleneck, recent activity (the same payload the admin console polls every 15 s) |
271
- | `privacy://status` | Privacy / PII scrubber status for the project |
272
- | `evolution://history` | Evolution / PDCA history snapshot |
273
- | `mushi://activation` | Activation / connection status for the project |
274
- | `project://integration-health` | Integration health probes (Slack, Sentry, GitHub, …) |
275
- | `inventory://current` | Current inventory snapshot |
51
+ ## What your editor gets
276
52
 
277
- ## Prompts
278
-
279
- Named templates the MCP client surfaces in its slash-menu. Each one bakes in the house voice ("lead with the fix, skip the preamble") so agents produce consistent outputs across editors.
280
-
281
- | Prompt | When to use |
282
- |---|---|
283
- | `summarize_report_for_fix` | Before asking the agent to write the patch: produces a one-line root cause, smallest file set, repro steps, and blast-radius warnings |
284
- | `explain_judge_result` | After the judge scores a fix: turns the raw scores into ship / iterate / dismiss guidance |
285
- | `triage_next_steps` | "What should I focus on right now?": five-item markdown list drawn from the dashboard + recent classified queue |
286
- | `mushi_setup` | Guided first-time MCP / SDK setup checklist |
287
-
288
- ## Environment variables
289
-
290
- | Variable | Required | Default | Notes |
291
- |---|---|---|---|
292
- | `MUSHI_API_KEY` | yes | — | Project API key with `mcp:read` or `mcp:write` scope. Mint one in the admin console → **Projects** (the one-time reveal card has a **Copy as `.env.local`** tab). |
293
- | `MUSHI_PROJECT_ID` | yes | — | UUID from the admin console URL (`/projects/<uuid>/...`) or the reveal card. |
294
- | `MUSHI_API_ENDPOINT` | no | `https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api` | Override only if you self-host. Localhost: `http://localhost:54321/functions/v1/api`. |
295
- | `MUSHI_MCP_SENTRY_DSN` | no | — | Reports this server's own errors to your Sentry project. Needs `@sentry/node` installed next to the server (an optional peer, not installed by default): `npx -p @sentry/node -p @mushi-mushi/mcp mushi-mcp`. |
296
-
297
- If a client passes a variable reference through unexpanded (the server receives the literal text `${MUSHI_API_KEY}`), the server treats it as unset: it falls back to the `mushi login` config, or serves setup mode and prints which client syntax to use. Claude Desktop expands no variables; Cursor and VS Code expand `${env:MUSHI_API_KEY}`; Claude Code expands `${MUSHI_API_KEY}`.
298
-
299
- ### Storing the key in `.env.local`
300
-
301
- The MCP binary reads these three vars from `process.env` on spawn; that means **anywhere you normally put env vars works**. The zero-friction path:
302
-
303
- 1. In the admin console, mint a key and pick **Copy as `.env.local`** on the reveal card. You get a pre-formatted block:
304
-
305
- ```bash
306
- # Mushi MCP; drop into .env.local (gitignored). The MCP binary picks these up on spawn.
307
- MUSHI_API_ENDPOINT=https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api
308
- MUSHI_PROJECT_ID=<your-uuid>
309
- MUSHI_API_KEY=mushi_…
310
- ```
311
-
312
- 2. Paste it into your repo's `.env.local` (already gitignored by every Vite / Next.js / Node project scaffold). Confirm `.env.local` is in `.gitignore` if you're in an unusual setup.
313
-
314
- 3. Tell your MCP client to inherit the shell env. For Cursor, the simplest form:
315
-
316
- ```json
317
- {
318
- "mcpServers": {
319
- "mushi-mushi": {
320
- "command": "npx",
321
- "args": ["-y", "@mushi-mushi/mcp@latest"]
322
- }
323
- }
324
- }
325
- ```
326
-
327
- Cursor spawns the subprocess with the parent shell's env, so as long as you ran Cursor from a terminal that has `.env.local` sourced (or you're using `direnv` / `dotenv-cli`), the three vars are already in place. If you prefer to inline them; Cursor / Claude Desktop both support an `env` block in `mcp.json`; use the **Copy as `.cursor/mcp.json`** tab on the reveal card, which hard-codes the three values into the JSON for you.
328
-
329
- 4. **Never** commit `.env.local`, and **never** paste a key into a repo-tracked `.cursor/mcp.json`. If you accidentally do, rotate the key from the admin console; the denormalised owner binding is rebuilt automatically on rotation.
330
-
331
- ## API key scopes
332
-
333
- The admin routes the MCP server hits enforce per-key scopes. When you mint a key, pick the smallest scope that works for your agent workflow:
334
-
335
- | Scope | Grants | Use for |
336
- |---|---|---|
337
- | `report:write` | SDK ingest only (`/v1/reports`, `/v1/notifications`). **No admin access.** | Your app's runtime Mushi SDK: never give this to an MCP client. |
338
- | `mcp:read` | Every MCP read tool (`get_recent_reports`, `search_reports`, `get_fix_context`, `get_fix_timeline`, `get_blast_radius`, `get_knowledge_graph`) and every `project://*` resource. | Safe default for agents that only *read* from Mushi. |
339
- | `mcp:write` | Everything `mcp:read` grants **plus** mutating tools (`dispatch_fix`, `submit_fix_result`, `trigger_judge`, `transition_status`, `run_nl_query`). | Agents that should act on bugs (open PRs, judge, transition status). |
340
-
341
- The middleware replies **403 `INSUFFICIENT_SCOPE`** with a human-readable message if your key is missing a required scope; no silent failures.
342
-
343
- ## When MCP helps (and when it doesn't)
344
-
345
- Useful if you already fix bugs in an AI-augmented editor. If your team still opens bugs exclusively in Jira and writes patches longhand, this server is solving a problem you don't have yet; use the SDK + Discord webhook and come back later.
346
-
347
- For teams that live in Cursor / Claude Code / Continue / Cline / Zed / Windsurf:
348
-
349
- | Use case | What it replaces | Why MCP wins |
350
- |---|---|---|
351
- | **"What should I triage right now?"** | Flipping to the admin tab, squinting at the dashboard, copying a report URL into chat | `triage_next_steps` prompt reads the live dashboard and gives the agent a five-item plan grounded in today's numbers: zero context-switch |
352
- | **"Fix this bug"** (from an agent) | Copy-pasting the Sentry issue body, guessing at the blast radius, hoping the agent knows which files to touch | `get_fix_context` returns a pre-baked brief (root cause + smallest file set + repro + ontology tags) over a standardised MCP transport every client supports |
353
- | **Cross-IDE parity** | Shipping a Cursor plugin AND a VS Code extension AND a JetBrains plugin | Ship **one** MCP server; every MCP-compatible editor picks it up. Cursor, Claude Desktop, Continue, Cline, Zed, Windsurf all already speak the protocol |
354
- | **Scoped automation** | Giving the agent a full admin token or writing a brittle REST wrapper | `mcp:read` vs `mcp:write` scopes are enforced at the edge function. The agent can safely loop on reads; writes require the stricter key. No bespoke ACLs |
355
- | **Natural-language data questions** | Opening the admin `/query` page, writing SQL by hand | `run_nl_query`: ask the agent "how many critical reports landed this week by component?" and it goes through the same NL→SQL pipeline the admin UI uses, rate-limited to 60/hour |
356
- | **Ad-hoc dashboards inside chat** | Refreshing the admin tab every 15 s during a release | `project://dashboard` resource returns the live PDCA snapshot; clients can re-read the URI whenever the conversation needs fresh numbers |
357
-
358
- ### MCP spec coverage
359
-
360
- | Status | Capability |
53
+ | Start here | What it does |
361
54
  | --- | --- |
362
- | Shipped | Tools, resources, prompts; tool annotations; progress on `dispatch_fix`; scope-aware errors; stdio + Streamable HTTP; `outputSchema` / `structuredContent` on key tools; inventory action anchors on `dispatch_fix` / `get_fix_context` |
363
- | Waiting on clients | Resource subscriptions / `list_changed` push; sampling / elicitation |
364
-
365
- Detail and tool tables: [docs `/sdks/mcp`](https://kensaur.us/mushi-mushi/docs/sdks/mcp) and the generated [MCP tools reference](https://kensaur.us/mushi-mushi/docs/sdks/mcp-tools) page. Open an issue for a waiting-on-clients row once ≥2 major clients ship support.
366
-
367
- ## Admin console: `/mcp` page
368
-
369
- The admin app ships an `/mcp` page (sidebar → **Act → MCP**) with connection status, install snippets, the use-case table above (clickable into the catalog), and the full tool / resource / prompt list from the same `catalog.ts` the server registers.
370
-
371
- The page is the recommended first stop for a new team member; it takes about 60 seconds to go from "I have a Mushi account" to "Cursor is calling `get_recent_reports` for me". The source of truth lives at `apps/admin/src/pages/McpPage.tsx`.
372
-
373
- ## Security
374
-
375
- - The server runs locally; your API key never leaves your machine except in calls to your configured `MUSHI_API_ENDPOINT`.
376
- - **Scope keys tightly.** Give MCP the smallest scope that works; `mcp:read` is fine for 90% of agent loops.
377
- - **Keep your SDK key (`report:write`) separate from your MCP key.** Your app's Mushi SDK key is embedded in client-side code (e.g. `NEXT_PUBLIC_MUSHI_API_KEY`) and should carry only `report:write` scope. This scope is intentionally rejected by every admin route; so even if extracted from a browser bundle, it cannot triage, dispatch fixes, or mutate report status. Mint a dedicated `mcp:write` key for Cursor/Claude (use the **"⚡ Add to Cursor"** deeplink on the `/mcp` console page; it mints one automatically). If you discover your public SDK key carries `mcp:write`, rotate it immediately.
378
- - Never paste a service-role key; it bypasses RLS on every table.
379
- - Rotate keys from the admin console if a laptop is lost; the denormalised owner binding is rebuilt automatically on rotation.
380
- - The server logs to stderr; redirect to a file if you need an audit trail.
381
-
382
- ## Testing locally
383
-
384
- Three layers of testing, each solving a different problem.
385
-
386
- ### Layer 1; In-process integration tests (fastest, no subprocess)
387
-
388
- Real `Client ↔ Server` handshake over `InMemoryTransport` with a mocked `fetch`. Catches protocol regressions in under a second.
389
-
390
- ```bash
391
- pnpm --filter @mushi-mushi/mcp test
392
- # 49/49 pass; handshake, tool contracts, envelope unwrapping, scope errors, annotation contract, outputSchema, catalog parity
393
- ```
394
-
395
- ### Layer 2; Stdio smoke test (verifies the built bin boots)
396
-
397
- Spawns `dist/index.js` with a dummy unreachable endpoint and confirms it advertises the expected tools/resources/prompts over stdio. Good CI gate before publishing.
398
-
399
- ```bash
400
- pnpm --filter @mushi-mushi/mcp build
401
- pnpm --filter @mushi-mushi/mcp test:smoke
402
- # OK; prints live tool/resource/prompt counts from the catalog
403
- # (see packages/mcp/src/catalog.ts — currently 117 tools / 8 resources / 4 prompts)
404
- ```
405
-
406
- ### Layer 3; Full localhost E2E (real binary + real backend behaviour)
407
-
408
- Boots a tiny `node:http` mock of `/v1/admin/*`, spawns the real MCP binary pointed at it, and runs a real `StdioClientTransport` client through every tool + resource + a scope-denial path. This is the closest you can get to a production handshake without running Supabase Edge Functions.
55
+ | `triage_next_steps` | What needs attention right now, from the live queue |
56
+ | `get_fix_context` | One brief for a report: root cause, repro, the smallest set of files |
57
+ | `triage_issue` | Everything about one report: evidence, similar bugs, blast radius, logs, next actions |
58
+ | `dispatch_fix` / `merge_fix` | Have an agent open a draft PR, then merge it and close the report |
59
+ | `diagnose_setup` | Explains a broken install and the one next step |
60
+ | `search_mushi_docs` | Answers setup and API questions from the docs |
409
61
 
410
- ```bash
411
- pnpm --filter @mushi-mushi/mcp build
412
- node packages/mcp/scripts/localhost-e2e.mjs
413
- # 27/27 assertions; every tool, every resource, scope denial surfaced correctly
414
- ```
415
-
416
- The harness is also the quickest way to iterate on new tools: extend the `FIXTURES` + the route switch in `scripts/localhost-e2e.mjs`, rebuild, rerun. No migrations, no Supabase boot time, no DB state.
62
+ The full catalog has 117 tools, plus 8 resources (`project://dashboard`, `project://stats`, …) and 4 prompts (`summarize_report_for_fix`, `triage_next_steps`, …). Every tool carries read-only and destructive hints, so your editor can ask before it changes anything. Full list: [MCP tool reference](https://kensaur.us/mushi-mushi/docs/sdks/mcp-tools).
417
63
 
418
- ## Configuring against your own localhost
64
+ **Tool groups.** New installs get a lean default: `triage`, `fixes`, `inventory`, `setup`, `docs`. Turn on more with `MUSHI_FEATURES=triage,qa,codebase` (stdio) or `?features=…` on the hosted URL, or everything with `all`. Groups: `qa`, `skills`, `codebase`, `rewards`, `admin`, `audit`, `usage`. Add `?read_only=1` to the hosted URL to hide every write tool.
419
65
 
420
- When you're ready to wire the MCP into your local Mushi Mushi stack (i.e. `pnpm dev` is running the admin console + local Supabase), use these endpoints:
66
+ ## Keys and safety
421
67
 
422
- | Env var | Localhost value | Notes |
423
- |---|---|---|
424
- | `MUSHI_API_ENDPOINT` | `http://localhost:54321/functions/v1/api` | Default Supabase CLI port; the `/api` suffix is the Hono `basePath`. |
425
- | `MUSHI_API_KEY` | the key you minted (see below) | Must have `mcp:read` or `mcp:write` scope. |
426
- | `MUSHI_PROJECT_ID` | the UUID from the admin URL | `/projects/<uuid>` in the admin console. |
68
+ | Scope | Can do | Give it to |
69
+ | --- | --- | --- |
70
+ | `report:write` | Send reports only. No admin access | Your app's SDK. Never an MCP client |
71
+ | `mcp:read` | Every read tool and resource | Most agent loops |
72
+ | `mcp:write` | Reads plus `dispatch_fix`, `merge_fix`, `transition_status` and other changes | Agents that should act on bugs |
427
73
 
428
- ### Minting a localhost key
74
+ A key without the needed scope gets a clear `INSUFFICIENT_SCOPE` error, never a silent failure. Your SDK key ships in your app's bundle, so it must never carry `mcp:write`; the console mints MCP keys separately. Never use a Supabase service-role key. If a laptop is lost, rotate the key in the console.
429
75
 
430
- 1. Start the stack: `pnpm dev` (admin on `:6464`, Supabase on `:54321`).
431
- 2. Sign in and open **Settings → API keys**.
432
- 3. Click **New key**, pick **MCP read** or **MCP read-write** (the scope picker on the "New key" form), and copy the plain-text key that appears once; it's not retrievable later.
433
- 4. The admin console URL is `http://localhost:6464/projects/<uuid>/...`; the `<uuid>` is your `MUSHI_PROJECT_ID`.
76
+ ## Troubleshooting
434
77
 
435
- ### Pointing Cursor/Claude Desktop at localhost
78
+ - **No tools showing?** Check the MCP panel for a green dot, then fully restart the editor after any config change.
79
+ - **Keep one config.** Put the Mushi entry in your global `~/.cursor/mcp.json` only; a second copy in a project file can cause connection storms.
80
+ - **Windows paths** in JSON need forward slashes (`C:/Users/...`) or escaped backslashes.
81
+ - **Still stuck?** Ask your editor to run `diagnose_setup`, or run `mushi doctor --mcp`.
436
82
 
437
- Replace the public endpoint block in your client's MCP config with the three env vars above. For Cursor, this lives in `.cursor/mcp.json` at your repo root:
83
+ ## Programmatic use
438
84
 
439
- ```json
440
- {
441
- "mcpServers": {
442
- "mushi-mushi-local": {
443
- "command": "node",
444
- "args": ["/absolute/path/to/mushi-mushi/packages/mcp/dist/index.js"],
445
- "env": {
446
- "MUSHI_API_ENDPOINT": "http://localhost:54321/functions/v1/api",
447
- "MUSHI_API_KEY": "mushi_abc…",
448
- "MUSHI_PROJECT_ID": "00000000-0000-0000-0000-000000000000"
449
- }
450
- }
451
- }
452
- }
453
- ```
454
-
455
- Rebuild the package (`pnpm --filter @mushi-mushi/mcp build`) after any MCP source change; Cursor re-spawns the subprocess on config reload but doesn't recompile for you.
456
-
457
- ### Sanity check: did it connect?
458
-
459
- In Cursor chat, type `/`; you should see the Mushi Mushi slash-prompts (`/summarize_report_for_fix`, `/explain_judge_result`, `/triage_next_steps`). Or ask the agent directly: _"Use the Mushi MCP to list my recent reports"_. If scope is wrong you'll see the `[INSUFFICIENT_SCOPE]` error text verbatim; rotate the key with the right scope and retry.
460
-
461
- ## Debug MCP logs in Cursor
462
-
463
- If tools are not showing up or returning unexpected errors:
464
-
465
- 1. **Check the Cursor MCP logs**: Cursor → Help → Toggle Developer Tools → Console. Filter by `mushi`.
466
- 2. **Verify the server started**: In the MCP panel (Cursor → Settings → MCP), look for a green dot next to the Mushi server.
467
- 3. **Check scope errors**: A `INSUFFICIENT_SCOPE` response means your API key lacks the required scope; mint a new key with `mcp:read` (or `mcp:write` for mutating tools).
468
- 4. **Run the health check**: `/test-mushi-mcp` command or call `list_projects`; a clean response confirms auth is working.
469
- 5. **Restart Cursor**: After changing environment variables or `mcp.json`, restart Cursor to pick up the new config.
470
-
471
- ## Mushi vs Sentry MCP
472
-
473
- | | Sentry MCP | Mushi MCP |
474
- |--|-----------|-----------|
475
- | Signal source | Thrown exceptions | User-felt bugs (rage-click, console errors, network failures flagged by real users) |
476
- | Evidence | Stack traces, breadcrumbs | Screenshots, console logs, network excerpts, user comments, replay pointers |
477
- | Triage tool | `sentry_get_issue` | `triage_issue` (evidence + similar bugs + blast radius + logs + recommended actions) |
478
- | Fix dispatch | — | `dispatch_fix` → draft GitHub PR → human review |
479
- | QA coverage | — | QA story runner, PDCA improvement loop |
480
-
481
- Both are complementary; use Sentry for exception noise, Mushi for "the user says it's broken" signal.
85
+ | Import | Exports |
86
+ | --- | --- |
87
+ | `@mushi-mushi/mcp/server` | `createMushiServer()` for a custom host |
88
+ | `@mushi-mushi/mcp/catalog` | `TOOL_CATALOG`, scopes and tool specs |
89
+ | `@mushi-mushi/mcp/feature-groups` | Feature-group filtering |
90
+ | `@mushi-mushi/mcp/clients` | The supported editors and how each one installs |
91
+ | `@mushi-mushi/mcp/branding` | Icons and server metadata |
482
92
 
483
- ## See also
93
+ ## Learn more
484
94
 
485
- - [Fix orchestrator](https://kensaur.us/mushi-mushi/docs/concepts/fix-orchestrator); the agentic fix architecture this server feeds into.
486
- - [MCP tool reference](https://kensaur.us/mushi-mushi/docs/sdks/mcp-tools); every tool's parameters, generated from the catalog.
487
- - [`@mushi-mushi/agents`](https://www.npmjs.com/package/@mushi-mushi/agents); orchestrator that consumes MCP-exposed fix workers.
95
+ [MCP guide](https://kensaur.us/mushi-mushi/docs/sdks/mcp) · [MCP quickstart](https://kensaur.us/mushi-mushi/docs/quickstart/mcp) · [The incident loop](https://kensaur.us/mushi-mushi/docs/quickstart/incident-loop) · [Fix orchestrator](https://kensaur.us/mushi-mushi/docs/concepts/fix-orchestrator)
488
96
 
489
97
  ## License
490
98
 
491
99
  MIT
492
-
493
-
494
- <!-- mushi-readme-stats-footer -->
495
- ---
496
-
497
- <sub>Monorepo scale (July 2026): 64 edge functions · 422 SQL migrations · 13 outbound plugins · 11 inbound adapters · 19 pipeline agents. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>
package/dist/catalog.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  TOOL_CATALOG,
9
9
  USE_MUSHI_INTENTS,
10
10
  routeUseMushiIntent
11
- } from "./chunk-3IVSUYFV.js";
11
+ } from "./chunk-V3M4GZBV.js";
12
12
  export {
13
13
  ALL_SCOPES,
14
14
  CODEBASE_TOOL_CATALOG,
@@ -820,7 +820,7 @@ var TDD_TOOL_CATALOG = [
820
820
  {
821
821
  name: "list_byok_keys",
822
822
  title: "List your API key pool",
823
- description: "List the project's BYOK API keys grouped by provider (anthropic | openai | firecrawl | browserbase | cursor | supabase). Returns pooled { keys: [{ id, provider_slug, label, priority, status, cooldown_until, test_status, key_hint, base_url, last_tested_at, last_used_at }] } plus read-only { legacyKeys } metadata for credentials saved before the pooled lifecycle \u2014 never the raw secret. Read-only. Use to see which keys are validated, active, pending, legacy, or rate-limited; use add_byok_key to add one.",
823
+ description: "List the project's BYOK API keys grouped by provider (anthropic | openai | openrouter | firecrawl | browserbase | cursor | supabase). Returns pooled { keys: [{ id, provider_slug, label, priority, status, cooldown_until, test_status, key_hint, base_url, last_tested_at, last_used_at }] } plus read-only { legacyKeys } metadata for credentials saved before the pooled lifecycle \u2014 never the raw secret. Read-only. Use to see which keys are validated, active, pending, legacy, or rate-limited; use add_byok_key to add one.",
824
824
  scope: "mcp:read",
825
825
  hints: { readOnly: true, idempotent: true, openWorld: true },
826
826
  useCase: "Which API keys are active and which are rate-limited?"
@@ -828,7 +828,7 @@ var TDD_TOOL_CATALOG = [
828
828
  {
829
829
  name: "add_byok_key",
830
830
  title: "Add an API key",
831
- description: "Add and immediately validate a BYOK API key for anthropic | openai | firecrawl | browserbase | cursor | supabase (a scoped, read-only Supabase access token, checked against the linked supabase_project_ref). The raw key is stored encrypted in Supabase Vault and never returned; failed probes remain quarantined. Optional baseUrl is accepted only for allow-listed OpenAI-compatible HTTPS providers. Write; NOT idempotent.",
831
+ description: "Add and immediately validate a BYOK API key for anthropic | openai | openrouter | firecrawl | browserbase | cursor | supabase (a scoped, read-only Supabase access token, checked against the linked supabase_project_ref). The raw key is stored encrypted in Supabase Vault and never returned; failed probes remain quarantined. Optional baseUrl is accepted only for allow-listed OpenAI-compatible HTTPS providers. Write; NOT idempotent.",
832
832
  scope: "mcp:write",
833
833
  hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
834
834
  useCase: "Add a backup Anthropic key to the pool."
package/dist/clients.d.ts CHANGED
@@ -46,7 +46,7 @@ import { FeatureGroup } from './feature-groups.js';
46
46
  * editor launch. Synced to package.json by `scripts/sync-mcp-pin.mjs` — never
47
47
  * hand-edit the version.
48
48
  */
49
- declare const MCP_PIN_SPEC = "@mushi-mushi/mcp@0.24.3";
49
+ declare const MCP_PIN_SPEC = "@mushi-mushi/mcp@0.24.5";
50
50
  interface StdioConfig {
51
51
  command: string;
52
52
  args: string[];
package/dist/clients.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-F65T4IGT.js";
9
9
 
10
10
  // src/clients.ts
11
- var MCP_PIN_SPEC = "@mushi-mushi/mcp@0.24.3";
11
+ var MCP_PIN_SPEC = "@mushi-mushi/mcp@0.24.5";
12
12
  var PIN_SPEC_RE = /^@mushi-mushi\/mcp@\d+\.\d+\.\d+$/;
13
13
  function pinOf(pinSpec) {
14
14
  return pinSpec && PIN_SPEC_RE.test(pinSpec) ? pinSpec : MCP_PIN_SPEC;
package/dist/index.js CHANGED
@@ -812,7 +812,7 @@ var TDD_TOOL_CATALOG = [
812
812
  {
813
813
  name: "list_byok_keys",
814
814
  title: "List your API key pool",
815
- description: "List the project's BYOK API keys grouped by provider (anthropic | openai | firecrawl | browserbase | cursor | supabase). Returns pooled { keys: [{ id, provider_slug, label, priority, status, cooldown_until, test_status, key_hint, base_url, last_tested_at, last_used_at }] } plus read-only { legacyKeys } metadata for credentials saved before the pooled lifecycle \u2014 never the raw secret. Read-only. Use to see which keys are validated, active, pending, legacy, or rate-limited; use add_byok_key to add one.",
815
+ description: "List the project's BYOK API keys grouped by provider (anthropic | openai | openrouter | firecrawl | browserbase | cursor | supabase). Returns pooled { keys: [{ id, provider_slug, label, priority, status, cooldown_until, test_status, key_hint, base_url, last_tested_at, last_used_at }] } plus read-only { legacyKeys } metadata for credentials saved before the pooled lifecycle \u2014 never the raw secret. Read-only. Use to see which keys are validated, active, pending, legacy, or rate-limited; use add_byok_key to add one.",
816
816
  scope: "mcp:read",
817
817
  hints: { readOnly: true, idempotent: true, openWorld: true },
818
818
  useCase: "Which API keys are active and which are rate-limited?"
@@ -820,7 +820,7 @@ var TDD_TOOL_CATALOG = [
820
820
  {
821
821
  name: "add_byok_key",
822
822
  title: "Add an API key",
823
- description: "Add and immediately validate a BYOK API key for anthropic | openai | firecrawl | browserbase | cursor | supabase (a scoped, read-only Supabase access token, checked against the linked supabase_project_ref). The raw key is stored encrypted in Supabase Vault and never returned; failed probes remain quarantined. Optional baseUrl is accepted only for allow-listed OpenAI-compatible HTTPS providers. Write; NOT idempotent.",
823
+ description: "Add and immediately validate a BYOK API key for anthropic | openai | openrouter | firecrawl | browserbase | cursor | supabase (a scoped, read-only Supabase access token, checked against the linked supabase_project_ref). The raw key is stored encrypted in Supabase Vault and never returned; failed probes remain quarantined. Optional baseUrl is accepted only for allow-listed OpenAI-compatible HTTPS providers. Write; NOT idempotent.",
824
824
  scope: "mcp:write",
825
825
  hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
826
826
  useCase: "Add a backup Anthropic key to the pool."
@@ -1674,7 +1674,7 @@ var MUSHI_DOCS_INDEX = [
1674
1674
  route: "/admin/inventory",
1675
1675
  markdown: "admin/inventory.md",
1676
1676
  keywords: ["admin", "inventory", "user", "stories"],
1677
- headings: ["What you see", "Run gates / Run crawler from a row", "SDK-driven discovery", "Surface mode in the graph", "Five gates", "Synthetic monitor", "Spec traceability \u2014 every fix carries the originating Action", "See also"],
1677
+ headings: ["What you see", "Run gates / Run crawler", "SDK-driven discovery", "Surface mode in the graph", "Five gates", "Synthetic monitor", "Spec traceability \u2014 every fix carries the originating Action", "See also"],
1678
1678
  excerpt: "The User stories page manages your inventory.yaml \u2014 every page, action and story your app should have \u2014 and shows which of them the gates cover."
1679
1679
  },
1680
1680
  {
@@ -1929,6 +1929,15 @@ var MUSHI_DOCS_INDEX = [
1929
1929
  headings: ["Providers", "Configuring a custom bucket", "Required IAM permissions (S3)", "Required R2 permissions", "Required GCS permissions", "Data residency", "Related pages"],
1930
1930
  excerpt: "The Storage page chooses where Mushi keeps report attachments and recordings \u2014 managed storage, or your own bucket for residency or cost."
1931
1931
  },
1932
+ {
1933
+ title: "Team",
1934
+ url: docUrl("/admin/team"),
1935
+ route: "/admin/team",
1936
+ markdown: "admin/team.md",
1937
+ keywords: ["admin", "team"],
1938
+ headings: [],
1939
+ excerpt: "The Team page in the Mushi console brings members, billing, AI spend, audit log, single sign-on, compliance and storage together as views of one page."
1940
+ },
1932
1941
  {
1933
1942
  title: "Teams and Members",
1934
1943
  url: docUrl("/admin/teams"),
@@ -1947,6 +1956,15 @@ var MUSHI_DOCS_INDEX = [
1947
1956
  headings: ["Metrics row", "User directory", "User detail drawer", "API", "Related pages"],
1948
1957
  excerpt: "The Users page is an operator-only directory of every Mushi account with plan, MRR and churn; other visitors see a not-found page instead."
1949
1958
  },
1959
+ {
1960
+ title: "UX runs",
1961
+ url: docUrl("/admin/ux-runs"),
1962
+ route: "/admin/ux-runs",
1963
+ markdown: "admin/ux-runs.md",
1964
+ keywords: ["admin", "ux-runs", "runs", "ux"],
1965
+ headings: ["Run in the cloud", "What you see", "File as bug", "Where the changes are"],
1966
+ excerpt: "Each screen your coding agent worked on in a mushi ux run, with its plan, every attempt, before and after screenshots, and what was kept."
1967
+ },
1950
1968
  {
1951
1969
  title: "Voice intake",
1952
1970
  url: docUrl("/admin/voice"),
@@ -3123,8 +3141,8 @@ var MUSHI_DOCS_INDEX = [
3123
3141
  route: "/security/byok",
3124
3142
  markdown: "security/byok.md",
3125
3143
  keywords: ["security", "byok", "bring-your-own-key"],
3126
- headings: ["Setup", "What uses the key", "Audit trail", "Rotation", "Langfuse trace attribution"],
3127
- excerpt: "Use your own Anthropic or OpenAI API key for a Mushi project, so every classification, judge and fix run bills to your provider account."
3144
+ headings: ["Setup", "What uses the key", "OpenRouter", "Audit trail", "Rotation", "Langfuse trace attribution"],
3145
+ excerpt: "Use your own Anthropic, OpenAI or OpenRouter key for a Mushi project, so every diagnosis, fix and grading run bills to your provider account."
3128
3146
  },
3129
3147
  {
3130
3148
  title: "Data residency",
@@ -6693,7 +6711,7 @@ Be specific. No generic advice.`
6693
6711
  annotations: annotationsFor("add_byok_key", TDD_TOOL_CATALOG),
6694
6712
  inputSchema: z.object({
6695
6713
  projectId: z.string().describe("Project id"),
6696
- provider: z.enum(["anthropic", "openai", "firecrawl", "browserbase", "cursor", "supabase"]).describe("Provider slug"),
6714
+ provider: z.enum(["anthropic", "openai", "openrouter", "firecrawl", "browserbase", "cursor", "supabase"]).describe("Provider slug"),
6697
6715
  key: z.string().min(8).max(4096).describe("The API key value to add"),
6698
6716
  label: z.string().optional().describe("Human-readable label for this key"),
6699
6717
  priority: z.number().int().min(0).max(1e4).optional().describe("Priority for ordering (lower = higher priority)"),
@@ -7523,7 +7541,7 @@ function createSetupModeServer(config) {
7523
7541
  features: "all",
7524
7542
  ...config.fetch ? { fetch: config.fetch } : {},
7525
7543
  ...config.timeoutMs ? { timeoutMs: config.timeoutMs } : {},
7526
- instructions: "Mushi is running in setup mode: no API key is configured, so only search_mushi_docs, get_mushi_doc and diagnose_setup work. Call diagnose_setup for the exact steps to connect (run `npx mushi-mushi` or `mushi login`, or put MUSHI_API_KEY in this server's env block), then restart the MCP server."
7544
+ instructions: config.reason === "sdk-key" ? "Mushi is running in setup mode: the configured API key is an SDK key (report:write). It can send bug reports but not read them, so only search_mushi_docs, get_mushi_doc and diagnose_setup work. Call diagnose_setup for how to mint an MCP key (mcp:read), then restart the MCP server." : "Mushi is running in setup mode: no API key is configured, so only search_mushi_docs, get_mushi_doc and diagnose_setup work. Call diagnose_setup for the exact steps to connect (run `npx mushi-mushi` or `mushi login`, or put MUSHI_API_KEY in this server's env block), then restart the MCP server."
7527
7545
  });
7528
7546
  const internals = server;
7529
7547
  for (const [name, tool] of Object.entries(internals._registeredTools)) {
@@ -7538,7 +7556,8 @@ function createSetupModeServer(config) {
7538
7556
  }
7539
7557
  const spec = TOOL_CATALOG.find((t) => t.name === "diagnose_setup");
7540
7558
  if (!spec) throw new Error("[mushi-mcp] diagnose_setup is missing from TOOL_CATALOG");
7541
- const nextAction = "Run `npx mushi-mushi` in your project (signs you in and writes the key) or `mushi login`, then restart this MCP server.";
7559
+ const sdkKey = config.reason === "sdk-key";
7560
+ const nextAction = sdkKey ? `Mint an MCP key in the console (${MUSHI_CONSOLE_URL}/mcp \u2192 "Mint mcp:read key") or run \`mushi login\`, put it in MUSHI_API_KEY for this server, then restart it.` : "Run `npx mushi-mushi` in your project (signs you in and writes the key) or `mushi login`, then restart this MCP server.";
7542
7561
  server.registerTool(
7543
7562
  "diagnose_setup",
7544
7563
  {
@@ -7560,7 +7579,12 @@ function createSetupModeServer(config) {
7560
7579
  ready: false,
7561
7580
  mode: "setup",
7562
7581
  steps: [
7563
- {
7582
+ sdkKey ? {
7583
+ label: "MCP server key can read reports (mcp:read)",
7584
+ complete: false,
7585
+ required: true,
7586
+ hint: `${nextAction} The SDK key (report:write) belongs in your app; MCP and the CLI need a key with mcp:read, or mcp:write to also triage and dispatch fixes.`
7587
+ } : {
7564
7588
  label: "MCP server has an API key",
7565
7589
  complete: false,
7566
7590
  required: true,
@@ -7577,6 +7601,50 @@ function createSetupModeServer(config) {
7577
7601
  return server;
7578
7602
  }
7579
7603
 
7604
+ // src/key-scopes.ts
7605
+ async function fetchKeyScopes(opts) {
7606
+ const doFetch = opts.fetch ?? fetch;
7607
+ try {
7608
+ const res = await doFetch(`${opts.apiEndpoint.replace(/\/+$/, "")}/v1/sync/whoami`, {
7609
+ headers: {
7610
+ "X-Mushi-Api-Key": opts.apiKey,
7611
+ ...opts.projectId ? { "X-Mushi-Project-Id": opts.projectId } : {}
7612
+ },
7613
+ signal: AbortSignal.timeout(opts.timeoutMs ?? 5e3)
7614
+ });
7615
+ if (!res.ok) return null;
7616
+ const body = await res.json();
7617
+ const scopes = body?.data?.scopes;
7618
+ if (!Array.isArray(scopes)) return null;
7619
+ return scopes.filter((s) => typeof s === "string");
7620
+ } catch {
7621
+ return null;
7622
+ }
7623
+ }
7624
+ function decideScopes(keyScopes, configured) {
7625
+ if (keyScopes === null) return { kind: "serve", scopes: configured };
7626
+ const granted = /* @__PURE__ */ new Set();
7627
+ if (keyScopes.includes("mcp:write")) {
7628
+ granted.add("mcp:read");
7629
+ granted.add("mcp:write");
7630
+ } else if (keyScopes.includes("mcp:read")) {
7631
+ granted.add("mcp:read");
7632
+ }
7633
+ if (granted.size === 0) return { kind: "sdk-key", keyScopes };
7634
+ return { kind: "serve", scopes: configured.filter((s) => granted.has(s)) };
7635
+ }
7636
+ function sdkKeyReport(keyScopes, consoleUrl) {
7637
+ const held = keyScopes.length > 0 ? keyScopes.join(", ") : "none";
7638
+ return [
7639
+ "",
7640
+ `[mushi-mcp] This API key has scopes: ${held}. It can send bug reports (the SDK key) but not read them,`,
7641
+ " so the MCP tools would all be refused. Serving setup mode.",
7642
+ ` Fix: mint an MCP key in the console (${consoleUrl}/mcp \u2192 "Mint mcp:read key"),`,
7643
+ " or run `mushi login`, then put it in MUSHI_API_KEY for this server and restart it.",
7644
+ ""
7645
+ ].join("\n");
7646
+ }
7647
+
7580
7648
  // src/inventory-poll.ts
7581
7649
  function startInventoryPoll(options) {
7582
7650
  const doFetch = options.fetch ?? globalThis.fetch;
@@ -7836,6 +7904,23 @@ async function main() {
7836
7904
  );
7837
7905
  }
7838
7906
  }
7907
+ let scopes = SCOPES;
7908
+ if (!SCOPES_RAW) {
7909
+ const keyScopes = await fetchKeyScopes({ apiEndpoint: API_ENDPOINT, apiKey: API_KEY, projectId: PROJECT_ID || void 0 });
7910
+ const decision = decideScopes(keyScopes, SCOPES);
7911
+ if (decision.kind === "sdk-key") {
7912
+ const report = sdkKeyReport(decision.keyScopes, MUSHI_CONSOLE_URL);
7913
+ process.stderr.write(report);
7914
+ log.warn("The API key has no MCP scope (mcp:read / mcp:write) \u2014 serving setup mode.", {
7915
+ keyScopes: decision.keyScopes.join(",")
7916
+ });
7917
+ serveUntilClosed(serveStdio(() => createSetupModeServer({ version: VERSION, missingKeyReport: report, reason: "sdk-key" }), {
7918
+ onerror: (err) => log.error("stdio transport error", { err: String(err) })
7919
+ }));
7920
+ return;
7921
+ }
7922
+ scopes = decision.scopes;
7923
+ }
7839
7924
  const mode = PROJECT_ID ? "single-project" : "account";
7840
7925
  if (!PROJECT_ID) {
7841
7926
  log.info(
@@ -7847,7 +7932,7 @@ async function main() {
7847
7932
  mode,
7848
7933
  endpoint: API_ENDPOINT,
7849
7934
  hasProjectId: !!PROJECT_ID,
7850
- scopes: SCOPES.join(",")
7935
+ scopes: scopes.join(",")
7851
7936
  });
7852
7937
  let server;
7853
7938
  const handle = serveStdio(
@@ -7857,7 +7942,7 @@ async function main() {
7857
7942
  apiEndpoint: API_ENDPOINT,
7858
7943
  apiKey: API_KEY,
7859
7944
  projectId: PROJECT_ID || void 0,
7860
- scopes: SCOPES,
7945
+ scopes,
7861
7946
  features: FEATURES
7862
7947
  });
7863
7948
  log.debug("[mushi-mcp] server instance created", { era: ctx.era });
package/dist/server.d.ts CHANGED
@@ -63,10 +63,16 @@ interface MushiServerConfig {
63
63
  declare function createMushiServer(config: MushiServerConfig): McpServer;
64
64
  /** Tools that work before an API key exists: they read only the public docs. */
65
65
  declare const SETUP_MODE_TOOLS: readonly ["search_mushi_docs", "get_mushi_doc", "diagnose_setup"];
66
+ declare const MUSHI_CONSOLE_URL = "https://kensaur.us/mushi-mushi/admin";
66
67
  interface SetupModeServerConfig {
67
68
  version: string;
68
69
  /** Why there is no key, as printed to stderr (sources checked, config path). */
69
70
  missingKeyReport: string;
71
+ /**
72
+ * `missing-key` (default): no key reached the server. `sdk-key`: a valid
73
+ * key without mcp:read or mcp:write, such as the report:write SDK key.
74
+ */
75
+ reason?: 'missing-key' | 'sdk-key';
70
76
  fetch?: typeof fetch;
71
77
  timeoutMs?: number;
72
78
  }
@@ -78,4 +84,4 @@ interface SetupModeServerConfig {
78
84
  */
79
85
  declare function createSetupModeServer(config: SetupModeServerConfig): McpServer;
80
86
 
81
- export { MushiApiError, type MushiServerConfig, SETUP_MODE_TOOLS, type SetupModeServerConfig, createMushiServer, createSetupModeServer, resolveTimeoutMsFromEnv };
87
+ export { MUSHI_CONSOLE_URL, MushiApiError, type MushiServerConfig, SETUP_MODE_TOOLS, type SetupModeServerConfig, createMushiServer, createSetupModeServer, resolveTimeoutMsFromEnv };
package/dist/server.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  TDD_TOOL_CATALOG,
5
5
  TOOL_CATALOG,
6
6
  routeUseMushiIntent
7
- } from "./chunk-3IVSUYFV.js";
7
+ } from "./chunk-V3M4GZBV.js";
8
8
  import {
9
9
  MUSHI_SERVER_METADATA
10
10
  } from "./chunk-FJRPC4VR.js";
@@ -284,7 +284,7 @@ var MUSHI_DOCS_INDEX = [
284
284
  route: "/admin/inventory",
285
285
  markdown: "admin/inventory.md",
286
286
  keywords: ["admin", "inventory", "user", "stories"],
287
- headings: ["What you see", "Run gates / Run crawler from a row", "SDK-driven discovery", "Surface mode in the graph", "Five gates", "Synthetic monitor", "Spec traceability \u2014 every fix carries the originating Action", "See also"],
287
+ headings: ["What you see", "Run gates / Run crawler", "SDK-driven discovery", "Surface mode in the graph", "Five gates", "Synthetic monitor", "Spec traceability \u2014 every fix carries the originating Action", "See also"],
288
288
  excerpt: "The User stories page manages your inventory.yaml \u2014 every page, action and story your app should have \u2014 and shows which of them the gates cover."
289
289
  },
290
290
  {
@@ -539,6 +539,15 @@ var MUSHI_DOCS_INDEX = [
539
539
  headings: ["Providers", "Configuring a custom bucket", "Required IAM permissions (S3)", "Required R2 permissions", "Required GCS permissions", "Data residency", "Related pages"],
540
540
  excerpt: "The Storage page chooses where Mushi keeps report attachments and recordings \u2014 managed storage, or your own bucket for residency or cost."
541
541
  },
542
+ {
543
+ title: "Team",
544
+ url: docUrl("/admin/team"),
545
+ route: "/admin/team",
546
+ markdown: "admin/team.md",
547
+ keywords: ["admin", "team"],
548
+ headings: [],
549
+ excerpt: "The Team page in the Mushi console brings members, billing, AI spend, audit log, single sign-on, compliance and storage together as views of one page."
550
+ },
542
551
  {
543
552
  title: "Teams and Members",
544
553
  url: docUrl("/admin/teams"),
@@ -557,6 +566,15 @@ var MUSHI_DOCS_INDEX = [
557
566
  headings: ["Metrics row", "User directory", "User detail drawer", "API", "Related pages"],
558
567
  excerpt: "The Users page is an operator-only directory of every Mushi account with plan, MRR and churn; other visitors see a not-found page instead."
559
568
  },
569
+ {
570
+ title: "UX runs",
571
+ url: docUrl("/admin/ux-runs"),
572
+ route: "/admin/ux-runs",
573
+ markdown: "admin/ux-runs.md",
574
+ keywords: ["admin", "ux-runs", "runs", "ux"],
575
+ headings: ["Run in the cloud", "What you see", "File as bug", "Where the changes are"],
576
+ excerpt: "Each screen your coding agent worked on in a mushi ux run, with its plan, every attempt, before and after screenshots, and what was kept."
577
+ },
560
578
  {
561
579
  title: "Voice intake",
562
580
  url: docUrl("/admin/voice"),
@@ -1733,8 +1751,8 @@ var MUSHI_DOCS_INDEX = [
1733
1751
  route: "/security/byok",
1734
1752
  markdown: "security/byok.md",
1735
1753
  keywords: ["security", "byok", "bring-your-own-key"],
1736
- headings: ["Setup", "What uses the key", "Audit trail", "Rotation", "Langfuse trace attribution"],
1737
- excerpt: "Use your own Anthropic or OpenAI API key for a Mushi project, so every classification, judge and fix run bills to your provider account."
1754
+ headings: ["Setup", "What uses the key", "OpenRouter", "Audit trail", "Rotation", "Langfuse trace attribution"],
1755
+ excerpt: "Use your own Anthropic, OpenAI or OpenRouter key for a Mushi project, so every diagnosis, fix and grading run bills to your provider account."
1738
1756
  },
1739
1757
  {
1740
1758
  title: "Data residency",
@@ -5369,7 +5387,7 @@ Be specific. No generic advice.`
5369
5387
  annotations: annotationsFor("add_byok_key", TDD_TOOL_CATALOG),
5370
5388
  inputSchema: z.object({
5371
5389
  projectId: z.string().describe("Project id"),
5372
- provider: z.enum(["anthropic", "openai", "firecrawl", "browserbase", "cursor", "supabase"]).describe("Provider slug"),
5390
+ provider: z.enum(["anthropic", "openai", "openrouter", "firecrawl", "browserbase", "cursor", "supabase"]).describe("Provider slug"),
5373
5391
  key: z.string().min(8).max(4096).describe("The API key value to add"),
5374
5392
  label: z.string().optional().describe("Human-readable label for this key"),
5375
5393
  priority: z.number().int().min(0).max(1e4).optional().describe("Priority for ordering (lower = higher priority)"),
@@ -6199,7 +6217,7 @@ function createSetupModeServer(config) {
6199
6217
  features: "all",
6200
6218
  ...config.fetch ? { fetch: config.fetch } : {},
6201
6219
  ...config.timeoutMs ? { timeoutMs: config.timeoutMs } : {},
6202
- instructions: "Mushi is running in setup mode: no API key is configured, so only search_mushi_docs, get_mushi_doc and diagnose_setup work. Call diagnose_setup for the exact steps to connect (run `npx mushi-mushi` or `mushi login`, or put MUSHI_API_KEY in this server's env block), then restart the MCP server."
6220
+ instructions: config.reason === "sdk-key" ? "Mushi is running in setup mode: the configured API key is an SDK key (report:write). It can send bug reports but not read them, so only search_mushi_docs, get_mushi_doc and diagnose_setup work. Call diagnose_setup for how to mint an MCP key (mcp:read), then restart the MCP server." : "Mushi is running in setup mode: no API key is configured, so only search_mushi_docs, get_mushi_doc and diagnose_setup work. Call diagnose_setup for the exact steps to connect (run `npx mushi-mushi` or `mushi login`, or put MUSHI_API_KEY in this server's env block), then restart the MCP server."
6203
6221
  });
6204
6222
  const internals = server;
6205
6223
  for (const [name, tool] of Object.entries(internals._registeredTools)) {
@@ -6214,7 +6232,8 @@ function createSetupModeServer(config) {
6214
6232
  }
6215
6233
  const spec = TOOL_CATALOG.find((t) => t.name === "diagnose_setup");
6216
6234
  if (!spec) throw new Error("[mushi-mcp] diagnose_setup is missing from TOOL_CATALOG");
6217
- const nextAction = "Run `npx mushi-mushi` in your project (signs you in and writes the key) or `mushi login`, then restart this MCP server.";
6235
+ const sdkKey = config.reason === "sdk-key";
6236
+ const nextAction = sdkKey ? `Mint an MCP key in the console (${MUSHI_CONSOLE_URL}/mcp \u2192 "Mint mcp:read key") or run \`mushi login\`, put it in MUSHI_API_KEY for this server, then restart it.` : "Run `npx mushi-mushi` in your project (signs you in and writes the key) or `mushi login`, then restart this MCP server.";
6218
6237
  server.registerTool(
6219
6238
  "diagnose_setup",
6220
6239
  {
@@ -6236,7 +6255,12 @@ function createSetupModeServer(config) {
6236
6255
  ready: false,
6237
6256
  mode: "setup",
6238
6257
  steps: [
6239
- {
6258
+ sdkKey ? {
6259
+ label: "MCP server key can read reports (mcp:read)",
6260
+ complete: false,
6261
+ required: true,
6262
+ hint: `${nextAction} The SDK key (report:write) belongs in your app; MCP and the CLI need a key with mcp:read, or mcp:write to also triage and dispatch fixes.`
6263
+ } : {
6240
6264
  label: "MCP server has an API key",
6241
6265
  complete: false,
6242
6266
  required: true,
@@ -6253,6 +6277,7 @@ function createSetupModeServer(config) {
6253
6277
  return server;
6254
6278
  }
6255
6279
  export {
6280
+ MUSHI_CONSOLE_URL,
6256
6281
  MushiApiError,
6257
6282
  SETUP_MODE_TOOLS,
6258
6283
  createMushiServer,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mushi-mushi/mcp",
3
3
  "mcpName": "io.github.kensaurus/mushi-mushi",
4
- "version": "0.24.3",
4
+ "version": "0.24.5",
5
5
  "license": "MIT",
6
6
  "description": "MCP server for Cursor, Claude Code and Copilot. The bug mediator for AI-built apps: plain-English diagnosis + a ready fix, in your editor.",
7
7
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  "@modelcontextprotocol/core": "^2.0.0",
46
46
  "@modelcontextprotocol/server": "^2.0.0",
47
47
  "zod": "^4.4.3",
48
- "@mushi-mushi/core": "^1.31.0"
48
+ "@mushi-mushi/core": "^1.32.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@sentry/node": "^10.57.0"