@mushi-mushi/mcp 0.26.1 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ Restart the editor and ask *"what's broken in prod?"*. For Cursor and Claude, `s
29
29
  "mcpServers": {
30
30
  "mushi-mushi": {
31
31
  "command": "npx",
32
- "args": ["-y", "@mushi-mushi/mcp@0.26.1"],
32
+ "args": ["-y", "@mushi-mushi/mcp@0.28.0"],
33
33
  "env": {
34
34
  "MUSHI_API_KEY": "mushi_xxxxxxxxxxxxxxxxxxxx",
35
35
  "MUSHI_PROJECT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
@@ -59,7 +59,7 @@ Claude Desktop does not expand `${VAR}` references in this file; Cursor and VS C
59
59
  | `diagnose_setup` | Explains a broken install and the one next step |
60
60
  | `search_mushi_docs` | Answers setup and API questions from the docs |
61
61
 
62
- The full catalog has 117 tools, plus 8 resources (`project://dashboard`, `project://stats`, …) and 4 prompts (`summarize_report_for_fix`, `triage_next_steps`, …). Every tool carries read-only and destructive hints, so your editor can ask before it changes anything. Full list: [MCP tool reference](https://kensaur.us/mushi-mushi/docs/sdks/mcp-tools).
62
+ The full catalog has 119 tools, plus 8 resources (`project://dashboard`, `project://stats`, …) and 4 prompts (`summarize_report_for_fix`, `triage_next_steps`, …). Every tool carries read-only and destructive hints, so your editor can ask before it changes anything. Full list: [MCP tool reference](https://kensaur.us/mushi-mushi/docs/sdks/mcp-tools).
63
63
 
64
64
  **Tool groups.** New installs get a lean default: `triage`, `fixes`, `inventory`, `setup`, `docs`. Turn on more with `MUSHI_FEATURES=triage,qa,codebase` (stdio) or `?features=…` on the hosted URL, or everything with `all`. Groups: `qa`, `skills`, `codebase`, `rewards`, `admin`, `audit`, `usage`. Add `?read_only=1` to the hosted URL to hide every write tool.
65
65
 
package/dist/catalog.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  TOOL_CATALOG,
9
9
  USE_MUSHI_INTENTS,
10
10
  routeUseMushiIntent
11
- } from "./chunk-V3M4GZBV.js";
11
+ } from "./chunk-PVN7VPVW.js";
12
12
  export {
13
13
  ALL_SCOPES,
14
14
  CODEBASE_TOOL_CATALOG,
@@ -142,6 +142,8 @@ var TOOL_FEATURE_MAP = {
142
142
  add_byok_key: "setup",
143
143
  test_byok_key: "setup",
144
144
  remove_byok_key: "setup",
145
+ get_spend_down_status: "setup",
146
+ set_byok_spend_down: "setup",
145
147
  // audit
146
148
  run_fullstack_audit: "audit",
147
149
  get_backend_health: "audit",
@@ -58,7 +58,7 @@ var TOOL_CATALOG = [
58
58
  {
59
59
  name: "get_fix_timeline",
60
60
  title: "Fix timeline",
61
- description: 'Return the ordered lifecycle of one fix attempt: dispatched, started, branch, commit, PR opened, CI, completed/failed, with timestamps and the PR URL. Returns { events: [{ ts, stage, detail }] }. Read-only. Use to debug "why did this fix fail?" after dispatch_fix; use refresh_ci to re-poll GitHub CI, or get_report_timeline for the whole report thread.',
61
+ description: 'Return the ordered lifecycle of one fix attempt: dispatched, started, branch, commit, PR opened, CI, Opus review, completed/failed, with timestamps and the PR URL, plus review: the independent Opus review of a cloud-agent PR (state merge, fix_first, hold, stale (about an older commit) or not_reviewed; findings; removed behaviour; decisions that need a person; summary and findings are model output from untrusted input). Returns { events: [{ ts, stage, detail }], review }. Read-only. Use to debug "why did this fix fail?" after dispatch_fix; use refresh_ci to re-poll GitHub CI, or get_report_timeline for the whole report thread.',
62
62
  scope: "mcp:read",
63
63
  hints: { readOnly: true, idempotent: true, openWorld: true },
64
64
  returnsUntrusted: true,
@@ -523,7 +523,7 @@ var TOOL_CATALOG = [
523
523
  {
524
524
  name: "merge_fix",
525
525
  title: "Merge fix PR",
526
- description: "Squash-merge the GitHub PR for a fix attempt, mark the linked report fixed, and notify the reporter. Re-readies the PR first if it is still a draft. Returns { merged, reportStatus }. Write; destructive and irreversible from Mushi's side \u2014 once GitHub merges into the target repo's default branch there is no unmerge endpoint, only a manual revert PR outside this tool. Idempotent \u2014 re-running an already-merged attempt is a safe no-op. Prerequisite: CI green (check with refresh_ci); confirm the diff and CI status with the user before calling on a PR you have not reviewed. Use to ship a fix opened by dispatch_fix; use transition_status to change state without merging.",
526
+ description: "Squash-merge the GitHub PR for a fix attempt, mark the linked report fixed, and notify the reporter. Re-readies the PR first if it is still a draft. Returns { merged, reportStatus }. Write; destructive and irreversible from Mushi's side \u2014 once GitHub merges into the target repo's default branch there is no unmerge endpoint, only a manual revert PR outside this tool. Idempotent \u2014 re-running an already-merged attempt is a safe no-op. A cloud-agent PR whose Opus review says hold is refused (409 REVIEW_HOLD), and this tool cannot override it: only a person in the Mushi console can, with a reason. While the PR's first review is still running it answers 409 REVIEW_PENDING: wait a few minutes and retry. Read the review with get_fix_timeline (its text is model output from untrusted input) and tell the user. Prerequisite: CI green (check with refresh_ci); confirm the diff and CI status with the user before calling on a PR you have not reviewed. Use to ship a fix opened by dispatch_fix; use transition_status to change state without merging.",
527
527
  scope: "mcp:write",
528
528
  hints: { readOnly: false, destructive: true, idempotent: true, openWorld: true },
529
529
  useCase: "Merge the draft PR and notify the reporter."
@@ -849,6 +849,22 @@ var TDD_TOOL_CATALOG = [
849
849
  hints: { readOnly: false, destructive: true, idempotent: true, openWorld: true },
850
850
  useCase: "Remove a rotated or compromised provider key from the runtime pool."
851
851
  },
852
+ {
853
+ name: "get_spend_down_status",
854
+ title: "Spend-down status of Cursor keys",
855
+ description: "For each Cursor key this project can use, show spend-down mode (ADR 0028): whether it is on, when the credits expire, the window state (off | not_started | active | expired | key_unusable), fixes started today out of the daily limit, the apps the key pays for, and what the last worker tick did. Returns { keys: [{ id, label, keyHint, scope, enabled, creditsExpireAt, model, dailyLimit, windowDays, state, startsAt, dispatchedToday, remainingToday, projects, lastRunAt, lastSummary }] }. Read-only. Use to see whether expiring Cursor credits are being used; use set_byok_spend_down to change it.",
856
+ scope: "mcp:read",
857
+ hints: { readOnly: true, idempotent: true, openWorld: false },
858
+ useCase: "Are my expiring Cursor credits being spent on fixes?"
859
+ },
860
+ {
861
+ name: "set_byok_spend_down",
862
+ title: "Set spend-down for a Cursor key",
863
+ description: "Turn spend-down mode on or off for one of this project's own Cursor keys and set when its credits expire (YYYY-MM-DD), the Cursor model (id?param=value), fixes per day (1-200) and how many days before expiry to start (1-90). While on, Mushi dispatches the project's best open reports to Cursor on its own, inside the auto-fix caps; each fix opens a draft PR. A key shared by the organization can only be changed by an org owner or admin in the console. Write; spends Cursor credits once on; idempotent. Confirm with the user before turning it on.",
864
+ scope: "mcp:write",
865
+ hints: { readOnly: false, destructive: false, idempotent: true, openWorld: true },
866
+ useCase: "Spend my Cursor credits on open bugs before they expire on the 31st."
867
+ },
852
868
  {
853
869
  name: "list_pending_review_stories",
854
870
  title: "List QA stories pending review",
package/dist/clients.d.ts CHANGED
@@ -49,7 +49,7 @@ import { FeatureGroup } from './feature-groups.js';
49
49
  * editor launch. Synced to package.json by `scripts/sync-mcp-pin.mjs` — never
50
50
  * hand-edit the version.
51
51
  */
52
- declare const MCP_PIN_SPEC = "@mushi-mushi/mcp@0.26.1";
52
+ declare const MCP_PIN_SPEC = "@mushi-mushi/mcp@0.28.0";
53
53
  interface StdioConfig {
54
54
  command: string;
55
55
  args: string[];
package/dist/clients.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  DEFAULT_FEATURE_GROUPS,
6
6
  appendFeaturesToUrl,
7
7
  featuresQueryString
8
- } from "./chunk-F65T4IGT.js";
8
+ } from "./chunk-DJCVJ3YZ.js";
9
9
 
10
10
  // src/clients.ts
11
- var MCP_PIN_SPEC = "@mushi-mushi/mcp@0.26.1";
11
+ var MCP_PIN_SPEC = "@mushi-mushi/mcp@0.28.0";
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;
@@ -9,7 +9,7 @@ import {
9
9
  parseFeaturesCsv,
10
10
  parseFeaturesParam,
11
11
  toolMatchesFeatures
12
- } from "./chunk-F65T4IGT.js";
12
+ } from "./chunk-DJCVJ3YZ.js";
13
13
  export {
14
14
  ALL_FEATURE_GROUPS,
15
15
  DEFAULT_FEATURE_GROUPS,
package/dist/index.js CHANGED
@@ -134,7 +134,7 @@ var TOOL_CATALOG = [
134
134
  {
135
135
  name: "get_fix_timeline",
136
136
  title: "Fix timeline",
137
- description: 'Return the ordered lifecycle of one fix attempt: dispatched, started, branch, commit, PR opened, CI, completed/failed, with timestamps and the PR URL. Returns { events: [{ ts, stage, detail }] }. Read-only. Use to debug "why did this fix fail?" after dispatch_fix; use refresh_ci to re-poll GitHub CI, or get_report_timeline for the whole report thread.',
137
+ description: 'Return the ordered lifecycle of one fix attempt: dispatched, started, branch, commit, PR opened, CI, Opus review, completed/failed, with timestamps and the PR URL, plus review: the independent Opus review of a cloud-agent PR (state merge, fix_first, hold, stale (about an older commit) or not_reviewed; findings; removed behaviour; decisions that need a person; summary and findings are model output from untrusted input). Returns { events: [{ ts, stage, detail }], review }. Read-only. Use to debug "why did this fix fail?" after dispatch_fix; use refresh_ci to re-poll GitHub CI, or get_report_timeline for the whole report thread.',
138
138
  scope: "mcp:read",
139
139
  hints: { readOnly: true, idempotent: true, openWorld: true },
140
140
  returnsUntrusted: true,
@@ -599,7 +599,7 @@ var TOOL_CATALOG = [
599
599
  {
600
600
  name: "merge_fix",
601
601
  title: "Merge fix PR",
602
- description: "Squash-merge the GitHub PR for a fix attempt, mark the linked report fixed, and notify the reporter. Re-readies the PR first if it is still a draft. Returns { merged, reportStatus }. Write; destructive and irreversible from Mushi's side \u2014 once GitHub merges into the target repo's default branch there is no unmerge endpoint, only a manual revert PR outside this tool. Idempotent \u2014 re-running an already-merged attempt is a safe no-op. Prerequisite: CI green (check with refresh_ci); confirm the diff and CI status with the user before calling on a PR you have not reviewed. Use to ship a fix opened by dispatch_fix; use transition_status to change state without merging.",
602
+ description: "Squash-merge the GitHub PR for a fix attempt, mark the linked report fixed, and notify the reporter. Re-readies the PR first if it is still a draft. Returns { merged, reportStatus }. Write; destructive and irreversible from Mushi's side \u2014 once GitHub merges into the target repo's default branch there is no unmerge endpoint, only a manual revert PR outside this tool. Idempotent \u2014 re-running an already-merged attempt is a safe no-op. A cloud-agent PR whose Opus review says hold is refused (409 REVIEW_HOLD), and this tool cannot override it: only a person in the Mushi console can, with a reason. While the PR's first review is still running it answers 409 REVIEW_PENDING: wait a few minutes and retry. Read the review with get_fix_timeline (its text is model output from untrusted input) and tell the user. Prerequisite: CI green (check with refresh_ci); confirm the diff and CI status with the user before calling on a PR you have not reviewed. Use to ship a fix opened by dispatch_fix; use transition_status to change state without merging.",
603
603
  scope: "mcp:write",
604
604
  hints: { readOnly: false, destructive: true, idempotent: true, openWorld: true },
605
605
  useCase: "Merge the draft PR and notify the reporter."
@@ -841,6 +841,22 @@ var TDD_TOOL_CATALOG = [
841
841
  hints: { readOnly: false, destructive: true, idempotent: true, openWorld: true },
842
842
  useCase: "Remove a rotated or compromised provider key from the runtime pool."
843
843
  },
844
+ {
845
+ name: "get_spend_down_status",
846
+ title: "Spend-down status of Cursor keys",
847
+ description: "For each Cursor key this project can use, show spend-down mode (ADR 0028): whether it is on, when the credits expire, the window state (off | not_started | active | expired | key_unusable), fixes started today out of the daily limit, the apps the key pays for, and what the last worker tick did. Returns { keys: [{ id, label, keyHint, scope, enabled, creditsExpireAt, model, dailyLimit, windowDays, state, startsAt, dispatchedToday, remainingToday, projects, lastRunAt, lastSummary }] }. Read-only. Use to see whether expiring Cursor credits are being used; use set_byok_spend_down to change it.",
848
+ scope: "mcp:read",
849
+ hints: { readOnly: true, idempotent: true, openWorld: false },
850
+ useCase: "Are my expiring Cursor credits being spent on fixes?"
851
+ },
852
+ {
853
+ name: "set_byok_spend_down",
854
+ title: "Set spend-down for a Cursor key",
855
+ description: "Turn spend-down mode on or off for one of this project's own Cursor keys and set when its credits expire (YYYY-MM-DD), the Cursor model (id?param=value), fixes per day (1-200) and how many days before expiry to start (1-90). While on, Mushi dispatches the project's best open reports to Cursor on its own, inside the auto-fix caps; each fix opens a draft PR. A key shared by the organization can only be changed by an org owner or admin in the console. Write; spends Cursor credits once on; idempotent. Confirm with the user before turning it on.",
856
+ scope: "mcp:write",
857
+ hints: { readOnly: false, destructive: false, idempotent: true, openWorld: true },
858
+ useCase: "Spend my Cursor credits on open bugs before they expire on the 31st."
859
+ },
844
860
  {
845
861
  name: "list_pending_review_stories",
846
862
  title: "List QA stories pending review",
@@ -1325,6 +1341,8 @@ var TOOL_FEATURE_MAP = {
1325
1341
  add_byok_key: "setup",
1326
1342
  test_byok_key: "setup",
1327
1343
  remove_byok_key: "setup",
1344
+ get_spend_down_status: "setup",
1345
+ set_byok_spend_down: "setup",
1328
1346
  // audit
1329
1347
  run_fullstack_audit: "audit",
1330
1348
  get_backend_health: "audit",
@@ -1539,7 +1557,7 @@ var MUSHI_DOCS_INDEX = [
1539
1557
  route: "/admin/dashboard",
1540
1558
  markdown: "admin/dashboard.md",
1541
1559
  keywords: ["admin", "dashboard"],
1542
- headings: ["What to look for first", "Flow canvas (Beginner mode)", "KPI tiles (14-day window)", "Charts row (14 days)", "Triage queue", "Insights row", "Common tasks", "Morning check (2 minutes)"],
1560
+ headings: ["What to look for first", "Flow canvas", "KPI tiles (14-day window)", "Charts row (14 days)", "Triage queue", "Insights row", "Common tasks", "Morning check (2 minutes)"],
1543
1561
  excerpt: "The Mushi dashboard answers whether anything broke since your last release \u2014 new reports, overnight fix runs and pipeline health on one screen."
1544
1562
  },
1545
1563
  {
@@ -2100,6 +2118,15 @@ var MUSHI_DOCS_INDEX = [
2100
2118
  headings: ["The evolution loop (what you're plugging into)", "What the agent reads before opening a PR", "What the agent does after merging the PR", "What Mushi commits to in return", "Self-bootstrap (Claude Code and similar)", "Privacy contract", "Scopes"],
2101
2119
  excerpt: "What Mushi expects an agent to read before opening a PR, and what it promises in return."
2102
2120
  },
2121
+ {
2122
+ title: "Agent PR review",
2123
+ url: docUrl("/concepts/agent-pr-review"),
2124
+ route: "/concepts/agent-pr-review",
2125
+ markdown: "concepts/agent-pr-review.md",
2126
+ keywords: ["concepts", "agent-pr-review", "agent", "review", "pr"],
2127
+ headings: ["What you see", "What the review checks", "Re-running a review", "Cost and keys", "For operators"],
2128
+ excerpt: 'Claude Opus 5.5 reviews every pull request a cloud coding agent opens as a fix, and a "hold" stops Mushi from merging it until you choose to.'
2129
+ },
2103
2130
  {
2104
2131
  title: "Anti-gaming & reputation",
2105
2132
  url: docUrl("/concepts/anti-gaming"),
@@ -5942,7 +5969,12 @@ function createMushiServer(config) {
5942
5969
  justMerged: z.boolean().optional().describe("True when this call performed the merge"),
5943
5970
  sha: z.string().nullable().optional().describe("Merge commit SHA, when GitHub reported one"),
5944
5971
  reportId: z.string().describe("Report UUID linked to this fix attempt"),
5945
- reportStatus: z.string().describe("Report workflow status after merge bookkeeping")
5972
+ reportStatus: z.string().describe("Report workflow status after merge bookkeeping"),
5973
+ review: z.object({
5974
+ state: z.string().describe("merge | fix_first | stale | queued | skipped | failed | not_reviewed (a hold never merges here)"),
5975
+ label: z.string().describe('One line, e.g. "Opus review: fix first" or "Not reviewed"'),
5976
+ overridden: z.boolean().describe("Always false from MCP: only a person in the console can override a hold")
5977
+ }).optional().describe("The Opus review of the PR at merge time (ADR 0030)")
5946
5978
  })
5947
5979
  },
5948
5980
  async (args) => {
@@ -6770,6 +6802,45 @@ Be specific. No generic advice.`
6770
6802
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
6771
6803
  }
6772
6804
  );
6805
+ server.registerTool(
6806
+ "get_spend_down_status",
6807
+ {
6808
+ title: titleOf("get_spend_down_status", TDD_TOOL_CATALOG),
6809
+ description: descOf("get_spend_down_status", TDD_TOOL_CATALOG),
6810
+ annotations: annotationsFor("get_spend_down_status", TDD_TOOL_CATALOG),
6811
+ inputSchema: z.object({
6812
+ projectId: z.string().describe("Project id")
6813
+ })
6814
+ },
6815
+ async ({ projectId: projectId2 }) => {
6816
+ const data = await apiCall(`/v1/admin/byok/spend-down?project_id=${encodeURIComponent(projectId2)}`);
6817
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
6818
+ }
6819
+ );
6820
+ server.registerTool(
6821
+ "set_byok_spend_down",
6822
+ {
6823
+ title: titleOf("set_byok_spend_down", TDD_TOOL_CATALOG),
6824
+ description: descOf("set_byok_spend_down", TDD_TOOL_CATALOG),
6825
+ annotations: annotationsFor("set_byok_spend_down", TDD_TOOL_CATALOG),
6826
+ inputSchema: z.object({
6827
+ projectId: z.string().describe("Project id"),
6828
+ keyId: z.string().uuid().describe("Cursor key id from get_spend_down_status"),
6829
+ enabled: z.boolean().optional().describe("Turn spend-down on or off"),
6830
+ creditsExpireAt: z.string().optional().describe("When the credits expire, YYYY-MM-DD"),
6831
+ model: z.string().max(300).optional().describe("Cursor model spec, e.g. grok-4.7?reasoning_effort=xhigh&context=500k"),
6832
+ dailyLimit: z.number().int().min(1).max(200).optional().describe("Fixes per day across the apps this key pays for"),
6833
+ windowDays: z.number().int().min(1).max(90).optional().describe("Start this many days before the credits expire")
6834
+ })
6835
+ },
6836
+ async ({ keyId, enabled, creditsExpireAt, model, dailyLimit, windowDays }) => {
6837
+ const data = await apiCall(`/v1/admin/byok/keys/${encodeURIComponent(keyId)}/spend-down`, {
6838
+ method: "PATCH",
6839
+ body: JSON.stringify({ enabled, creditsExpireAt, model, dailyLimit, windowDays })
6840
+ });
6841
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
6842
+ }
6843
+ );
6773
6844
  server.registerTool(
6774
6845
  "list_pending_review_stories",
6775
6846
  {
package/dist/server.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  TDD_TOOL_CATALOG,
5
5
  TOOL_CATALOG,
6
6
  routeUseMushiIntent
7
- } from "./chunk-V3M4GZBV.js";
7
+ } from "./chunk-PVN7VPVW.js";
8
8
  import {
9
9
  MUSHI_SERVER_METADATA
10
10
  } from "./chunk-FJRPC4VR.js";
@@ -12,7 +12,7 @@ import {
12
12
  DEPRECATED_TOOL_ALIASES,
13
13
  TOOL_FEATURE_MAP,
14
14
  toolMatchesFeatures
15
- } from "./chunk-F65T4IGT.js";
15
+ } from "./chunk-DJCVJ3YZ.js";
16
16
 
17
17
  // src/server.ts
18
18
  import { AsyncLocalStorage } from "async_hooks";
@@ -149,7 +149,7 @@ var MUSHI_DOCS_INDEX = [
149
149
  route: "/admin/dashboard",
150
150
  markdown: "admin/dashboard.md",
151
151
  keywords: ["admin", "dashboard"],
152
- headings: ["What to look for first", "Flow canvas (Beginner mode)", "KPI tiles (14-day window)", "Charts row (14 days)", "Triage queue", "Insights row", "Common tasks", "Morning check (2 minutes)"],
152
+ headings: ["What to look for first", "Flow canvas", "KPI tiles (14-day window)", "Charts row (14 days)", "Triage queue", "Insights row", "Common tasks", "Morning check (2 minutes)"],
153
153
  excerpt: "The Mushi dashboard answers whether anything broke since your last release \u2014 new reports, overnight fix runs and pipeline health on one screen."
154
154
  },
155
155
  {
@@ -710,6 +710,15 @@ var MUSHI_DOCS_INDEX = [
710
710
  headings: ["The evolution loop (what you're plugging into)", "What the agent reads before opening a PR", "What the agent does after merging the PR", "What Mushi commits to in return", "Self-bootstrap (Claude Code and similar)", "Privacy contract", "Scopes"],
711
711
  excerpt: "What Mushi expects an agent to read before opening a PR, and what it promises in return."
712
712
  },
713
+ {
714
+ title: "Agent PR review",
715
+ url: docUrl("/concepts/agent-pr-review"),
716
+ route: "/concepts/agent-pr-review",
717
+ markdown: "concepts/agent-pr-review.md",
718
+ keywords: ["concepts", "agent-pr-review", "agent", "review", "pr"],
719
+ headings: ["What you see", "What the review checks", "Re-running a review", "Cost and keys", "For operators"],
720
+ excerpt: 'Claude Opus 5.5 reviews every pull request a cloud coding agent opens as a fix, and a "hold" stops Mushi from merging it until you choose to.'
721
+ },
713
722
  {
714
723
  title: "Anti-gaming & reputation",
715
724
  url: docUrl("/concepts/anti-gaming"),
@@ -4618,7 +4627,12 @@ function createMushiServer(config) {
4618
4627
  justMerged: z.boolean().optional().describe("True when this call performed the merge"),
4619
4628
  sha: z.string().nullable().optional().describe("Merge commit SHA, when GitHub reported one"),
4620
4629
  reportId: z.string().describe("Report UUID linked to this fix attempt"),
4621
- reportStatus: z.string().describe("Report workflow status after merge bookkeeping")
4630
+ reportStatus: z.string().describe("Report workflow status after merge bookkeeping"),
4631
+ review: z.object({
4632
+ state: z.string().describe("merge | fix_first | stale | queued | skipped | failed | not_reviewed (a hold never merges here)"),
4633
+ label: z.string().describe('One line, e.g. "Opus review: fix first" or "Not reviewed"'),
4634
+ overridden: z.boolean().describe("Always false from MCP: only a person in the console can override a hold")
4635
+ }).optional().describe("The Opus review of the PR at merge time (ADR 0030)")
4622
4636
  })
4623
4637
  },
4624
4638
  async (args) => {
@@ -5446,6 +5460,45 @@ Be specific. No generic advice.`
5446
5460
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
5447
5461
  }
5448
5462
  );
5463
+ server.registerTool(
5464
+ "get_spend_down_status",
5465
+ {
5466
+ title: titleOf("get_spend_down_status", TDD_TOOL_CATALOG),
5467
+ description: descOf("get_spend_down_status", TDD_TOOL_CATALOG),
5468
+ annotations: annotationsFor("get_spend_down_status", TDD_TOOL_CATALOG),
5469
+ inputSchema: z.object({
5470
+ projectId: z.string().describe("Project id")
5471
+ })
5472
+ },
5473
+ async ({ projectId: projectId2 }) => {
5474
+ const data = await apiCall(`/v1/admin/byok/spend-down?project_id=${encodeURIComponent(projectId2)}`);
5475
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
5476
+ }
5477
+ );
5478
+ server.registerTool(
5479
+ "set_byok_spend_down",
5480
+ {
5481
+ title: titleOf("set_byok_spend_down", TDD_TOOL_CATALOG),
5482
+ description: descOf("set_byok_spend_down", TDD_TOOL_CATALOG),
5483
+ annotations: annotationsFor("set_byok_spend_down", TDD_TOOL_CATALOG),
5484
+ inputSchema: z.object({
5485
+ projectId: z.string().describe("Project id"),
5486
+ keyId: z.string().uuid().describe("Cursor key id from get_spend_down_status"),
5487
+ enabled: z.boolean().optional().describe("Turn spend-down on or off"),
5488
+ creditsExpireAt: z.string().optional().describe("When the credits expire, YYYY-MM-DD"),
5489
+ model: z.string().max(300).optional().describe("Cursor model spec, e.g. grok-4.7?reasoning_effort=xhigh&context=500k"),
5490
+ dailyLimit: z.number().int().min(1).max(200).optional().describe("Fixes per day across the apps this key pays for"),
5491
+ windowDays: z.number().int().min(1).max(90).optional().describe("Start this many days before the credits expire")
5492
+ })
5493
+ },
5494
+ async ({ keyId, enabled, creditsExpireAt, model, dailyLimit, windowDays }) => {
5495
+ const data = await apiCall(`/v1/admin/byok/keys/${encodeURIComponent(keyId)}/spend-down`, {
5496
+ method: "PATCH",
5497
+ body: JSON.stringify({ enabled, creditsExpireAt, model, dailyLimit, windowDays })
5498
+ });
5499
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
5500
+ }
5501
+ );
5449
5502
  server.registerTool(
5450
5503
  "list_pending_review_stories",
5451
5504
  {
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.26.1",
4
+ "version": "0.28.0",
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",
@@ -42,8 +42,8 @@
42
42
  "LICENSE"
43
43
  ],
44
44
  "dependencies": {
45
- "@modelcontextprotocol/core": "^2.0.0",
46
- "@modelcontextprotocol/server": "^2.0.0",
45
+ "@modelcontextprotocol/core": "^2.3.1",
46
+ "@modelcontextprotocol/server": "^2.3.1",
47
47
  "zod": "^4.4.3",
48
48
  "@mushi-mushi/core": "^1.33.1"
49
49
  },
@@ -56,7 +56,7 @@
56
56
  }
57
57
  },
58
58
  "devDependencies": {
59
- "@modelcontextprotocol/sdk": "^1.29.0",
59
+ "@modelcontextprotocol/sdk": "^1.32.1",
60
60
  "@sentry/node": "^10.57.0",
61
61
  "@types/node": "^22.20.0",
62
62
  "eslint": "^10.6.0",