@mushi-mushi/mcp 0.17.0 → 0.17.1
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 +10 -4
- package/dist/branding.js +1 -1
- package/dist/catalog.js +1 -1
- package/dist/{chunk-MM3IMFM4.js → chunk-7UOTJ2LI.js} +21 -21
- package/dist/{chunk-EHB2BGWX.js → chunk-EANW5YTI.js} +3 -1
- package/dist/{chunk-ZX3XIJ7S.js → chunk-PW4AK6SV.js} +1 -0
- package/dist/clients.d.ts +17 -1
- package/dist/clients.js +40 -19
- package/dist/feature-groups.d.ts +1 -1
- package/dist/feature-groups.js +1 -1
- package/dist/index.js +60 -26
- package/dist/server.js +35 -12
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
> **Your AI wrote it. Mushi tells you why it broke.**
|
|
4
4
|
|
|
5
|
-
[
|
|
5
|
+
[](https://kensaur.us/mushi-mushi/docs/connect)
|
|
6
|
+
[](https://kensaur.us/mushi-mushi/docs/connect)
|
|
7
|
+
[](https://kensaur.us/mushi-mushi/docs/connect)
|
|
8
|
+
[](https://www.npmjs.com/package/@mushi-mushi/mcp)
|
|
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.
|
|
6
11
|
|
|
7
12
|
Wire it into Cursor, Claude Code, or any MCP client in one command:
|
|
8
13
|
|
|
@@ -259,7 +264,7 @@ Named templates the MCP client surfaces in its slash-menu. Each one bakes in the
|
|
|
259
264
|
|---|---|---|---|
|
|
260
265
|
| `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). |
|
|
261
266
|
| `MUSHI_PROJECT_ID` | yes | — | UUID from the admin console URL (`/projects/<uuid>/...`) or the reveal card. |
|
|
262
|
-
| `MUSHI_API_ENDPOINT` | no | `https://
|
|
267
|
+
| `MUSHI_API_ENDPOINT` | no | `https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api` | Override only if you self-host. Localhost: `http://localhost:54321/functions/v1/api`. |
|
|
263
268
|
|
|
264
269
|
### Storing the key in `.env.local`
|
|
265
270
|
|
|
@@ -269,7 +274,7 @@ The MCP binary reads these three vars from `process.env` on spawn — that means
|
|
|
269
274
|
|
|
270
275
|
```bash
|
|
271
276
|
# Mushi MCP — drop into .env.local (gitignored). The MCP binary picks these up on spawn.
|
|
272
|
-
MUSHI_API_ENDPOINT=https://
|
|
277
|
+
MUSHI_API_ENDPOINT=https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api
|
|
273
278
|
MUSHI_PROJECT_ID=<your-uuid>
|
|
274
279
|
MUSHI_API_KEY=mushi_live_…
|
|
275
280
|
```
|
|
@@ -459,6 +464,7 @@ Both are complementary — use Sentry for exception noise, Mushi for "the user s
|
|
|
459
464
|
|
|
460
465
|
## See also
|
|
461
466
|
|
|
467
|
+
- [GTM distribution runbook](../../docs/marketing/GTM-DISTRIBUTION.md) — MCP registry, Glama, Connect, cursor.directory, release checklist.
|
|
462
468
|
- [V5.3 whitepaper §2.10](../../MushiMushi_Whitepaper_V5.md) — the agentic fix architecture this server feeds into.
|
|
463
469
|
- [`@mushi-mushi/agents`](../agents/README.md) — orchestrator that consumes MCP-exposed fix workers.
|
|
464
470
|
|
|
@@ -470,4 +476,4 @@ MIT
|
|
|
470
476
|
<!-- mushi-readme-stats-footer -->
|
|
471
477
|
---
|
|
472
478
|
|
|
473
|
-
<sub>Monorepo scale (June 2026):
|
|
479
|
+
<sub>Monorepo scale (June 2026): 51 edge functions · 298 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/branding.js
CHANGED
package/dist/catalog.js
CHANGED
|
@@ -4,10 +4,10 @@ var TOOL_CATALOG = [
|
|
|
4
4
|
{
|
|
5
5
|
name: "get_recent_reports",
|
|
6
6
|
title: "Recent bug reports",
|
|
7
|
-
description: "List recent bug reports with optional filters (status / category / severity). Use this to
|
|
7
|
+
description: "List recent bug reports with optional filters (status / category / severity). Use this to see what is waiting in your reports inbox right now.",
|
|
8
8
|
scope: "mcp:read",
|
|
9
9
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
10
|
-
useCase: "What landed in my
|
|
10
|
+
useCase: "What landed in my bug queue today?"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
name: "get_report_detail",
|
|
@@ -134,7 +134,7 @@ var TOOL_CATALOG = [
|
|
|
134
134
|
{
|
|
135
135
|
name: "setup_check",
|
|
136
136
|
title: "Dispatch preflight check",
|
|
137
|
-
description: "[Deprecated \u2014 use diagnose_setup with mode=dispatch or diagnose_connection.] Run the 4 **dispatch-readiness** checks for a project and return their pass/fail status (GitHub repo connected, codebase indexed, Anthropic
|
|
137
|
+
description: "[Deprecated \u2014 use diagnose_setup with mode=dispatch or diagnose_connection.] Run the 4 **dispatch-readiness** checks for a project and return their pass/fail status (GitHub repo connected, codebase indexed, your Anthropic API key present, autofix enabled). Also returns the target repo URL when GitHub is connected.",
|
|
138
138
|
scope: "mcp:read",
|
|
139
139
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
140
140
|
useCase: "Is this project ready to auto-fix bugs? What is blocking dispatch?"
|
|
@@ -184,7 +184,7 @@ var TOOL_CATALOG = [
|
|
|
184
184
|
{
|
|
185
185
|
name: "dispatch_fix",
|
|
186
186
|
title: "Dispatch Mushi fix agent",
|
|
187
|
-
description: '
|
|
187
|
+
description: 'Start the Mushi fix agent for a classified report. Set agent="cursor_cloud" to dispatch a Cursor Cloud Agent that opens a signed draft PR. Returns a fix_attempt id; poll get_fix_timeline for progress.',
|
|
188
188
|
scope: "mcp:write",
|
|
189
189
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
190
190
|
useCase: "Let the in-repo agent attempt this fix for me (or: dispatch a Cursor Cloud Agent)."
|
|
@@ -200,7 +200,7 @@ var TOOL_CATALOG = [
|
|
|
200
200
|
{
|
|
201
201
|
name: "test_gen_from_report",
|
|
202
202
|
title: "Generate Playwright test from report",
|
|
203
|
-
description: "
|
|
203
|
+
description: "Generate a Playwright spec from a classified report using your project LLM key and open a draft PR. Requires inventory_v2 + GitHub + LLM keys.",
|
|
204
204
|
scope: "mcp:write",
|
|
205
205
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
206
206
|
useCase: "Turn this regression report into an E2E test PR."
|
|
@@ -232,7 +232,7 @@ var TOOL_CATALOG = [
|
|
|
232
232
|
{
|
|
233
233
|
name: "reopen_report",
|
|
234
234
|
title: "Reopen report (operator)",
|
|
235
|
-
description: "Move a report to reopened for regression
|
|
235
|
+
description: "Move a report to reopened for regression review.",
|
|
236
236
|
scope: "mcp:write",
|
|
237
237
|
hints: { readOnly: false, destructive: false, idempotent: true, openWorld: true },
|
|
238
238
|
useCase: "Reopen a regression the reporter flagged as not fixed."
|
|
@@ -290,10 +290,10 @@ var TOOL_CATALOG = [
|
|
|
290
290
|
{
|
|
291
291
|
name: "get_project_context",
|
|
292
292
|
title: "Project context snapshot",
|
|
293
|
-
description: "Return a rich context snapshot for a project: name, repo URL, SDK heartbeat, ingest status, open report count, autofix readiness,
|
|
293
|
+
description: "Return a rich context snapshot for a project: name, repo URL, SDK heartbeat, ingest status, open report count, autofix readiness, your LLM key config, plan tier, and active integration health. Equivalent to a merged preflight + activation + settings read. Agents should call this at the start of a review session to orient themselves.",
|
|
294
294
|
scope: "mcp:read",
|
|
295
295
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
296
|
-
useCase: "Give me a status overview of this project before I start
|
|
296
|
+
useCase: "Give me a status overview of this project before I start reviewing bugs."
|
|
297
297
|
},
|
|
298
298
|
{
|
|
299
299
|
name: "get_pipeline_logs",
|
|
@@ -314,7 +314,7 @@ var TOOL_CATALOG = [
|
|
|
314
314
|
{
|
|
315
315
|
name: "triage_issue",
|
|
316
316
|
title: "Triage issue end-to-end",
|
|
317
|
-
description: 'Read-only
|
|
317
|
+
description: 'Read-only combined tool: merges report detail, evidence, similar bugs, fix context, blast radius, and recent pipeline logs for a report into a single structured review packet. Returns a prioritised list of recommended next actions (investigate, dispatch_fix, group_with, dismiss). Equivalent to a Sentry "Analyze with Seer" flow grounded in user-felt reports. Pass report_id to kick off review. Call this before dispatch_fix.',
|
|
318
318
|
scope: "mcp:read",
|
|
319
319
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
320
320
|
useCase: "Analyze this bug report end-to-end and tell me what to do."
|
|
@@ -341,8 +341,8 @@ var RESOURCE_CATALOG = [
|
|
|
341
341
|
{
|
|
342
342
|
name: "project_dashboard",
|
|
343
343
|
uri: "project://dashboard",
|
|
344
|
-
title: "
|
|
345
|
-
description: "
|
|
344
|
+
title: "Loop dashboard snapshot",
|
|
345
|
+
description: "Loop health snapshot \u2014 stage counts, bottleneck, recent activity (same payload the admin console polls).",
|
|
346
346
|
scope: "mcp:read"
|
|
347
347
|
},
|
|
348
348
|
{
|
|
@@ -363,14 +363,14 @@ var RESOURCE_CATALOG = [
|
|
|
363
363
|
name: "privacy_status",
|
|
364
364
|
uri: "privacy://status",
|
|
365
365
|
title: "Privacy posture",
|
|
366
|
-
description: "Returns the privacy posture for this project: storage region, LLM provider, whether
|
|
366
|
+
description: "Returns the privacy posture for this project: storage region, LLM provider, whether your own LLM key is configured, data retention window, and last audit timestamp. Agents should read this before dispatching a fix to confirm that client data stays within the expected boundary. Reads as project data does not leave the project's own LLM account when byok_configured=true.",
|
|
367
367
|
scope: "mcp:read"
|
|
368
368
|
},
|
|
369
369
|
{
|
|
370
370
|
name: "evolution_history",
|
|
371
371
|
uri: "evolution://history",
|
|
372
372
|
title: "Evolution history",
|
|
373
|
-
description: "Returns the project's last 30 days of judge scores, prompt promotions, fixed-bug count, and lesson inductions. Agents can read this to see whether the loop is converging (rising judge scores, falling recurrence) or stalling (flat scores, same bugs re-appearing). Use before
|
|
373
|
+
description: "Returns the project's last 30 days of judge scores, prompt promotions, fixed-bug count, and lesson inductions. Agents can read this to see whether the loop is converging (rising judge scores, falling recurrence) or stalling (flat scores, same bugs re-appearing). Use before review to understand which bug classes the loop has already learned to handle, and which still need human attention.",
|
|
374
374
|
scope: "mcp:read"
|
|
375
375
|
},
|
|
376
376
|
{
|
|
@@ -384,7 +384,7 @@ var RESOURCE_CATALOG = [
|
|
|
384
384
|
name: "project_integration_health",
|
|
385
385
|
uri: "project://integration-health",
|
|
386
386
|
title: "Integration health",
|
|
387
|
-
description: "Live health status of every configured
|
|
387
|
+
description: "Live health status of every configured integration channel (Sentry, GitHub, LangFuse, PagerDuty, \u2026). Check this before dispatching a fix to fail-fast on broken channels rather than burning LLM budget and discovering the failure mid-run.",
|
|
388
388
|
scope: "mcp:read"
|
|
389
389
|
},
|
|
390
390
|
{
|
|
@@ -448,8 +448,8 @@ var TDD_TOOL_CATALOG = [
|
|
|
448
448
|
},
|
|
449
449
|
{
|
|
450
450
|
name: "improve_qa_story",
|
|
451
|
-
title: "
|
|
452
|
-
description: "
|
|
451
|
+
title: "Auto-improve a failing QA story",
|
|
452
|
+
description: "Find recently failed qa_story_runs and use Claude to write improved test scripts. New tests are created with source=pdca and approval gated by the original story's automation_mode.",
|
|
453
453
|
scope: "mcp:write",
|
|
454
454
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
455
455
|
useCase: "Fix my failing QA tests automatically."
|
|
@@ -464,16 +464,16 @@ var TDD_TOOL_CATALOG = [
|
|
|
464
464
|
},
|
|
465
465
|
{
|
|
466
466
|
name: "list_byok_keys",
|
|
467
|
-
title: "List
|
|
468
|
-
description: "List all
|
|
467
|
+
title: "List your API key pool",
|
|
468
|
+
description: "List all project API keys, grouped by provider. Shows label, priority, status, and cooldown. Never returns the raw key value \u2014 only metadata. Use this to see which keys are active or exhausted.",
|
|
469
469
|
scope: "mcp:read",
|
|
470
470
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
471
471
|
useCase: "Which API keys are active and which are rate-limited?"
|
|
472
472
|
},
|
|
473
473
|
{
|
|
474
474
|
name: "add_byok_key",
|
|
475
|
-
title: "Add
|
|
476
|
-
description: "Add a new API key to the project
|
|
475
|
+
title: "Add an API key",
|
|
476
|
+
description: "Add a new API key to the project pool for a given provider (anthropic, openai, firecrawl, browserbase, cursor). Specify label and priority for ordering. The key is stored encrypted in Supabase Vault.",
|
|
477
477
|
scope: "mcp:write",
|
|
478
478
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
479
479
|
useCase: "Add a backup Anthropic key to the pool."
|
|
@@ -622,7 +622,7 @@ var CODEBASE_TOOL_CATALOG = [
|
|
|
622
622
|
{
|
|
623
623
|
name: "ask_codebase",
|
|
624
624
|
title: "Ask about the indexed codebase",
|
|
625
|
-
description: "Ask a plain-English question about the connected repo. Grounds on pgvector retrieval over project_codebase_files and returns an answer with file:line citations. Requires codebase indexing enabled and
|
|
625
|
+
description: "Ask a plain-English question about the connected repo. Grounds on pgvector retrieval over project_codebase_files and returns an answer with file:line citations. Requires codebase indexing enabled and your Anthropic or OpenAI API key.",
|
|
626
626
|
scope: "mcp:write",
|
|
627
627
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
628
628
|
useCase: "How does authentication work in this repo?"
|
|
@@ -3,7 +3,9 @@ var MUSHI_WEBSITE_URL = "https://kensaur.us/mushi-mushi";
|
|
|
3
3
|
var MUSHI_ICON_PNG_URL = `${MUSHI_WEBSITE_URL}/integrations/mushi-mark-512.png`;
|
|
4
4
|
var MUSHI_ICON_SVG_URL = `${MUSHI_WEBSITE_URL}/favicon.svg`;
|
|
5
5
|
function mcpIconUrl(mcpBaseUrl) {
|
|
6
|
-
|
|
6
|
+
let end = mcpBaseUrl.length;
|
|
7
|
+
while (end > 0 && mcpBaseUrl.charCodeAt(end - 1) === 47) end--;
|
|
8
|
+
const base = mcpBaseUrl.slice(0, end);
|
|
7
9
|
return `${base}?icon=1`;
|
|
8
10
|
}
|
|
9
11
|
var MUSHI_SERVER_ICONS = [
|
package/dist/clients.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { FeatureGroup } from './feature-groups.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* FILE: packages/mcp/src/clients.ts
|
|
3
5
|
* PURPOSE: Shared, pure (React-free) client registry + install-config builders for
|
|
@@ -37,6 +39,7 @@
|
|
|
37
39
|
* - Windsurf uses `serverUrl` for remote HTTP (NOT `url`) — encoding both would break it.
|
|
38
40
|
* - The `cliIde` field drives `mushi setup --ide <cliIde>` in the CLI lane.
|
|
39
41
|
*/
|
|
42
|
+
|
|
40
43
|
interface StdioConfig {
|
|
41
44
|
command: string;
|
|
42
45
|
args: string[];
|
|
@@ -61,6 +64,19 @@ interface McpBuildInput {
|
|
|
61
64
|
endpoint: string;
|
|
62
65
|
/** Hosted Streamable HTTP MCP URL (`RESOLVED_MCP_HTTP_URL`). */
|
|
63
66
|
mcpHttpUrl: string;
|
|
67
|
+
/**
|
|
68
|
+
* Restrict the exposed tool groups. Omitted → each client's existing default
|
|
69
|
+
* (the lean `DEFAULT_FEATURE_GROUPS` for stdio deeplinks; all tools for the
|
|
70
|
+
* config-json clients that historically set no `MUSHI_FEATURES`). The public
|
|
71
|
+
* keyless demo passes an explicit read-only subset here.
|
|
72
|
+
*/
|
|
73
|
+
features?: readonly FeatureGroup[];
|
|
74
|
+
/**
|
|
75
|
+
* Hosted HTTP transport only: append `?read_only=1` so the server hides and
|
|
76
|
+
* blocks write tools regardless of key scope. Used by the public demo on top
|
|
77
|
+
* of an `mcp:read` key for defence in depth. No-op for stdio configs.
|
|
78
|
+
*/
|
|
79
|
+
readOnly?: boolean;
|
|
64
80
|
}
|
|
65
81
|
type McpBuildResult = {
|
|
66
82
|
kind: 'deeplink';
|
|
@@ -91,7 +107,7 @@ interface McpClientDef {
|
|
|
91
107
|
/** Build a stable, unique, human-readable MCP server slug for a project. */
|
|
92
108
|
declare function projectServerName(projectId: string, projectName: string): string;
|
|
93
109
|
declare function buildStdioConfigObj(projectId: string | undefined, apiKey: string, apiEndpoint: string, features?: readonly string[]): StdioConfig;
|
|
94
|
-
declare function buildHttpConfigObj(projectId: string | undefined, apiKey: string, mcpHttpUrl: string, features?: readonly string[]): HttpConfig;
|
|
110
|
+
declare function buildHttpConfigObj(projectId: string | undefined, apiKey: string, mcpHttpUrl: string, features?: readonly string[], readOnly?: boolean): HttpConfig;
|
|
95
111
|
declare const MCP_CLIENTS: McpClientDef[];
|
|
96
112
|
/** Look up a client by id — throws if not found. */
|
|
97
113
|
declare function getMcpClient(id: McpClientId): McpClientDef;
|
package/dist/clients.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MUSHI_ICON_PNG_URL
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EANW5YTI.js";
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_FEATURE_GROUPS,
|
|
6
6
|
appendFeaturesToUrl,
|
|
7
7
|
featuresQueryString
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PW4AK6SV.js";
|
|
9
9
|
|
|
10
10
|
// src/clients.ts
|
|
11
11
|
function projectServerName(projectId, projectName) {
|
|
@@ -27,8 +27,17 @@ function buildStdioConfigObj(projectId, apiKey, apiEndpoint, features = DEFAULT_
|
|
|
27
27
|
icon: MUSHI_ICON_PNG_URL
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
30
|
+
function withReadOnly(baseUrl, readOnly) {
|
|
31
|
+
if (!readOnly) return baseUrl;
|
|
32
|
+
const url = new URL(baseUrl);
|
|
33
|
+
url.searchParams.set("read_only", "1");
|
|
34
|
+
return url.toString();
|
|
35
|
+
}
|
|
36
|
+
function buildHttpConfigObj(projectId, apiKey, mcpHttpUrl, features = DEFAULT_FEATURE_GROUPS, readOnly = false) {
|
|
37
|
+
const url = withReadOnly(
|
|
38
|
+
appendFeaturesToUrl(mcpHttpUrl, features),
|
|
39
|
+
readOnly
|
|
40
|
+
);
|
|
32
41
|
const headers = {
|
|
33
42
|
Authorization: `Bearer ${apiKey}`,
|
|
34
43
|
"X-Mushi-Api-Key": apiKey
|
|
@@ -57,9 +66,9 @@ var MCP_CLIENTS = [
|
|
|
57
66
|
method: "deeplink",
|
|
58
67
|
transport: "stdio",
|
|
59
68
|
cliIde: "cursor",
|
|
60
|
-
build({ projectId, projectName, apiKey, endpoint }) {
|
|
69
|
+
build({ projectId, projectName, apiKey, endpoint, features }) {
|
|
61
70
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
62
|
-
const config = buildStdioConfigObj(projectId, apiKey, endpoint);
|
|
71
|
+
const config = buildStdioConfigObj(projectId, apiKey, endpoint, features);
|
|
63
72
|
return { kind: "deeplink", url: encodeCursorDeeplink(name, config) };
|
|
64
73
|
}
|
|
65
74
|
},
|
|
@@ -70,9 +79,9 @@ var MCP_CLIENTS = [
|
|
|
70
79
|
description: "One-click install via VS Code MCP extension",
|
|
71
80
|
method: "deeplink",
|
|
72
81
|
transport: "stdio",
|
|
73
|
-
build({ projectId, projectName, apiKey, endpoint }) {
|
|
82
|
+
build({ projectId, projectName, apiKey, endpoint, features }) {
|
|
74
83
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
75
|
-
const config = buildStdioConfigObj(projectId, apiKey, endpoint);
|
|
84
|
+
const config = buildStdioConfigObj(projectId, apiKey, endpoint, features);
|
|
76
85
|
return { kind: "deeplink", url: encodeVsCodeDeeplink("vscode", name, config) };
|
|
77
86
|
}
|
|
78
87
|
},
|
|
@@ -83,9 +92,9 @@ var MCP_CLIENTS = [
|
|
|
83
92
|
description: "One-click install via VS Code Insiders MCP extension",
|
|
84
93
|
method: "deeplink",
|
|
85
94
|
transport: "stdio",
|
|
86
|
-
build({ projectId, projectName, apiKey, endpoint }) {
|
|
95
|
+
build({ projectId, projectName, apiKey, endpoint, features }) {
|
|
87
96
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
88
|
-
const config = buildStdioConfigObj(projectId, apiKey, endpoint);
|
|
97
|
+
const config = buildStdioConfigObj(projectId, apiKey, endpoint, features);
|
|
89
98
|
return { kind: "deeplink", url: encodeVsCodeDeeplink("vscode-insiders", name, config) };
|
|
90
99
|
}
|
|
91
100
|
},
|
|
@@ -96,9 +105,12 @@ var MCP_CLIENTS = [
|
|
|
96
105
|
description: "Copy config into ~/.codeium/windsurf/mcp_config.json",
|
|
97
106
|
method: "config-json",
|
|
98
107
|
transport: "http",
|
|
99
|
-
build({ projectId, projectName, apiKey, mcpHttpUrl }) {
|
|
108
|
+
build({ projectId, projectName, apiKey, mcpHttpUrl, features, readOnly }) {
|
|
100
109
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
101
|
-
const url =
|
|
110
|
+
const url = withReadOnly(
|
|
111
|
+
appendFeaturesToUrl(mcpHttpUrl, features ?? DEFAULT_FEATURE_GROUPS),
|
|
112
|
+
readOnly
|
|
113
|
+
);
|
|
102
114
|
const headers = {
|
|
103
115
|
Authorization: `Bearer ${apiKey}`,
|
|
104
116
|
"X-Mushi-Api-Key": apiKey
|
|
@@ -124,12 +136,13 @@ var MCP_CLIENTS = [
|
|
|
124
136
|
description: "Copy config into cline_mcp_settings.json",
|
|
125
137
|
method: "config-json",
|
|
126
138
|
transport: "stdio",
|
|
127
|
-
build({ projectId, projectName, apiKey, endpoint }) {
|
|
139
|
+
build({ projectId, projectName, apiKey, endpoint, features }) {
|
|
128
140
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
129
141
|
const env = {
|
|
130
142
|
MUSHI_API_ENDPOINT: endpoint,
|
|
131
143
|
MUSHI_API_KEY: apiKey
|
|
132
144
|
};
|
|
145
|
+
if (features) env.MUSHI_FEATURES = featuresQueryString(features);
|
|
133
146
|
if (projectId) env.MUSHI_PROJECT_ID = projectId;
|
|
134
147
|
const clineConfig = {
|
|
135
148
|
mcpServers: {
|
|
@@ -152,9 +165,12 @@ var MCP_CLIENTS = [
|
|
|
152
165
|
method: "cli-command",
|
|
153
166
|
transport: "http",
|
|
154
167
|
cliIde: "claude",
|
|
155
|
-
build({ projectId, projectName, apiKey, mcpHttpUrl }) {
|
|
168
|
+
build({ projectId, projectName, apiKey, mcpHttpUrl, features, readOnly }) {
|
|
156
169
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
157
|
-
const url =
|
|
170
|
+
const url = withReadOnly(
|
|
171
|
+
appendFeaturesToUrl(mcpHttpUrl, features ?? DEFAULT_FEATURE_GROUPS),
|
|
172
|
+
readOnly
|
|
173
|
+
);
|
|
158
174
|
const cmd = `claude mcp add --transport http ${name} "${url}" --header "Authorization: Bearer ${apiKey}"`;
|
|
159
175
|
return { kind: "command", text: cmd };
|
|
160
176
|
}
|
|
@@ -166,12 +182,13 @@ var MCP_CLIENTS = [
|
|
|
166
182
|
description: "Copy config into claude_desktop_config.json",
|
|
167
183
|
method: "config-json",
|
|
168
184
|
transport: "stdio",
|
|
169
|
-
build({ projectId, projectName, apiKey, endpoint }) {
|
|
185
|
+
build({ projectId, projectName, apiKey, endpoint, features }) {
|
|
170
186
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
171
187
|
const env = {
|
|
172
188
|
MUSHI_API_ENDPOINT: endpoint,
|
|
173
189
|
MUSHI_API_KEY: apiKey
|
|
174
190
|
};
|
|
191
|
+
if (features) env.MUSHI_FEATURES = featuresQueryString(features);
|
|
175
192
|
if (projectId) env.MUSHI_PROJECT_ID = projectId;
|
|
176
193
|
const desktopConfig = {
|
|
177
194
|
mcpServers: {
|
|
@@ -193,12 +210,13 @@ var MCP_CLIENTS = [
|
|
|
193
210
|
method: "config-json",
|
|
194
211
|
transport: "stdio",
|
|
195
212
|
cliIde: "zed",
|
|
196
|
-
build({ projectId, projectName, apiKey, endpoint }) {
|
|
213
|
+
build({ projectId, projectName, apiKey, endpoint, features }) {
|
|
197
214
|
const name = projectId ? projectServerName(projectId, projectName) : `mushi-${projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 24)}`;
|
|
198
215
|
const env = {
|
|
199
216
|
MUSHI_API_ENDPOINT: endpoint,
|
|
200
217
|
MUSHI_API_KEY: apiKey
|
|
201
218
|
};
|
|
219
|
+
if (features) env.MUSHI_FEATURES = featuresQueryString(features);
|
|
202
220
|
if (projectId) env.MUSHI_PROJECT_ID = projectId;
|
|
203
221
|
const zedConfig = {
|
|
204
222
|
context_servers: {
|
|
@@ -226,8 +244,11 @@ var MCP_CLIENTS = [
|
|
|
226
244
|
description: "Streamable HTTP URL \u2014 works with OpenClaw, Hermes, Gemini CLI, ChatGPT, and more",
|
|
227
245
|
method: "remote-url",
|
|
228
246
|
transport: "http",
|
|
229
|
-
build({ projectId, apiKey, mcpHttpUrl }) {
|
|
230
|
-
const url =
|
|
247
|
+
build({ projectId, apiKey, mcpHttpUrl, features, readOnly }) {
|
|
248
|
+
const url = withReadOnly(
|
|
249
|
+
appendFeaturesToUrl(mcpHttpUrl, features ?? DEFAULT_FEATURE_GROUPS),
|
|
250
|
+
readOnly
|
|
251
|
+
);
|
|
231
252
|
const headerSnippet = [
|
|
232
253
|
`Authorization: Bearer ${apiKey}`,
|
|
233
254
|
projectId ? `X-Mushi-Project-Id: ${projectId}` : ""
|
package/dist/feature-groups.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* When `features` is omitted → all tools (backward compatible).
|
|
5
5
|
* New installs default to DEFAULT_FEATURE_GROUPS via deeplink / docs.
|
|
6
6
|
*/
|
|
7
|
-
declare const FEATURE_GROUPS: readonly ["triage", "fixes", "inventory", "setup", "qa", "skills", "rewards", "admin", "audit", "docs", "usage", "legacy"];
|
|
7
|
+
declare const FEATURE_GROUPS: readonly ["triage", "fixes", "inventory", "setup", "qa", "skills", "rewards", "admin", "audit", "docs", "usage", "usage", "legacy"];
|
|
8
8
|
type FeatureGroup = (typeof FEATURE_GROUPS)[number];
|
|
9
9
|
/** Lean default for new Cursor installs (~45 tools vs 70 full). */
|
|
10
10
|
declare const DEFAULT_FEATURE_GROUPS: readonly FeatureGroup[];
|
package/dist/feature-groups.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -11,10 +11,10 @@ var TOOL_CATALOG = [
|
|
|
11
11
|
{
|
|
12
12
|
name: "get_recent_reports",
|
|
13
13
|
title: "Recent bug reports",
|
|
14
|
-
description: "List recent bug reports with optional filters (status / category / severity). Use this to
|
|
14
|
+
description: "List recent bug reports with optional filters (status / category / severity). Use this to see what is waiting in your reports inbox right now.",
|
|
15
15
|
scope: "mcp:read",
|
|
16
16
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
17
|
-
useCase: "What landed in my
|
|
17
|
+
useCase: "What landed in my bug queue today?"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
name: "get_report_detail",
|
|
@@ -141,7 +141,7 @@ var TOOL_CATALOG = [
|
|
|
141
141
|
{
|
|
142
142
|
name: "setup_check",
|
|
143
143
|
title: "Dispatch preflight check",
|
|
144
|
-
description: "[Deprecated \u2014 use diagnose_setup with mode=dispatch or diagnose_connection.] Run the 4 **dispatch-readiness** checks for a project and return their pass/fail status (GitHub repo connected, codebase indexed, Anthropic
|
|
144
|
+
description: "[Deprecated \u2014 use diagnose_setup with mode=dispatch or diagnose_connection.] Run the 4 **dispatch-readiness** checks for a project and return their pass/fail status (GitHub repo connected, codebase indexed, your Anthropic API key present, autofix enabled). Also returns the target repo URL when GitHub is connected.",
|
|
145
145
|
scope: "mcp:read",
|
|
146
146
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
147
147
|
useCase: "Is this project ready to auto-fix bugs? What is blocking dispatch?"
|
|
@@ -191,7 +191,7 @@ var TOOL_CATALOG = [
|
|
|
191
191
|
{
|
|
192
192
|
name: "dispatch_fix",
|
|
193
193
|
title: "Dispatch Mushi fix agent",
|
|
194
|
-
description: '
|
|
194
|
+
description: 'Start the Mushi fix agent for a classified report. Set agent="cursor_cloud" to dispatch a Cursor Cloud Agent that opens a signed draft PR. Returns a fix_attempt id; poll get_fix_timeline for progress.',
|
|
195
195
|
scope: "mcp:write",
|
|
196
196
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
197
197
|
useCase: "Let the in-repo agent attempt this fix for me (or: dispatch a Cursor Cloud Agent)."
|
|
@@ -207,7 +207,7 @@ var TOOL_CATALOG = [
|
|
|
207
207
|
{
|
|
208
208
|
name: "test_gen_from_report",
|
|
209
209
|
title: "Generate Playwright test from report",
|
|
210
|
-
description: "
|
|
210
|
+
description: "Generate a Playwright spec from a classified report using your project LLM key and open a draft PR. Requires inventory_v2 + GitHub + LLM keys.",
|
|
211
211
|
scope: "mcp:write",
|
|
212
212
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
213
213
|
useCase: "Turn this regression report into an E2E test PR."
|
|
@@ -239,7 +239,7 @@ var TOOL_CATALOG = [
|
|
|
239
239
|
{
|
|
240
240
|
name: "reopen_report",
|
|
241
241
|
title: "Reopen report (operator)",
|
|
242
|
-
description: "Move a report to reopened for regression
|
|
242
|
+
description: "Move a report to reopened for regression review.",
|
|
243
243
|
scope: "mcp:write",
|
|
244
244
|
hints: { readOnly: false, destructive: false, idempotent: true, openWorld: true },
|
|
245
245
|
useCase: "Reopen a regression the reporter flagged as not fixed."
|
|
@@ -297,10 +297,10 @@ var TOOL_CATALOG = [
|
|
|
297
297
|
{
|
|
298
298
|
name: "get_project_context",
|
|
299
299
|
title: "Project context snapshot",
|
|
300
|
-
description: "Return a rich context snapshot for a project: name, repo URL, SDK heartbeat, ingest status, open report count, autofix readiness,
|
|
300
|
+
description: "Return a rich context snapshot for a project: name, repo URL, SDK heartbeat, ingest status, open report count, autofix readiness, your LLM key config, plan tier, and active integration health. Equivalent to a merged preflight + activation + settings read. Agents should call this at the start of a review session to orient themselves.",
|
|
301
301
|
scope: "mcp:read",
|
|
302
302
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
303
|
-
useCase: "Give me a status overview of this project before I start
|
|
303
|
+
useCase: "Give me a status overview of this project before I start reviewing bugs."
|
|
304
304
|
},
|
|
305
305
|
{
|
|
306
306
|
name: "get_pipeline_logs",
|
|
@@ -321,7 +321,7 @@ var TOOL_CATALOG = [
|
|
|
321
321
|
{
|
|
322
322
|
name: "triage_issue",
|
|
323
323
|
title: "Triage issue end-to-end",
|
|
324
|
-
description: 'Read-only
|
|
324
|
+
description: 'Read-only combined tool: merges report detail, evidence, similar bugs, fix context, blast radius, and recent pipeline logs for a report into a single structured review packet. Returns a prioritised list of recommended next actions (investigate, dispatch_fix, group_with, dismiss). Equivalent to a Sentry "Analyze with Seer" flow grounded in user-felt reports. Pass report_id to kick off review. Call this before dispatch_fix.',
|
|
325
325
|
scope: "mcp:read",
|
|
326
326
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
327
327
|
useCase: "Analyze this bug report end-to-end and tell me what to do."
|
|
@@ -371,8 +371,8 @@ var TDD_TOOL_CATALOG = [
|
|
|
371
371
|
},
|
|
372
372
|
{
|
|
373
373
|
name: "improve_qa_story",
|
|
374
|
-
title: "
|
|
375
|
-
description: "
|
|
374
|
+
title: "Auto-improve a failing QA story",
|
|
375
|
+
description: "Find recently failed qa_story_runs and use Claude to write improved test scripts. New tests are created with source=pdca and approval gated by the original story's automation_mode.",
|
|
376
376
|
scope: "mcp:write",
|
|
377
377
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
378
378
|
useCase: "Fix my failing QA tests automatically."
|
|
@@ -387,16 +387,16 @@ var TDD_TOOL_CATALOG = [
|
|
|
387
387
|
},
|
|
388
388
|
{
|
|
389
389
|
name: "list_byok_keys",
|
|
390
|
-
title: "List
|
|
391
|
-
description: "List all
|
|
390
|
+
title: "List your API key pool",
|
|
391
|
+
description: "List all project API keys, grouped by provider. Shows label, priority, status, and cooldown. Never returns the raw key value \u2014 only metadata. Use this to see which keys are active or exhausted.",
|
|
392
392
|
scope: "mcp:read",
|
|
393
393
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
394
394
|
useCase: "Which API keys are active and which are rate-limited?"
|
|
395
395
|
},
|
|
396
396
|
{
|
|
397
397
|
name: "add_byok_key",
|
|
398
|
-
title: "Add
|
|
399
|
-
description: "Add a new API key to the project
|
|
398
|
+
title: "Add an API key",
|
|
399
|
+
description: "Add a new API key to the project pool for a given provider (anthropic, openai, firecrawl, browserbase, cursor). Specify label and priority for ordering. The key is stored encrypted in Supabase Vault.",
|
|
400
400
|
scope: "mcp:write",
|
|
401
401
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
402
402
|
useCase: "Add a backup Anthropic key to the pool."
|
|
@@ -545,7 +545,7 @@ var CODEBASE_TOOL_CATALOG = [
|
|
|
545
545
|
{
|
|
546
546
|
name: "ask_codebase",
|
|
547
547
|
title: "Ask about the indexed codebase",
|
|
548
|
-
description: "Ask a plain-English question about the connected repo. Grounds on pgvector retrieval over project_codebase_files and returns an answer with file:line citations. Requires codebase indexing enabled and
|
|
548
|
+
description: "Ask a plain-English question about the connected repo. Grounds on pgvector retrieval over project_codebase_files and returns an answer with file:line citations. Requires codebase indexing enabled and your Anthropic or OpenAI API key.",
|
|
549
549
|
scope: "mcp:write",
|
|
550
550
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: true },
|
|
551
551
|
useCase: "How does authentication work in this repo?"
|
|
@@ -613,6 +613,7 @@ var FEATURE_GROUPS = [
|
|
|
613
613
|
"audit",
|
|
614
614
|
"docs",
|
|
615
615
|
"usage",
|
|
616
|
+
"usage",
|
|
616
617
|
/** Deprecated aliases kept for one release — hidden unless `legacy` or `all`. */
|
|
617
618
|
"legacy"
|
|
618
619
|
];
|
|
@@ -857,6 +858,7 @@ function searchMushiDocs(query, limit = 8) {
|
|
|
857
858
|
}
|
|
858
859
|
|
|
859
860
|
// src/server.ts
|
|
861
|
+
var NO_ARG_INPUT = {};
|
|
860
862
|
var MushiApiError = class extends Error {
|
|
861
863
|
constructor(status, code, message) {
|
|
862
864
|
super(`[${code}] ${message}`);
|
|
@@ -1093,7 +1095,7 @@ function createMushiServer(config) {
|
|
|
1093
1095
|
title: titleOf("get_two_way_comms_health"),
|
|
1094
1096
|
description: descOf("get_two_way_comms_health"),
|
|
1095
1097
|
annotations: annotationsFor("get_two_way_comms_health"),
|
|
1096
|
-
inputSchema:
|
|
1098
|
+
inputSchema: NO_ARG_INPUT
|
|
1097
1099
|
},
|
|
1098
1100
|
async () => jsonText(await apiCall("/v1/sync/two-way-health"))
|
|
1099
1101
|
);
|
|
@@ -1400,7 +1402,7 @@ function createMushiServer(config) {
|
|
|
1400
1402
|
title: titleOf("ingest_setup_check"),
|
|
1401
1403
|
description: descOf("ingest_setup_check"),
|
|
1402
1404
|
annotations: annotationsFor("ingest_setup_check"),
|
|
1403
|
-
inputSchema:
|
|
1405
|
+
inputSchema: NO_ARG_INPUT
|
|
1404
1406
|
},
|
|
1405
1407
|
async () => {
|
|
1406
1408
|
const data = await apiCall("/v1/sync/ingest-setup");
|
|
@@ -1494,9 +1496,11 @@ function createMushiServer(config) {
|
|
|
1494
1496
|
const failed = preflight.checks.filter((c) => !c.ready);
|
|
1495
1497
|
dispatchBlock = failed[0]?.hint;
|
|
1496
1498
|
}
|
|
1497
|
-
} catch {
|
|
1499
|
+
} catch (err) {
|
|
1498
1500
|
dispatchReady = false;
|
|
1499
|
-
|
|
1501
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1502
|
+
dispatchBlock = `Could not run dispatch preflight \u2014 ${detail}`;
|
|
1503
|
+
apiLog.warn("diagnose_setup dispatch preflight failed", { error: detail });
|
|
1500
1504
|
}
|
|
1501
1505
|
}
|
|
1502
1506
|
const ingestFailed = ingest.steps.filter((s) => s.required && !s.complete);
|
|
@@ -1520,7 +1524,7 @@ function createMushiServer(config) {
|
|
|
1520
1524
|
title: titleOf("diagnose_connection"),
|
|
1521
1525
|
description: descOf("diagnose_connection"),
|
|
1522
1526
|
annotations: annotationsFor("diagnose_connection"),
|
|
1523
|
-
inputSchema:
|
|
1527
|
+
inputSchema: NO_ARG_INPUT,
|
|
1524
1528
|
outputSchema: {
|
|
1525
1529
|
ready: z.boolean(),
|
|
1526
1530
|
healthOk: z.boolean(),
|
|
@@ -1673,7 +1677,7 @@ function createMushiServer(config) {
|
|
|
1673
1677
|
title: titleOf("list_projects"),
|
|
1674
1678
|
description: descOf("list_projects"),
|
|
1675
1679
|
annotations: annotationsFor("list_projects"),
|
|
1676
|
-
inputSchema:
|
|
1680
|
+
inputSchema: NO_ARG_INPUT,
|
|
1677
1681
|
outputSchema: {
|
|
1678
1682
|
projects: z.array(z.unknown()),
|
|
1679
1683
|
total: z.number().optional(),
|
|
@@ -1694,7 +1698,7 @@ function createMushiServer(config) {
|
|
|
1694
1698
|
title: titleOf("get_account_overview"),
|
|
1695
1699
|
description: descOf("get_account_overview"),
|
|
1696
1700
|
annotations: annotationsFor("get_account_overview"),
|
|
1697
|
-
inputSchema:
|
|
1701
|
+
inputSchema: NO_ARG_INPUT,
|
|
1698
1702
|
outputSchema: {
|
|
1699
1703
|
projects: z.array(z.unknown()),
|
|
1700
1704
|
total: z.number(),
|
|
@@ -1813,7 +1817,7 @@ function createMushiServer(config) {
|
|
|
1813
1817
|
description: descOf("triage_issue"),
|
|
1814
1818
|
annotations: annotationsFor("triage_issue"),
|
|
1815
1819
|
inputSchema: {
|
|
1816
|
-
report_id: z.string().describe("Report UUID to triage."),
|
|
1820
|
+
report_id: z.string().uuid().describe("Report UUID to triage."),
|
|
1817
1821
|
project_id: z.string().optional().describe("Project UUID. Defaults to configured project."),
|
|
1818
1822
|
include_logs: z.boolean().optional().describe("Include recent pipeline logs in triage packet (default: true).")
|
|
1819
1823
|
},
|
|
@@ -1874,11 +1878,31 @@ function createMushiServer(config) {
|
|
|
1874
1878
|
args: { reportId: args.report_id }
|
|
1875
1879
|
});
|
|
1876
1880
|
}
|
|
1881
|
+
const partial_errors = [];
|
|
1882
|
+
if (reportRes.status === "rejected") {
|
|
1883
|
+
partial_errors.push(`report: ${String(reportRes.reason)}`);
|
|
1884
|
+
}
|
|
1885
|
+
if (evidenceRes.status === "rejected") {
|
|
1886
|
+
partial_errors.push(`timeline: ${String(evidenceRes.reason)}`);
|
|
1887
|
+
}
|
|
1888
|
+
if (similarRes.status === "rejected") {
|
|
1889
|
+
partial_errors.push(`similarity: ${String(similarRes.reason)}`);
|
|
1890
|
+
}
|
|
1891
|
+
if (fixCtxRes.status === "rejected") {
|
|
1892
|
+
partial_errors.push(`fix_context: ${String(fixCtxRes.reason)}`);
|
|
1893
|
+
}
|
|
1894
|
+
if (blastRes.status === "rejected") {
|
|
1895
|
+
partial_errors.push(`blast_radius: ${String(blastRes.reason)}`);
|
|
1896
|
+
}
|
|
1897
|
+
if (includeLogs && logsRes.status === "rejected") {
|
|
1898
|
+
partial_errors.push(`recent_logs: ${String(logsRes.reason)}`);
|
|
1899
|
+
}
|
|
1877
1900
|
const result = {
|
|
1878
1901
|
report_id: args.report_id,
|
|
1879
1902
|
severity,
|
|
1880
1903
|
category,
|
|
1881
1904
|
status,
|
|
1905
|
+
partial_errors,
|
|
1882
1906
|
report: reportRes.status === "fulfilled" ? reportRes.value : { error: String(reportRes.reason) },
|
|
1883
1907
|
reporter_thread: evidenceRes.status === "fulfilled" ? evidenceRes.value : null,
|
|
1884
1908
|
similar_bugs: similarRes.status === "fulfilled" ? similarRes.value : null,
|
|
@@ -1943,7 +1967,7 @@ function createMushiServer(config) {
|
|
|
1943
1967
|
description: descOf("dispatch_fix"),
|
|
1944
1968
|
annotations: annotationsFor("dispatch_fix"),
|
|
1945
1969
|
inputSchema: {
|
|
1946
|
-
reportId: z.string().describe("Report UUID to fix"),
|
|
1970
|
+
reportId: z.string().uuid().describe("Report UUID to fix"),
|
|
1947
1971
|
agent: z.enum(["claude_code", "codex", "rest_worker", "mcp"]).optional().describe("Override the agent adapter"),
|
|
1948
1972
|
idempotencyKey: z.string().uuid().optional().describe("Optional RFC 4122 UUID. Resend the same key to safely retry without dispatching a duplicate fix job (Idempotency-Key IETF draft)."),
|
|
1949
1973
|
inventoryActionNodeId: z.string().uuid().optional().describe("Optional inventory Action node UUID for spec-traceability (\xA72.10). When provided, the fix-worker embeds the expected_outcome contract in the LLM prompt and runs validateAgainstSpec before opening the PR.")
|
|
@@ -3110,6 +3134,7 @@ Be specific. No generic advice.`
|
|
|
3110
3134
|
}
|
|
3111
3135
|
|
|
3112
3136
|
// src/index.ts
|
|
3137
|
+
import * as Sentry from "@sentry/node";
|
|
3113
3138
|
var _writeStderr = (...args) => process.stderr.write(
|
|
3114
3139
|
args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ") + "\n"
|
|
3115
3140
|
);
|
|
@@ -3125,6 +3150,14 @@ var SCOPES_RAW = process.env.MUSHI_SCOPES ?? "";
|
|
|
3125
3150
|
var parsedScopes = SCOPES_RAW ? SCOPES_RAW.split(",").map((s) => s.trim()).filter((s) => s === "mcp:read" || s === "mcp:write") : ALL_SCOPES;
|
|
3126
3151
|
var SCOPES = SCOPES_RAW && parsedScopes.length === 0 ? ALL_SCOPES : parsedScopes;
|
|
3127
3152
|
var FEATURES = parseFeaturesCsv(process.env.MUSHI_FEATURES);
|
|
3153
|
+
var MCP_SENTRY_DSN = process.env.MUSHI_MCP_SENTRY_DSN?.trim();
|
|
3154
|
+
if (MCP_SENTRY_DSN) {
|
|
3155
|
+
Sentry.init({
|
|
3156
|
+
dsn: MCP_SENTRY_DSN,
|
|
3157
|
+
environment: process.env.MUSHI_SENTRY_ENVIRONMENT ?? process.env.NODE_ENV ?? "development",
|
|
3158
|
+
tracesSampleRate: 0
|
|
3159
|
+
});
|
|
3160
|
+
}
|
|
3128
3161
|
async function main() {
|
|
3129
3162
|
if (!API_KEY) {
|
|
3130
3163
|
log.fatal("MUSHI_API_KEY environment variable is required");
|
|
@@ -3180,7 +3213,8 @@ async function main() {
|
|
|
3180
3213
|
}
|
|
3181
3214
|
lastInventoryAt = updatedAt;
|
|
3182
3215
|
}
|
|
3183
|
-
} catch {
|
|
3216
|
+
} catch (pollErr) {
|
|
3217
|
+
log.debug("inventory poll failed", { err: String(pollErr) });
|
|
3184
3218
|
}
|
|
3185
3219
|
};
|
|
3186
3220
|
void pollInventory();
|
package/dist/server.js
CHANGED
|
@@ -2,13 +2,13 @@ import {
|
|
|
2
2
|
CODEBASE_TOOL_CATALOG,
|
|
3
3
|
TDD_TOOL_CATALOG,
|
|
4
4
|
TOOL_CATALOG
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-7UOTJ2LI.js";
|
|
6
6
|
import {
|
|
7
7
|
MUSHI_SERVER_METADATA
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EANW5YTI.js";
|
|
9
9
|
import {
|
|
10
10
|
toolMatchesFeatures
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-PW4AK6SV.js";
|
|
12
12
|
|
|
13
13
|
// src/server.ts
|
|
14
14
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -123,6 +123,7 @@ function searchMushiDocs(query, limit = 8) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
// src/server.ts
|
|
126
|
+
var NO_ARG_INPUT = {};
|
|
126
127
|
var MushiApiError = class extends Error {
|
|
127
128
|
constructor(status, code, message) {
|
|
128
129
|
super(`[${code}] ${message}`);
|
|
@@ -359,7 +360,7 @@ function createMushiServer(config) {
|
|
|
359
360
|
title: titleOf("get_two_way_comms_health"),
|
|
360
361
|
description: descOf("get_two_way_comms_health"),
|
|
361
362
|
annotations: annotationsFor("get_two_way_comms_health"),
|
|
362
|
-
inputSchema:
|
|
363
|
+
inputSchema: NO_ARG_INPUT
|
|
363
364
|
},
|
|
364
365
|
async () => jsonText(await apiCall("/v1/sync/two-way-health"))
|
|
365
366
|
);
|
|
@@ -666,7 +667,7 @@ function createMushiServer(config) {
|
|
|
666
667
|
title: titleOf("ingest_setup_check"),
|
|
667
668
|
description: descOf("ingest_setup_check"),
|
|
668
669
|
annotations: annotationsFor("ingest_setup_check"),
|
|
669
|
-
inputSchema:
|
|
670
|
+
inputSchema: NO_ARG_INPUT
|
|
670
671
|
},
|
|
671
672
|
async () => {
|
|
672
673
|
const data = await apiCall("/v1/sync/ingest-setup");
|
|
@@ -760,9 +761,11 @@ function createMushiServer(config) {
|
|
|
760
761
|
const failed = preflight.checks.filter((c) => !c.ready);
|
|
761
762
|
dispatchBlock = failed[0]?.hint;
|
|
762
763
|
}
|
|
763
|
-
} catch {
|
|
764
|
+
} catch (err) {
|
|
764
765
|
dispatchReady = false;
|
|
765
|
-
|
|
766
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
767
|
+
dispatchBlock = `Could not run dispatch preflight \u2014 ${detail}`;
|
|
768
|
+
apiLog.warn("diagnose_setup dispatch preflight failed", { error: detail });
|
|
766
769
|
}
|
|
767
770
|
}
|
|
768
771
|
const ingestFailed = ingest.steps.filter((s) => s.required && !s.complete);
|
|
@@ -786,7 +789,7 @@ function createMushiServer(config) {
|
|
|
786
789
|
title: titleOf("diagnose_connection"),
|
|
787
790
|
description: descOf("diagnose_connection"),
|
|
788
791
|
annotations: annotationsFor("diagnose_connection"),
|
|
789
|
-
inputSchema:
|
|
792
|
+
inputSchema: NO_ARG_INPUT,
|
|
790
793
|
outputSchema: {
|
|
791
794
|
ready: z.boolean(),
|
|
792
795
|
healthOk: z.boolean(),
|
|
@@ -939,7 +942,7 @@ function createMushiServer(config) {
|
|
|
939
942
|
title: titleOf("list_projects"),
|
|
940
943
|
description: descOf("list_projects"),
|
|
941
944
|
annotations: annotationsFor("list_projects"),
|
|
942
|
-
inputSchema:
|
|
945
|
+
inputSchema: NO_ARG_INPUT,
|
|
943
946
|
outputSchema: {
|
|
944
947
|
projects: z.array(z.unknown()),
|
|
945
948
|
total: z.number().optional(),
|
|
@@ -960,7 +963,7 @@ function createMushiServer(config) {
|
|
|
960
963
|
title: titleOf("get_account_overview"),
|
|
961
964
|
description: descOf("get_account_overview"),
|
|
962
965
|
annotations: annotationsFor("get_account_overview"),
|
|
963
|
-
inputSchema:
|
|
966
|
+
inputSchema: NO_ARG_INPUT,
|
|
964
967
|
outputSchema: {
|
|
965
968
|
projects: z.array(z.unknown()),
|
|
966
969
|
total: z.number(),
|
|
@@ -1079,7 +1082,7 @@ function createMushiServer(config) {
|
|
|
1079
1082
|
description: descOf("triage_issue"),
|
|
1080
1083
|
annotations: annotationsFor("triage_issue"),
|
|
1081
1084
|
inputSchema: {
|
|
1082
|
-
report_id: z.string().describe("Report UUID to triage."),
|
|
1085
|
+
report_id: z.string().uuid().describe("Report UUID to triage."),
|
|
1083
1086
|
project_id: z.string().optional().describe("Project UUID. Defaults to configured project."),
|
|
1084
1087
|
include_logs: z.boolean().optional().describe("Include recent pipeline logs in triage packet (default: true).")
|
|
1085
1088
|
},
|
|
@@ -1140,11 +1143,31 @@ function createMushiServer(config) {
|
|
|
1140
1143
|
args: { reportId: args.report_id }
|
|
1141
1144
|
});
|
|
1142
1145
|
}
|
|
1146
|
+
const partial_errors = [];
|
|
1147
|
+
if (reportRes.status === "rejected") {
|
|
1148
|
+
partial_errors.push(`report: ${String(reportRes.reason)}`);
|
|
1149
|
+
}
|
|
1150
|
+
if (evidenceRes.status === "rejected") {
|
|
1151
|
+
partial_errors.push(`timeline: ${String(evidenceRes.reason)}`);
|
|
1152
|
+
}
|
|
1153
|
+
if (similarRes.status === "rejected") {
|
|
1154
|
+
partial_errors.push(`similarity: ${String(similarRes.reason)}`);
|
|
1155
|
+
}
|
|
1156
|
+
if (fixCtxRes.status === "rejected") {
|
|
1157
|
+
partial_errors.push(`fix_context: ${String(fixCtxRes.reason)}`);
|
|
1158
|
+
}
|
|
1159
|
+
if (blastRes.status === "rejected") {
|
|
1160
|
+
partial_errors.push(`blast_radius: ${String(blastRes.reason)}`);
|
|
1161
|
+
}
|
|
1162
|
+
if (includeLogs && logsRes.status === "rejected") {
|
|
1163
|
+
partial_errors.push(`recent_logs: ${String(logsRes.reason)}`);
|
|
1164
|
+
}
|
|
1143
1165
|
const result = {
|
|
1144
1166
|
report_id: args.report_id,
|
|
1145
1167
|
severity,
|
|
1146
1168
|
category,
|
|
1147
1169
|
status,
|
|
1170
|
+
partial_errors,
|
|
1148
1171
|
report: reportRes.status === "fulfilled" ? reportRes.value : { error: String(reportRes.reason) },
|
|
1149
1172
|
reporter_thread: evidenceRes.status === "fulfilled" ? evidenceRes.value : null,
|
|
1150
1173
|
similar_bugs: similarRes.status === "fulfilled" ? similarRes.value : null,
|
|
@@ -1209,7 +1232,7 @@ function createMushiServer(config) {
|
|
|
1209
1232
|
description: descOf("dispatch_fix"),
|
|
1210
1233
|
annotations: annotationsFor("dispatch_fix"),
|
|
1211
1234
|
inputSchema: {
|
|
1212
|
-
reportId: z.string().describe("Report UUID to fix"),
|
|
1235
|
+
reportId: z.string().uuid().describe("Report UUID to fix"),
|
|
1213
1236
|
agent: z.enum(["claude_code", "codex", "rest_worker", "mcp"]).optional().describe("Override the agent adapter"),
|
|
1214
1237
|
idempotencyKey: z.string().uuid().optional().describe("Optional RFC 4122 UUID. Resend the same key to safely retry without dispatching a duplicate fix job (Idempotency-Key IETF draft)."),
|
|
1215
1238
|
inventoryActionNodeId: z.string().uuid().optional().describe("Optional inventory Action node UUID for spec-traceability (\xA72.10). When provided, the fix-worker embeds the expected_outcome contract in the LLM prompt and runs validateAgainstSpec before opening the PR.")
|
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.17.
|
|
4
|
+
"version": "0.17.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "MCP server for Mushi Mushi — triage user-felt bugs, pull evidence (screenshots, console logs, network requests), check blast radius, and dispatch fix PRs, all from your AI coding agent",
|
|
7
7
|
"type": "module",
|
|
@@ -46,8 +46,9 @@
|
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
|
+
"@sentry/node": "^10.57.0",
|
|
49
50
|
"zod": "^4.4.3",
|
|
50
|
-
"@mushi-mushi/core": "^1.
|
|
51
|
+
"@mushi-mushi/core": "^1.22.1"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@types/node": "^22.19.21",
|