@mushi-mushi/mcp 0.15.0 → 0.16.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/CONTRIBUTING.md +50 -9
- package/README.md +15 -9
- package/dist/catalog.js +1 -1
- package/dist/{chunk-FD6GVGQS.js → chunk-UYZEIJ5G.js} +3 -3
- package/dist/index.js +96 -21
- package/dist/server.js +84 -16
- package/package.json +3 -2
package/CONTRIBUTING.md
CHANGED
|
@@ -58,12 +58,12 @@ packages/
|
|
|
58
58
|
react-native/ React Native SDK (MIT)
|
|
59
59
|
cli/ CLI tool (MIT)
|
|
60
60
|
mcp/ MCP server for coding agents (MIT)
|
|
61
|
-
server/ Supabase Edge Functions (
|
|
62
|
-
agents/ Agentic fix pipeline (
|
|
63
|
-
verify/ Fix verification (
|
|
61
|
+
server/ Supabase Edge Functions (AGPLv3)
|
|
62
|
+
agents/ Agentic fix pipeline (AGPLv3)
|
|
63
|
+
verify/ Fix verification (AGPLv3)
|
|
64
64
|
apps/
|
|
65
65
|
admin/ Admin dashboard (React + Tailwind)
|
|
66
|
-
docs/ Documentation site (
|
|
66
|
+
docs/ Documentation site (Nextra — apps/docs)
|
|
67
67
|
tooling/
|
|
68
68
|
eslint-config/ Shared ESLint flat config
|
|
69
69
|
tsconfig/ Shared TypeScript configs
|
|
@@ -81,6 +81,30 @@ tooling/
|
|
|
81
81
|
```
|
|
82
82
|
6. Open a pull request
|
|
83
83
|
|
|
84
|
+
### Documentation (docs-as-code)
|
|
85
|
+
|
|
86
|
+
If your PR changes **user-visible SDK or CLI behavior**, update docs in the **same PR**:
|
|
87
|
+
|
|
88
|
+
| Surface | When to update |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `packages/*/README.md` | npm-facing install/API/config changes for that package |
|
|
91
|
+
| `apps/docs/content/**/*.mdx` | Long-form guides, quickstarts, admin console docs |
|
|
92
|
+
| Root `README.md` | Marketing stats only when counts change — run `pnpm check:docs-stats` |
|
|
93
|
+
|
|
94
|
+
Guardrails (run locally before pushing):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pnpm check:docs-stats # root README stat badges
|
|
98
|
+
pnpm check:sdk-version-matrix # apps/docs/content/sdks/index.mdx versions
|
|
99
|
+
pnpm check:internal-doc-links # dead /foo links in MDX
|
|
100
|
+
pnpm check:onboarding-drift # phantom MCP env vars / stale tool names
|
|
101
|
+
pnpm check:bundle-docs # @mushi-mushi/web size-limit vs README
|
|
102
|
+
pnpm gen:llms-txt # regenerate apps/docs/public/llms.txt after nav changes
|
|
103
|
+
pnpm gen:mcp-tools-doc # regenerate sdks/mcp-tools.generated.mdx from catalog.ts
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
README changes on npm packages only appear on [npmjs.com](https://www.npmjs.com) after the next **Changesets publish**.
|
|
107
|
+
|
|
84
108
|
## Changesets
|
|
85
109
|
|
|
86
110
|
We use [Changesets](https://github.com/changesets/changesets) for versioning. If your PR modifies a published package (`core`, `web`, `react`, `vue`, `svelte`, `angular`, `react-native`, `cli`, `mcp`), add a changeset:
|
|
@@ -93,13 +117,30 @@ Select the affected packages, the semver bump type, and write a summary. The cha
|
|
|
93
117
|
|
|
94
118
|
## Release flow
|
|
95
119
|
|
|
96
|
-
Releases are fully automated. Maintainers don't run
|
|
120
|
+
Releases are fully automated once the version PR is merged. Maintainers don't run
|
|
121
|
+
`npm publish` by hand for routine bumps. See **[`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md)**
|
|
122
|
+
for the full production runbook (edge functions, admin SPA, docs site, migrations).
|
|
97
123
|
|
|
98
124
|
1. PRs land on `master` with one or more changeset files in `.changeset/`.
|
|
99
|
-
|
|
100
|
-
|
|
125
|
+
Orphaned changesets (only ignored packages) fail `pnpm check:changeset-orphans`.
|
|
126
|
+
2. `release.yml` runs on every push to `master`. It opens (or updates) a
|
|
127
|
+
**`chore: version packages`** PR on `changeset-release/master` that bumps
|
|
128
|
+
affected `package.json` files, rolls up changelogs, and deletes consumed
|
|
129
|
+
changesets.
|
|
130
|
+
3. **Wait for CI on the version PR.** If checks don't appear (bot-branch
|
|
131
|
+
suppression), push an empty commit to `changeset-release/master`. If
|
|
132
|
+
`check:sdk-version-matrix` fails, run `pnpm gen:sdk-version-matrix` on that
|
|
133
|
+
branch and commit `apps/docs/content/sdks/index.mdx`.
|
|
134
|
+
4. Merge the version PR. The publish step uses **OIDC Trusted Publishers** +
|
|
135
|
+
Sigstore provenance (with `NPM_TOKEN` only for brand-new package bootstrap).
|
|
136
|
+
5. **Manually dispatch Release** unless a run starts within ~2 minutes:
|
|
137
|
+
**Actions → Release → Run workflow → `master`**. Squash-merges attributed to
|
|
138
|
+
`github-actions[bot]` usually suppress the auto `push` trigger — manual
|
|
139
|
+
dispatch is the normal path, not a fallback of last resort.
|
|
101
140
|
|
|
102
|
-
|
|
141
|
+
```bash
|
|
142
|
+
gh workflow run release.yml --ref master
|
|
143
|
+
```
|
|
103
144
|
|
|
104
145
|
### Adding a brand-new publishable package
|
|
105
146
|
|
|
@@ -146,7 +187,7 @@ chore: bump dependencies
|
|
|
146
187
|
## License
|
|
147
188
|
|
|
148
189
|
- SDK packages are MIT — your contributions will be MIT-licensed
|
|
149
|
-
- Server/agents/verify are
|
|
190
|
+
- Server/agents/verify are AGPLv3 — contributions to those packages fall under AGPLv3
|
|
150
191
|
|
|
151
192
|
## Questions?
|
|
152
193
|
|
package/README.md
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
# @mushi-mushi/mcp
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **Your AI wrote it. Mushi tells you why it broke.**
|
|
4
4
|
|
|
5
|
-
[Model Context Protocol](https://spec.modelcontextprotocol.io/) server that wires Mushi
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
User feels a bug → Mushi captures it → AI triages → AI opens a PR
|
|
9
|
-
→ QA verifies → Judge scores → Lesson library remembers → next agent is smarter
|
|
10
|
-
```
|
|
5
|
+
[Model Context Protocol](https://spec.modelcontextprotocol.io/) server that wires Mushi into Cursor, Claude Code, and any MCP client. Pull fix context, run triage, and dispatch fixes without a second LLM vendor key.
|
|
11
6
|
|
|
12
7
|
Wire it into Cursor, Claude Code, or any MCP client in one command:
|
|
13
8
|
|
|
@@ -16,7 +11,7 @@ npx mushi-mushi setup --ide cursor
|
|
|
16
11
|
# or: npx mushi-mushi setup --ide claude
|
|
17
12
|
```
|
|
18
13
|
|
|
19
|
-
That command reads `~/.mushirc
|
|
14
|
+
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
15
|
|
|
21
16
|
### Codebase Understand tools (indexed repos)
|
|
22
17
|
|
|
@@ -146,7 +141,7 @@ The Mushi backend now exposes the same tool catalog over the **Streamable HTTP**
|
|
|
146
141
|
|
|
147
142
|
### Feature groups (`?features=` / `MUSHI_FEATURES`)
|
|
148
143
|
|
|
149
|
-
Full catalog is **
|
|
144
|
+
Full catalog is **71 tools**. New installs default to a lean set via:
|
|
150
145
|
|
|
151
146
|
- **Stdio:** `MUSHI_FEATURES=triage,fixes,inventory,setup,docs`
|
|
152
147
|
- **HTTP:** `?features=triage,fixes,inventory,setup,docs` on the MCP URL
|
|
@@ -157,6 +152,17 @@ New unified tools: `diagnose_setup` (replaces setup trilogy), `search_mushi_docs
|
|
|
157
152
|
|
|
158
153
|
Append `?read_only=1` to the URL to hide write tools (Supabase-parity mode).
|
|
159
154
|
|
|
155
|
+
## Programmatic imports
|
|
156
|
+
|
|
157
|
+
For custom MCP hosts or tests:
|
|
158
|
+
|
|
159
|
+
| Subpath | Exports |
|
|
160
|
+
| --- | --- |
|
|
161
|
+
| `@mushi-mushi/mcp/catalog` | `TOOL_CATALOG`, scopes, tool specs |
|
|
162
|
+
| `@mushi-mushi/mcp/server` | `createMushiServer()` |
|
|
163
|
+
| `@mushi-mushi/mcp/branding` | Icons and server metadata |
|
|
164
|
+
| `@mushi-mushi/mcp/feature-groups` | `MUSHI_FEATURES` filtering |
|
|
165
|
+
|
|
160
166
|
## Cursor config hygiene
|
|
161
167
|
|
|
162
168
|
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.
|
package/dist/catalog.js
CHANGED
|
@@ -44,7 +44,7 @@ var TOOL_CATALOG = [
|
|
|
44
44
|
{
|
|
45
45
|
name: "get_fix_context",
|
|
46
46
|
title: "Fix context bundle",
|
|
47
|
-
description: "Bundle the full context an agent needs to fix a bug: report detail, reproduction steps, component, root cause, ontology tags. One call instead of several.",
|
|
47
|
+
description: "Bundle the full context an agent needs to fix a bug: a paste-ready fixPrompt (plain-English diagnosis + reproduction + suggested fix + relevant code + blast radius), plus report detail, reproduction steps, component, root cause, and ontology tags. One call instead of several. No second LLM key needed.",
|
|
48
48
|
scope: "mcp:read",
|
|
49
49
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
50
50
|
useCase: "Give me everything I need to fix this in one payload."
|
|
@@ -274,7 +274,7 @@ var TOOL_CATALOG = [
|
|
|
274
274
|
{
|
|
275
275
|
name: "list_projects",
|
|
276
276
|
title: "List accessible projects",
|
|
277
|
-
description:
|
|
277
|
+
description: "List all Mushi projects accessible to this API key. For project-scoped keys returns a single-item list; for org-scoped keys (account mode) returns every project owned by this account. Call this first when MUSHI_PROJECT_ID is not configured \u2014 use the returned id with subsequent tool calls. If multiple projects are returned, pass the target projectId explicitly to project-scoped tools. Multi-project tip: run `mushi setup --all-projects` in your terminal to create one named MCP server entry per project in .cursor/mcp.json.",
|
|
278
278
|
scope: "mcp:read",
|
|
279
279
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
280
280
|
useCase: "Which projects can I access with this API key?"
|
|
@@ -282,7 +282,7 @@ var TOOL_CATALOG = [
|
|
|
282
282
|
{
|
|
283
283
|
name: "get_account_overview",
|
|
284
284
|
title: "Account overview \u2014 all projects",
|
|
285
|
-
description: "Return
|
|
285
|
+
description: "Return an enriched summary of every Mushi project accessible to this API key: id, name, recent report count (last 30 days), number of connected MCP keys, and last-seen heartbeat timestamp. For project-scoped keys this is a one-item list; for org-scoped (account) keys it lists every owned project. Also includes toolCount, resourceCount, promptCount so agents know how many tools are available. Call this at the start of a multi-repo or multi-app triage session to orient yourself.",
|
|
286
286
|
scope: "mcp:read",
|
|
287
287
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
288
288
|
useCase: "Show me all my Mushi projects and their health at a glance."
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,7 @@ var TOOL_CATALOG = [
|
|
|
51
51
|
{
|
|
52
52
|
name: "get_fix_context",
|
|
53
53
|
title: "Fix context bundle",
|
|
54
|
-
description: "Bundle the full context an agent needs to fix a bug: report detail, reproduction steps, component, root cause, ontology tags. One call instead of several.",
|
|
54
|
+
description: "Bundle the full context an agent needs to fix a bug: a paste-ready fixPrompt (plain-English diagnosis + reproduction + suggested fix + relevant code + blast radius), plus report detail, reproduction steps, component, root cause, and ontology tags. One call instead of several. No second LLM key needed.",
|
|
55
55
|
scope: "mcp:read",
|
|
56
56
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
57
57
|
useCase: "Give me everything I need to fix this in one payload."
|
|
@@ -281,7 +281,7 @@ var TOOL_CATALOG = [
|
|
|
281
281
|
{
|
|
282
282
|
name: "list_projects",
|
|
283
283
|
title: "List accessible projects",
|
|
284
|
-
description:
|
|
284
|
+
description: "List all Mushi projects accessible to this API key. For project-scoped keys returns a single-item list; for org-scoped keys (account mode) returns every project owned by this account. Call this first when MUSHI_PROJECT_ID is not configured \u2014 use the returned id with subsequent tool calls. If multiple projects are returned, pass the target projectId explicitly to project-scoped tools. Multi-project tip: run `mushi setup --all-projects` in your terminal to create one named MCP server entry per project in .cursor/mcp.json.",
|
|
285
285
|
scope: "mcp:read",
|
|
286
286
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
287
287
|
useCase: "Which projects can I access with this API key?"
|
|
@@ -289,7 +289,7 @@ var TOOL_CATALOG = [
|
|
|
289
289
|
{
|
|
290
290
|
name: "get_account_overview",
|
|
291
291
|
title: "Account overview \u2014 all projects",
|
|
292
|
-
description: "Return
|
|
292
|
+
description: "Return an enriched summary of every Mushi project accessible to this API key: id, name, recent report count (last 30 days), number of connected MCP keys, and last-seen heartbeat timestamp. For project-scoped keys this is a one-item list; for org-scoped (account) keys it lists every owned project. Also includes toolCount, resourceCount, promptCount so agents know how many tools are available. Call this at the start of a multi-repo or multi-app triage session to orient yourself.",
|
|
293
293
|
scope: "mcp:read",
|
|
294
294
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
295
295
|
useCase: "Show me all my Mushi projects and their health at a glance."
|
|
@@ -749,14 +749,26 @@ var MUSHI_DOCS_INDEX = [
|
|
|
749
749
|
{
|
|
750
750
|
title: "MCP setup",
|
|
751
751
|
path: `${BASE}/guides/mcp-setup`,
|
|
752
|
-
keywords: ["mcp", "cursor", "api key", "stdio", "http"],
|
|
753
|
-
excerpt: "Wire Mushi MCP into Cursor, Claude, or any MCP client."
|
|
752
|
+
keywords: ["mcp", "cursor", "api key", "stdio", "http", "multi-project", "account mode", "install", "setup", "deeplink"],
|
|
753
|
+
excerpt: "Wire Mushi MCP into Cursor, Claude, or any MCP client. Supports per-project and account-level keys."
|
|
754
754
|
},
|
|
755
755
|
{
|
|
756
756
|
title: "API key scopes",
|
|
757
757
|
path: `${BASE}/guides/api-keys`,
|
|
758
|
-
keywords: ["api key", "mcp:read", "mcp:write", "scopes", "security"],
|
|
759
|
-
excerpt: "Separate SDK ingest keys from MCP read/write keys."
|
|
758
|
+
keywords: ["api key", "mcp:read", "mcp:write", "scopes", "security", "account key", "org-scoped", "multi-project"],
|
|
759
|
+
excerpt: "Separate SDK ingest keys from MCP read/write keys. Mint an org-scoped account key for multi-project access."
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
title: "Account key (org-scoped)",
|
|
763
|
+
path: `${BASE}/guides/mcp-setup`,
|
|
764
|
+
keywords: ["account key", "org-scoped", "multi-project", "MUSHI_PROJECT_ID", "all projects", "mint-org-key", "get_account_overview"],
|
|
765
|
+
excerpt: "Mint one org-scoped key that covers all your projects; no MUSHI_PROJECT_ID needed. The agent calls get_account_overview to discover projects."
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
title: "Cursor MCP troubleshooting",
|
|
769
|
+
path: `${BASE}/guides/mcp-setup`,
|
|
770
|
+
keywords: ["cursor", "mcp.json", "red badge", "transport error", "stdout", "stderr", "json-rpc", "INVALID_TOKEN", "syntax helper", "diagnose_connection"],
|
|
771
|
+
excerpt: "Cursor stdio MCP requires stdout to contain only JSON-RPC. Use the console syntax helper, restart Cursor MCP, then run diagnose_connection."
|
|
760
772
|
},
|
|
761
773
|
{
|
|
762
774
|
title: "Judge loop",
|
|
@@ -848,7 +860,8 @@ function createMushiServer(config) {
|
|
|
848
860
|
const doFetch = config.fetch ?? globalThis.fetch;
|
|
849
861
|
const apiLog = createLogger({
|
|
850
862
|
scope: "mushi:mcp:api",
|
|
851
|
-
level: process.env.MUSHI_LOG_LEVEL ?? "info"
|
|
863
|
+
level: process.env.MUSHI_LOG_LEVEL ?? "info",
|
|
864
|
+
destination: "stderr"
|
|
852
865
|
});
|
|
853
866
|
if (config.scopes !== void 0 && config.scopes.length === 0) {
|
|
854
867
|
return new McpServer({
|
|
@@ -907,6 +920,38 @@ function createMushiServer(config) {
|
|
|
907
920
|
apiLog.info("api.done", { path, requestId, status: res.status, durationMs });
|
|
908
921
|
return body;
|
|
909
922
|
}
|
|
923
|
+
async function resolveProjectId(explicitId) {
|
|
924
|
+
if (explicitId) return explicitId;
|
|
925
|
+
if (projectId) return projectId;
|
|
926
|
+
try {
|
|
927
|
+
const data = await apiCall(
|
|
928
|
+
"/v1/admin/mcp/account-overview"
|
|
929
|
+
);
|
|
930
|
+
if (data.total === 1 && data.projects[0]) {
|
|
931
|
+
return data.projects[0].id;
|
|
932
|
+
}
|
|
933
|
+
if (data.total === 0) {
|
|
934
|
+
throw new MushiApiError(
|
|
935
|
+
400,
|
|
936
|
+
"NO_ACCESSIBLE_PROJECTS",
|
|
937
|
+
"This API key has no accessible projects. Mint an API key on a project in the admin console."
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
const projectList = data.projects.map((p) => `${p.name ?? "unnamed"} (${p.id})`).join(", ");
|
|
941
|
+
throw new MushiApiError(
|
|
942
|
+
400,
|
|
943
|
+
"PROJECT_ID_REQUIRED",
|
|
944
|
+
`Multiple projects are accessible with this key: ${projectList}. Pass projectId explicitly to target a specific project, or set MUSHI_PROJECT_ID in your MCP env config.`
|
|
945
|
+
);
|
|
946
|
+
} catch (err) {
|
|
947
|
+
if (err instanceof MushiApiError) throw err;
|
|
948
|
+
throw new MushiApiError(
|
|
949
|
+
400,
|
|
950
|
+
"MISSING_PROJECT_ID",
|
|
951
|
+
"projectId is required. Set MUSHI_PROJECT_ID in .cursor/mcp.json or pass it explicitly."
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
910
955
|
function jsonText(value) {
|
|
911
956
|
return {
|
|
912
957
|
content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
|
|
@@ -974,8 +1019,8 @@ function createMushiServer(config) {
|
|
|
974
1019
|
if (args.category) params.set("category", args.category);
|
|
975
1020
|
if (args.severity) params.set("severity", args.severity);
|
|
976
1021
|
params.set("limit", String(Math.min(args.limit ?? 20, 100)));
|
|
977
|
-
const pid = args.project_id
|
|
978
|
-
const extraHeaders = pid
|
|
1022
|
+
const pid = await resolveProjectId(args.project_id);
|
|
1023
|
+
const extraHeaders = pid !== projectId ? { "X-Mushi-Project-Id": pid } : {};
|
|
979
1024
|
const data = await apiCall(`/v1/admin/reports?${params}`, {
|
|
980
1025
|
headers: extraHeaders
|
|
981
1026
|
});
|
|
@@ -1086,6 +1131,7 @@ function createMushiServer(config) {
|
|
|
1086
1131
|
inputSchema: { reportId: z.string().describe("The report UUID to fix") },
|
|
1087
1132
|
outputSchema: {
|
|
1088
1133
|
report: z.unknown(),
|
|
1134
|
+
fixPrompt: z.unknown(),
|
|
1089
1135
|
reproductionSteps: z.unknown(),
|
|
1090
1136
|
component: z.unknown(),
|
|
1091
1137
|
rootCause: z.unknown(),
|
|
@@ -1096,6 +1142,10 @@ function createMushiServer(config) {
|
|
|
1096
1142
|
const report = await apiCall(`/v1/admin/reports/${args.reportId}`);
|
|
1097
1143
|
return jsonResult({
|
|
1098
1144
|
report,
|
|
1145
|
+
// Paste-ready fix prompt composed server-side by composeFixPacket()
|
|
1146
|
+
// (diagnosis + repro + suggested fix + relevant code + blast radius).
|
|
1147
|
+
// Hand this straight to the editing agent — no second LLM key needed.
|
|
1148
|
+
fixPrompt: report.fix_packet ?? null,
|
|
1099
1149
|
reproductionSteps: report.reproduction_steps ?? [],
|
|
1100
1150
|
component: report.component,
|
|
1101
1151
|
rootCause: report.stage2_analysis?.rootCause,
|
|
@@ -1436,6 +1486,7 @@ function createMushiServer(config) {
|
|
|
1436
1486
|
dispatchReady: z.boolean(),
|
|
1437
1487
|
endpoint: z.string().nullable(),
|
|
1438
1488
|
projectId: z.string().nullable(),
|
|
1489
|
+
accessibleProjectCount: z.number().nullable(),
|
|
1439
1490
|
issues: z.array(z.unknown()),
|
|
1440
1491
|
nextAction: z.string(),
|
|
1441
1492
|
summary: z.string()
|
|
@@ -1450,13 +1501,6 @@ function createMushiServer(config) {
|
|
|
1450
1501
|
fix: "Run `mushi connect` to write MUSHI_API_KEY into .cursor/mcp.json, then restart the MCP server."
|
|
1451
1502
|
});
|
|
1452
1503
|
}
|
|
1453
|
-
if (!projectId) {
|
|
1454
|
-
issues.push({
|
|
1455
|
-
check: "mcp_project_id",
|
|
1456
|
-
detail: "No projectId configured on the MCP server",
|
|
1457
|
-
fix: "Add MUSHI_PROJECT_ID to .cursor/mcp.json (copy UUID from console \u2192 Projects)."
|
|
1458
|
-
});
|
|
1459
|
-
}
|
|
1460
1504
|
if (!apiEndpoint) {
|
|
1461
1505
|
issues.push({
|
|
1462
1506
|
check: "mcp_endpoint",
|
|
@@ -1488,6 +1532,21 @@ function createMushiServer(config) {
|
|
|
1488
1532
|
}
|
|
1489
1533
|
let ingestReady = false;
|
|
1490
1534
|
let dispatchReady = false;
|
|
1535
|
+
let accessibleProjectCount = null;
|
|
1536
|
+
if (!projectId && healthOk) {
|
|
1537
|
+
try {
|
|
1538
|
+
const overview = await apiCall("/v1/admin/mcp/account-overview");
|
|
1539
|
+
accessibleProjectCount = overview.total;
|
|
1540
|
+
if (overview.total === 0) {
|
|
1541
|
+
issues.push({
|
|
1542
|
+
check: "no_accessible_projects",
|
|
1543
|
+
detail: "API key has no accessible projects",
|
|
1544
|
+
fix: "Mint an API key on a project (console \u2192 Projects \u2192 API Keys) or add MUSHI_PROJECT_ID to restrict to a single project."
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
} catch {
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1491
1550
|
try {
|
|
1492
1551
|
const ingest = await apiCall("/v1/sync/ingest-setup");
|
|
1493
1552
|
ingestReady = ingest.ready;
|
|
@@ -1530,6 +1589,7 @@ function createMushiServer(config) {
|
|
|
1530
1589
|
dispatchReady,
|
|
1531
1590
|
endpoint: apiEndpoint ?? null,
|
|
1532
1591
|
projectId: projectId ?? null,
|
|
1592
|
+
accessibleProjectCount,
|
|
1533
1593
|
issues,
|
|
1534
1594
|
nextAction,
|
|
1535
1595
|
summary: ready ? "MCP credentials valid; ingest pipeline ready." : `Connection issue \u2014 ${issues[0]?.check ?? "unknown"}: ${nextAction}`
|
|
@@ -1595,16 +1655,24 @@ function createMushiServer(config) {
|
|
|
1595
1655
|
inputSchema: {},
|
|
1596
1656
|
outputSchema: {
|
|
1597
1657
|
projects: z.array(z.unknown()),
|
|
1658
|
+
total: z.number(),
|
|
1598
1659
|
active_project_id: z.string().nullable(),
|
|
1660
|
+
toolCount: z.number().optional(),
|
|
1661
|
+
resourceCount: z.number().optional(),
|
|
1662
|
+
promptCount: z.number().optional(),
|
|
1599
1663
|
multi_project_hint: z.string()
|
|
1600
1664
|
}
|
|
1601
1665
|
},
|
|
1602
1666
|
async () => {
|
|
1603
|
-
const data = await apiCall("/v1/admin/mcp/
|
|
1667
|
+
const data = await apiCall("/v1/admin/mcp/account-overview");
|
|
1604
1668
|
const projects = Array.isArray(data?.projects) ? data.projects : [];
|
|
1605
1669
|
return jsonResult({
|
|
1606
1670
|
projects,
|
|
1671
|
+
total: data?.total ?? projects.length,
|
|
1607
1672
|
active_project_id: projectId ?? null,
|
|
1673
|
+
toolCount: data?.toolCount,
|
|
1674
|
+
resourceCount: data?.resourceCount,
|
|
1675
|
+
promptCount: data?.promptCount,
|
|
1608
1676
|
multi_project_hint: projects.length <= 1 ? 'You are currently connected to one project. To connect additional Mushi projects, open the Mushi console \u2192 switch to each project \u2192 MCP \u2192 Setup \u2192 "\u26A1 Add to Cursor". Each click adds a uniquely-named entry (mushi-{name}-{id}) to your global ~/.cursor/mcp.json so you can triage reports across all your apps from a single Cursor session.' : `You have access to ${projects.length} projects. To connect any unconnected project, open the Mushi console \u2192 switch to that project \u2192 MCP \u2192 Setup \u2192 "\u26A1 Add to Cursor".`
|
|
1609
1677
|
});
|
|
1610
1678
|
}
|
|
@@ -2956,9 +3024,14 @@ Be specific. No generic advice.`
|
|
|
2956
3024
|
}
|
|
2957
3025
|
|
|
2958
3026
|
// src/index.ts
|
|
3027
|
+
var _writeStderr = (...args) => process.stderr.write(
|
|
3028
|
+
args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ") + "\n"
|
|
3029
|
+
);
|
|
3030
|
+
console.log = _writeStderr;
|
|
3031
|
+
console.warn = _writeStderr;
|
|
2959
3032
|
var require2 = createRequire(import.meta.url);
|
|
2960
3033
|
var VERSION = require2("../package.json").version;
|
|
2961
|
-
var log = createLogger2({ scope: "mushi:mcp", level: "info" });
|
|
3034
|
+
var log = createLogger2({ scope: "mushi:mcp", level: "info", destination: "stderr" });
|
|
2962
3035
|
var API_ENDPOINT = process.env.MUSHI_API_ENDPOINT ?? "";
|
|
2963
3036
|
var API_KEY = process.env.MUSHI_API_KEY ?? "";
|
|
2964
3037
|
var PROJECT_ID = process.env.MUSHI_PROJECT_ID ?? "";
|
|
@@ -2976,13 +3049,15 @@ async function main() {
|
|
|
2976
3049
|
"[mushi-mcp] MUSHI_API_ENDPOINT is not set. All tool calls will fail.\nSet MUSHI_API_ENDPOINT to your Supabase edge function URL, e.g. https://xyz.supabase.co/functions/v1/api"
|
|
2977
3050
|
);
|
|
2978
3051
|
}
|
|
3052
|
+
const mode = PROJECT_ID ? "single-project" : "account";
|
|
2979
3053
|
if (!PROJECT_ID) {
|
|
2980
|
-
|
|
2981
|
-
"[mushi-mcp]
|
|
3054
|
+
log.info(
|
|
3055
|
+
"[mushi-mcp] Running in account mode (no MUSHI_PROJECT_ID set). Project-scoped tools accept an explicit projectId argument. Run `get_account_overview` to see accessible projects."
|
|
2982
3056
|
);
|
|
2983
3057
|
}
|
|
2984
3058
|
log.info("Starting Mushi MCP server", {
|
|
2985
3059
|
version: VERSION,
|
|
3060
|
+
mode,
|
|
2986
3061
|
endpoint: API_ENDPOINT || "(unset)",
|
|
2987
3062
|
hasProjectId: !!PROJECT_ID,
|
|
2988
3063
|
scopes: SCOPES.join(",")
|
package/dist/server.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
CODEBASE_TOOL_CATALOG,
|
|
3
3
|
TDD_TOOL_CATALOG,
|
|
4
4
|
TOOL_CATALOG
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UYZEIJ5G.js";
|
|
6
6
|
import {
|
|
7
7
|
MUSHI_SERVER_METADATA
|
|
8
8
|
} from "./chunk-EHB2BGWX.js";
|
|
@@ -27,14 +27,26 @@ var MUSHI_DOCS_INDEX = [
|
|
|
27
27
|
{
|
|
28
28
|
title: "MCP setup",
|
|
29
29
|
path: `${BASE}/guides/mcp-setup`,
|
|
30
|
-
keywords: ["mcp", "cursor", "api key", "stdio", "http"],
|
|
31
|
-
excerpt: "Wire Mushi MCP into Cursor, Claude, or any MCP client."
|
|
30
|
+
keywords: ["mcp", "cursor", "api key", "stdio", "http", "multi-project", "account mode", "install", "setup", "deeplink"],
|
|
31
|
+
excerpt: "Wire Mushi MCP into Cursor, Claude, or any MCP client. Supports per-project and account-level keys."
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
title: "API key scopes",
|
|
35
35
|
path: `${BASE}/guides/api-keys`,
|
|
36
|
-
keywords: ["api key", "mcp:read", "mcp:write", "scopes", "security"],
|
|
37
|
-
excerpt: "Separate SDK ingest keys from MCP read/write keys."
|
|
36
|
+
keywords: ["api key", "mcp:read", "mcp:write", "scopes", "security", "account key", "org-scoped", "multi-project"],
|
|
37
|
+
excerpt: "Separate SDK ingest keys from MCP read/write keys. Mint an org-scoped account key for multi-project access."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: "Account key (org-scoped)",
|
|
41
|
+
path: `${BASE}/guides/mcp-setup`,
|
|
42
|
+
keywords: ["account key", "org-scoped", "multi-project", "MUSHI_PROJECT_ID", "all projects", "mint-org-key", "get_account_overview"],
|
|
43
|
+
excerpt: "Mint one org-scoped key that covers all your projects; no MUSHI_PROJECT_ID needed. The agent calls get_account_overview to discover projects."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
title: "Cursor MCP troubleshooting",
|
|
47
|
+
path: `${BASE}/guides/mcp-setup`,
|
|
48
|
+
keywords: ["cursor", "mcp.json", "red badge", "transport error", "stdout", "stderr", "json-rpc", "INVALID_TOKEN", "syntax helper", "diagnose_connection"],
|
|
49
|
+
excerpt: "Cursor stdio MCP requires stdout to contain only JSON-RPC. Use the console syntax helper, restart Cursor MCP, then run diagnose_connection."
|
|
38
50
|
},
|
|
39
51
|
{
|
|
40
52
|
title: "Judge loop",
|
|
@@ -126,7 +138,8 @@ function createMushiServer(config) {
|
|
|
126
138
|
const doFetch = config.fetch ?? globalThis.fetch;
|
|
127
139
|
const apiLog = createLogger({
|
|
128
140
|
scope: "mushi:mcp:api",
|
|
129
|
-
level: process.env.MUSHI_LOG_LEVEL ?? "info"
|
|
141
|
+
level: process.env.MUSHI_LOG_LEVEL ?? "info",
|
|
142
|
+
destination: "stderr"
|
|
130
143
|
});
|
|
131
144
|
if (config.scopes !== void 0 && config.scopes.length === 0) {
|
|
132
145
|
return new McpServer({
|
|
@@ -185,6 +198,38 @@ function createMushiServer(config) {
|
|
|
185
198
|
apiLog.info("api.done", { path, requestId, status: res.status, durationMs });
|
|
186
199
|
return body;
|
|
187
200
|
}
|
|
201
|
+
async function resolveProjectId(explicitId) {
|
|
202
|
+
if (explicitId) return explicitId;
|
|
203
|
+
if (projectId) return projectId;
|
|
204
|
+
try {
|
|
205
|
+
const data = await apiCall(
|
|
206
|
+
"/v1/admin/mcp/account-overview"
|
|
207
|
+
);
|
|
208
|
+
if (data.total === 1 && data.projects[0]) {
|
|
209
|
+
return data.projects[0].id;
|
|
210
|
+
}
|
|
211
|
+
if (data.total === 0) {
|
|
212
|
+
throw new MushiApiError(
|
|
213
|
+
400,
|
|
214
|
+
"NO_ACCESSIBLE_PROJECTS",
|
|
215
|
+
"This API key has no accessible projects. Mint an API key on a project in the admin console."
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const projectList = data.projects.map((p) => `${p.name ?? "unnamed"} (${p.id})`).join(", ");
|
|
219
|
+
throw new MushiApiError(
|
|
220
|
+
400,
|
|
221
|
+
"PROJECT_ID_REQUIRED",
|
|
222
|
+
`Multiple projects are accessible with this key: ${projectList}. Pass projectId explicitly to target a specific project, or set MUSHI_PROJECT_ID in your MCP env config.`
|
|
223
|
+
);
|
|
224
|
+
} catch (err) {
|
|
225
|
+
if (err instanceof MushiApiError) throw err;
|
|
226
|
+
throw new MushiApiError(
|
|
227
|
+
400,
|
|
228
|
+
"MISSING_PROJECT_ID",
|
|
229
|
+
"projectId is required. Set MUSHI_PROJECT_ID in .cursor/mcp.json or pass it explicitly."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
188
233
|
function jsonText(value) {
|
|
189
234
|
return {
|
|
190
235
|
content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
|
|
@@ -252,8 +297,8 @@ function createMushiServer(config) {
|
|
|
252
297
|
if (args.category) params.set("category", args.category);
|
|
253
298
|
if (args.severity) params.set("severity", args.severity);
|
|
254
299
|
params.set("limit", String(Math.min(args.limit ?? 20, 100)));
|
|
255
|
-
const pid = args.project_id
|
|
256
|
-
const extraHeaders = pid
|
|
300
|
+
const pid = await resolveProjectId(args.project_id);
|
|
301
|
+
const extraHeaders = pid !== projectId ? { "X-Mushi-Project-Id": pid } : {};
|
|
257
302
|
const data = await apiCall(`/v1/admin/reports?${params}`, {
|
|
258
303
|
headers: extraHeaders
|
|
259
304
|
});
|
|
@@ -364,6 +409,7 @@ function createMushiServer(config) {
|
|
|
364
409
|
inputSchema: { reportId: z.string().describe("The report UUID to fix") },
|
|
365
410
|
outputSchema: {
|
|
366
411
|
report: z.unknown(),
|
|
412
|
+
fixPrompt: z.unknown(),
|
|
367
413
|
reproductionSteps: z.unknown(),
|
|
368
414
|
component: z.unknown(),
|
|
369
415
|
rootCause: z.unknown(),
|
|
@@ -374,6 +420,10 @@ function createMushiServer(config) {
|
|
|
374
420
|
const report = await apiCall(`/v1/admin/reports/${args.reportId}`);
|
|
375
421
|
return jsonResult({
|
|
376
422
|
report,
|
|
423
|
+
// Paste-ready fix prompt composed server-side by composeFixPacket()
|
|
424
|
+
// (diagnosis + repro + suggested fix + relevant code + blast radius).
|
|
425
|
+
// Hand this straight to the editing agent — no second LLM key needed.
|
|
426
|
+
fixPrompt: report.fix_packet ?? null,
|
|
377
427
|
reproductionSteps: report.reproduction_steps ?? [],
|
|
378
428
|
component: report.component,
|
|
379
429
|
rootCause: report.stage2_analysis?.rootCause,
|
|
@@ -714,6 +764,7 @@ function createMushiServer(config) {
|
|
|
714
764
|
dispatchReady: z.boolean(),
|
|
715
765
|
endpoint: z.string().nullable(),
|
|
716
766
|
projectId: z.string().nullable(),
|
|
767
|
+
accessibleProjectCount: z.number().nullable(),
|
|
717
768
|
issues: z.array(z.unknown()),
|
|
718
769
|
nextAction: z.string(),
|
|
719
770
|
summary: z.string()
|
|
@@ -728,13 +779,6 @@ function createMushiServer(config) {
|
|
|
728
779
|
fix: "Run `mushi connect` to write MUSHI_API_KEY into .cursor/mcp.json, then restart the MCP server."
|
|
729
780
|
});
|
|
730
781
|
}
|
|
731
|
-
if (!projectId) {
|
|
732
|
-
issues.push({
|
|
733
|
-
check: "mcp_project_id",
|
|
734
|
-
detail: "No projectId configured on the MCP server",
|
|
735
|
-
fix: "Add MUSHI_PROJECT_ID to .cursor/mcp.json (copy UUID from console \u2192 Projects)."
|
|
736
|
-
});
|
|
737
|
-
}
|
|
738
782
|
if (!apiEndpoint) {
|
|
739
783
|
issues.push({
|
|
740
784
|
check: "mcp_endpoint",
|
|
@@ -766,6 +810,21 @@ function createMushiServer(config) {
|
|
|
766
810
|
}
|
|
767
811
|
let ingestReady = false;
|
|
768
812
|
let dispatchReady = false;
|
|
813
|
+
let accessibleProjectCount = null;
|
|
814
|
+
if (!projectId && healthOk) {
|
|
815
|
+
try {
|
|
816
|
+
const overview = await apiCall("/v1/admin/mcp/account-overview");
|
|
817
|
+
accessibleProjectCount = overview.total;
|
|
818
|
+
if (overview.total === 0) {
|
|
819
|
+
issues.push({
|
|
820
|
+
check: "no_accessible_projects",
|
|
821
|
+
detail: "API key has no accessible projects",
|
|
822
|
+
fix: "Mint an API key on a project (console \u2192 Projects \u2192 API Keys) or add MUSHI_PROJECT_ID to restrict to a single project."
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
} catch {
|
|
826
|
+
}
|
|
827
|
+
}
|
|
769
828
|
try {
|
|
770
829
|
const ingest = await apiCall("/v1/sync/ingest-setup");
|
|
771
830
|
ingestReady = ingest.ready;
|
|
@@ -808,6 +867,7 @@ function createMushiServer(config) {
|
|
|
808
867
|
dispatchReady,
|
|
809
868
|
endpoint: apiEndpoint ?? null,
|
|
810
869
|
projectId: projectId ?? null,
|
|
870
|
+
accessibleProjectCount,
|
|
811
871
|
issues,
|
|
812
872
|
nextAction,
|
|
813
873
|
summary: ready ? "MCP credentials valid; ingest pipeline ready." : `Connection issue \u2014 ${issues[0]?.check ?? "unknown"}: ${nextAction}`
|
|
@@ -873,16 +933,24 @@ function createMushiServer(config) {
|
|
|
873
933
|
inputSchema: {},
|
|
874
934
|
outputSchema: {
|
|
875
935
|
projects: z.array(z.unknown()),
|
|
936
|
+
total: z.number(),
|
|
876
937
|
active_project_id: z.string().nullable(),
|
|
938
|
+
toolCount: z.number().optional(),
|
|
939
|
+
resourceCount: z.number().optional(),
|
|
940
|
+
promptCount: z.number().optional(),
|
|
877
941
|
multi_project_hint: z.string()
|
|
878
942
|
}
|
|
879
943
|
},
|
|
880
944
|
async () => {
|
|
881
|
-
const data = await apiCall("/v1/admin/mcp/
|
|
945
|
+
const data = await apiCall("/v1/admin/mcp/account-overview");
|
|
882
946
|
const projects = Array.isArray(data?.projects) ? data.projects : [];
|
|
883
947
|
return jsonResult({
|
|
884
948
|
projects,
|
|
949
|
+
total: data?.total ?? projects.length,
|
|
885
950
|
active_project_id: projectId ?? null,
|
|
951
|
+
toolCount: data?.toolCount,
|
|
952
|
+
resourceCount: data?.resourceCount,
|
|
953
|
+
promptCount: data?.promptCount,
|
|
886
954
|
multi_project_hint: projects.length <= 1 ? 'You are currently connected to one project. To connect additional Mushi projects, open the Mushi console \u2192 switch to each project \u2192 MCP \u2192 Setup \u2192 "\u26A1 Add to Cursor". Each click adds a uniquely-named entry (mushi-{name}-{id}) to your global ~/.cursor/mcp.json so you can triage reports across all your apps from a single Cursor session.' : `You have access to ${projects.length} projects. To connect any unconnected project, open the Mushi console \u2192 switch to that project \u2192 MCP \u2192 Setup \u2192 "\u26A1 Add to Cursor".`
|
|
887
955
|
});
|
|
888
956
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mushi-mushi/mcp",
|
|
3
|
-
"
|
|
3
|
+
"mcpName": "io.github.kensaurus/mushi-mushi",
|
|
4
|
+
"version": "0.16.1",
|
|
4
5
|
"license": "MIT",
|
|
5
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",
|
|
6
7
|
"type": "module",
|
|
@@ -42,7 +43,7 @@
|
|
|
42
43
|
"dependencies": {
|
|
43
44
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
44
45
|
"zod": "^4.4.2",
|
|
45
|
-
"@mushi-mushi/core": "^1.
|
|
46
|
+
"@mushi-mushi/core": "^1.16.0"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
49
|
"@types/node": "^22.19.17",
|