@mushi-mushi/mcp 0.17.1 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -9
- package/dist/catalog.js +1 -1
- package/dist/{chunk-7UOTJ2LI.js → chunk-TJSPX5CD.js} +63 -95
- 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 +373 -411
- package/dist/server.js +269 -304
- package/package.json +2 -2
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-TJSPX5CD.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",
|
|
@@ -489,8 +490,12 @@ function createMushiServer(config) {
|
|
|
489
490
|
description: descOf("get_knowledge_graph"),
|
|
490
491
|
annotations: annotationsFor("get_knowledge_graph"),
|
|
491
492
|
inputSchema: {
|
|
492
|
-
seed: z.string().describe("Starting node id or label"),
|
|
493
|
-
depth: z.number().optional().describe("
|
|
493
|
+
seed: z.string().describe("Starting graph node id or human-readable label to traverse from"),
|
|
494
|
+
depth: z.number().optional().describe("BFS hops outward from seed \u2014 clamped to 4 in the handler (default 2)")
|
|
495
|
+
},
|
|
496
|
+
outputSchema: {
|
|
497
|
+
nodes: z.array(z.unknown()).describe("Graph nodes within the depth budget"),
|
|
498
|
+
edges: z.array(z.unknown()).describe("Edges connecting the returned nodes")
|
|
494
499
|
}
|
|
495
500
|
},
|
|
496
501
|
async (args) => {
|
|
@@ -498,18 +503,23 @@ function createMushiServer(config) {
|
|
|
498
503
|
seed: args.seed,
|
|
499
504
|
depth: String(Math.min(args.depth ?? 2, 4))
|
|
500
505
|
});
|
|
501
|
-
|
|
506
|
+
const data = await apiCall(`/v1/admin/graph/traverse?${params}`);
|
|
507
|
+
return jsonResult(data);
|
|
502
508
|
}
|
|
503
509
|
);
|
|
504
510
|
server.registerTool(
|
|
505
|
-
"
|
|
511
|
+
"get_graph_neighborhood",
|
|
506
512
|
{
|
|
507
|
-
title: titleOf("
|
|
508
|
-
description: descOf("
|
|
509
|
-
annotations: annotationsFor("
|
|
513
|
+
title: titleOf("get_graph_neighborhood"),
|
|
514
|
+
description: descOf("get_graph_neighborhood"),
|
|
515
|
+
annotations: annotationsFor("get_graph_neighborhood"),
|
|
510
516
|
inputSchema: {
|
|
511
|
-
seed: z.string().describe("Starting node id or label"),
|
|
512
|
-
depth: z.number().optional().describe("
|
|
517
|
+
seed: z.string().describe("Starting graph node id or label to expand around (e.g. an inventory Action id or component name)"),
|
|
518
|
+
depth: z.number().int().min(1).max(4).optional().describe("BFS hops to traverse outward. Default 2; clamped to a max of 4.")
|
|
519
|
+
},
|
|
520
|
+
outputSchema: {
|
|
521
|
+
nodes: z.array(z.unknown()).describe("Graph nodes within the depth budget"),
|
|
522
|
+
edges: z.array(z.unknown()).describe("Edges connecting the returned nodes")
|
|
513
523
|
}
|
|
514
524
|
},
|
|
515
525
|
async (args) => {
|
|
@@ -517,88 +527,108 @@ function createMushiServer(config) {
|
|
|
517
527
|
seed: args.seed,
|
|
518
528
|
depth: String(Math.min(args.depth ?? 2, 4))
|
|
519
529
|
});
|
|
520
|
-
|
|
530
|
+
const data = await apiCall(`/v1/admin/graph/traverse?${params}`);
|
|
531
|
+
return jsonResult(data);
|
|
521
532
|
}
|
|
522
533
|
);
|
|
523
534
|
server.registerTool(
|
|
524
|
-
"
|
|
535
|
+
"get_graph_node",
|
|
525
536
|
{
|
|
526
|
-
title: titleOf("
|
|
527
|
-
description: descOf("
|
|
528
|
-
annotations: annotationsFor("
|
|
529
|
-
inputSchema: { nodeId: z.string().describe("graph_nodes.id") }
|
|
537
|
+
title: titleOf("get_graph_node"),
|
|
538
|
+
description: descOf("get_graph_node"),
|
|
539
|
+
annotations: annotationsFor("get_graph_node"),
|
|
540
|
+
inputSchema: { nodeId: z.string().describe("The graph_nodes.id of the node to fetch (UUID).") },
|
|
541
|
+
outputSchema: {
|
|
542
|
+
node: z.unknown().describe("Single graph_nodes row including metadata (Action nodes carry v2 status)")
|
|
543
|
+
}
|
|
530
544
|
},
|
|
531
|
-
async (args) =>
|
|
545
|
+
async (args) => {
|
|
546
|
+
const data = await apiCall(`/v1/admin/graph/node/${args.nodeId}`);
|
|
547
|
+
return jsonResult(data);
|
|
548
|
+
}
|
|
532
549
|
);
|
|
533
550
|
server.registerTool(
|
|
534
|
-
"
|
|
551
|
+
"get_inventory",
|
|
535
552
|
{
|
|
536
|
-
title: titleOf("
|
|
537
|
-
description: descOf("
|
|
538
|
-
annotations: annotationsFor("
|
|
553
|
+
title: titleOf("get_inventory"),
|
|
554
|
+
description: descOf("get_inventory"),
|
|
555
|
+
annotations: annotationsFor("get_inventory"),
|
|
539
556
|
inputSchema: {
|
|
540
557
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to the server-configured project when omitted")
|
|
541
558
|
}
|
|
542
559
|
},
|
|
543
560
|
async (args) => {
|
|
544
561
|
const pid = args.projectId ?? projectId;
|
|
545
|
-
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for
|
|
562
|
+
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for get_inventory");
|
|
546
563
|
return jsonText(await apiCall(`/v1/admin/inventory/${pid}`));
|
|
547
564
|
}
|
|
548
565
|
);
|
|
549
566
|
server.registerTool(
|
|
550
|
-
"
|
|
567
|
+
"diff_inventory",
|
|
551
568
|
{
|
|
552
|
-
title: titleOf("
|
|
553
|
-
description: descOf("
|
|
554
|
-
annotations: annotationsFor("
|
|
569
|
+
title: titleOf("diff_inventory"),
|
|
570
|
+
description: descOf("diff_inventory"),
|
|
571
|
+
annotations: annotationsFor("diff_inventory"),
|
|
555
572
|
inputSchema: {
|
|
556
573
|
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)")
|
|
574
|
+
fromSha: z.string().describe("Older commit SHA (the baseline to diff from)"),
|
|
575
|
+
toSha: z.string().describe("Newer commit SHA (the candidate to diff to)")
|
|
559
576
|
}
|
|
560
577
|
},
|
|
561
578
|
async (args) => {
|
|
562
579
|
const pid = args.projectId ?? projectId;
|
|
563
|
-
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for
|
|
580
|
+
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for diff_inventory");
|
|
564
581
|
const q = new URLSearchParams({ from: args.fromSha, to: args.toSha });
|
|
565
582
|
return jsonText(await apiCall(`/v1/admin/inventory/${pid}/diff?${q}`));
|
|
566
583
|
}
|
|
567
584
|
);
|
|
568
585
|
server.registerTool(
|
|
569
|
-
"
|
|
586
|
+
"list_gate_findings",
|
|
570
587
|
{
|
|
571
|
-
title: titleOf("
|
|
572
|
-
description: descOf("
|
|
573
|
-
annotations: annotationsFor("
|
|
588
|
+
title: titleOf("list_gate_findings"),
|
|
589
|
+
description: descOf("list_gate_findings"),
|
|
590
|
+
annotations: annotationsFor("list_gate_findings"),
|
|
574
591
|
inputSchema: {
|
|
575
592
|
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("
|
|
593
|
+
gate: z.string().optional().describe("Filter to one gate id: dead-handler | mock-leak | crawl | status-claim"),
|
|
594
|
+
severity: z.string().optional().describe("Minimum severity to include: low | medium | high | critical")
|
|
595
|
+
},
|
|
596
|
+
outputSchema: {
|
|
597
|
+
runs: z.array(z.unknown()).describe("Recent gate_runs rows, newest first"),
|
|
598
|
+
findings: z.array(z.unknown()).describe("gate_findings rows for those runs")
|
|
578
599
|
}
|
|
579
600
|
},
|
|
580
601
|
async (args) => {
|
|
581
602
|
const pid = args.projectId ?? projectId;
|
|
582
|
-
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for
|
|
603
|
+
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required for list_gate_findings");
|
|
583
604
|
const q = new URLSearchParams();
|
|
584
605
|
if (args.gate) q.set("gate", args.gate);
|
|
585
606
|
if (args.severity) q.set("severity", args.severity);
|
|
586
607
|
const suffix = q.toString() ? `?${q}` : "";
|
|
587
|
-
|
|
608
|
+
const data = await apiCall(`/v1/admin/inventory/${pid}/findings${suffix}`);
|
|
609
|
+
return jsonResult(data);
|
|
588
610
|
}
|
|
589
611
|
);
|
|
590
612
|
server.registerTool(
|
|
591
|
-
"
|
|
613
|
+
"suggest_fix",
|
|
592
614
|
{
|
|
593
|
-
title: titleOf("
|
|
594
|
-
description: descOf("
|
|
595
|
-
annotations: annotationsFor("
|
|
596
|
-
inputSchema: { reportId: z.string().describe("Report UUID") }
|
|
615
|
+
title: titleOf("suggest_fix"),
|
|
616
|
+
description: descOf("suggest_fix"),
|
|
617
|
+
annotations: annotationsFor("suggest_fix"),
|
|
618
|
+
inputSchema: { reportId: z.string().describe("Report UUID to read the Stage-2 suggested-fix slice for") },
|
|
619
|
+
outputSchema: {
|
|
620
|
+
reportId: z.string().describe("The report this slice was read from"),
|
|
621
|
+
rootCause: z.unknown().describe("Stage-2 root-cause hint, or null if not yet classified"),
|
|
622
|
+
suggestedFix: z.unknown().describe("Stage-2 suggested fix, or null if not yet classified"),
|
|
623
|
+
reproductionSteps: z.unknown().describe("Reproduction steps recorded on the report (array; [] if none)"),
|
|
624
|
+
summary: z.unknown().describe("One-line report summary, or null"),
|
|
625
|
+
component: z.unknown().describe("Component/page the bug was attributed to, or null")
|
|
626
|
+
}
|
|
597
627
|
},
|
|
598
628
|
async (args) => {
|
|
599
629
|
const report = await apiCall(`/v1/admin/reports/${args.reportId}`);
|
|
600
630
|
const s2 = report.stage2_analysis;
|
|
601
|
-
return
|
|
631
|
+
return jsonResult({
|
|
602
632
|
reportId: args.reportId,
|
|
603
633
|
rootCause: s2?.rootCause ?? null,
|
|
604
634
|
suggestedFix: s2?.suggestedFix ?? null,
|
|
@@ -624,73 +654,6 @@ function createMushiServer(config) {
|
|
|
624
654
|
return jsonText(data);
|
|
625
655
|
}
|
|
626
656
|
);
|
|
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
657
|
server.registerTool(
|
|
695
658
|
"diagnose_setup",
|
|
696
659
|
{
|
|
@@ -708,7 +671,8 @@ function createMushiServer(config) {
|
|
|
708
671
|
summary: z.string(),
|
|
709
672
|
nextAction: z.string().optional(),
|
|
710
673
|
ingest: z.unknown().optional(),
|
|
711
|
-
dispatch: z.unknown().optional()
|
|
674
|
+
dispatch: z.unknown().optional(),
|
|
675
|
+
connection: z.unknown().optional()
|
|
712
676
|
}
|
|
713
677
|
},
|
|
714
678
|
async (args) => {
|
|
@@ -748,162 +712,99 @@ function createMushiServer(config) {
|
|
|
748
712
|
dispatch: { repoUrl: data.repoUrl ?? null, checks: data.checks }
|
|
749
713
|
});
|
|
750
714
|
}
|
|
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 = [];
|
|
715
|
+
const connIssues = [];
|
|
716
|
+
let healthOk = false;
|
|
808
717
|
if (!apiKey?.startsWith("mushi_")) {
|
|
809
|
-
|
|
718
|
+
connIssues.push({
|
|
810
719
|
check: "mcp_api_key",
|
|
811
|
-
detail: "MCP server API key missing or malformed",
|
|
812
|
-
fix: "Run `mushi connect`
|
|
720
|
+
detail: "MCP server API key missing or malformed (expected prefix: mushi_)",
|
|
721
|
+
fix: "Run `mushi connect` or set MUSHI_API_KEY to a valid key in your MCP config."
|
|
813
722
|
});
|
|
814
723
|
}
|
|
815
724
|
if (!apiEndpoint) {
|
|
816
|
-
|
|
725
|
+
connIssues.push({
|
|
817
726
|
check: "mcp_endpoint",
|
|
818
727
|
detail: "No API endpoint configured",
|
|
819
|
-
fix: "Set MUSHI_API_ENDPOINT to your
|
|
728
|
+
fix: "Set MUSHI_API_ENDPOINT to your `.../functions/v1/api` URL in your MCP config."
|
|
820
729
|
});
|
|
821
|
-
}
|
|
822
|
-
let healthOk = false;
|
|
823
|
-
if (apiEndpoint) {
|
|
730
|
+
} else {
|
|
824
731
|
try {
|
|
825
732
|
const healthRes = await doFetch(`${apiEndpoint.replace(/\/$/, "")}/health`, {
|
|
826
733
|
signal: AbortSignal.timeout(5e3)
|
|
827
734
|
});
|
|
828
735
|
healthOk = healthRes.status === 200;
|
|
829
736
|
if (!healthOk) {
|
|
830
|
-
|
|
737
|
+
connIssues.push({
|
|
831
738
|
check: "endpoint_health",
|
|
832
739
|
detail: `GET /health \u2192 HTTP ${healthRes.status}`,
|
|
833
740
|
fix: "Verify MUSHI_API_ENDPOINT and that the Supabase edge function is deployed."
|
|
834
741
|
});
|
|
835
742
|
}
|
|
836
743
|
} catch (err) {
|
|
837
|
-
|
|
744
|
+
connIssues.push({
|
|
838
745
|
check: "endpoint_health",
|
|
839
746
|
detail: err instanceof Error ? err.message : String(err),
|
|
840
|
-
fix: "Check network connectivity and
|
|
747
|
+
fix: "Check network connectivity and MUSHI_API_ENDPOINT in your MCP config."
|
|
841
748
|
});
|
|
842
749
|
}
|
|
843
750
|
}
|
|
844
|
-
let ingestReady = false;
|
|
845
|
-
let dispatchReady = false;
|
|
846
751
|
let accessibleProjectCount = null;
|
|
847
|
-
if (!
|
|
752
|
+
if (!resolvedId && healthOk) {
|
|
848
753
|
try {
|
|
849
|
-
const overview = await apiCall(
|
|
754
|
+
const overview = await apiCall(
|
|
755
|
+
"/v1/admin/mcp/account-overview"
|
|
756
|
+
);
|
|
850
757
|
accessibleProjectCount = overview.total;
|
|
851
758
|
if (overview.total === 0) {
|
|
852
|
-
|
|
759
|
+
connIssues.push({
|
|
853
760
|
check: "no_accessible_projects",
|
|
854
761
|
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
|
|
762
|
+
fix: "Mint an API key on a project (console \u2192 Projects \u2192 API Keys) or add MUSHI_PROJECT_ID."
|
|
856
763
|
});
|
|
857
764
|
}
|
|
858
765
|
} catch {
|
|
859
766
|
}
|
|
860
767
|
}
|
|
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) {
|
|
768
|
+
const ingest = await apiCall("/v1/sync/ingest-setup");
|
|
769
|
+
let dispatchReady = true;
|
|
770
|
+
let dispatchBlock;
|
|
771
|
+
let dispatchChecks = null;
|
|
772
|
+
if (resolvedId) {
|
|
880
773
|
try {
|
|
881
|
-
const preflight = await apiCall(`/v1/admin/projects/${
|
|
774
|
+
const preflight = await apiCall(`/v1/admin/projects/${resolvedId}/preflight`);
|
|
882
775
|
dispatchReady = preflight.ready;
|
|
776
|
+
dispatchChecks = preflight.checks;
|
|
883
777
|
if (!preflight.ready) {
|
|
884
778
|
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
|
-
});
|
|
779
|
+
dispatchBlock = failed[0]?.hint;
|
|
890
780
|
}
|
|
891
|
-
} catch {
|
|
781
|
+
} catch (err) {
|
|
782
|
+
dispatchReady = false;
|
|
783
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
784
|
+
dispatchBlock = `Could not run dispatch preflight \u2014 ${detail}`;
|
|
785
|
+
apiLog.warn("diagnose_setup dispatch preflight failed", { error: detail });
|
|
892
786
|
}
|
|
893
787
|
}
|
|
894
|
-
const
|
|
895
|
-
const
|
|
788
|
+
const ingestFailed = ingest.steps.filter((s) => s.required && !s.complete);
|
|
789
|
+
const ingestBlock = ingestFailed[0]?.hint;
|
|
790
|
+
const connOk = connIssues.length === 0;
|
|
791
|
+
const ready = connOk && ingest.ready && dispatchReady;
|
|
792
|
+
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.";
|
|
793
|
+
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
794
|
return jsonResult({
|
|
795
|
+
mode: "full",
|
|
897
796
|
ready,
|
|
898
|
-
|
|
899
|
-
ingestReady,
|
|
900
|
-
dispatchReady,
|
|
901
|
-
endpoint: apiEndpoint ?? null,
|
|
902
|
-
projectId: projectId ?? null,
|
|
903
|
-
accessibleProjectCount,
|
|
904
|
-
issues,
|
|
797
|
+
summary,
|
|
905
798
|
nextAction,
|
|
906
|
-
|
|
799
|
+
connection: {
|
|
800
|
+
healthOk,
|
|
801
|
+
endpoint: apiEndpoint ?? null,
|
|
802
|
+
projectId: resolvedId ?? null,
|
|
803
|
+
accessibleProjectCount,
|
|
804
|
+
issues: connIssues
|
|
805
|
+
},
|
|
806
|
+
ingest: { ready: ingest.ready, steps: ingest.steps },
|
|
807
|
+
dispatch: resolvedId ? { ready: dispatchReady, checks: dispatchChecks } : null
|
|
907
808
|
});
|
|
908
809
|
}
|
|
909
810
|
);
|
|
@@ -1194,13 +1095,17 @@ function createMushiServer(config) {
|
|
|
1194
1095
|
description: descOf("submit_fix_result"),
|
|
1195
1096
|
annotations: annotationsFor("submit_fix_result"),
|
|
1196
1097
|
inputSchema: {
|
|
1197
|
-
reportId: z.string().describe("
|
|
1198
|
-
branch: z.string().describe("Git branch name"),
|
|
1199
|
-
prUrl: z.string().optional().describe("GitHub PR
|
|
1200
|
-
filesChanged: z.array(z.string()).describe("
|
|
1201
|
-
linesChanged: z.number().describe("Total lines
|
|
1202
|
-
summary: z.string().describe("
|
|
1098
|
+
reportId: z.string().describe("Report UUID to attach this external fix attempt to"),
|
|
1099
|
+
branch: z.string().describe("Git branch name where the fix was implemented"),
|
|
1100
|
+
prUrl: z.string().optional().describe("GitHub pull request URL, if a PR was opened"),
|
|
1101
|
+
filesChanged: z.array(z.string()).describe("Repo-relative paths modified by the fix"),
|
|
1102
|
+
linesChanged: z.number().describe("Total lines added + removed across filesChanged"),
|
|
1103
|
+
summary: z.string().describe("One-line human summary of what the fix changed"),
|
|
1203
1104
|
idempotencyKey: z.string().uuid().optional().describe("Optional UUID \u2014 resend the same key to safely retry without creating duplicate fix rows")
|
|
1105
|
+
},
|
|
1106
|
+
outputSchema: {
|
|
1107
|
+
ok: z.boolean().describe("True when the fix_attempt row was created and marked completed"),
|
|
1108
|
+
fixId: z.string().describe("UUID of the new fix_attempt row")
|
|
1204
1109
|
}
|
|
1205
1110
|
},
|
|
1206
1111
|
async (args) => {
|
|
@@ -1222,7 +1127,7 @@ function createMushiServer(config) {
|
|
|
1222
1127
|
completed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1223
1128
|
})
|
|
1224
1129
|
});
|
|
1225
|
-
return
|
|
1130
|
+
return jsonResult({ ok: true, fixId: created.fixId });
|
|
1226
1131
|
}
|
|
1227
1132
|
);
|
|
1228
1133
|
server.registerTool(
|
|
@@ -1279,6 +1184,9 @@ function createMushiServer(config) {
|
|
|
1279
1184
|
inputSchema: {
|
|
1280
1185
|
limit: z.number().optional().describe("Max reports to judge in this batch (default 25, max 100)"),
|
|
1281
1186
|
projectId: z.string().optional().describe("Restrict to one project when the API key owns multiple")
|
|
1187
|
+
},
|
|
1188
|
+
outputSchema: {
|
|
1189
|
+
dispatched: z.number().describe("Number of judge-batch jobs dispatched (one per accessible project)")
|
|
1282
1190
|
}
|
|
1283
1191
|
},
|
|
1284
1192
|
async (args) => {
|
|
@@ -1289,7 +1197,7 @@ function createMushiServer(config) {
|
|
|
1289
1197
|
projectId: args.projectId ?? projectId ?? void 0
|
|
1290
1198
|
})
|
|
1291
1199
|
});
|
|
1292
|
-
return
|
|
1200
|
+
return jsonResult(data);
|
|
1293
1201
|
}
|
|
1294
1202
|
);
|
|
1295
1203
|
server.registerTool(
|
|
@@ -1316,12 +1224,18 @@ function createMushiServer(config) {
|
|
|
1316
1224
|
server.registerTool(
|
|
1317
1225
|
"merge_fix",
|
|
1318
1226
|
{
|
|
1319
|
-
title: "
|
|
1320
|
-
description: "
|
|
1227
|
+
title: titleOf("merge_fix"),
|
|
1228
|
+
description: descOf("merge_fix"),
|
|
1321
1229
|
annotations: annotationsFor("merge_fix"),
|
|
1322
1230
|
inputSchema: {
|
|
1323
|
-
fixId: z.string().describe("Fix attempt UUID"),
|
|
1324
|
-
mergeMethod: z.enum(["squash", "merge", "rebase"]).optional().describe("GitHub merge method")
|
|
1231
|
+
fixId: z.string().describe("Fix attempt UUID whose GitHub PR should be squash-merged"),
|
|
1232
|
+
mergeMethod: z.enum(["squash", "merge", "rebase"]).optional().describe("GitHub merge method (default squash)")
|
|
1233
|
+
},
|
|
1234
|
+
outputSchema: {
|
|
1235
|
+
merged: z.boolean().optional().describe("True when GitHub accepted the merge in this call"),
|
|
1236
|
+
alreadyMerged: z.boolean().optional().describe("True when the PR was already merged (idempotent no-op)"),
|
|
1237
|
+
reportId: z.string().describe("Report UUID linked to this fix attempt"),
|
|
1238
|
+
reportStatus: z.string().describe("Report workflow status after merge bookkeeping")
|
|
1325
1239
|
}
|
|
1326
1240
|
},
|
|
1327
1241
|
async (args) => {
|
|
@@ -1329,22 +1243,27 @@ function createMushiServer(config) {
|
|
|
1329
1243
|
method: "POST",
|
|
1330
1244
|
body: JSON.stringify({ mergeMethod: args.mergeMethod ?? "squash" })
|
|
1331
1245
|
});
|
|
1332
|
-
return
|
|
1246
|
+
return jsonResult(data);
|
|
1333
1247
|
}
|
|
1334
1248
|
);
|
|
1335
1249
|
server.registerTool(
|
|
1336
1250
|
"refresh_ci",
|
|
1337
1251
|
{
|
|
1338
|
-
title: "
|
|
1339
|
-
description: "
|
|
1252
|
+
title: titleOf("refresh_ci"),
|
|
1253
|
+
description: descOf("refresh_ci"),
|
|
1340
1254
|
annotations: annotationsFor("refresh_ci"),
|
|
1341
1255
|
inputSchema: {
|
|
1342
|
-
fixId: z.string().describe("Fix attempt UUID")
|
|
1256
|
+
fixId: z.string().describe("Fix attempt UUID whose PR check-runs should be re-polled")
|
|
1257
|
+
},
|
|
1258
|
+
outputSchema: {
|
|
1259
|
+
check_run_status: z.string().nullable().describe("GitHub check run status after refresh"),
|
|
1260
|
+
check_run_conclusion: z.string().nullable().describe("success | failure | neutral | null while pending"),
|
|
1261
|
+
check_run_updated_at: z.string().nullable().describe("ISO timestamp when CI status was last persisted")
|
|
1343
1262
|
}
|
|
1344
1263
|
},
|
|
1345
1264
|
async (args) => {
|
|
1346
1265
|
const data = await apiCall(`/v1/admin/fixes/${args.fixId}/refresh-ci`, { method: "POST" });
|
|
1347
|
-
return
|
|
1266
|
+
return jsonResult(data);
|
|
1348
1267
|
}
|
|
1349
1268
|
);
|
|
1350
1269
|
server.registerTool(
|
|
@@ -1354,16 +1273,19 @@ function createMushiServer(config) {
|
|
|
1354
1273
|
description: descOf("reopen_report"),
|
|
1355
1274
|
annotations: annotationsFor("reopen_report"),
|
|
1356
1275
|
inputSchema: {
|
|
1357
|
-
reportId: z.string().describe("Report UUID"),
|
|
1358
|
-
note: z.string().optional().describe("
|
|
1276
|
+
reportId: z.string().describe("Report UUID to move back to reopened status"),
|
|
1277
|
+
note: z.string().optional().describe("Operator note recorded on the reopen transition")
|
|
1278
|
+
},
|
|
1279
|
+
outputSchema: {
|
|
1280
|
+
report: z.unknown().describe("Updated report row with status=reopened")
|
|
1359
1281
|
}
|
|
1360
1282
|
},
|
|
1361
1283
|
async (args) => {
|
|
1362
|
-
const
|
|
1284
|
+
const report = await apiCall(`/v1/sync/reports/${args.reportId}`, {
|
|
1363
1285
|
method: "PATCH",
|
|
1364
1286
|
body: JSON.stringify({ status: "reopened", note: args.note })
|
|
1365
1287
|
});
|
|
1366
|
-
return
|
|
1288
|
+
return jsonResult({ report });
|
|
1367
1289
|
}
|
|
1368
1290
|
);
|
|
1369
1291
|
server.registerTool(
|
|
@@ -1440,9 +1362,12 @@ function createMushiServer(config) {
|
|
|
1440
1362
|
description: descOf("list_lessons"),
|
|
1441
1363
|
annotations: annotationsFor("list_lessons"),
|
|
1442
1364
|
inputSchema: {
|
|
1443
|
-
severity: z.enum(["info", "warn", "critical"]).optional().describe("Filter
|
|
1444
|
-
limit: z.number().optional().describe("Max
|
|
1445
|
-
project_id: z.string().optional().describe("Project UUID
|
|
1365
|
+
severity: z.enum(["info", "warn", "critical"]).optional().describe("Filter to one severity level"),
|
|
1366
|
+
limit: z.number().optional().describe("Max lessons to return (default 50, max 200)"),
|
|
1367
|
+
project_id: z.string().optional().describe("Project UUID \u2014 defaults to configured project")
|
|
1368
|
+
},
|
|
1369
|
+
outputSchema: {
|
|
1370
|
+
lessons: z.array(z.unknown()).describe("Promoted lesson rows ordered by frequency")
|
|
1446
1371
|
}
|
|
1447
1372
|
},
|
|
1448
1373
|
async (args) => {
|
|
@@ -1451,8 +1376,8 @@ function createMushiServer(config) {
|
|
|
1451
1376
|
if (args.severity) params.set("severity", args.severity);
|
|
1452
1377
|
params.set("limit", String(Math.min(args.limit ?? 50, 200)));
|
|
1453
1378
|
if (pid) params.set("projectId", pid);
|
|
1454
|
-
const
|
|
1455
|
-
return
|
|
1379
|
+
const lessons = await apiCall(`/v1/admin/lessons?${params}`);
|
|
1380
|
+
return jsonResult({ lessons });
|
|
1456
1381
|
}
|
|
1457
1382
|
);
|
|
1458
1383
|
server.resource(
|
|
@@ -1618,6 +1543,22 @@ function createMushiServer(config) {
|
|
|
1618
1543
|
};
|
|
1619
1544
|
}
|
|
1620
1545
|
);
|
|
1546
|
+
server.registerTool(
|
|
1547
|
+
"activation_status",
|
|
1548
|
+
{
|
|
1549
|
+
title: titleOf("activation_status"),
|
|
1550
|
+
description: descOf("activation_status"),
|
|
1551
|
+
annotations: annotationsFor("activation_status"),
|
|
1552
|
+
inputSchema: {
|
|
1553
|
+
project_id: z.string().optional().describe("Project UUID (defaults to the configured project).")
|
|
1554
|
+
}
|
|
1555
|
+
},
|
|
1556
|
+
async (args) => {
|
|
1557
|
+
const pid = args.project_id ?? projectId;
|
|
1558
|
+
const qs = pid ? `?project_id=${encodeURIComponent(pid)}` : "";
|
|
1559
|
+
return jsonResult(await apiCall(`/v1/admin/activation${qs}`));
|
|
1560
|
+
}
|
|
1561
|
+
);
|
|
1621
1562
|
server.resource(
|
|
1622
1563
|
"activation_status",
|
|
1623
1564
|
"mushi://activation",
|
|
@@ -1716,7 +1657,7 @@ Prefer items that are bottlenecks or critical severity. Skip filler.`
|
|
|
1716
1657
|
text: `You are a Mushi onboarding copilot. Use the MCP tools:
|
|
1717
1658
|
1. Read mushi://activation for unified setup posture.
|
|
1718
1659
|
2. Read project://integration-health if GitHub or Sentry looks blocked.
|
|
1719
|
-
3. Call
|
|
1660
|
+
3. Call diagnose_setup if the resource is unavailable.
|
|
1720
1661
|
|
|
1721
1662
|
Then output:
|
|
1722
1663
|
- **Status:** one sentence on what is done vs blocked
|
|
@@ -1774,11 +1715,17 @@ Be specific. No generic advice.`
|
|
|
1774
1715
|
description: descOf("generate_tdd_from_story", TDD_TOOL_CATALOG),
|
|
1775
1716
|
annotations: annotationsFor("generate_tdd_from_story", TDD_TOOL_CATALOG),
|
|
1776
1717
|
inputSchema: {
|
|
1777
|
-
projectId: z.string().describe("Project
|
|
1778
|
-
storyNodeId: z.string().describe("User story id
|
|
1779
|
-
automationMode: z.enum(["auto", "review", "approve"]).optional().describe("
|
|
1780
|
-
baseUrl: z.string().url().optional().describe("Override the app
|
|
1781
|
-
openPr: z.boolean().optional().describe("Open a draft GitHub PR (default
|
|
1718
|
+
projectId: z.string().describe("Project UUID that owns the inventory story"),
|
|
1719
|
+
storyNodeId: z.string().describe("User story node id/slug from accepted inventory (from map_user_stories or inventory.yaml)"),
|
|
1720
|
+
automationMode: z.enum(["auto", "review", "approve"]).optional().describe("Approval gate for the generated qa_story (default review \u2192 pending_review)"),
|
|
1721
|
+
baseUrl: z.string().url().optional().describe("Override the live app URL the Playwright test should target"),
|
|
1722
|
+
openPr: z.boolean().optional().describe("Open a draft GitHub PR with the generated spec (default true)")
|
|
1723
|
+
},
|
|
1724
|
+
outputSchema: {
|
|
1725
|
+
qaStoryId: z.string().describe("UUID of the inserted qa_stories row"),
|
|
1726
|
+
prUrl: z.string().nullable().describe("GitHub PR URL when openPr=true and GitHub is connected"),
|
|
1727
|
+
approvalStatus: z.string().describe("pending_review | approved \u2014 follows automationMode and project defaults"),
|
|
1728
|
+
needsHumanReview: z.boolean().describe("True when the story requires operator approval before scheduled runs")
|
|
1782
1729
|
}
|
|
1783
1730
|
},
|
|
1784
1731
|
async ({ projectId: projectId2, storyNodeId, automationMode, baseUrl, openPr }) => {
|
|
@@ -1787,7 +1734,7 @@ Be specific. No generic advice.`
|
|
|
1787
1734
|
`/v1/admin/inventory/${projectId2}/stories/${storyNodeId}/generate-test`,
|
|
1788
1735
|
{ method: "POST", body: JSON.stringify({ automation_mode: automationMode, base_url: baseUrl, open_pr: openPr }) }
|
|
1789
1736
|
);
|
|
1790
|
-
return
|
|
1737
|
+
return jsonResult(data);
|
|
1791
1738
|
}
|
|
1792
1739
|
);
|
|
1793
1740
|
server.registerTool(
|
|
@@ -2149,36 +2096,6 @@ Be specific. No generic advice.`
|
|
|
2149
2096
|
return jsonText({ ok: true, message: `Step ${step_index} \u2192 ${args.status}` });
|
|
2150
2097
|
}
|
|
2151
2098
|
);
|
|
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
2099
|
server.registerTool(
|
|
2183
2100
|
"ask_codebase",
|
|
2184
2101
|
{
|
|
@@ -2263,23 +2180,31 @@ Be specific. No generic advice.`
|
|
|
2263
2180
|
annotations: annotationsFor("search_codebase", CODEBASE_TOOL_CATALOG),
|
|
2264
2181
|
inputSchema: {
|
|
2265
2182
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
2266
|
-
query: z.string().describe("Plain-English search query"),
|
|
2267
|
-
k: z.number().optional().describe("
|
|
2268
|
-
scope_prefix: z.string().optional().describe("Optional subdirectory scope
|
|
2183
|
+
query: z.string().describe("Plain-English search query against indexed source files"),
|
|
2184
|
+
k: z.number().int().min(1).max(20).optional().describe("Max hits to return (default 8, max 20)"),
|
|
2185
|
+
scope_prefix: z.string().optional().describe("Optional repo subdirectory prefix to limit search scope")
|
|
2186
|
+
},
|
|
2187
|
+
outputSchema: {
|
|
2188
|
+
results: z.array(z.unknown()).describe("Ranked file/symbol hits with paths, line ranges, and similarity"),
|
|
2189
|
+
query: z.string().describe("Normalized query string that was searched"),
|
|
2190
|
+
mode: z.string().optional().describe("semantic (embeddings) or name (path/symbol match)")
|
|
2269
2191
|
}
|
|
2270
2192
|
},
|
|
2271
2193
|
async (args) => {
|
|
2272
2194
|
const pid = args.project_id ?? projectId;
|
|
2273
2195
|
if (!pid) throw new MushiApiError(400, "MISSING_PROJECT", "project_id is required");
|
|
2274
|
-
const data = await apiCall(
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2196
|
+
const data = await apiCall(
|
|
2197
|
+
`/v1/admin/projects/${pid}/codebase/search`,
|
|
2198
|
+
{
|
|
2199
|
+
method: "POST",
|
|
2200
|
+
body: JSON.stringify({
|
|
2201
|
+
query: args.query,
|
|
2202
|
+
k: args.k ?? 8,
|
|
2203
|
+
scope_prefix: args.scope_prefix ?? void 0
|
|
2204
|
+
})
|
|
2205
|
+
}
|
|
2206
|
+
);
|
|
2207
|
+
return jsonResult(data);
|
|
2283
2208
|
}
|
|
2284
2209
|
);
|
|
2285
2210
|
server.registerTool(
|
|
@@ -2313,10 +2238,17 @@ Be specific. No generic advice.`
|
|
|
2313
2238
|
annotations: annotationsFor("analyze_codebase_impact", CODEBASE_TOOL_CATALOG),
|
|
2314
2239
|
inputSchema: {
|
|
2315
2240
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
2316
|
-
paths: z.array(z.string()).optional().describe("Changed file paths"),
|
|
2317
|
-
source: z.enum(["last_push", "compare", "fix"]).optional().describe("Auto-resolve changed paths"),
|
|
2318
|
-
compare: z.string().optional().describe("GitHub compare range base...head"),
|
|
2319
|
-
fix_id: z.string().optional().describe("Fix attempt UUID
|
|
2241
|
+
paths: z.array(z.string()).optional().describe("Changed repo-relative file paths to analyze"),
|
|
2242
|
+
source: z.enum(["last_push", "compare", "fix"]).optional().describe("Auto-resolve changed paths instead of manual paths"),
|
|
2243
|
+
compare: z.string().optional().describe("GitHub compare range base...head when source=compare"),
|
|
2244
|
+
fix_id: z.string().optional().describe("Fix attempt UUID \u2014 uses that PR's changed files when source=fix")
|
|
2245
|
+
},
|
|
2246
|
+
outputSchema: {
|
|
2247
|
+
changed_paths: z.array(z.string()).describe("Resolved set of changed paths analyzed"),
|
|
2248
|
+
source: z.string().describe("How changed_paths were resolved (manual, last_push, compare, fix, \u2026)"),
|
|
2249
|
+
affected_file_paths: z.array(z.string()).describe("Indexed files that import or depend on changed paths"),
|
|
2250
|
+
affected_node_ids: z.array(z.string()).describe("Codebase graph node ids impacted by the change"),
|
|
2251
|
+
meta: z.unknown().nullable().optional().describe("Extra resolution metadata when auto-sourced")
|
|
2320
2252
|
}
|
|
2321
2253
|
},
|
|
2322
2254
|
async (args) => {
|
|
@@ -2331,7 +2263,7 @@ Be specific. No generic advice.`
|
|
|
2331
2263
|
throw new MushiApiError(400, "BAD_REQUEST", "Provide paths, source=last_push, compare, or fix_id");
|
|
2332
2264
|
}
|
|
2333
2265
|
const data = await apiCall(`/v1/admin/projects/${pid}/codebase/impact?${qs}`);
|
|
2334
|
-
return
|
|
2266
|
+
return jsonResult(data);
|
|
2335
2267
|
}
|
|
2336
2268
|
);
|
|
2337
2269
|
server.registerTool(
|
|
@@ -2395,6 +2327,39 @@ Be specific. No generic advice.`
|
|
|
2395
2327
|
return result;
|
|
2396
2328
|
});
|
|
2397
2329
|
}
|
|
2330
|
+
{
|
|
2331
|
+
const llAliasServer = server.server;
|
|
2332
|
+
const innerHandler = llAliasServer?._requestHandlers?.get("tools/call");
|
|
2333
|
+
if (typeof innerHandler === "function") {
|
|
2334
|
+
llAliasServer._requestHandlers.set("tools/call", async (...args) => {
|
|
2335
|
+
const req = args[0];
|
|
2336
|
+
const originalName = req?.params?.name;
|
|
2337
|
+
const canonicalName = originalName ? DEPRECATED_TOOL_ALIASES[originalName] : void 0;
|
|
2338
|
+
if (canonicalName) {
|
|
2339
|
+
const rewritten = {
|
|
2340
|
+
...args[0],
|
|
2341
|
+
params: { ...req?.params ?? {}, name: canonicalName }
|
|
2342
|
+
};
|
|
2343
|
+
const result = await innerHandler(rewritten, ...args.slice(1));
|
|
2344
|
+
if (result != null && typeof result === "object" && "content" in result && Array.isArray(result.content)) {
|
|
2345
|
+
const r = result;
|
|
2346
|
+
return {
|
|
2347
|
+
...r,
|
|
2348
|
+
content: [
|
|
2349
|
+
{
|
|
2350
|
+
type: "text",
|
|
2351
|
+
text: `\u26A0\uFE0F Deprecated: \`${originalName}\` was renamed to \`${canonicalName}\`. Update your agent config \u2014 this alias will be removed in the next release.`
|
|
2352
|
+
},
|
|
2353
|
+
...r.content
|
|
2354
|
+
]
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
return result;
|
|
2358
|
+
}
|
|
2359
|
+
return innerHandler(...args);
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2398
2363
|
return server;
|
|
2399
2364
|
}
|
|
2400
2365
|
export {
|