@mushi-mushi/mcp 0.17.1 → 0.18.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 +18 -9
- package/dist/catalog.js +1 -1
- package/dist/{chunk-7UOTJ2LI.js → chunk-KNVB6HA7.js} +61 -93
- package/dist/{chunk-PW4AK6SV.js → chunk-VBXXUK5G.js} +31 -14
- package/dist/clients.js +1 -1
- package/dist/feature-groups.d.ts +8 -2
- package/dist/feature-groups.js +1 -1
- package/dist/index.js +254 -358
- package/dist/server.js +152 -253
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -2,13 +2,14 @@ import {
|
|
|
2
2
|
CODEBASE_TOOL_CATALOG,
|
|
3
3
|
TDD_TOOL_CATALOG,
|
|
4
4
|
TOOL_CATALOG
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KNVB6HA7.js";
|
|
6
6
|
import {
|
|
7
7
|
MUSHI_SERVER_METADATA
|
|
8
8
|
} from "./chunk-EANW5YTI.js";
|
|
9
9
|
import {
|
|
10
|
+
DEPRECATED_TOOL_ALIASES,
|
|
10
11
|
toolMatchesFeatures
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-VBXXUK5G.js";
|
|
12
13
|
|
|
13
14
|
// src/server.ts
|
|
14
15
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -45,8 +46,8 @@ var MUSHI_DOCS_INDEX = [
|
|
|
45
46
|
{
|
|
46
47
|
title: "Cursor MCP troubleshooting",
|
|
47
48
|
path: `${BASE}/guides/mcp-setup`,
|
|
48
|
-
keywords: ["cursor", "mcp.json", "red badge", "transport error", "stdout", "stderr", "json-rpc", "INVALID_TOKEN", "syntax helper", "
|
|
49
|
-
excerpt: "Cursor stdio MCP requires stdout to contain only JSON-RPC. Use the console syntax helper, restart Cursor MCP, then run
|
|
49
|
+
keywords: ["cursor", "mcp.json", "red badge", "transport error", "stdout", "stderr", "json-rpc", "INVALID_TOKEN", "syntax helper", "diagnose_setup"],
|
|
50
|
+
excerpt: "Cursor stdio MCP requires stdout to contain only JSON-RPC. Use the console syntax helper, restart Cursor MCP, then run diagnose_setup."
|
|
50
51
|
},
|
|
51
52
|
{
|
|
52
53
|
title: "Judge loop",
|
|
@@ -502,14 +503,14 @@ function createMushiServer(config) {
|
|
|
502
503
|
}
|
|
503
504
|
);
|
|
504
505
|
server.registerTool(
|
|
505
|
-
"
|
|
506
|
+
"get_graph_neighborhood",
|
|
506
507
|
{
|
|
507
|
-
title: titleOf("
|
|
508
|
-
description: descOf("
|
|
509
|
-
annotations: annotationsFor("
|
|
508
|
+
title: titleOf("get_graph_neighborhood"),
|
|
509
|
+
description: descOf("get_graph_neighborhood"),
|
|
510
|
+
annotations: annotationsFor("get_graph_neighborhood"),
|
|
510
511
|
inputSchema: {
|
|
511
|
-
seed: z.string().describe("Starting node id or label"),
|
|
512
|
-
depth: z.number().optional().describe("
|
|
512
|
+
seed: z.string().describe("Starting graph node id or label to expand around (e.g. an inventory Action id or component name)"),
|
|
513
|
+
depth: z.number().int().min(1).max(4).optional().describe("BFS hops to traverse outward. Default 2; clamped to a max of 4.")
|
|
513
514
|
}
|
|
514
515
|
},
|
|
515
516
|
async (args) => {
|
|
@@ -521,65 +522,65 @@ function createMushiServer(config) {
|
|
|
521
522
|
}
|
|
522
523
|
);
|
|
523
524
|
server.registerTool(
|
|
524
|
-
"
|
|
525
|
+
"get_graph_node",
|
|
525
526
|
{
|
|
526
|
-
title: titleOf("
|
|
527
|
-
description: descOf("
|
|
528
|
-
annotations: annotationsFor("
|
|
529
|
-
inputSchema: { nodeId: z.string().describe("graph_nodes.id") }
|
|
527
|
+
title: titleOf("get_graph_node"),
|
|
528
|
+
description: descOf("get_graph_node"),
|
|
529
|
+
annotations: annotationsFor("get_graph_node"),
|
|
530
|
+
inputSchema: { nodeId: z.string().describe("The graph_nodes.id of the node to fetch (UUID).") }
|
|
530
531
|
},
|
|
531
532
|
async (args) => jsonText(await apiCall(`/v1/admin/graph/node/${args.nodeId}`))
|
|
532
533
|
);
|
|
533
534
|
server.registerTool(
|
|
534
|
-
"
|
|
535
|
+
"get_inventory",
|
|
535
536
|
{
|
|
536
|
-
title: titleOf("
|
|
537
|
-
description: descOf("
|
|
538
|
-
annotations: annotationsFor("
|
|
537
|
+
title: titleOf("get_inventory"),
|
|
538
|
+
description: descOf("get_inventory"),
|
|
539
|
+
annotations: annotationsFor("get_inventory"),
|
|
539
540
|
inputSchema: {
|
|
540
541
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to the server-configured project when omitted")
|
|
541
542
|
}
|
|
542
543
|
},
|
|
543
544
|
async (args) => {
|
|
544
545
|
const pid = args.projectId ?? projectId;
|
|
545
|
-
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for
|
|
546
|
+
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for get_inventory");
|
|
546
547
|
return jsonText(await apiCall(`/v1/admin/inventory/${pid}`));
|
|
547
548
|
}
|
|
548
549
|
);
|
|
549
550
|
server.registerTool(
|
|
550
|
-
"
|
|
551
|
+
"diff_inventory",
|
|
551
552
|
{
|
|
552
|
-
title: titleOf("
|
|
553
|
-
description: descOf("
|
|
554
|
-
annotations: annotationsFor("
|
|
553
|
+
title: titleOf("diff_inventory"),
|
|
554
|
+
description: descOf("diff_inventory"),
|
|
555
|
+
annotations: annotationsFor("diff_inventory"),
|
|
555
556
|
inputSchema: {
|
|
556
557
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to configured project"),
|
|
557
|
-
fromSha: z.string().describe("Older commit SHA (baseline)"),
|
|
558
|
-
toSha: z.string().describe("Newer commit SHA (candidate)")
|
|
558
|
+
fromSha: z.string().describe("Older commit SHA (the baseline to diff from)"),
|
|
559
|
+
toSha: z.string().describe("Newer commit SHA (the candidate to diff to)")
|
|
559
560
|
}
|
|
560
561
|
},
|
|
561
562
|
async (args) => {
|
|
562
563
|
const pid = args.projectId ?? projectId;
|
|
563
|
-
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for
|
|
564
|
+
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for diff_inventory");
|
|
564
565
|
const q = new URLSearchParams({ from: args.fromSha, to: args.toSha });
|
|
565
566
|
return jsonText(await apiCall(`/v1/admin/inventory/${pid}/diff?${q}`));
|
|
566
567
|
}
|
|
567
568
|
);
|
|
568
569
|
server.registerTool(
|
|
569
|
-
"
|
|
570
|
+
"list_gate_findings",
|
|
570
571
|
{
|
|
571
|
-
title: titleOf("
|
|
572
|
-
description: descOf("
|
|
573
|
-
annotations: annotationsFor("
|
|
572
|
+
title: titleOf("list_gate_findings"),
|
|
573
|
+
description: descOf("list_gate_findings"),
|
|
574
|
+
annotations: annotationsFor("list_gate_findings"),
|
|
574
575
|
inputSchema: {
|
|
575
576
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to configured project"),
|
|
576
|
-
gate: z.string().optional().describe("Filter
|
|
577
|
-
severity: z.string().optional().describe("
|
|
577
|
+
gate: z.string().optional().describe("Filter to one gate id: dead-handler | mock-leak | crawl | status-claim"),
|
|
578
|
+
severity: z.string().optional().describe("Minimum severity to include: low | medium | high | critical")
|
|
578
579
|
}
|
|
579
580
|
},
|
|
580
581
|
async (args) => {
|
|
581
582
|
const pid = args.projectId ?? projectId;
|
|
582
|
-
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for
|
|
583
|
+
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for list_gate_findings");
|
|
583
584
|
const q = new URLSearchParams();
|
|
584
585
|
if (args.gate) q.set("gate", args.gate);
|
|
585
586
|
if (args.severity) q.set("severity", args.severity);
|
|
@@ -588,17 +589,25 @@ function createMushiServer(config) {
|
|
|
588
589
|
}
|
|
589
590
|
);
|
|
590
591
|
server.registerTool(
|
|
591
|
-
"
|
|
592
|
+
"suggest_fix",
|
|
592
593
|
{
|
|
593
|
-
title: titleOf("
|
|
594
|
-
description: descOf("
|
|
595
|
-
annotations: annotationsFor("
|
|
596
|
-
inputSchema: { reportId: z.string().describe("Report UUID") }
|
|
594
|
+
title: titleOf("suggest_fix"),
|
|
595
|
+
description: descOf("suggest_fix"),
|
|
596
|
+
annotations: annotationsFor("suggest_fix"),
|
|
597
|
+
inputSchema: { reportId: z.string().describe("Report UUID to read the Stage-2 suggested-fix slice for") },
|
|
598
|
+
outputSchema: {
|
|
599
|
+
reportId: z.string().describe("The report this slice was read from"),
|
|
600
|
+
rootCause: z.unknown().describe("Stage-2 root-cause hint, or null if not yet classified"),
|
|
601
|
+
suggestedFix: z.unknown().describe("Stage-2 suggested fix, or null if not yet classified"),
|
|
602
|
+
reproductionSteps: z.unknown().describe("Reproduction steps recorded on the report (array; [] if none)"),
|
|
603
|
+
summary: z.unknown().describe("One-line report summary, or null"),
|
|
604
|
+
component: z.unknown().describe("Component/page the bug was attributed to, or null")
|
|
605
|
+
}
|
|
597
606
|
},
|
|
598
607
|
async (args) => {
|
|
599
608
|
const report = await apiCall(`/v1/admin/reports/${args.reportId}`);
|
|
600
609
|
const s2 = report.stage2_analysis;
|
|
601
|
-
return
|
|
610
|
+
return jsonResult({
|
|
602
611
|
reportId: args.reportId,
|
|
603
612
|
rootCause: s2?.rootCause ?? null,
|
|
604
613
|
suggestedFix: s2?.suggestedFix ?? null,
|
|
@@ -624,73 +633,6 @@ function createMushiServer(config) {
|
|
|
624
633
|
return jsonText(data);
|
|
625
634
|
}
|
|
626
635
|
);
|
|
627
|
-
server.registerTool(
|
|
628
|
-
"setup_check",
|
|
629
|
-
{
|
|
630
|
-
title: titleOf("setup_check"),
|
|
631
|
-
description: descOf("setup_check"),
|
|
632
|
-
annotations: annotationsFor("setup_check"),
|
|
633
|
-
inputSchema: {
|
|
634
|
-
projectId: z.string().optional().describe(
|
|
635
|
-
"Project UUID to check. Falls back to the projectId the server was initialised with."
|
|
636
|
-
)
|
|
637
|
-
}
|
|
638
|
-
},
|
|
639
|
-
async (args) => {
|
|
640
|
-
const resolvedId = args.projectId ?? projectId;
|
|
641
|
-
if (!resolvedId) {
|
|
642
|
-
return jsonText({
|
|
643
|
-
ok: false,
|
|
644
|
-
error: "No projectId provided and none configured on the MCP server. Pass projectId explicitly."
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
const data = await apiCall(`/v1/admin/projects/${resolvedId}/preflight`);
|
|
648
|
-
const summary = data.checks.map((c) => ({
|
|
649
|
-
check: c.key,
|
|
650
|
-
label: c.label,
|
|
651
|
-
passed: c.ready,
|
|
652
|
-
hint: c.hint,
|
|
653
|
-
fixPath: c.fixHref
|
|
654
|
-
}));
|
|
655
|
-
return jsonText({
|
|
656
|
-
ready: data.ready,
|
|
657
|
-
repoUrl: data.repoUrl ?? null,
|
|
658
|
-
checks: summary,
|
|
659
|
-
// Human-readable summary for agents that paste the result into a prompt
|
|
660
|
-
summary: data.ready ? `Project ${resolvedId} is ready to dispatch auto-fixes${data.repoUrl ? ` (target: ${data.repoUrl})` : ""}.` : `Project ${resolvedId} cannot dispatch yet \u2014 ${summary.filter((c) => !c.passed).map((c) => c.label).join(", ")}.`
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
);
|
|
664
|
-
server.registerTool(
|
|
665
|
-
"ingest_setup_check",
|
|
666
|
-
{
|
|
667
|
-
title: titleOf("ingest_setup_check"),
|
|
668
|
-
description: descOf("ingest_setup_check"),
|
|
669
|
-
annotations: annotationsFor("ingest_setup_check"),
|
|
670
|
-
inputSchema: NO_ARG_INPUT
|
|
671
|
-
},
|
|
672
|
-
async () => {
|
|
673
|
-
const data = await apiCall("/v1/sync/ingest-setup");
|
|
674
|
-
const failed = data.steps.filter((s) => s.required && !s.complete);
|
|
675
|
-
const summary = data.ready ? `Ingest setup complete (${data.required_complete}/${data.required_total}) for ${data.project_name}.` : `Ingest incomplete (${data.required_complete}/${data.required_total}) \u2014 still need: ${failed.map((s) => s.label).join(", ")}.`;
|
|
676
|
-
return jsonText({
|
|
677
|
-
ready: data.ready,
|
|
678
|
-
projectId: data.project_id,
|
|
679
|
-
projectName: data.project_name,
|
|
680
|
-
requiredComplete: data.required_complete,
|
|
681
|
-
requiredTotal: data.required_total,
|
|
682
|
-
steps: data.steps.map((s) => ({
|
|
683
|
-
id: s.id,
|
|
684
|
-
label: s.label,
|
|
685
|
-
passed: s.complete,
|
|
686
|
-
required: s.required,
|
|
687
|
-
hint: s.hint
|
|
688
|
-
})),
|
|
689
|
-
diagnostic: data.diagnostic ?? null,
|
|
690
|
-
summary
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
);
|
|
694
636
|
server.registerTool(
|
|
695
637
|
"diagnose_setup",
|
|
696
638
|
{
|
|
@@ -708,7 +650,8 @@ function createMushiServer(config) {
|
|
|
708
650
|
summary: z.string(),
|
|
709
651
|
nextAction: z.string().optional(),
|
|
710
652
|
ingest: z.unknown().optional(),
|
|
711
|
-
dispatch: z.unknown().optional()
|
|
653
|
+
dispatch: z.unknown().optional(),
|
|
654
|
+
connection: z.unknown().optional()
|
|
712
655
|
}
|
|
713
656
|
},
|
|
714
657
|
async (args) => {
|
|
@@ -748,162 +691,99 @@ function createMushiServer(config) {
|
|
|
748
691
|
dispatch: { repoUrl: data.repoUrl ?? null, checks: data.checks }
|
|
749
692
|
});
|
|
750
693
|
}
|
|
751
|
-
const
|
|
752
|
-
let
|
|
753
|
-
let dispatchBlock;
|
|
754
|
-
let dispatchChecks = null;
|
|
755
|
-
if (resolvedId) {
|
|
756
|
-
try {
|
|
757
|
-
const preflight = await apiCall(`/v1/admin/projects/${resolvedId}/preflight`);
|
|
758
|
-
dispatchReady = preflight.ready;
|
|
759
|
-
dispatchChecks = preflight.checks;
|
|
760
|
-
if (!preflight.ready) {
|
|
761
|
-
const failed = preflight.checks.filter((c) => !c.ready);
|
|
762
|
-
dispatchBlock = failed[0]?.hint;
|
|
763
|
-
}
|
|
764
|
-
} catch (err) {
|
|
765
|
-
dispatchReady = false;
|
|
766
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
767
|
-
dispatchBlock = `Could not run dispatch preflight \u2014 ${detail}`;
|
|
768
|
-
apiLog.warn("diagnose_setup dispatch preflight failed", { error: detail });
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
const ingestFailed = ingest.steps.filter((s) => s.required && !s.complete);
|
|
772
|
-
const ingestBlock = ingestFailed[0]?.hint;
|
|
773
|
-
const ready = ingest.ready && dispatchReady;
|
|
774
|
-
const nextAction = !ingest.ready ? ingestBlock ?? "Complete SDK ingest setup." : !dispatchReady ? dispatchBlock ?? "Complete dispatch preflight in Settings \u2192 Integrations." : "All setup checks pass \u2014 submit a test report to confirm end-to-end.";
|
|
775
|
-
const summary = ready ? "Mushi ingest and dispatch setup look healthy." : !ingest.ready ? `Ingest incomplete \u2014 ${ingestFailed.map((s) => s.label).join(", ")}.` : "Ingest OK; dispatch preflight still has blockers.";
|
|
776
|
-
return jsonResult({
|
|
777
|
-
mode: "full",
|
|
778
|
-
ready,
|
|
779
|
-
summary,
|
|
780
|
-
nextAction,
|
|
781
|
-
ingest: { ready: ingest.ready, steps: ingest.steps },
|
|
782
|
-
dispatch: resolvedId ? { ready: dispatchReady, checks: dispatchChecks } : null
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
);
|
|
786
|
-
server.registerTool(
|
|
787
|
-
"diagnose_connection",
|
|
788
|
-
{
|
|
789
|
-
title: titleOf("diagnose_connection"),
|
|
790
|
-
description: descOf("diagnose_connection"),
|
|
791
|
-
annotations: annotationsFor("diagnose_connection"),
|
|
792
|
-
inputSchema: NO_ARG_INPUT,
|
|
793
|
-
outputSchema: {
|
|
794
|
-
ready: z.boolean(),
|
|
795
|
-
healthOk: z.boolean(),
|
|
796
|
-
ingestReady: z.boolean(),
|
|
797
|
-
dispatchReady: z.boolean(),
|
|
798
|
-
endpoint: z.string().nullable(),
|
|
799
|
-
projectId: z.string().nullable(),
|
|
800
|
-
accessibleProjectCount: z.number().nullable(),
|
|
801
|
-
issues: z.array(z.unknown()),
|
|
802
|
-
nextAction: z.string(),
|
|
803
|
-
summary: z.string()
|
|
804
|
-
}
|
|
805
|
-
},
|
|
806
|
-
async () => {
|
|
807
|
-
const issues = [];
|
|
694
|
+
const connIssues = [];
|
|
695
|
+
let healthOk = false;
|
|
808
696
|
if (!apiKey?.startsWith("mushi_")) {
|
|
809
|
-
|
|
697
|
+
connIssues.push({
|
|
810
698
|
check: "mcp_api_key",
|
|
811
|
-
detail: "MCP server API key missing or malformed",
|
|
812
|
-
fix: "Run `mushi connect`
|
|
699
|
+
detail: "MCP server API key missing or malformed (expected prefix: mushi_)",
|
|
700
|
+
fix: "Run `mushi connect` or set MUSHI_API_KEY to a valid key in your MCP config."
|
|
813
701
|
});
|
|
814
702
|
}
|
|
815
703
|
if (!apiEndpoint) {
|
|
816
|
-
|
|
704
|
+
connIssues.push({
|
|
817
705
|
check: "mcp_endpoint",
|
|
818
706
|
detail: "No API endpoint configured",
|
|
819
|
-
fix: "Set MUSHI_API_ENDPOINT to your
|
|
707
|
+
fix: "Set MUSHI_API_ENDPOINT to your `.../functions/v1/api` URL in your MCP config."
|
|
820
708
|
});
|
|
821
|
-
}
|
|
822
|
-
let healthOk = false;
|
|
823
|
-
if (apiEndpoint) {
|
|
709
|
+
} else {
|
|
824
710
|
try {
|
|
825
711
|
const healthRes = await doFetch(`${apiEndpoint.replace(/\/$/, "")}/health`, {
|
|
826
712
|
signal: AbortSignal.timeout(5e3)
|
|
827
713
|
});
|
|
828
714
|
healthOk = healthRes.status === 200;
|
|
829
715
|
if (!healthOk) {
|
|
830
|
-
|
|
716
|
+
connIssues.push({
|
|
831
717
|
check: "endpoint_health",
|
|
832
718
|
detail: `GET /health \u2192 HTTP ${healthRes.status}`,
|
|
833
719
|
fix: "Verify MUSHI_API_ENDPOINT and that the Supabase edge function is deployed."
|
|
834
720
|
});
|
|
835
721
|
}
|
|
836
722
|
} catch (err) {
|
|
837
|
-
|
|
723
|
+
connIssues.push({
|
|
838
724
|
check: "endpoint_health",
|
|
839
725
|
detail: err instanceof Error ? err.message : String(err),
|
|
840
|
-
fix: "Check network connectivity and
|
|
726
|
+
fix: "Check network connectivity and MUSHI_API_ENDPOINT in your MCP config."
|
|
841
727
|
});
|
|
842
728
|
}
|
|
843
729
|
}
|
|
844
|
-
let ingestReady = false;
|
|
845
|
-
let dispatchReady = false;
|
|
846
730
|
let accessibleProjectCount = null;
|
|
847
|
-
if (!
|
|
731
|
+
if (!resolvedId && healthOk) {
|
|
848
732
|
try {
|
|
849
|
-
const overview = await apiCall(
|
|
733
|
+
const overview = await apiCall(
|
|
734
|
+
"/v1/admin/mcp/account-overview"
|
|
735
|
+
);
|
|
850
736
|
accessibleProjectCount = overview.total;
|
|
851
737
|
if (overview.total === 0) {
|
|
852
|
-
|
|
738
|
+
connIssues.push({
|
|
853
739
|
check: "no_accessible_projects",
|
|
854
740
|
detail: "API key has no accessible projects",
|
|
855
|
-
fix: "Mint an API key on a project (console \u2192 Projects \u2192 API Keys) or add MUSHI_PROJECT_ID
|
|
741
|
+
fix: "Mint an API key on a project (console \u2192 Projects \u2192 API Keys) or add MUSHI_PROJECT_ID."
|
|
856
742
|
});
|
|
857
743
|
}
|
|
858
744
|
} catch {
|
|
859
745
|
}
|
|
860
746
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
issues.push({
|
|
867
|
-
check: "ingest_setup",
|
|
868
|
-
detail: `Incomplete: ${failed.map((s) => s.label).join(", ")}`,
|
|
869
|
-
fix: failed[0]?.hint ?? "Paste the SDK snippet, start your dev server, submit a test report."
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
} catch (err) {
|
|
873
|
-
issues.push({
|
|
874
|
-
check: "ingest_setup",
|
|
875
|
-
detail: err instanceof Error ? err.message : String(err),
|
|
876
|
-
fix: "Confirm API key is active for this project (Projects \u2192 API Keys)."
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
if (projectId) {
|
|
747
|
+
const ingest = await apiCall("/v1/sync/ingest-setup");
|
|
748
|
+
let dispatchReady = true;
|
|
749
|
+
let dispatchBlock;
|
|
750
|
+
let dispatchChecks = null;
|
|
751
|
+
if (resolvedId) {
|
|
880
752
|
try {
|
|
881
|
-
const preflight = await apiCall(`/v1/admin/projects/${
|
|
753
|
+
const preflight = await apiCall(`/v1/admin/projects/${resolvedId}/preflight`);
|
|
882
754
|
dispatchReady = preflight.ready;
|
|
755
|
+
dispatchChecks = preflight.checks;
|
|
883
756
|
if (!preflight.ready) {
|
|
884
757
|
const failed = preflight.checks.filter((c) => !c.ready);
|
|
885
|
-
|
|
886
|
-
check: "dispatch_preflight",
|
|
887
|
-
detail: `Blocked: ${failed.map((c) => c.label).join(", ")}`,
|
|
888
|
-
fix: failed[0]?.hint ?? "Open Settings \u2192 Integrations and complete GitHub + BYOK setup."
|
|
889
|
-
});
|
|
758
|
+
dispatchBlock = failed[0]?.hint;
|
|
890
759
|
}
|
|
891
|
-
} catch {
|
|
760
|
+
} catch (err) {
|
|
761
|
+
dispatchReady = false;
|
|
762
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
763
|
+
dispatchBlock = `Could not run dispatch preflight \u2014 ${detail}`;
|
|
764
|
+
apiLog.warn("diagnose_setup dispatch preflight failed", { error: detail });
|
|
892
765
|
}
|
|
893
766
|
}
|
|
894
|
-
const
|
|
895
|
-
const
|
|
767
|
+
const ingestFailed = ingest.steps.filter((s) => s.required && !s.complete);
|
|
768
|
+
const ingestBlock = ingestFailed[0]?.hint;
|
|
769
|
+
const connOk = connIssues.length === 0;
|
|
770
|
+
const ready = connOk && ingest.ready && dispatchReady;
|
|
771
|
+
const nextAction = !connOk ? connIssues[0]?.fix ?? "Fix the connection issue above." : !ingest.ready ? ingestBlock ?? "Complete SDK ingest setup." : !dispatchReady ? dispatchBlock ?? "Complete dispatch preflight in Settings \u2192 Integrations." : "All setup checks pass \u2014 submit a test report to confirm end-to-end.";
|
|
772
|
+
const summary = ready ? "Mushi connection, ingest, and dispatch setup look healthy." : !connOk ? `Connection issue \u2014 ${connIssues[0]?.check}: ${connIssues[0]?.detail}` : !ingest.ready ? `Ingest incomplete \u2014 ${ingestFailed.map((s) => s.label).join(", ")}.` : "Ingest OK; dispatch preflight still has blockers.";
|
|
896
773
|
return jsonResult({
|
|
774
|
+
mode: "full",
|
|
897
775
|
ready,
|
|
898
|
-
|
|
899
|
-
ingestReady,
|
|
900
|
-
dispatchReady,
|
|
901
|
-
endpoint: apiEndpoint ?? null,
|
|
902
|
-
projectId: projectId ?? null,
|
|
903
|
-
accessibleProjectCount,
|
|
904
|
-
issues,
|
|
776
|
+
summary,
|
|
905
777
|
nextAction,
|
|
906
|
-
|
|
778
|
+
connection: {
|
|
779
|
+
healthOk,
|
|
780
|
+
endpoint: apiEndpoint ?? null,
|
|
781
|
+
projectId: resolvedId ?? null,
|
|
782
|
+
accessibleProjectCount,
|
|
783
|
+
issues: connIssues
|
|
784
|
+
},
|
|
785
|
+
ingest: { ready: ingest.ready, steps: ingest.steps },
|
|
786
|
+
dispatch: resolvedId ? { ready: dispatchReady, checks: dispatchChecks } : null
|
|
907
787
|
});
|
|
908
788
|
}
|
|
909
789
|
);
|
|
@@ -1316,8 +1196,8 @@ function createMushiServer(config) {
|
|
|
1316
1196
|
server.registerTool(
|
|
1317
1197
|
"merge_fix",
|
|
1318
1198
|
{
|
|
1319
|
-
title: "
|
|
1320
|
-
description: "
|
|
1199
|
+
title: titleOf("merge_fix"),
|
|
1200
|
+
description: descOf("merge_fix"),
|
|
1321
1201
|
annotations: annotationsFor("merge_fix"),
|
|
1322
1202
|
inputSchema: {
|
|
1323
1203
|
fixId: z.string().describe("Fix attempt UUID"),
|
|
@@ -1335,8 +1215,8 @@ function createMushiServer(config) {
|
|
|
1335
1215
|
server.registerTool(
|
|
1336
1216
|
"refresh_ci",
|
|
1337
1217
|
{
|
|
1338
|
-
title: "
|
|
1339
|
-
description: "
|
|
1218
|
+
title: titleOf("refresh_ci"),
|
|
1219
|
+
description: descOf("refresh_ci"),
|
|
1340
1220
|
annotations: annotationsFor("refresh_ci"),
|
|
1341
1221
|
inputSchema: {
|
|
1342
1222
|
fixId: z.string().describe("Fix attempt UUID")
|
|
@@ -1618,6 +1498,22 @@ function createMushiServer(config) {
|
|
|
1618
1498
|
};
|
|
1619
1499
|
}
|
|
1620
1500
|
);
|
|
1501
|
+
server.registerTool(
|
|
1502
|
+
"activation_status",
|
|
1503
|
+
{
|
|
1504
|
+
title: titleOf("activation_status"),
|
|
1505
|
+
description: descOf("activation_status"),
|
|
1506
|
+
annotations: annotationsFor("activation_status"),
|
|
1507
|
+
inputSchema: {
|
|
1508
|
+
project_id: z.string().optional().describe("Project UUID (defaults to the configured project).")
|
|
1509
|
+
}
|
|
1510
|
+
},
|
|
1511
|
+
async (args) => {
|
|
1512
|
+
const pid = args.project_id ?? projectId;
|
|
1513
|
+
const qs = pid ? `?project_id=${encodeURIComponent(pid)}` : "";
|
|
1514
|
+
return jsonResult(await apiCall(`/v1/admin/activation${qs}`));
|
|
1515
|
+
}
|
|
1516
|
+
);
|
|
1621
1517
|
server.resource(
|
|
1622
1518
|
"activation_status",
|
|
1623
1519
|
"mushi://activation",
|
|
@@ -1716,7 +1612,7 @@ Prefer items that are bottlenecks or critical severity. Skip filler.`
|
|
|
1716
1612
|
text: `You are a Mushi onboarding copilot. Use the MCP tools:
|
|
1717
1613
|
1. Read mushi://activation for unified setup posture.
|
|
1718
1614
|
2. Read project://integration-health if GitHub or Sentry looks blocked.
|
|
1719
|
-
3. Call
|
|
1615
|
+
3. Call diagnose_setup if the resource is unavailable.
|
|
1720
1616
|
|
|
1721
1617
|
Then output:
|
|
1722
1618
|
- **Status:** one sentence on what is done vs blocked
|
|
@@ -2149,36 +2045,6 @@ Be specific. No generic advice.`
|
|
|
2149
2045
|
return jsonText({ ok: true, message: `Step ${step_index} \u2192 ${args.status}` });
|
|
2150
2046
|
}
|
|
2151
2047
|
);
|
|
2152
|
-
server.registerTool(
|
|
2153
|
-
"get_activation_status",
|
|
2154
|
-
{
|
|
2155
|
-
title: titleOf("get_activation_status"),
|
|
2156
|
-
description: descOf("get_activation_status"),
|
|
2157
|
-
annotations: annotationsFor("get_activation_status"),
|
|
2158
|
-
inputSchema: {
|
|
2159
|
-
project_id: z.string().optional().describe("Optional project UUID override")
|
|
2160
|
-
}
|
|
2161
|
-
},
|
|
2162
|
-
async (args) => {
|
|
2163
|
-
const qs = args.project_id ? `?project_id=${encodeURIComponent(args.project_id)}` : "";
|
|
2164
|
-
const data = await apiCall(`/v1/admin/activation${qs}`);
|
|
2165
|
-
return jsonText(data);
|
|
2166
|
-
}
|
|
2167
|
-
);
|
|
2168
|
-
server.registerTool(
|
|
2169
|
-
"get_reporter_thread",
|
|
2170
|
-
{
|
|
2171
|
-
title: titleOf("get_reporter_thread"),
|
|
2172
|
-
description: descOf("get_reporter_thread"),
|
|
2173
|
-
annotations: annotationsFor("get_reporter_thread"),
|
|
2174
|
-
inputSchema: { reportId: z.string().describe("The report UUID") }
|
|
2175
|
-
},
|
|
2176
|
-
// The reporter thread is the `comments` lane of the unified report
|
|
2177
|
-
// timeline. There is no standalone admin `/comments` route (only the
|
|
2178
|
-
// reporter-token-gated `/v1/reporter/reports/:id/comments`), so we read the
|
|
2179
|
-
// admin-authed timeline, which also carries fix / QA / status lanes.
|
|
2180
|
-
async (args) => jsonText(await apiCall(`/v1/admin/reports/${args.reportId}/timeline`))
|
|
2181
|
-
);
|
|
2182
2048
|
server.registerTool(
|
|
2183
2049
|
"ask_codebase",
|
|
2184
2050
|
{
|
|
@@ -2395,6 +2261,39 @@ Be specific. No generic advice.`
|
|
|
2395
2261
|
return result;
|
|
2396
2262
|
});
|
|
2397
2263
|
}
|
|
2264
|
+
{
|
|
2265
|
+
const llAliasServer = server.server;
|
|
2266
|
+
const innerHandler = llAliasServer?._requestHandlers?.get("tools/call");
|
|
2267
|
+
if (typeof innerHandler === "function") {
|
|
2268
|
+
llAliasServer._requestHandlers.set("tools/call", async (...args) => {
|
|
2269
|
+
const req = args[0];
|
|
2270
|
+
const originalName = req?.params?.name;
|
|
2271
|
+
const canonicalName = originalName ? DEPRECATED_TOOL_ALIASES[originalName] : void 0;
|
|
2272
|
+
if (canonicalName) {
|
|
2273
|
+
const rewritten = {
|
|
2274
|
+
...args[0],
|
|
2275
|
+
params: { ...req?.params ?? {}, name: canonicalName }
|
|
2276
|
+
};
|
|
2277
|
+
const result = await innerHandler(rewritten, ...args.slice(1));
|
|
2278
|
+
if (result != null && typeof result === "object" && "content" in result && Array.isArray(result.content)) {
|
|
2279
|
+
const r = result;
|
|
2280
|
+
return {
|
|
2281
|
+
...r,
|
|
2282
|
+
content: [
|
|
2283
|
+
{
|
|
2284
|
+
type: "text",
|
|
2285
|
+
text: `\u26A0\uFE0F Deprecated: \`${originalName}\` was renamed to \`${canonicalName}\`. Update your agent config \u2014 this alias will be removed in the next release.`
|
|
2286
|
+
},
|
|
2287
|
+
...r.content
|
|
2288
|
+
]
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
return result;
|
|
2292
|
+
}
|
|
2293
|
+
return innerHandler(...args);
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2398
2297
|
return server;
|
|
2399
2298
|
}
|
|
2400
2299
|
export {
|
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.18.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "MCP server for Mushi Mushi — triage user-felt bugs, pull evidence (screenshots, console logs, network requests), check blast radius, and dispatch fix PRs, all from your AI coding agent",
|
|
7
7
|
"type": "module",
|