@mushi-mushi/mcp 0.22.0 → 0.23.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 +3 -3
- package/dist/catalog.js +1 -1
- package/dist/{chunk-LFSAKI6Z.js → chunk-CXSLU5V5.js} +4 -0
- package/dist/{chunk-RPSPV4FC.js → chunk-EFENR3EA.js} +34 -1
- package/dist/clients.d.ts +1 -1
- package/dist/clients.js +2 -2
- package/dist/feature-groups.js +1 -1
- package/dist/index.js +156 -6
- package/dist/server.js +120 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -132,7 +132,7 @@ The Mushi backend now exposes the same tool catalog over the **Streamable HTTP**
|
|
|
132
132
|
|
|
133
133
|
### Feature groups (`?features=` / `MUSHI_FEATURES`)
|
|
134
134
|
|
|
135
|
-
Full catalog is **
|
|
135
|
+
Full catalog is **80 tools** (stdio / `MUSHI_FEATURES=all`). The hosted HTTP
|
|
136
136
|
endpoint exposes a leaner subset filtered by feature groups (see
|
|
137
137
|
`mcp-hosted-tool-manifest.json`). New installs now default to the lean
|
|
138
138
|
`triage,fixes,inventory,setup,docs` set automatically (stdio: when
|
|
@@ -399,7 +399,7 @@ Spawns `dist/index.js` with a dummy unreachable endpoint and confirms it adverti
|
|
|
399
399
|
pnpm --filter @mushi-mushi/mcp build
|
|
400
400
|
pnpm --filter @mushi-mushi/mcp test:smoke
|
|
401
401
|
# OK; prints live tool/resource/prompt counts from the catalog
|
|
402
|
-
# (see packages/mcp/src/catalog.ts — currently
|
|
402
|
+
# (see packages/mcp/src/catalog.ts — currently 80 tools / 8 resources / 4 prompts)
|
|
403
403
|
```
|
|
404
404
|
|
|
405
405
|
### Layer 3; Full localhost E2E (real binary + real backend behaviour)
|
|
@@ -493,4 +493,4 @@ MIT
|
|
|
493
493
|
<!-- mushi-readme-stats-footer -->
|
|
494
494
|
---
|
|
495
495
|
|
|
496
|
-
<sub>Monorepo scale (July 2026):
|
|
496
|
+
<sub>Monorepo scale (July 2026): 60 edge functions · 383 SQL migrations · 13 outbound plugins · 11 inbound adapters · 19 pipeline agents. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>
|
package/dist/catalog.js
CHANGED
|
@@ -40,6 +40,7 @@ var TOOL_FEATURE_MAP = {
|
|
|
40
40
|
run_nl_query: "triage",
|
|
41
41
|
get_report_evidence: "triage",
|
|
42
42
|
triage_issue: "triage",
|
|
43
|
+
import_sentry_issues: "triage",
|
|
43
44
|
query_lessons: "triage",
|
|
44
45
|
list_lessons: "triage",
|
|
45
46
|
suggest_fix: "triage",
|
|
@@ -64,6 +65,9 @@ var TOOL_FEATURE_MAP = {
|
|
|
64
65
|
refresh_ci: "fixes",
|
|
65
66
|
reopen_report: "fixes",
|
|
66
67
|
reply_to_reporter: "fixes",
|
|
68
|
+
request_reporter_info: "fixes",
|
|
69
|
+
list_reporter_outbox: "fixes",
|
|
70
|
+
release_reporter_update: "fixes",
|
|
67
71
|
// rewards
|
|
68
72
|
list_top_contributors: "rewards",
|
|
69
73
|
award_bonus_points: "rewards",
|
|
@@ -213,7 +213,7 @@ var TOOL_CATALOG = [
|
|
|
213
213
|
{
|
|
214
214
|
name: "transition_status",
|
|
215
215
|
title: "Move report between states",
|
|
216
|
-
description: "Move a report to a new workflow state, enforcing the same transition rules as the admin UI. Valid targets: classified, grouped, fixing, fixed, verified, reopened, dismissed.
|
|
216
|
+
description: "Move a report to a new workflow state, enforcing the same transition rules as the admin UI. Valid targets: classified, grouped, fixing, fixed, verified, reopened, dismissed. When dismissing, closedReason (duplicate, not_reproducible, wont_fix, working_as_intended, spam) sets what the reporter is told \u2014 spam closes silently, and duplicate needs the report grouped under another one first; reporterMessage posts your note to the reporter verbatim. Returns { ok }. Write; idempotent (setting the current status is a no-op); rejects illegal transitions. Use to dismiss a duplicate or mark fixed; use merge_fix to mark fixed via a merged PR, or reopen_report for the reopened path.",
|
|
217
217
|
scope: "mcp:write",
|
|
218
218
|
hints: { readOnly: false, destructive: true, idempotent: true, openWorld: true },
|
|
219
219
|
useCase: "Dismiss this duplicate / mark it fixed."
|
|
@@ -319,6 +319,14 @@ var TOOL_CATALOG = [
|
|
|
319
319
|
returnsUntrusted: true,
|
|
320
320
|
useCase: "Analyze this bug report end-to-end and tell me what to do."
|
|
321
321
|
},
|
|
322
|
+
{
|
|
323
|
+
name: "import_sentry_issues",
|
|
324
|
+
title: "Import Sentry issues",
|
|
325
|
+
description: "Pull existing Sentry issues into Mushi's report queue: by issueIds (numeric ids or short ids like WEB-12, at most 10) or by a Sentry search query (default is:unresolved) within the project's configured Sentry project, limit 1-10. Each issue goes through the same path as a Sentry webhook delivery: deduped per issue, linked, classified. An issue already linked to a report answers linked and is never reopened. Returns { items: [{ input, issueId, shortId, outcome, reportId, error? }], created, linked, failed, indexing }. Write; idempotent; spends classification budget per new report. Needs the Sentry org slug, project slug and an auth token (event:read, project:read) in Integrations \u2192 Sentry. Use for issues that existed before the webhook was wired; then call triage_issue on a created report.",
|
|
326
|
+
scope: "mcp:write",
|
|
327
|
+
hints: { readOnly: false, destructive: false, idempotent: true, openWorld: true },
|
|
328
|
+
useCase: "Pull my open Sentry issues into Mushi so I can triage and fix them."
|
|
329
|
+
},
|
|
322
330
|
{
|
|
323
331
|
name: "triage_next_steps",
|
|
324
332
|
title: "What should I work on now?",
|
|
@@ -563,6 +571,31 @@ var TDD_TOOL_CATALOG = [
|
|
|
563
571
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: false },
|
|
564
572
|
useCase: "Reply to a reporter asking for more info or confirming a fix."
|
|
565
573
|
},
|
|
574
|
+
{
|
|
575
|
+
name: "request_reporter_info",
|
|
576
|
+
title: "Ask the reporter a question",
|
|
577
|
+
description: 'Ask the end-user who filed a report a question: it appears in their in-app "Your reports" thread, marks the report "Waiting on you", and the waiting state clears when they answer (their reply reaches Slack and the console). Returns { comment_id, awaiting_reporter }. Write; messages a real end user and is NOT idempotent \u2014 each call posts another question, so confirm the wording with the user first. Fails with NO_REPORTER for reports that came from an integration. Use when you need reproduction details; use reply_to_reporter for a plain reply.',
|
|
578
|
+
scope: "mcp:write",
|
|
579
|
+
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: false },
|
|
580
|
+
useCase: "Ask the reporter which page or device this happened on."
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
name: "list_reporter_outbox",
|
|
584
|
+
title: "List held reporter updates",
|
|
585
|
+
description: 'List pipeline messages waiting for review before they reach reporters (projects in review mode hold "fix in progress", "fixed", "shipped in vX" and "closed" messages). Each row has { id, report_id, report_title, notification_type, text, body_override, created_at }; text is exactly what the reporter will see. Read-only. Use before release_reporter_update; an empty list means nothing is waiting (or the project sends updates automatically).',
|
|
586
|
+
scope: "mcp:read",
|
|
587
|
+
hints: { readOnly: true, idempotent: true, openWorld: false },
|
|
588
|
+
returnsUntrusted: true,
|
|
589
|
+
useCase: "What reporter updates are waiting for my review?"
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
name: "release_reporter_update",
|
|
593
|
+
title: "Release or discard a held reporter update",
|
|
594
|
+
description: "Send (action=release, the default) or drop (action=discard) one held reporter message from list_reporter_outbox; bodyOverride replaces its text before sending. Returns { delivered, skipped, failed }. Write; messages a real end user \u2014 confirm with the user first. Idempotent in effect: a message that is no longer held returns CONFLICT instead of sending twice.",
|
|
595
|
+
scope: "mcp:write",
|
|
596
|
+
hints: { readOnly: false, destructive: false, idempotent: true, openWorld: false },
|
|
597
|
+
useCase: 'Send the "fixed in v1.4" update to the reporter.'
|
|
598
|
+
},
|
|
566
599
|
{
|
|
567
600
|
name: "get_two_way_comms_health",
|
|
568
601
|
title: "Two-way communication health",
|
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.
|
|
49
|
+
declare const MCP_PIN_SPEC = "@mushi-mushi/mcp@0.23.0";
|
|
50
50
|
interface StdioConfig {
|
|
51
51
|
command: string;
|
|
52
52
|
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-
|
|
8
|
+
} from "./chunk-CXSLU5V5.js";
|
|
9
9
|
|
|
10
10
|
// src/clients.ts
|
|
11
|
-
var MCP_PIN_SPEC = "@mushi-mushi/mcp@0.
|
|
11
|
+
var MCP_PIN_SPEC = "@mushi-mushi/mcp@0.23.0";
|
|
12
12
|
function projectServerName(projectId, projectName) {
|
|
13
13
|
const nameSlug = projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 22);
|
|
14
14
|
const idSuffix = projectId.replace(/-/g, "").slice(0, 6);
|
package/dist/feature-groups.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -289,7 +289,7 @@ var TOOL_CATALOG = [
|
|
|
289
289
|
{
|
|
290
290
|
name: "transition_status",
|
|
291
291
|
title: "Move report between states",
|
|
292
|
-
description: "Move a report to a new workflow state, enforcing the same transition rules as the admin UI. Valid targets: classified, grouped, fixing, fixed, verified, reopened, dismissed.
|
|
292
|
+
description: "Move a report to a new workflow state, enforcing the same transition rules as the admin UI. Valid targets: classified, grouped, fixing, fixed, verified, reopened, dismissed. When dismissing, closedReason (duplicate, not_reproducible, wont_fix, working_as_intended, spam) sets what the reporter is told \u2014 spam closes silently, and duplicate needs the report grouped under another one first; reporterMessage posts your note to the reporter verbatim. Returns { ok }. Write; idempotent (setting the current status is a no-op); rejects illegal transitions. Use to dismiss a duplicate or mark fixed; use merge_fix to mark fixed via a merged PR, or reopen_report for the reopened path.",
|
|
293
293
|
scope: "mcp:write",
|
|
294
294
|
hints: { readOnly: false, destructive: true, idempotent: true, openWorld: true },
|
|
295
295
|
useCase: "Dismiss this duplicate / mark it fixed."
|
|
@@ -395,6 +395,14 @@ var TOOL_CATALOG = [
|
|
|
395
395
|
returnsUntrusted: true,
|
|
396
396
|
useCase: "Analyze this bug report end-to-end and tell me what to do."
|
|
397
397
|
},
|
|
398
|
+
{
|
|
399
|
+
name: "import_sentry_issues",
|
|
400
|
+
title: "Import Sentry issues",
|
|
401
|
+
description: "Pull existing Sentry issues into Mushi's report queue: by issueIds (numeric ids or short ids like WEB-12, at most 10) or by a Sentry search query (default is:unresolved) within the project's configured Sentry project, limit 1-10. Each issue goes through the same path as a Sentry webhook delivery: deduped per issue, linked, classified. An issue already linked to a report answers linked and is never reopened. Returns { items: [{ input, issueId, shortId, outcome, reportId, error? }], created, linked, failed, indexing }. Write; idempotent; spends classification budget per new report. Needs the Sentry org slug, project slug and an auth token (event:read, project:read) in Integrations \u2192 Sentry. Use for issues that existed before the webhook was wired; then call triage_issue on a created report.",
|
|
402
|
+
scope: "mcp:write",
|
|
403
|
+
hints: { readOnly: false, destructive: false, idempotent: true, openWorld: true },
|
|
404
|
+
useCase: "Pull my open Sentry issues into Mushi so I can triage and fix them."
|
|
405
|
+
},
|
|
398
406
|
{
|
|
399
407
|
name: "triage_next_steps",
|
|
400
408
|
title: "What should I work on now?",
|
|
@@ -555,6 +563,31 @@ var TDD_TOOL_CATALOG = [
|
|
|
555
563
|
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: false },
|
|
556
564
|
useCase: "Reply to a reporter asking for more info or confirming a fix."
|
|
557
565
|
},
|
|
566
|
+
{
|
|
567
|
+
name: "request_reporter_info",
|
|
568
|
+
title: "Ask the reporter a question",
|
|
569
|
+
description: 'Ask the end-user who filed a report a question: it appears in their in-app "Your reports" thread, marks the report "Waiting on you", and the waiting state clears when they answer (their reply reaches Slack and the console). Returns { comment_id, awaiting_reporter }. Write; messages a real end user and is NOT idempotent \u2014 each call posts another question, so confirm the wording with the user first. Fails with NO_REPORTER for reports that came from an integration. Use when you need reproduction details; use reply_to_reporter for a plain reply.',
|
|
570
|
+
scope: "mcp:write",
|
|
571
|
+
hints: { readOnly: false, destructive: false, idempotent: false, openWorld: false },
|
|
572
|
+
useCase: "Ask the reporter which page or device this happened on."
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
name: "list_reporter_outbox",
|
|
576
|
+
title: "List held reporter updates",
|
|
577
|
+
description: 'List pipeline messages waiting for review before they reach reporters (projects in review mode hold "fix in progress", "fixed", "shipped in vX" and "closed" messages). Each row has { id, report_id, report_title, notification_type, text, body_override, created_at }; text is exactly what the reporter will see. Read-only. Use before release_reporter_update; an empty list means nothing is waiting (or the project sends updates automatically).',
|
|
578
|
+
scope: "mcp:read",
|
|
579
|
+
hints: { readOnly: true, idempotent: true, openWorld: false },
|
|
580
|
+
returnsUntrusted: true,
|
|
581
|
+
useCase: "What reporter updates are waiting for my review?"
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
name: "release_reporter_update",
|
|
585
|
+
title: "Release or discard a held reporter update",
|
|
586
|
+
description: "Send (action=release, the default) or drop (action=discard) one held reporter message from list_reporter_outbox; bodyOverride replaces its text before sending. Returns { delivered, skipped, failed }. Write; messages a real end user \u2014 confirm with the user first. Idempotent in effect: a message that is no longer held returns CONFLICT instead of sending twice.",
|
|
587
|
+
scope: "mcp:write",
|
|
588
|
+
hints: { readOnly: false, destructive: false, idempotent: true, openWorld: false },
|
|
589
|
+
useCase: 'Send the "fixed in v1.4" update to the reporter.'
|
|
590
|
+
},
|
|
558
591
|
{
|
|
559
592
|
name: "get_two_way_comms_health",
|
|
560
593
|
title: "Two-way communication health",
|
|
@@ -865,6 +898,7 @@ var TOOL_FEATURE_MAP = {
|
|
|
865
898
|
run_nl_query: "triage",
|
|
866
899
|
get_report_evidence: "triage",
|
|
867
900
|
triage_issue: "triage",
|
|
901
|
+
import_sentry_issues: "triage",
|
|
868
902
|
query_lessons: "triage",
|
|
869
903
|
list_lessons: "triage",
|
|
870
904
|
suggest_fix: "triage",
|
|
@@ -889,6 +923,9 @@ var TOOL_FEATURE_MAP = {
|
|
|
889
923
|
refresh_ci: "fixes",
|
|
890
924
|
reopen_report: "fixes",
|
|
891
925
|
reply_to_reporter: "fixes",
|
|
926
|
+
request_reporter_info: "fixes",
|
|
927
|
+
list_reporter_outbox: "fixes",
|
|
928
|
+
release_reporter_update: "fixes",
|
|
892
929
|
// rewards
|
|
893
930
|
list_top_contributors: "rewards",
|
|
894
931
|
award_bonus_points: "rewards",
|
|
@@ -1016,7 +1053,7 @@ var MUSHI_DOCS_INDEX = [
|
|
|
1016
1053
|
route: "/",
|
|
1017
1054
|
markdown: "index.md",
|
|
1018
1055
|
keywords: ["know", "ai-built", "app", "broke", "fix", "ready"],
|
|
1019
|
-
headings: ["See it in action", "What this is (and is not)", "Get started with the SDK", "Install in your framework", "One queue. Sentry flows in, fixes flow out."],
|
|
1056
|
+
headings: ["This is what a diagnosis looks like", "See it in action", "What this is (and is not)", "Get started with the SDK", "Install in your framework", "One queue. Sentry flows in, fixes flow out."],
|
|
1020
1057
|
excerpt: "Your AI shipped it. Mushi tells you why it broke: a plain-English diagnosis and a ready fix in your editor. Open source, Sentry optional."
|
|
1021
1058
|
},
|
|
1022
1059
|
{
|
|
@@ -1485,7 +1522,7 @@ var MUSHI_DOCS_INDEX = [
|
|
|
1485
1522
|
markdown: "admin/skill-pipelines.md",
|
|
1486
1523
|
keywords: ["admin", "skill-pipelines", "skill", "pipelines"],
|
|
1487
1524
|
headings: ["How it works", "The three tabs", "Catalog", "Pipelines", "Sources", "Execution modes", "Triage links (?skill=)", "CLI quick reference"],
|
|
1488
|
-
excerpt: "Skill Pipelines recommend agent skills from the
|
|
1525
|
+
excerpt: "Skill Pipelines recommend agent skills from the kenji skills and skills.sh ecosystem for each classified bug and run them during review in Mushi."
|
|
1489
1526
|
},
|
|
1490
1527
|
{
|
|
1491
1528
|
title: "SSO",
|
|
@@ -2027,6 +2064,15 @@ var MUSHI_DOCS_INDEX = [
|
|
|
2027
2064
|
headings: ["What changes (high level)", "API mapping (Mushi-specific)", "Migration checklist", "Common gotchas", "Mushi behaviour during the migration", "References"],
|
|
2028
2065
|
excerpt: "Upgrade a Vue 2 app to Vue 3 and move from the vanilla Mushi web SDK to the @mushi-mushi/vue plugin, with an interactive migration checklist."
|
|
2029
2066
|
},
|
|
2067
|
+
{
|
|
2068
|
+
title: "Open metrics",
|
|
2069
|
+
url: docUrl("/open"),
|
|
2070
|
+
route: "/open",
|
|
2071
|
+
markdown: "open.md",
|
|
2072
|
+
keywords: ["open", "metrics"],
|
|
2073
|
+
headings: ["What is not on this page, and why", "Where the numbers come from"],
|
|
2074
|
+
excerpt: "Mushi Mushi's public numbers (releases, commits, contributors, npm downloads), fetched from public APIs at build time, with what each one does not mean."
|
|
2075
|
+
},
|
|
2030
2076
|
{
|
|
2031
2077
|
title: "Operating (maintainers)",
|
|
2032
2078
|
url: docUrl("/operating"),
|
|
@@ -2591,7 +2637,7 @@ var MUSHI_DOCS_INDEX = [
|
|
|
2591
2637
|
route: "/sdks/react-native",
|
|
2592
2638
|
markdown: "sdks/react-native.md",
|
|
2593
2639
|
keywords: ["sdks", "react-native", "react", "native", "@mushi-mushi/react-native"],
|
|
2594
|
-
headings: ["Install", "Mount the provider", "Submit a report from a screen", "Offline queue", "What gets captured (v0.19+)", "Screenshots (react-native-view-shot)", "
|
|
2640
|
+
headings: ["Install", "Mount the provider", "Submit a report from a screen", "Offline queue", "What gets captured (v0.19+)", "Screenshots (react-native-view-shot)", "Theming the report sheet", "Manual breadcrumbs"],
|
|
2595
2641
|
excerpt: "Reference for @mushi-mushi/react-native \u2014 MushiProvider, hooks, shake-to-report, screenshots, identity and the offline queue for React Native and Expo."
|
|
2596
2642
|
},
|
|
2597
2643
|
{
|
|
@@ -4839,6 +4885,44 @@ function createMushiServer(config) {
|
|
|
4839
4885
|
return jsonResult({ report });
|
|
4840
4886
|
}
|
|
4841
4887
|
);
|
|
4888
|
+
server.registerTool(
|
|
4889
|
+
"import_sentry_issues",
|
|
4890
|
+
{
|
|
4891
|
+
title: titleOf("import_sentry_issues"),
|
|
4892
|
+
description: descOf("import_sentry_issues"),
|
|
4893
|
+
annotations: annotationsFor("import_sentry_issues"),
|
|
4894
|
+
inputSchema: z.object({
|
|
4895
|
+
issueIds: z.array(z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/)).max(10).optional().describe('Sentry issue ids or short ids (e.g. "4501", "WEB-12"), at most 10'),
|
|
4896
|
+
query: z.string().max(200).optional().describe("Sentry search query within the configured Sentry project (default is:unresolved). Not with issueIds."),
|
|
4897
|
+
limit: z.number().int().min(1).max(10).optional().describe("How many issues a query imports (1-10, default 5)"),
|
|
4898
|
+
projectId: z.string().optional().describe("Project UUID. Defaults to configured project.")
|
|
4899
|
+
}),
|
|
4900
|
+
outputSchema: z.object({
|
|
4901
|
+
items: z.array(
|
|
4902
|
+
z.looseObject({
|
|
4903
|
+
input: z.string(),
|
|
4904
|
+
issueId: z.string().nullable(),
|
|
4905
|
+
shortId: z.string().nullable(),
|
|
4906
|
+
outcome: z.string().describe("created | linked | deduped | ignored | error"),
|
|
4907
|
+
reportId: z.string().nullable(),
|
|
4908
|
+
error: z.string().optional()
|
|
4909
|
+
})
|
|
4910
|
+
).describe("One entry per requested or matched issue"),
|
|
4911
|
+
created: z.array(z.string().nullable()).describe("Report ids created by this import"),
|
|
4912
|
+
linked: z.array(z.string().nullable()).describe("Report ids that already existed for these issues"),
|
|
4913
|
+
failed: z.number().describe("Issues that could not be imported"),
|
|
4914
|
+
indexing: z.looseObject({ queued: z.boolean(), paths: z.number() }).describe("Whether stack-frame files were queued for codebase indexing")
|
|
4915
|
+
})
|
|
4916
|
+
},
|
|
4917
|
+
async (args) => {
|
|
4918
|
+
const pid = await resolveProjectId(args.projectId);
|
|
4919
|
+
const data = await apiCall(`/v1/admin/projects/${pid}/sentry/import`, {
|
|
4920
|
+
method: "POST",
|
|
4921
|
+
body: JSON.stringify({ issueIds: args.issueIds, query: args.query, limit: args.limit })
|
|
4922
|
+
});
|
|
4923
|
+
return jsonResult(data);
|
|
4924
|
+
}
|
|
4925
|
+
);
|
|
4842
4926
|
server.registerTool(
|
|
4843
4927
|
"transition_status",
|
|
4844
4928
|
{
|
|
@@ -4863,13 +4947,20 @@ function createMushiServer(config) {
|
|
|
4863
4947
|
"reopened",
|
|
4864
4948
|
"dismissed"
|
|
4865
4949
|
]).describe("Target status (resolved is stored as fixed)"),
|
|
4866
|
-
reason: z.string().optional().describe("Reason for the transition (audit trail)")
|
|
4950
|
+
reason: z.string().optional().describe("Reason for the transition (audit trail)"),
|
|
4951
|
+
closedReason: z.enum(["duplicate", "not_reproducible", "wont_fix", "working_as_intended", "spam"]).optional().describe("When dismissing: what the reporter is told (spam closes silently)"),
|
|
4952
|
+
reporterMessage: z.string().max(1e4).optional().describe("Optional note posted to the reporter verbatim")
|
|
4867
4953
|
})
|
|
4868
4954
|
},
|
|
4869
4955
|
async (args) => {
|
|
4870
4956
|
const data = await apiCall(`/v1/admin/reports/${args.reportId}`, {
|
|
4871
4957
|
method: "PATCH",
|
|
4872
|
-
body: JSON.stringify({
|
|
4958
|
+
body: JSON.stringify({
|
|
4959
|
+
status: args.status,
|
|
4960
|
+
reason: args.reason,
|
|
4961
|
+
closed_reason: args.closedReason,
|
|
4962
|
+
reporter_message: args.reporterMessage
|
|
4963
|
+
})
|
|
4873
4964
|
});
|
|
4874
4965
|
return jsonText(data);
|
|
4875
4966
|
}
|
|
@@ -5613,6 +5704,65 @@ Be specific. No generic advice.`
|
|
|
5613
5704
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
5614
5705
|
}
|
|
5615
5706
|
);
|
|
5707
|
+
server.registerTool(
|
|
5708
|
+
"request_reporter_info",
|
|
5709
|
+
{
|
|
5710
|
+
title: titleOf("request_reporter_info", TDD_TOOL_CATALOG),
|
|
5711
|
+
description: descOf("request_reporter_info", TDD_TOOL_CATALOG),
|
|
5712
|
+
annotations: annotationsFor("request_reporter_info", TDD_TOOL_CATALOG),
|
|
5713
|
+
inputSchema: z.object({
|
|
5714
|
+
reportId: z.string().describe("Report id to ask about"),
|
|
5715
|
+
question: z.string().min(1).max(2e3).describe("The question, shown to the reporter verbatim"),
|
|
5716
|
+
authorName: z.string().optional().describe('Display name for the sender (default: "Developer")')
|
|
5717
|
+
})
|
|
5718
|
+
},
|
|
5719
|
+
async ({ reportId, question, authorName }) => {
|
|
5720
|
+
const data = await apiCall(`/v1/admin/reports/${reportId}/request-info`, {
|
|
5721
|
+
method: "POST",
|
|
5722
|
+
body: JSON.stringify({ question, author_name: authorName })
|
|
5723
|
+
});
|
|
5724
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
5725
|
+
}
|
|
5726
|
+
);
|
|
5727
|
+
server.registerTool(
|
|
5728
|
+
"list_reporter_outbox",
|
|
5729
|
+
{
|
|
5730
|
+
title: titleOf("list_reporter_outbox", TDD_TOOL_CATALOG),
|
|
5731
|
+
description: descOf("list_reporter_outbox", TDD_TOOL_CATALOG),
|
|
5732
|
+
annotations: annotationsFor("list_reporter_outbox", TDD_TOOL_CATALOG),
|
|
5733
|
+
inputSchema: z.object({
|
|
5734
|
+
projectId: z.string().optional().describe("Project UUID. Defaults to configured project.")
|
|
5735
|
+
})
|
|
5736
|
+
},
|
|
5737
|
+
async ({ projectId: pid }) => {
|
|
5738
|
+
const scoped = pid ?? config.projectId;
|
|
5739
|
+
const data = await apiCall(
|
|
5740
|
+
`/v1/admin/reporter-outbox${scoped ? `?project_id=${encodeURIComponent(scoped)}` : ""}`
|
|
5741
|
+
);
|
|
5742
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
5743
|
+
}
|
|
5744
|
+
);
|
|
5745
|
+
server.registerTool(
|
|
5746
|
+
"release_reporter_update",
|
|
5747
|
+
{
|
|
5748
|
+
title: titleOf("release_reporter_update", TDD_TOOL_CATALOG),
|
|
5749
|
+
description: descOf("release_reporter_update", TDD_TOOL_CATALOG),
|
|
5750
|
+
annotations: annotationsFor("release_reporter_update", TDD_TOOL_CATALOG),
|
|
5751
|
+
inputSchema: z.object({
|
|
5752
|
+
messageId: z.string().describe("Held message id from list_reporter_outbox"),
|
|
5753
|
+
action: z.enum(["release", "discard"]).optional().describe("release (default) sends it; discard drops it"),
|
|
5754
|
+
bodyOverride: z.string().min(1).max(1e3).optional().describe("Replacement text to send instead")
|
|
5755
|
+
})
|
|
5756
|
+
},
|
|
5757
|
+
async ({ messageId, action, bodyOverride }) => {
|
|
5758
|
+
const verb = action === "discard" ? "discard" : "release";
|
|
5759
|
+
const data = await apiCall(`/v1/admin/reporter-outbox/${messageId}/${verb}`, {
|
|
5760
|
+
method: "POST",
|
|
5761
|
+
body: JSON.stringify(verb === "release" && bodyOverride ? { body_override: bodyOverride } : {})
|
|
5762
|
+
});
|
|
5763
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
5764
|
+
}
|
|
5765
|
+
);
|
|
5616
5766
|
server.registerTool(
|
|
5617
5767
|
"list_qa_story_runs",
|
|
5618
5768
|
{
|
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-
|
|
7
|
+
} from "./chunk-EFENR3EA.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-
|
|
15
|
+
} from "./chunk-CXSLU5V5.js";
|
|
16
16
|
|
|
17
17
|
// src/server.ts
|
|
18
18
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -32,7 +32,7 @@ var MUSHI_DOCS_INDEX = [
|
|
|
32
32
|
route: "/",
|
|
33
33
|
markdown: "index.md",
|
|
34
34
|
keywords: ["know", "ai-built", "app", "broke", "fix", "ready"],
|
|
35
|
-
headings: ["See it in action", "What this is (and is not)", "Get started with the SDK", "Install in your framework", "One queue. Sentry flows in, fixes flow out."],
|
|
35
|
+
headings: ["This is what a diagnosis looks like", "See it in action", "What this is (and is not)", "Get started with the SDK", "Install in your framework", "One queue. Sentry flows in, fixes flow out."],
|
|
36
36
|
excerpt: "Your AI shipped it. Mushi tells you why it broke: a plain-English diagnosis and a ready fix in your editor. Open source, Sentry optional."
|
|
37
37
|
},
|
|
38
38
|
{
|
|
@@ -501,7 +501,7 @@ var MUSHI_DOCS_INDEX = [
|
|
|
501
501
|
markdown: "admin/skill-pipelines.md",
|
|
502
502
|
keywords: ["admin", "skill-pipelines", "skill", "pipelines"],
|
|
503
503
|
headings: ["How it works", "The three tabs", "Catalog", "Pipelines", "Sources", "Execution modes", "Triage links (?skill=)", "CLI quick reference"],
|
|
504
|
-
excerpt: "Skill Pipelines recommend agent skills from the
|
|
504
|
+
excerpt: "Skill Pipelines recommend agent skills from the kenji skills and skills.sh ecosystem for each classified bug and run them during review in Mushi."
|
|
505
505
|
},
|
|
506
506
|
{
|
|
507
507
|
title: "SSO",
|
|
@@ -1043,6 +1043,15 @@ var MUSHI_DOCS_INDEX = [
|
|
|
1043
1043
|
headings: ["What changes (high level)", "API mapping (Mushi-specific)", "Migration checklist", "Common gotchas", "Mushi behaviour during the migration", "References"],
|
|
1044
1044
|
excerpt: "Upgrade a Vue 2 app to Vue 3 and move from the vanilla Mushi web SDK to the @mushi-mushi/vue plugin, with an interactive migration checklist."
|
|
1045
1045
|
},
|
|
1046
|
+
{
|
|
1047
|
+
title: "Open metrics",
|
|
1048
|
+
url: docUrl("/open"),
|
|
1049
|
+
route: "/open",
|
|
1050
|
+
markdown: "open.md",
|
|
1051
|
+
keywords: ["open", "metrics"],
|
|
1052
|
+
headings: ["What is not on this page, and why", "Where the numbers come from"],
|
|
1053
|
+
excerpt: "Mushi Mushi's public numbers (releases, commits, contributors, npm downloads), fetched from public APIs at build time, with what each one does not mean."
|
|
1054
|
+
},
|
|
1046
1055
|
{
|
|
1047
1056
|
title: "Operating (maintainers)",
|
|
1048
1057
|
url: docUrl("/operating"),
|
|
@@ -1607,7 +1616,7 @@ var MUSHI_DOCS_INDEX = [
|
|
|
1607
1616
|
route: "/sdks/react-native",
|
|
1608
1617
|
markdown: "sdks/react-native.md",
|
|
1609
1618
|
keywords: ["sdks", "react-native", "react", "native", "@mushi-mushi/react-native"],
|
|
1610
|
-
headings: ["Install", "Mount the provider", "Submit a report from a screen", "Offline queue", "What gets captured (v0.19+)", "Screenshots (react-native-view-shot)", "
|
|
1619
|
+
headings: ["Install", "Mount the provider", "Submit a report from a screen", "Offline queue", "What gets captured (v0.19+)", "Screenshots (react-native-view-shot)", "Theming the report sheet", "Manual breadcrumbs"],
|
|
1611
1620
|
excerpt: "Reference for @mushi-mushi/react-native \u2014 MushiProvider, hooks, shake-to-report, screenshots, identity and the offline queue for React Native and Expo."
|
|
1612
1621
|
},
|
|
1613
1622
|
{
|
|
@@ -3921,6 +3930,44 @@ function createMushiServer(config) {
|
|
|
3921
3930
|
return jsonResult({ report });
|
|
3922
3931
|
}
|
|
3923
3932
|
);
|
|
3933
|
+
server.registerTool(
|
|
3934
|
+
"import_sentry_issues",
|
|
3935
|
+
{
|
|
3936
|
+
title: titleOf("import_sentry_issues"),
|
|
3937
|
+
description: descOf("import_sentry_issues"),
|
|
3938
|
+
annotations: annotationsFor("import_sentry_issues"),
|
|
3939
|
+
inputSchema: z.object({
|
|
3940
|
+
issueIds: z.array(z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/)).max(10).optional().describe('Sentry issue ids or short ids (e.g. "4501", "WEB-12"), at most 10'),
|
|
3941
|
+
query: z.string().max(200).optional().describe("Sentry search query within the configured Sentry project (default is:unresolved). Not with issueIds."),
|
|
3942
|
+
limit: z.number().int().min(1).max(10).optional().describe("How many issues a query imports (1-10, default 5)"),
|
|
3943
|
+
projectId: z.string().optional().describe("Project UUID. Defaults to configured project.")
|
|
3944
|
+
}),
|
|
3945
|
+
outputSchema: z.object({
|
|
3946
|
+
items: z.array(
|
|
3947
|
+
z.looseObject({
|
|
3948
|
+
input: z.string(),
|
|
3949
|
+
issueId: z.string().nullable(),
|
|
3950
|
+
shortId: z.string().nullable(),
|
|
3951
|
+
outcome: z.string().describe("created | linked | deduped | ignored | error"),
|
|
3952
|
+
reportId: z.string().nullable(),
|
|
3953
|
+
error: z.string().optional()
|
|
3954
|
+
})
|
|
3955
|
+
).describe("One entry per requested or matched issue"),
|
|
3956
|
+
created: z.array(z.string().nullable()).describe("Report ids created by this import"),
|
|
3957
|
+
linked: z.array(z.string().nullable()).describe("Report ids that already existed for these issues"),
|
|
3958
|
+
failed: z.number().describe("Issues that could not be imported"),
|
|
3959
|
+
indexing: z.looseObject({ queued: z.boolean(), paths: z.number() }).describe("Whether stack-frame files were queued for codebase indexing")
|
|
3960
|
+
})
|
|
3961
|
+
},
|
|
3962
|
+
async (args) => {
|
|
3963
|
+
const pid = await resolveProjectId(args.projectId);
|
|
3964
|
+
const data = await apiCall(`/v1/admin/projects/${pid}/sentry/import`, {
|
|
3965
|
+
method: "POST",
|
|
3966
|
+
body: JSON.stringify({ issueIds: args.issueIds, query: args.query, limit: args.limit })
|
|
3967
|
+
});
|
|
3968
|
+
return jsonResult(data);
|
|
3969
|
+
}
|
|
3970
|
+
);
|
|
3924
3971
|
server.registerTool(
|
|
3925
3972
|
"transition_status",
|
|
3926
3973
|
{
|
|
@@ -3945,13 +3992,20 @@ function createMushiServer(config) {
|
|
|
3945
3992
|
"reopened",
|
|
3946
3993
|
"dismissed"
|
|
3947
3994
|
]).describe("Target status (resolved is stored as fixed)"),
|
|
3948
|
-
reason: z.string().optional().describe("Reason for the transition (audit trail)")
|
|
3995
|
+
reason: z.string().optional().describe("Reason for the transition (audit trail)"),
|
|
3996
|
+
closedReason: z.enum(["duplicate", "not_reproducible", "wont_fix", "working_as_intended", "spam"]).optional().describe("When dismissing: what the reporter is told (spam closes silently)"),
|
|
3997
|
+
reporterMessage: z.string().max(1e4).optional().describe("Optional note posted to the reporter verbatim")
|
|
3949
3998
|
})
|
|
3950
3999
|
},
|
|
3951
4000
|
async (args) => {
|
|
3952
4001
|
const data = await apiCall(`/v1/admin/reports/${args.reportId}`, {
|
|
3953
4002
|
method: "PATCH",
|
|
3954
|
-
body: JSON.stringify({
|
|
4003
|
+
body: JSON.stringify({
|
|
4004
|
+
status: args.status,
|
|
4005
|
+
reason: args.reason,
|
|
4006
|
+
closed_reason: args.closedReason,
|
|
4007
|
+
reporter_message: args.reporterMessage
|
|
4008
|
+
})
|
|
3955
4009
|
});
|
|
3956
4010
|
return jsonText(data);
|
|
3957
4011
|
}
|
|
@@ -4695,6 +4749,65 @@ Be specific. No generic advice.`
|
|
|
4695
4749
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
4696
4750
|
}
|
|
4697
4751
|
);
|
|
4752
|
+
server.registerTool(
|
|
4753
|
+
"request_reporter_info",
|
|
4754
|
+
{
|
|
4755
|
+
title: titleOf("request_reporter_info", TDD_TOOL_CATALOG),
|
|
4756
|
+
description: descOf("request_reporter_info", TDD_TOOL_CATALOG),
|
|
4757
|
+
annotations: annotationsFor("request_reporter_info", TDD_TOOL_CATALOG),
|
|
4758
|
+
inputSchema: z.object({
|
|
4759
|
+
reportId: z.string().describe("Report id to ask about"),
|
|
4760
|
+
question: z.string().min(1).max(2e3).describe("The question, shown to the reporter verbatim"),
|
|
4761
|
+
authorName: z.string().optional().describe('Display name for the sender (default: "Developer")')
|
|
4762
|
+
})
|
|
4763
|
+
},
|
|
4764
|
+
async ({ reportId, question, authorName }) => {
|
|
4765
|
+
const data = await apiCall(`/v1/admin/reports/${reportId}/request-info`, {
|
|
4766
|
+
method: "POST",
|
|
4767
|
+
body: JSON.stringify({ question, author_name: authorName })
|
|
4768
|
+
});
|
|
4769
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
4770
|
+
}
|
|
4771
|
+
);
|
|
4772
|
+
server.registerTool(
|
|
4773
|
+
"list_reporter_outbox",
|
|
4774
|
+
{
|
|
4775
|
+
title: titleOf("list_reporter_outbox", TDD_TOOL_CATALOG),
|
|
4776
|
+
description: descOf("list_reporter_outbox", TDD_TOOL_CATALOG),
|
|
4777
|
+
annotations: annotationsFor("list_reporter_outbox", TDD_TOOL_CATALOG),
|
|
4778
|
+
inputSchema: z.object({
|
|
4779
|
+
projectId: z.string().optional().describe("Project UUID. Defaults to configured project.")
|
|
4780
|
+
})
|
|
4781
|
+
},
|
|
4782
|
+
async ({ projectId: pid }) => {
|
|
4783
|
+
const scoped = pid ?? config.projectId;
|
|
4784
|
+
const data = await apiCall(
|
|
4785
|
+
`/v1/admin/reporter-outbox${scoped ? `?project_id=${encodeURIComponent(scoped)}` : ""}`
|
|
4786
|
+
);
|
|
4787
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
4788
|
+
}
|
|
4789
|
+
);
|
|
4790
|
+
server.registerTool(
|
|
4791
|
+
"release_reporter_update",
|
|
4792
|
+
{
|
|
4793
|
+
title: titleOf("release_reporter_update", TDD_TOOL_CATALOG),
|
|
4794
|
+
description: descOf("release_reporter_update", TDD_TOOL_CATALOG),
|
|
4795
|
+
annotations: annotationsFor("release_reporter_update", TDD_TOOL_CATALOG),
|
|
4796
|
+
inputSchema: z.object({
|
|
4797
|
+
messageId: z.string().describe("Held message id from list_reporter_outbox"),
|
|
4798
|
+
action: z.enum(["release", "discard"]).optional().describe("release (default) sends it; discard drops it"),
|
|
4799
|
+
bodyOverride: z.string().min(1).max(1e3).optional().describe("Replacement text to send instead")
|
|
4800
|
+
})
|
|
4801
|
+
},
|
|
4802
|
+
async ({ messageId, action, bodyOverride }) => {
|
|
4803
|
+
const verb = action === "discard" ? "discard" : "release";
|
|
4804
|
+
const data = await apiCall(`/v1/admin/reporter-outbox/${messageId}/${verb}`, {
|
|
4805
|
+
method: "POST",
|
|
4806
|
+
body: JSON.stringify(verb === "release" && bodyOverride ? { body_override: bodyOverride } : {})
|
|
4807
|
+
});
|
|
4808
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
4809
|
+
}
|
|
4810
|
+
);
|
|
4698
4811
|
server.registerTool(
|
|
4699
4812
|
"list_qa_story_runs",
|
|
4700
4813
|
{
|
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.
|
|
4
|
+
"version": "0.23.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",
|
|
@@ -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.
|
|
48
|
+
"@mushi-mushi/core": "^1.30.0"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@sentry/node": "^10.57.0"
|