@mushi-mushi/mcp 0.24.4 → 0.24.6

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/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.4";
49
+ declare const MCP_PIN_SPEC = "@mushi-mushi/mcp@0.24.6";
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.4";
11
+ var MCP_PIN_SPEC = "@mushi-mushi/mcp@0.24.6";
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
@@ -1476,7 +1476,7 @@ var MUSHI_DOCS_INDEX = [
1476
1476
  route: "/admin/billing",
1477
1477
  markdown: "admin/billing.md",
1478
1478
  keywords: ["admin", "billing"],
1479
- headings: ["Reading your usage card", "Usage breakdown", "Predictability controls", "Upgrading your plan", "Managing payment and invoices", "CLI parity", "Related docs"],
1479
+ headings: ["Reading your usage card", "Usage breakdown", "Predictability controls", "Upgrading your plan", "Changing plan", "Managing payment and invoices", "CLI parity", "Related docs"],
1480
1480
  excerpt: "The Billing page shows your diagnosis quota, usage alerts at 50% and 80%, your projected bill, and spend caps for your Mushi plan."
1481
1481
  },
1482
1482
  {
@@ -1854,7 +1854,7 @@ var MUSHI_DOCS_INDEX = [
1854
1854
  route: "/admin/research",
1855
1855
  markdown: "admin/research.md",
1856
1856
  keywords: ["admin", "research"],
1857
- headings: ["What it's for", "Running a search", "Saving results", "Prerequisites", "Related pages"],
1857
+ headings: ["What it's for", "Running a search", "Saving results", "Automatic results on error reports", "Prerequisites", "Related pages"],
1858
1858
  excerpt: "The Research page runs a Firecrawl web search scoped to your tech stack and returns summarised answers with links to their sources."
1859
1859
  },
1860
1860
  {
@@ -3141,7 +3141,7 @@ var MUSHI_DOCS_INDEX = [
3141
3141
  route: "/security/byok",
3142
3142
  markdown: "security/byok.md",
3143
3143
  keywords: ["security", "byok", "bring-your-own-key"],
3144
- headings: ["Setup", "What uses the key", "OpenRouter", "Audit trail", "Rotation", "Langfuse trace attribution"],
3144
+ headings: ["Setup", "One key for every app", "What uses the key", "OpenRouter", "Audit trail", "Rotation", "Langfuse trace attribution"],
3145
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."
3146
3146
  },
3147
3147
  {
@@ -5305,7 +5305,8 @@ function createMushiServer(config) {
5305
5305
  );
5306
5306
  const latest = data.latest ?? data.version;
5307
5307
  const current = args.current;
5308
- const outdated = current && latest ? current !== latest : void 0;
5308
+ const pinned = current?.trim().replace(/^[\^~>=<v\s]+/, "");
5309
+ const outdated = pinned && latest ? pinned !== latest : void 0;
5309
5310
  return jsonResult({
5310
5311
  package: data.package ?? pkg,
5311
5312
  latest,
@@ -7541,7 +7542,7 @@ function createSetupModeServer(config) {
7541
7542
  features: "all",
7542
7543
  ...config.fetch ? { fetch: config.fetch } : {},
7543
7544
  ...config.timeoutMs ? { timeoutMs: config.timeoutMs } : {},
7544
- 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."
7545
+ 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."
7545
7546
  });
7546
7547
  const internals = server;
7547
7548
  for (const [name, tool] of Object.entries(internals._registeredTools)) {
@@ -7556,7 +7557,8 @@ function createSetupModeServer(config) {
7556
7557
  }
7557
7558
  const spec = TOOL_CATALOG.find((t) => t.name === "diagnose_setup");
7558
7559
  if (!spec) throw new Error("[mushi-mcp] diagnose_setup is missing from TOOL_CATALOG");
7559
- const nextAction = "Run `npx mushi-mushi` in your project (signs you in and writes the key) or `mushi login`, then restart this MCP server.";
7560
+ const sdkKey = config.reason === "sdk-key";
7561
+ 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.";
7560
7562
  server.registerTool(
7561
7563
  "diagnose_setup",
7562
7564
  {
@@ -7578,7 +7580,12 @@ function createSetupModeServer(config) {
7578
7580
  ready: false,
7579
7581
  mode: "setup",
7580
7582
  steps: [
7581
- {
7583
+ sdkKey ? {
7584
+ label: "MCP server key can read reports (mcp:read)",
7585
+ complete: false,
7586
+ required: true,
7587
+ 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.`
7588
+ } : {
7582
7589
  label: "MCP server has an API key",
7583
7590
  complete: false,
7584
7591
  required: true,
@@ -7595,6 +7602,50 @@ function createSetupModeServer(config) {
7595
7602
  return server;
7596
7603
  }
7597
7604
 
7605
+ // src/key-scopes.ts
7606
+ async function fetchKeyScopes(opts) {
7607
+ const doFetch = opts.fetch ?? fetch;
7608
+ try {
7609
+ const res = await doFetch(`${opts.apiEndpoint.replace(/\/+$/, "")}/v1/sync/whoami`, {
7610
+ headers: {
7611
+ "X-Mushi-Api-Key": opts.apiKey,
7612
+ ...opts.projectId ? { "X-Mushi-Project-Id": opts.projectId } : {}
7613
+ },
7614
+ signal: AbortSignal.timeout(opts.timeoutMs ?? 5e3)
7615
+ });
7616
+ if (!res.ok) return null;
7617
+ const body = await res.json();
7618
+ const scopes = body?.data?.scopes;
7619
+ if (!Array.isArray(scopes)) return null;
7620
+ return scopes.filter((s) => typeof s === "string");
7621
+ } catch {
7622
+ return null;
7623
+ }
7624
+ }
7625
+ function decideScopes(keyScopes, configured) {
7626
+ if (keyScopes === null) return { kind: "serve", scopes: configured };
7627
+ const granted = /* @__PURE__ */ new Set();
7628
+ if (keyScopes.includes("mcp:write")) {
7629
+ granted.add("mcp:read");
7630
+ granted.add("mcp:write");
7631
+ } else if (keyScopes.includes("mcp:read")) {
7632
+ granted.add("mcp:read");
7633
+ }
7634
+ if (granted.size === 0) return { kind: "sdk-key", keyScopes };
7635
+ return { kind: "serve", scopes: configured.filter((s) => granted.has(s)) };
7636
+ }
7637
+ function sdkKeyReport(keyScopes, consoleUrl) {
7638
+ const held = keyScopes.length > 0 ? keyScopes.join(", ") : "none";
7639
+ return [
7640
+ "",
7641
+ `[mushi-mcp] This API key has scopes: ${held}. It can send bug reports (the SDK key) but not read them,`,
7642
+ " so the MCP tools would all be refused. Serving setup mode.",
7643
+ ` Fix: mint an MCP key in the console (${consoleUrl}/mcp \u2192 "Mint mcp:read key"),`,
7644
+ " or run `mushi login`, then put it in MUSHI_API_KEY for this server and restart it.",
7645
+ ""
7646
+ ].join("\n");
7647
+ }
7648
+
7598
7649
  // src/inventory-poll.ts
7599
7650
  function startInventoryPoll(options) {
7600
7651
  const doFetch = options.fetch ?? globalThis.fetch;
@@ -7854,6 +7905,23 @@ async function main() {
7854
7905
  );
7855
7906
  }
7856
7907
  }
7908
+ let scopes = SCOPES;
7909
+ if (!SCOPES_RAW) {
7910
+ const keyScopes = await fetchKeyScopes({ apiEndpoint: API_ENDPOINT, apiKey: API_KEY, projectId: PROJECT_ID || void 0 });
7911
+ const decision = decideScopes(keyScopes, SCOPES);
7912
+ if (decision.kind === "sdk-key") {
7913
+ const report = sdkKeyReport(decision.keyScopes, MUSHI_CONSOLE_URL);
7914
+ process.stderr.write(report);
7915
+ log.warn("The API key has no MCP scope (mcp:read / mcp:write) \u2014 serving setup mode.", {
7916
+ keyScopes: decision.keyScopes.join(",")
7917
+ });
7918
+ serveUntilClosed(serveStdio(() => createSetupModeServer({ version: VERSION, missingKeyReport: report, reason: "sdk-key" }), {
7919
+ onerror: (err) => log.error("stdio transport error", { err: String(err) })
7920
+ }));
7921
+ return;
7922
+ }
7923
+ scopes = decision.scopes;
7924
+ }
7857
7925
  const mode = PROJECT_ID ? "single-project" : "account";
7858
7926
  if (!PROJECT_ID) {
7859
7927
  log.info(
@@ -7865,7 +7933,7 @@ async function main() {
7865
7933
  mode,
7866
7934
  endpoint: API_ENDPOINT,
7867
7935
  hasProjectId: !!PROJECT_ID,
7868
- scopes: SCOPES.join(",")
7936
+ scopes: scopes.join(",")
7869
7937
  });
7870
7938
  let server;
7871
7939
  const handle = serveStdio(
@@ -7875,7 +7943,7 @@ async function main() {
7875
7943
  apiEndpoint: API_ENDPOINT,
7876
7944
  apiKey: API_KEY,
7877
7945
  projectId: PROJECT_ID || void 0,
7878
- scopes: SCOPES,
7946
+ scopes,
7879
7947
  features: FEATURES
7880
7948
  });
7881
7949
  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
@@ -86,7 +86,7 @@ var MUSHI_DOCS_INDEX = [
86
86
  route: "/admin/billing",
87
87
  markdown: "admin/billing.md",
88
88
  keywords: ["admin", "billing"],
89
- headings: ["Reading your usage card", "Usage breakdown", "Predictability controls", "Upgrading your plan", "Managing payment and invoices", "CLI parity", "Related docs"],
89
+ headings: ["Reading your usage card", "Usage breakdown", "Predictability controls", "Upgrading your plan", "Changing plan", "Managing payment and invoices", "CLI parity", "Related docs"],
90
90
  excerpt: "The Billing page shows your diagnosis quota, usage alerts at 50% and 80%, your projected bill, and spend caps for your Mushi plan."
91
91
  },
92
92
  {
@@ -464,7 +464,7 @@ var MUSHI_DOCS_INDEX = [
464
464
  route: "/admin/research",
465
465
  markdown: "admin/research.md",
466
466
  keywords: ["admin", "research"],
467
- headings: ["What it's for", "Running a search", "Saving results", "Prerequisites", "Related pages"],
467
+ headings: ["What it's for", "Running a search", "Saving results", "Automatic results on error reports", "Prerequisites", "Related pages"],
468
468
  excerpt: "The Research page runs a Firecrawl web search scoped to your tech stack and returns summarised answers with links to their sources."
469
469
  },
470
470
  {
@@ -1751,7 +1751,7 @@ var MUSHI_DOCS_INDEX = [
1751
1751
  route: "/security/byok",
1752
1752
  markdown: "security/byok.md",
1753
1753
  keywords: ["security", "byok", "bring-your-own-key"],
1754
- headings: ["Setup", "What uses the key", "OpenRouter", "Audit trail", "Rotation", "Langfuse trace attribution"],
1754
+ headings: ["Setup", "One key for every app", "What uses the key", "OpenRouter", "Audit trail", "Rotation", "Langfuse trace attribution"],
1755
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."
1756
1756
  },
1757
1757
  {
@@ -3981,7 +3981,8 @@ function createMushiServer(config) {
3981
3981
  );
3982
3982
  const latest = data.latest ?? data.version;
3983
3983
  const current = args.current;
3984
- const outdated = current && latest ? current !== latest : void 0;
3984
+ const pinned = current?.trim().replace(/^[\^~>=<v\s]+/, "");
3985
+ const outdated = pinned && latest ? pinned !== latest : void 0;
3985
3986
  return jsonResult({
3986
3987
  package: data.package ?? pkg,
3987
3988
  latest,
@@ -6217,7 +6218,7 @@ function createSetupModeServer(config) {
6217
6218
  features: "all",
6218
6219
  ...config.fetch ? { fetch: config.fetch } : {},
6219
6220
  ...config.timeoutMs ? { timeoutMs: config.timeoutMs } : {},
6220
- 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."
6221
+ 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."
6221
6222
  });
6222
6223
  const internals = server;
6223
6224
  for (const [name, tool] of Object.entries(internals._registeredTools)) {
@@ -6232,7 +6233,8 @@ function createSetupModeServer(config) {
6232
6233
  }
6233
6234
  const spec = TOOL_CATALOG.find((t) => t.name === "diagnose_setup");
6234
6235
  if (!spec) throw new Error("[mushi-mcp] diagnose_setup is missing from TOOL_CATALOG");
6235
- const nextAction = "Run `npx mushi-mushi` in your project (signs you in and writes the key) or `mushi login`, then restart this MCP server.";
6236
+ const sdkKey = config.reason === "sdk-key";
6237
+ 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.";
6236
6238
  server.registerTool(
6237
6239
  "diagnose_setup",
6238
6240
  {
@@ -6254,7 +6256,12 @@ function createSetupModeServer(config) {
6254
6256
  ready: false,
6255
6257
  mode: "setup",
6256
6258
  steps: [
6257
- {
6259
+ sdkKey ? {
6260
+ label: "MCP server key can read reports (mcp:read)",
6261
+ complete: false,
6262
+ required: true,
6263
+ 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.`
6264
+ } : {
6258
6265
  label: "MCP server has an API key",
6259
6266
  complete: false,
6260
6267
  required: true,
@@ -6271,6 +6278,7 @@ function createSetupModeServer(config) {
6271
6278
  return server;
6272
6279
  }
6273
6280
  export {
6281
+ MUSHI_CONSOLE_URL,
6274
6282
  MushiApiError,
6275
6283
  SETUP_MODE_TOOLS,
6276
6284
  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.4",
4
+ "version": "0.24.6",
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.2"
48
+ "@mushi-mushi/core": "^1.32.2"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@sentry/node": "^10.57.0"