@mushi-mushi/mcp 0.20.2 → 0.21.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 +21 -4
- package/dist/catalog.js +1 -1
- package/dist/{chunk-RVZIKP4X.js → chunk-FNDGCFSJ.js} +9 -0
- package/dist/{chunk-ZSVRLSW5.js → chunk-XSL2FPLV.js} +1 -0
- package/dist/clients.d.ts +1 -1
- package/dist/clients.js +2 -2
- package/dist/feature-groups.js +1 -1
- package/dist/index.js +313 -234
- package/dist/server.d.ts +1 -1
- package/dist/server.js +284 -223
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import {
|
|
4
|
+
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
5
5
|
import { createRequire } from "module";
|
|
6
6
|
import { readFileSync } from "fs";
|
|
7
7
|
import { join } from "path";
|
|
@@ -215,6 +215,14 @@ var TOOL_CATALOG = [
|
|
|
215
215
|
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
216
216
|
useCase: "Why is Mushi setup broken \u2014 one call, clear next step."
|
|
217
217
|
},
|
|
218
|
+
{
|
|
219
|
+
name: "check_sdk_version",
|
|
220
|
+
title: "Check SDK freshness",
|
|
221
|
+
description: "Compare a published @mushi-mushi/* package version against the catalog (GET /v1/sdk/latest-version). Returns { package, current, latest, outdated } and, when outdated, suggestedActions (Sentry-style, max 1) pointing at search_mushi_docs plus the mushi-sdk-upgrade skill. Read-only. Use when Dependabot or mushi upgrade --check reports a drift, or before dispatching a fix that assumes a current SDK. Does not bump the pin \u2014 that stays a human/Dependabot change.",
|
|
222
|
+
scope: "mcp:read",
|
|
223
|
+
hints: { readOnly: true, idempotent: true, openWorld: true },
|
|
224
|
+
useCase: "Is this project on the current Mushi SDK?"
|
|
225
|
+
},
|
|
218
226
|
{
|
|
219
227
|
name: "search_mushi_docs",
|
|
220
228
|
title: "Search Mushi documentation",
|
|
@@ -653,6 +661,7 @@ var USE_MUSHI_INTENTS = {
|
|
|
653
661
|
label: "Set up Mushi",
|
|
654
662
|
tools: [
|
|
655
663
|
"diagnose_setup",
|
|
664
|
+
"check_sdk_version",
|
|
656
665
|
"activation_status",
|
|
657
666
|
"get_backend_health",
|
|
658
667
|
"list_byok_keys",
|
|
@@ -803,6 +812,7 @@ var TOOL_FEATURE_MAP = {
|
|
|
803
812
|
inventory_current: "admin",
|
|
804
813
|
// setup
|
|
805
814
|
diagnose_setup: "setup",
|
|
815
|
+
check_sdk_version: "setup",
|
|
806
816
|
activation_status: "setup",
|
|
807
817
|
project_integration_health: "setup",
|
|
808
818
|
setup_repo_for_mushi: "setup",
|
|
@@ -912,7 +922,7 @@ function toolMatchesFeatures(toolName, filter) {
|
|
|
912
922
|
}
|
|
913
923
|
|
|
914
924
|
// src/server.ts
|
|
915
|
-
import { McpServer } from "@modelcontextprotocol/
|
|
925
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
916
926
|
import { z } from "zod";
|
|
917
927
|
import { createLogger } from "@mushi-mushi/core";
|
|
918
928
|
|
|
@@ -1060,7 +1070,7 @@ function wrapUntrustedJson(value, role) {
|
|
|
1060
1070
|
|
|
1061
1071
|
// src/server.ts
|
|
1062
1072
|
installStdoutGuard();
|
|
1063
|
-
var NO_ARG_INPUT = {};
|
|
1073
|
+
var NO_ARG_INPUT = z.object({});
|
|
1064
1074
|
var DEFAULT_API_TIMEOUT_MS = 15e3;
|
|
1065
1075
|
var MIN_API_TIMEOUT_MS = 250;
|
|
1066
1076
|
var MAX_API_TIMEOUT_MS = 3e5;
|
|
@@ -1334,7 +1344,7 @@ function createMushiServer(config) {
|
|
|
1334
1344
|
title: titleOf("get_recent_reports"),
|
|
1335
1345
|
description: descOf("get_recent_reports"),
|
|
1336
1346
|
annotations: annotationsFor("get_recent_reports"),
|
|
1337
|
-
inputSchema: {
|
|
1347
|
+
inputSchema: z.object({
|
|
1338
1348
|
status: z.string().optional().describe("Filter by status: new, classified, grouped, fixing, fixed, dismissed"),
|
|
1339
1349
|
category: z.string().optional().describe("Filter by category: bug, slow, visual, confusing, other"),
|
|
1340
1350
|
severity: z.string().optional().describe("Filter by severity: critical, high, medium, low"),
|
|
@@ -1342,11 +1352,11 @@ function createMushiServer(config) {
|
|
|
1342
1352
|
project_id: z.string().optional().describe(
|
|
1343
1353
|
"Project UUID \u2014 defaults to the server-configured project. Useful when you have multiple projects and want to query a specific one by its ID. Get IDs by calling list_projects or get_account_overview first."
|
|
1344
1354
|
)
|
|
1345
|
-
},
|
|
1346
|
-
outputSchema: {
|
|
1355
|
+
}),
|
|
1356
|
+
outputSchema: z.object({
|
|
1347
1357
|
reports: z.array(z.unknown()),
|
|
1348
1358
|
total: z.number()
|
|
1349
|
-
}
|
|
1359
|
+
})
|
|
1350
1360
|
},
|
|
1351
1361
|
async (args) => {
|
|
1352
1362
|
const params = new URLSearchParams();
|
|
@@ -1371,11 +1381,11 @@ function createMushiServer(config) {
|
|
|
1371
1381
|
title: titleOf("get_report_detail"),
|
|
1372
1382
|
description: descOf("get_report_detail"),
|
|
1373
1383
|
annotations: annotationsFor("get_report_detail"),
|
|
1374
|
-
inputSchema: {
|
|
1384
|
+
inputSchema: z.object({
|
|
1375
1385
|
reportId: z.string().describe("The report UUID"),
|
|
1376
1386
|
project_id: z.string().optional().describe("Project UUID \u2014 required for org-scoped keys with multiple projects.")
|
|
1377
|
-
},
|
|
1378
|
-
outputSchema: { report: z.unknown() }
|
|
1387
|
+
}),
|
|
1388
|
+
outputSchema: z.object({ report: z.unknown() })
|
|
1379
1389
|
},
|
|
1380
1390
|
async (args) => {
|
|
1381
1391
|
const { headers } = await projectScopeHeaders(args.project_id);
|
|
@@ -1398,7 +1408,7 @@ function createMushiServer(config) {
|
|
|
1398
1408
|
title: titleOf("get_report_timeline"),
|
|
1399
1409
|
description: descOf("get_report_timeline"),
|
|
1400
1410
|
annotations: annotationsFor("get_report_timeline"),
|
|
1401
|
-
inputSchema: { reportId: z.string().describe("The report UUID") }
|
|
1411
|
+
inputSchema: z.object({ reportId: z.string().describe("The report UUID") })
|
|
1402
1412
|
},
|
|
1403
1413
|
async (args) => jsonText(await apiCall(`/v1/sync/reports/${args.reportId}/timeline`))
|
|
1404
1414
|
);
|
|
@@ -1418,14 +1428,14 @@ function createMushiServer(config) {
|
|
|
1418
1428
|
title: titleOf("search_reports"),
|
|
1419
1429
|
description: descOf("search_reports"),
|
|
1420
1430
|
annotations: annotationsFor("search_reports"),
|
|
1421
|
-
inputSchema: {
|
|
1431
|
+
inputSchema: z.object({
|
|
1422
1432
|
query: z.string().describe("Natural-language search text or component path"),
|
|
1423
1433
|
limit: z.number().optional().describe("Max results (default 10, max 50)"),
|
|
1424
1434
|
threshold: z.number().optional().describe("Similarity threshold 0..1, default 0.2")
|
|
1425
|
-
},
|
|
1426
|
-
outputSchema: {
|
|
1435
|
+
}),
|
|
1436
|
+
outputSchema: z.object({
|
|
1427
1437
|
results: z.array(z.unknown())
|
|
1428
|
-
}
|
|
1438
|
+
})
|
|
1429
1439
|
},
|
|
1430
1440
|
async (args) => {
|
|
1431
1441
|
const data = await apiCall("/v1/admin/reports/similarity", {
|
|
@@ -1446,13 +1456,13 @@ function createMushiServer(config) {
|
|
|
1446
1456
|
title: titleOf("get_similar_bugs"),
|
|
1447
1457
|
description: descOf("get_similar_bugs"),
|
|
1448
1458
|
annotations: annotationsFor("get_similar_bugs"),
|
|
1449
|
-
inputSchema: {
|
|
1459
|
+
inputSchema: z.object({
|
|
1450
1460
|
query: z.string().describe("Component name, page path, or bug description"),
|
|
1451
1461
|
limit: z.number().optional().describe("Max results (default 5, max 20)")
|
|
1452
|
-
},
|
|
1453
|
-
outputSchema: {
|
|
1462
|
+
}),
|
|
1463
|
+
outputSchema: z.object({
|
|
1454
1464
|
results: z.array(z.unknown())
|
|
1455
|
-
}
|
|
1465
|
+
})
|
|
1456
1466
|
},
|
|
1457
1467
|
async (args) => {
|
|
1458
1468
|
const data = await apiCall("/v1/admin/reports/similarity", {
|
|
@@ -1473,18 +1483,18 @@ function createMushiServer(config) {
|
|
|
1473
1483
|
title: titleOf("get_fix_context"),
|
|
1474
1484
|
description: descOf("get_fix_context"),
|
|
1475
1485
|
annotations: annotationsFor("get_fix_context"),
|
|
1476
|
-
inputSchema: {
|
|
1486
|
+
inputSchema: z.object({
|
|
1477
1487
|
reportId: z.string().describe("The report UUID to fix"),
|
|
1478
1488
|
project_id: z.string().optional().describe("Project UUID \u2014 required for org-scoped keys with multiple projects.")
|
|
1479
|
-
},
|
|
1480
|
-
outputSchema: {
|
|
1489
|
+
}),
|
|
1490
|
+
outputSchema: z.object({
|
|
1481
1491
|
report: z.unknown(),
|
|
1482
1492
|
fixPrompt: z.unknown(),
|
|
1483
1493
|
reproductionSteps: z.unknown(),
|
|
1484
1494
|
component: z.unknown(),
|
|
1485
1495
|
rootCause: z.unknown(),
|
|
1486
1496
|
bugOntologyTags: z.unknown()
|
|
1487
|
-
}
|
|
1497
|
+
})
|
|
1488
1498
|
},
|
|
1489
1499
|
async (args) => {
|
|
1490
1500
|
const { headers } = await projectScopeHeaders(args.project_id);
|
|
@@ -1513,10 +1523,10 @@ function createMushiServer(config) {
|
|
|
1513
1523
|
title: titleOf("get_fix_timeline"),
|
|
1514
1524
|
description: descOf("get_fix_timeline"),
|
|
1515
1525
|
annotations: annotationsFor("get_fix_timeline"),
|
|
1516
|
-
inputSchema: {
|
|
1526
|
+
inputSchema: z.object({
|
|
1517
1527
|
fixId: z.string().describe("fix_attempt UUID"),
|
|
1518
1528
|
project_id: z.string().optional().describe("Project UUID \u2014 required for org-scoped keys with multiple projects.")
|
|
1519
|
-
}
|
|
1529
|
+
})
|
|
1520
1530
|
},
|
|
1521
1531
|
async (args) => {
|
|
1522
1532
|
const { headers } = await projectScopeHeaders(args.project_id);
|
|
@@ -1529,7 +1539,7 @@ function createMushiServer(config) {
|
|
|
1529
1539
|
title: titleOf("get_blast_radius"),
|
|
1530
1540
|
description: descOf("get_blast_radius"),
|
|
1531
1541
|
annotations: annotationsFor("get_blast_radius"),
|
|
1532
|
-
inputSchema: { nodeId: z.string().describe("Graph node UUID") }
|
|
1542
|
+
inputSchema: z.object({ nodeId: z.string().describe("Graph node UUID") })
|
|
1533
1543
|
},
|
|
1534
1544
|
async (args) => jsonText(await apiCall(`/v1/admin/graph/blast-radius/${args.nodeId}`))
|
|
1535
1545
|
);
|
|
@@ -1539,14 +1549,14 @@ function createMushiServer(config) {
|
|
|
1539
1549
|
title: titleOf("get_knowledge_graph"),
|
|
1540
1550
|
description: descOf("get_knowledge_graph"),
|
|
1541
1551
|
annotations: annotationsFor("get_knowledge_graph"),
|
|
1542
|
-
inputSchema: {
|
|
1552
|
+
inputSchema: z.object({
|
|
1543
1553
|
seed: z.string().describe("Starting graph node id or human-readable label to traverse from"),
|
|
1544
1554
|
depth: z.number().optional().describe("BFS hops outward from seed \u2014 clamped to 4 in the handler (default 2)")
|
|
1545
|
-
},
|
|
1546
|
-
outputSchema: {
|
|
1555
|
+
}),
|
|
1556
|
+
outputSchema: z.object({
|
|
1547
1557
|
nodes: z.array(z.unknown()).describe("Graph nodes within the depth budget"),
|
|
1548
1558
|
edges: z.array(z.unknown()).describe("Edges connecting the returned nodes")
|
|
1549
|
-
}
|
|
1559
|
+
})
|
|
1550
1560
|
},
|
|
1551
1561
|
async (args) => {
|
|
1552
1562
|
const params = new URLSearchParams({
|
|
@@ -1565,16 +1575,16 @@ function createMushiServer(config) {
|
|
|
1565
1575
|
title: titleOf("get_graph_neighborhood"),
|
|
1566
1576
|
description: descOf("get_graph_neighborhood"),
|
|
1567
1577
|
annotations: annotationsFor("get_graph_neighborhood"),
|
|
1568
|
-
inputSchema: {
|
|
1578
|
+
inputSchema: z.object({
|
|
1569
1579
|
seed: z.string().describe(
|
|
1570
1580
|
"Starting graph node id or label to expand around (e.g. an inventory Action id or component name)"
|
|
1571
1581
|
),
|
|
1572
1582
|
depth: z.number().int().min(1).max(4).optional().describe("BFS hops to traverse outward. Default 2; clamped to a max of 4.")
|
|
1573
|
-
},
|
|
1574
|
-
outputSchema: {
|
|
1583
|
+
}),
|
|
1584
|
+
outputSchema: z.object({
|
|
1575
1585
|
nodes: z.array(z.unknown()).describe("Graph nodes within the depth budget"),
|
|
1576
1586
|
edges: z.array(z.unknown()).describe("Edges connecting the returned nodes")
|
|
1577
|
-
}
|
|
1587
|
+
})
|
|
1578
1588
|
},
|
|
1579
1589
|
async (args) => {
|
|
1580
1590
|
const params = new URLSearchParams({
|
|
@@ -1593,12 +1603,12 @@ function createMushiServer(config) {
|
|
|
1593
1603
|
title: titleOf("get_graph_node"),
|
|
1594
1604
|
description: descOf("get_graph_node"),
|
|
1595
1605
|
annotations: annotationsFor("get_graph_node"),
|
|
1596
|
-
inputSchema: {
|
|
1606
|
+
inputSchema: z.object({
|
|
1597
1607
|
nodeId: z.string().describe("The graph_nodes.id of the node to fetch (UUID).")
|
|
1598
|
-
},
|
|
1599
|
-
outputSchema: {
|
|
1608
|
+
}),
|
|
1609
|
+
outputSchema: z.object({
|
|
1600
1610
|
node: z.unknown().describe("Single graph_nodes row including metadata (Action nodes carry v2 status)")
|
|
1601
|
-
}
|
|
1611
|
+
})
|
|
1602
1612
|
},
|
|
1603
1613
|
async (args) => {
|
|
1604
1614
|
const data = await apiCall(`/v1/admin/graph/node/${args.nodeId}`);
|
|
@@ -1611,9 +1621,9 @@ function createMushiServer(config) {
|
|
|
1611
1621
|
title: titleOf("get_inventory"),
|
|
1612
1622
|
description: descOf("get_inventory"),
|
|
1613
1623
|
annotations: annotationsFor("get_inventory"),
|
|
1614
|
-
inputSchema: {
|
|
1624
|
+
inputSchema: z.object({
|
|
1615
1625
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to the server-configured project when omitted")
|
|
1616
|
-
}
|
|
1626
|
+
})
|
|
1617
1627
|
},
|
|
1618
1628
|
async (args) => {
|
|
1619
1629
|
const pid = args.projectId ?? projectId;
|
|
@@ -1628,11 +1638,11 @@ function createMushiServer(config) {
|
|
|
1628
1638
|
title: titleOf("diff_inventory"),
|
|
1629
1639
|
description: descOf("diff_inventory"),
|
|
1630
1640
|
annotations: annotationsFor("diff_inventory"),
|
|
1631
|
-
inputSchema: {
|
|
1641
|
+
inputSchema: z.object({
|
|
1632
1642
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to configured project"),
|
|
1633
1643
|
fromSha: z.string().describe("Older commit SHA (the baseline to diff from)"),
|
|
1634
1644
|
toSha: z.string().describe("Newer commit SHA (the candidate to diff to)")
|
|
1635
|
-
}
|
|
1645
|
+
})
|
|
1636
1646
|
},
|
|
1637
1647
|
async (args) => {
|
|
1638
1648
|
const pid = args.projectId ?? projectId;
|
|
@@ -1648,15 +1658,15 @@ function createMushiServer(config) {
|
|
|
1648
1658
|
title: titleOf("list_gate_findings"),
|
|
1649
1659
|
description: descOf("list_gate_findings"),
|
|
1650
1660
|
annotations: annotationsFor("list_gate_findings"),
|
|
1651
|
-
inputSchema: {
|
|
1661
|
+
inputSchema: z.object({
|
|
1652
1662
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to configured project"),
|
|
1653
1663
|
gate: z.string().optional().describe("Filter to one gate id: dead-handler | mock-leak | crawl | status-claim"),
|
|
1654
1664
|
severity: z.string().optional().describe("Minimum severity to include: low | medium | high | critical")
|
|
1655
|
-
},
|
|
1656
|
-
outputSchema: {
|
|
1665
|
+
}),
|
|
1666
|
+
outputSchema: z.object({
|
|
1657
1667
|
runs: z.array(z.unknown()).describe("Recent gate_runs rows, newest first"),
|
|
1658
1668
|
findings: z.array(z.unknown()).describe("gate_findings rows for those runs")
|
|
1659
|
-
}
|
|
1669
|
+
})
|
|
1660
1670
|
},
|
|
1661
1671
|
async (args) => {
|
|
1662
1672
|
const pid = args.projectId ?? projectId;
|
|
@@ -1682,18 +1692,20 @@ function createMushiServer(config) {
|
|
|
1682
1692
|
title: titleOf("suggest_fix"),
|
|
1683
1693
|
description: descOf("suggest_fix"),
|
|
1684
1694
|
annotations: annotationsFor("suggest_fix"),
|
|
1685
|
-
inputSchema: {
|
|
1695
|
+
inputSchema: z.object({
|
|
1686
1696
|
reportId: z.string().describe("Report UUID to read the Stage-2 suggested-fix slice for")
|
|
1687
|
-
},
|
|
1688
|
-
outputSchema: {
|
|
1697
|
+
}),
|
|
1698
|
+
outputSchema: z.object({
|
|
1689
1699
|
reportId: z.string().describe("The report this slice was read from"),
|
|
1690
1700
|
rootCause: z.unknown().describe("Stage-2 root-cause hint, or null if not yet classified"),
|
|
1691
1701
|
suggestedFix: z.unknown().describe("Stage-2 suggested fix, or null if not yet classified"),
|
|
1692
1702
|
reproductionSteps: z.unknown().describe("Reproduction steps recorded on the report (array; [] if none)"),
|
|
1693
1703
|
summary: z.unknown().describe("One-line report summary, or null"),
|
|
1694
1704
|
component: z.unknown().describe("Component/page the bug was attributed to, or null"),
|
|
1695
|
-
note: z.string().optional().describe(
|
|
1696
|
-
|
|
1705
|
+
note: z.string().optional().describe(
|
|
1706
|
+
"Present when no Stage-2 analysis exists \u2014 explains why and what to call instead"
|
|
1707
|
+
)
|
|
1708
|
+
})
|
|
1697
1709
|
},
|
|
1698
1710
|
async (args) => {
|
|
1699
1711
|
const report = await apiCall(`/v1/admin/reports/${args.reportId}`);
|
|
@@ -1725,11 +1737,11 @@ function createMushiServer(config) {
|
|
|
1725
1737
|
title: titleOf("run_nl_query"),
|
|
1726
1738
|
description: descOf("run_nl_query"),
|
|
1727
1739
|
annotations: annotationsFor("run_nl_query"),
|
|
1728
|
-
inputSchema: {
|
|
1740
|
+
inputSchema: z.object({
|
|
1729
1741
|
question: z.string().describe(
|
|
1730
1742
|
'Question in plain English, e.g. "Which components had the most critical bugs this week?"'
|
|
1731
1743
|
)
|
|
1732
|
-
}
|
|
1744
|
+
})
|
|
1733
1745
|
},
|
|
1734
1746
|
async (args) => {
|
|
1735
1747
|
const data = await apiCall("/v1/admin/query", {
|
|
@@ -1745,14 +1757,14 @@ function createMushiServer(config) {
|
|
|
1745
1757
|
title: titleOf("diagnose_setup"),
|
|
1746
1758
|
description: descOf("diagnose_setup"),
|
|
1747
1759
|
annotations: annotationsFor("diagnose_setup"),
|
|
1748
|
-
inputSchema: {
|
|
1760
|
+
inputSchema: z.object({
|
|
1749
1761
|
mode: z.enum(["full", "ingest", "dispatch"]).optional().describe(
|
|
1750
1762
|
"full (default) = ingest + dispatch; ingest = SDK pipeline only; dispatch = fix preflight only."
|
|
1751
1763
|
),
|
|
1752
1764
|
project_id: z.string().optional().describe("Project UUID for dispatch checks (defaults to configured project)."),
|
|
1753
1765
|
projectId: z.string().optional().describe("Alias for project_id.")
|
|
1754
|
-
},
|
|
1755
|
-
outputSchema: {
|
|
1766
|
+
}),
|
|
1767
|
+
outputSchema: z.object({
|
|
1756
1768
|
mode: z.string(),
|
|
1757
1769
|
ready: z.boolean(),
|
|
1758
1770
|
summary: z.string(),
|
|
@@ -1760,7 +1772,7 @@ function createMushiServer(config) {
|
|
|
1760
1772
|
ingest: z.unknown().optional(),
|
|
1761
1773
|
dispatch: z.unknown().optional(),
|
|
1762
1774
|
connection: z.unknown().optional()
|
|
1763
|
-
}
|
|
1775
|
+
})
|
|
1764
1776
|
},
|
|
1765
1777
|
async (args) => {
|
|
1766
1778
|
const mode = args.mode ?? "full";
|
|
@@ -1899,17 +1911,71 @@ function createMushiServer(config) {
|
|
|
1899
1911
|
});
|
|
1900
1912
|
}
|
|
1901
1913
|
);
|
|
1914
|
+
server.registerTool(
|
|
1915
|
+
"check_sdk_version",
|
|
1916
|
+
{
|
|
1917
|
+
title: titleOf("check_sdk_version"),
|
|
1918
|
+
description: descOf("check_sdk_version"),
|
|
1919
|
+
annotations: annotationsFor("check_sdk_version"),
|
|
1920
|
+
inputSchema: z.object({
|
|
1921
|
+
package: z.string().optional().describe(
|
|
1922
|
+
"npm package name (default @mushi-mushi/web). Examples: @mushi-mushi/web, @mushi-mushi/node, @mushi-mushi/core."
|
|
1923
|
+
),
|
|
1924
|
+
current: z.string().optional().describe("Installed version from package.json, if known (e.g. 1.27.0).")
|
|
1925
|
+
}),
|
|
1926
|
+
outputSchema: z.object({
|
|
1927
|
+
package: z.string(),
|
|
1928
|
+
latest: z.string().optional(),
|
|
1929
|
+
current: z.string().optional(),
|
|
1930
|
+
outdated: z.boolean().optional(),
|
|
1931
|
+
suggestedActions: z.array(
|
|
1932
|
+
z.object({
|
|
1933
|
+
type: z.literal("tool_call"),
|
|
1934
|
+
toolName: z.string(),
|
|
1935
|
+
arguments: z.record(z.string(), z.unknown()),
|
|
1936
|
+
reason: z.string()
|
|
1937
|
+
})
|
|
1938
|
+
).optional()
|
|
1939
|
+
})
|
|
1940
|
+
},
|
|
1941
|
+
async (args) => {
|
|
1942
|
+
const pkg = args.package?.trim() || "@mushi-mushi/web";
|
|
1943
|
+
const query = new URLSearchParams({ package: pkg }).toString();
|
|
1944
|
+
const data = await apiCall(
|
|
1945
|
+
`/v1/sdk/latest-version?${query}`
|
|
1946
|
+
);
|
|
1947
|
+
const latest = data.latest ?? data.version;
|
|
1948
|
+
const current = args.current;
|
|
1949
|
+
const outdated = current && latest ? current !== latest : void 0;
|
|
1950
|
+
return jsonResult({
|
|
1951
|
+
package: data.package ?? pkg,
|
|
1952
|
+
latest,
|
|
1953
|
+
current,
|
|
1954
|
+
outdated,
|
|
1955
|
+
...outdated ? {
|
|
1956
|
+
suggestedActions: [
|
|
1957
|
+
{
|
|
1958
|
+
type: "tool_call",
|
|
1959
|
+
toolName: "search_mushi_docs",
|
|
1960
|
+
arguments: { query: `${pkg} upgrade mushi-sdk-upgrade` },
|
|
1961
|
+
reason: "Read current upgrade notes, then apply the mushi-sdk-upgrade skill. This tool does not bump the pin."
|
|
1962
|
+
}
|
|
1963
|
+
]
|
|
1964
|
+
} : {}
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
);
|
|
1902
1968
|
server.registerTool(
|
|
1903
1969
|
"search_mushi_docs",
|
|
1904
1970
|
{
|
|
1905
1971
|
title: titleOf("search_mushi_docs"),
|
|
1906
1972
|
description: descOf("search_mushi_docs"),
|
|
1907
1973
|
annotations: annotationsFor("search_mushi_docs"),
|
|
1908
|
-
inputSchema: {
|
|
1974
|
+
inputSchema: z.object({
|
|
1909
1975
|
query: z.string().describe("Keywords to search official Mushi docs (guides, MCP, inventory, QA)."),
|
|
1910
1976
|
limit: z.number().int().min(1).max(20).optional().describe("Max results (default 8).")
|
|
1911
|
-
},
|
|
1912
|
-
outputSchema: {
|
|
1977
|
+
}),
|
|
1978
|
+
outputSchema: z.object({
|
|
1913
1979
|
query: z.string(),
|
|
1914
1980
|
results: z.array(
|
|
1915
1981
|
z.object({
|
|
@@ -1919,7 +1985,7 @@ function createMushiServer(config) {
|
|
|
1919
1985
|
score: z.number()
|
|
1920
1986
|
})
|
|
1921
1987
|
)
|
|
1922
|
-
}
|
|
1988
|
+
})
|
|
1923
1989
|
},
|
|
1924
1990
|
async (args) => {
|
|
1925
1991
|
const query = args.query ?? "";
|
|
@@ -1940,11 +2006,11 @@ function createMushiServer(config) {
|
|
|
1940
2006
|
description: descOf("list_projects"),
|
|
1941
2007
|
annotations: annotationsFor("list_projects"),
|
|
1942
2008
|
inputSchema: NO_ARG_INPUT,
|
|
1943
|
-
outputSchema: {
|
|
2009
|
+
outputSchema: z.object({
|
|
1944
2010
|
projects: z.array(z.unknown()),
|
|
1945
2011
|
total: z.number().optional(),
|
|
1946
2012
|
_multi_project_hint: z.string().optional()
|
|
1947
|
-
}
|
|
2013
|
+
})
|
|
1948
2014
|
},
|
|
1949
2015
|
async () => {
|
|
1950
2016
|
const data = await apiCall("/v1/admin/mcp/projects");
|
|
@@ -1961,7 +2027,7 @@ function createMushiServer(config) {
|
|
|
1961
2027
|
description: descOf("get_account_overview"),
|
|
1962
2028
|
annotations: annotationsFor("get_account_overview"),
|
|
1963
2029
|
inputSchema: NO_ARG_INPUT,
|
|
1964
|
-
outputSchema: {
|
|
2030
|
+
outputSchema: z.object({
|
|
1965
2031
|
projects: z.array(z.unknown()),
|
|
1966
2032
|
total: z.number(),
|
|
1967
2033
|
active_project_id: z.string().nullable(),
|
|
@@ -1969,7 +2035,7 @@ function createMushiServer(config) {
|
|
|
1969
2035
|
resourceCount: z.number().optional(),
|
|
1970
2036
|
promptCount: z.number().optional(),
|
|
1971
2037
|
multi_project_hint: z.string()
|
|
1972
|
-
}
|
|
2038
|
+
})
|
|
1973
2039
|
},
|
|
1974
2040
|
async () => {
|
|
1975
2041
|
const data = await apiCall("/v1/admin/mcp/account-overview");
|
|
@@ -1991,9 +2057,9 @@ function createMushiServer(config) {
|
|
|
1991
2057
|
title: titleOf("get_project_context"),
|
|
1992
2058
|
description: descOf("get_project_context"),
|
|
1993
2059
|
annotations: annotationsFor("get_project_context"),
|
|
1994
|
-
inputSchema: {
|
|
2060
|
+
inputSchema: z.object({
|
|
1995
2061
|
project_id: z.string().optional().describe("Project UUID. Defaults to configured project.")
|
|
1996
|
-
}
|
|
2062
|
+
})
|
|
1997
2063
|
},
|
|
1998
2064
|
async (args) => {
|
|
1999
2065
|
const pid = args.project_id ?? projectId;
|
|
@@ -2015,13 +2081,13 @@ function createMushiServer(config) {
|
|
|
2015
2081
|
title: titleOf("get_pipeline_logs"),
|
|
2016
2082
|
description: descOf("get_pipeline_logs"),
|
|
2017
2083
|
annotations: annotationsFor("get_pipeline_logs"),
|
|
2018
|
-
inputSchema: {
|
|
2084
|
+
inputSchema: z.object({
|
|
2019
2085
|
project_id: z.string().optional().describe("Project UUID. Defaults to configured project."),
|
|
2020
2086
|
service: z.enum(["fix-worker", "qa-story-runner", "pipeline", "all"]).optional().describe("Pipeline service to filter (default: all)."),
|
|
2021
2087
|
since: z.string().optional().describe("ISO-8601 timestamp \u2014 return only entries after this time."),
|
|
2022
2088
|
limit: z.number().optional().describe("Max entries to return (default 50, max 200)."),
|
|
2023
2089
|
level: z.enum(["info", "warn", "error", "fatal"]).optional().describe("Minimum severity level (default: warn).")
|
|
2024
|
-
}
|
|
2090
|
+
})
|
|
2025
2091
|
},
|
|
2026
2092
|
async (args) => {
|
|
2027
2093
|
const pid = args.project_id ?? projectId;
|
|
@@ -2041,9 +2107,9 @@ function createMushiServer(config) {
|
|
|
2041
2107
|
title: titleOf("get_report_evidence"),
|
|
2042
2108
|
description: descOf("get_report_evidence"),
|
|
2043
2109
|
annotations: annotationsFor("get_report_evidence"),
|
|
2044
|
-
inputSchema: {
|
|
2110
|
+
inputSchema: z.object({
|
|
2045
2111
|
report_id: z.string().describe("Report UUID.")
|
|
2046
|
-
}
|
|
2112
|
+
})
|
|
2047
2113
|
},
|
|
2048
2114
|
async (args) => {
|
|
2049
2115
|
const [reportRes, timelineRes] = await Promise.allSettled([
|
|
@@ -2091,12 +2157,12 @@ function createMushiServer(config) {
|
|
|
2091
2157
|
title: titleOf("triage_issue"),
|
|
2092
2158
|
description: descOf("triage_issue"),
|
|
2093
2159
|
annotations: annotationsFor("triage_issue"),
|
|
2094
|
-
inputSchema: {
|
|
2160
|
+
inputSchema: z.object({
|
|
2095
2161
|
report_id: z.string().uuid().describe("Report UUID to triage."),
|
|
2096
2162
|
project_id: z.string().optional().describe("Project UUID. Defaults to configured project."),
|
|
2097
2163
|
include_logs: z.boolean().optional().describe("Include recent pipeline logs in triage packet (default: true).")
|
|
2098
|
-
},
|
|
2099
|
-
outputSchema: {
|
|
2164
|
+
}),
|
|
2165
|
+
outputSchema: z.object({
|
|
2100
2166
|
report_id: z.string(),
|
|
2101
2167
|
severity: z.unknown(),
|
|
2102
2168
|
category: z.unknown(),
|
|
@@ -2109,7 +2175,7 @@ function createMushiServer(config) {
|
|
|
2109
2175
|
recent_logs: z.unknown().nullable(),
|
|
2110
2176
|
recommended_actions: z.array(z.unknown()),
|
|
2111
2177
|
triage_summary: z.string()
|
|
2112
|
-
}
|
|
2178
|
+
})
|
|
2113
2179
|
},
|
|
2114
2180
|
async (args) => {
|
|
2115
2181
|
const { projectId: pid, headers } = await projectScopeHeaders(args.project_id);
|
|
@@ -2233,7 +2299,7 @@ function createMushiServer(config) {
|
|
|
2233
2299
|
title: titleOf("submit_fix_result"),
|
|
2234
2300
|
description: descOf("submit_fix_result"),
|
|
2235
2301
|
annotations: annotationsFor("submit_fix_result"),
|
|
2236
|
-
inputSchema: {
|
|
2302
|
+
inputSchema: z.object({
|
|
2237
2303
|
reportId: z.string().describe("Report UUID to attach this external fix attempt to"),
|
|
2238
2304
|
branch: z.string().describe("Git branch name where the fix was implemented"),
|
|
2239
2305
|
prUrl: z.string().optional().describe("GitHub pull request URL, if a PR was opened"),
|
|
@@ -2243,19 +2309,14 @@ function createMushiServer(config) {
|
|
|
2243
2309
|
idempotencyKey: z.string().uuid().optional().describe(
|
|
2244
2310
|
"Optional UUID \u2014 resend the same key to safely retry without creating duplicate fix rows. Omit it and a stable key is derived from reportId + branch + prUrl, so a retried submission carries the identical key instead of a fresh random one."
|
|
2245
2311
|
)
|
|
2246
|
-
},
|
|
2247
|
-
outputSchema: {
|
|
2312
|
+
}),
|
|
2313
|
+
outputSchema: z.object({
|
|
2248
2314
|
ok: z.boolean().describe("True when the fix_attempt row was created and marked completed"),
|
|
2249
2315
|
fixId: z.string().describe("UUID of the new fix_attempt row")
|
|
2250
|
-
}
|
|
2316
|
+
})
|
|
2251
2317
|
},
|
|
2252
2318
|
async (args) => {
|
|
2253
|
-
const idemKey = args.idempotencyKey ?? await stableUuidFrom(
|
|
2254
|
-
IDEMPOTENCY_NAMESPACE,
|
|
2255
|
-
args.reportId,
|
|
2256
|
-
args.branch,
|
|
2257
|
-
args.prUrl ?? ""
|
|
2258
|
-
);
|
|
2319
|
+
const idemKey = args.idempotencyKey ?? await stableUuidFrom(IDEMPOTENCY_NAMESPACE, args.reportId, args.branch, args.prUrl ?? "");
|
|
2259
2320
|
const created = await apiCall("/v1/admin/fixes", {
|
|
2260
2321
|
method: "POST",
|
|
2261
2322
|
headers: { "Idempotency-Key": idemKey },
|
|
@@ -2291,10 +2352,10 @@ function createMushiServer(config) {
|
|
|
2291
2352
|
title: titleOf("triage_next_steps"),
|
|
2292
2353
|
description: descOf("triage_next_steps"),
|
|
2293
2354
|
annotations: annotationsFor("triage_next_steps"),
|
|
2294
|
-
inputSchema: {
|
|
2355
|
+
inputSchema: z.object({
|
|
2295
2356
|
project_id: z.string().uuid().optional().describe("Project UUID (defaults to the configured project).")
|
|
2296
|
-
},
|
|
2297
|
-
outputSchema: {
|
|
2357
|
+
}),
|
|
2358
|
+
outputSchema: z.object({
|
|
2298
2359
|
steps: z.array(
|
|
2299
2360
|
z.object({
|
|
2300
2361
|
priority: z.number(),
|
|
@@ -2305,7 +2366,7 @@ function createMushiServer(config) {
|
|
|
2305
2366
|
})
|
|
2306
2367
|
),
|
|
2307
2368
|
summary: z.string()
|
|
2308
|
-
}
|
|
2369
|
+
})
|
|
2309
2370
|
},
|
|
2310
2371
|
async (args) => {
|
|
2311
2372
|
const pid = await resolveProjectId(args.project_id);
|
|
@@ -2340,7 +2401,9 @@ function createMushiServer(config) {
|
|
|
2340
2401
|
args: { report_id: r.id }
|
|
2341
2402
|
});
|
|
2342
2403
|
}
|
|
2343
|
-
const openUserReports = reports.filter(
|
|
2404
|
+
const openUserReports = reports.filter(
|
|
2405
|
+
(r) => (r.status === "new" || r.status === "classified") && !isCron(r) && !isBlocked(r)
|
|
2406
|
+
).sort((a, b) => {
|
|
2344
2407
|
const rank = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
2345
2408
|
return (rank[String(a.severity)] ?? 4) - (rank[String(b.severity)] ?? 4);
|
|
2346
2409
|
});
|
|
@@ -2373,7 +2436,7 @@ function createMushiServer(config) {
|
|
|
2373
2436
|
title: titleOf("dispatch_fix"),
|
|
2374
2437
|
description: descOf("dispatch_fix"),
|
|
2375
2438
|
annotations: annotationsFor("dispatch_fix"),
|
|
2376
|
-
inputSchema: {
|
|
2439
|
+
inputSchema: z.object({
|
|
2377
2440
|
reportId: z.string().uuid().describe("Report UUID to fix"),
|
|
2378
2441
|
agent: z.enum(["claude_code", "codex", "rest_worker", "mcp"]).optional().describe("Override the agent adapter"),
|
|
2379
2442
|
idempotencyKey: z.string().uuid().optional().describe(
|
|
@@ -2382,19 +2445,19 @@ function createMushiServer(config) {
|
|
|
2382
2445
|
inventoryActionNodeId: z.string().uuid().optional().describe(
|
|
2383
2446
|
"Optional inventory Action node UUID for spec-traceability (\xA72.10). When provided, the fix-worker embeds the expected_outcome contract in the LLM prompt and runs validateAgainstSpec before opening the PR."
|
|
2384
2447
|
)
|
|
2385
|
-
},
|
|
2386
|
-
outputSchema: {
|
|
2448
|
+
}),
|
|
2449
|
+
outputSchema: z.object({
|
|
2387
2450
|
fixId: z.string(),
|
|
2388
2451
|
status: z.string()
|
|
2389
|
-
}
|
|
2452
|
+
})
|
|
2390
2453
|
},
|
|
2391
|
-
async (args,
|
|
2392
|
-
if (
|
|
2454
|
+
async (args, ctx) => {
|
|
2455
|
+
if (ctx?.mcpReq.notify && ctx?.mcpReq._meta?.progressToken) {
|
|
2393
2456
|
try {
|
|
2394
|
-
await
|
|
2457
|
+
await ctx.mcpReq.notify({
|
|
2395
2458
|
method: "notifications/progress",
|
|
2396
2459
|
params: {
|
|
2397
|
-
progressToken:
|
|
2460
|
+
progressToken: ctx.mcpReq._meta.progressToken,
|
|
2398
2461
|
progress: 0,
|
|
2399
2462
|
total: 100,
|
|
2400
2463
|
message: "Dispatching Mushi fix orchestrator\u2026"
|
|
@@ -2427,13 +2490,13 @@ function createMushiServer(config) {
|
|
|
2427
2490
|
title: titleOf("trigger_judge"),
|
|
2428
2491
|
description: descOf("trigger_judge"),
|
|
2429
2492
|
annotations: annotationsFor("trigger_judge"),
|
|
2430
|
-
inputSchema: {
|
|
2493
|
+
inputSchema: z.object({
|
|
2431
2494
|
limit: z.number().optional().describe("Max reports to judge in this batch (default 25, max 100)"),
|
|
2432
2495
|
projectId: z.string().optional().describe("Restrict to one project when the API key owns multiple")
|
|
2433
|
-
},
|
|
2434
|
-
outputSchema: {
|
|
2496
|
+
}),
|
|
2497
|
+
outputSchema: z.object({
|
|
2435
2498
|
dispatched: z.number().describe("Number of judge-batch jobs dispatched (one per accessible project)")
|
|
2436
|
-
}
|
|
2499
|
+
})
|
|
2437
2500
|
},
|
|
2438
2501
|
async (args) => {
|
|
2439
2502
|
const data = await apiCall("/v1/admin/judge/run", {
|
|
@@ -2452,10 +2515,10 @@ function createMushiServer(config) {
|
|
|
2452
2515
|
title: titleOf("test_gen_from_report"),
|
|
2453
2516
|
description: descOf("test_gen_from_report"),
|
|
2454
2517
|
annotations: annotationsFor("test_gen_from_report"),
|
|
2455
|
-
inputSchema: {
|
|
2518
|
+
inputSchema: z.object({
|
|
2456
2519
|
reportId: z.string().describe("Report UUID to turn into a Playwright PR"),
|
|
2457
2520
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to configured project")
|
|
2458
|
-
}
|
|
2521
|
+
})
|
|
2459
2522
|
},
|
|
2460
2523
|
async (args) => {
|
|
2461
2524
|
const pid = args.projectId ?? projectId;
|
|
@@ -2481,16 +2544,16 @@ function createMushiServer(config) {
|
|
|
2481
2544
|
title: titleOf("merge_fix"),
|
|
2482
2545
|
description: descOf("merge_fix"),
|
|
2483
2546
|
annotations: annotationsFor("merge_fix"),
|
|
2484
|
-
inputSchema: {
|
|
2547
|
+
inputSchema: z.object({
|
|
2485
2548
|
fixId: z.string().describe("Fix attempt UUID whose GitHub PR should be squash-merged"),
|
|
2486
2549
|
mergeMethod: z.enum(["squash", "merge", "rebase"]).optional().describe("GitHub merge method (default squash)")
|
|
2487
|
-
},
|
|
2488
|
-
outputSchema: {
|
|
2550
|
+
}),
|
|
2551
|
+
outputSchema: z.object({
|
|
2489
2552
|
merged: z.boolean().optional().describe("True when GitHub accepted the merge in this call"),
|
|
2490
2553
|
alreadyMerged: z.boolean().optional().describe("True when the PR was already merged (idempotent no-op)"),
|
|
2491
2554
|
reportId: z.string().describe("Report UUID linked to this fix attempt"),
|
|
2492
2555
|
reportStatus: z.string().describe("Report workflow status after merge bookkeeping")
|
|
2493
|
-
}
|
|
2556
|
+
})
|
|
2494
2557
|
},
|
|
2495
2558
|
async (args) => {
|
|
2496
2559
|
const data = await apiCall(`/v1/admin/fixes/${args.fixId}/merge`, {
|
|
@@ -2506,14 +2569,14 @@ function createMushiServer(config) {
|
|
|
2506
2569
|
title: titleOf("refresh_ci"),
|
|
2507
2570
|
description: descOf("refresh_ci"),
|
|
2508
2571
|
annotations: annotationsFor("refresh_ci"),
|
|
2509
|
-
inputSchema: {
|
|
2572
|
+
inputSchema: z.object({
|
|
2510
2573
|
fixId: z.string().describe("Fix attempt UUID whose PR check-runs should be re-polled")
|
|
2511
|
-
},
|
|
2512
|
-
outputSchema: {
|
|
2574
|
+
}),
|
|
2575
|
+
outputSchema: z.object({
|
|
2513
2576
|
check_run_status: z.string().nullable().describe("GitHub check run status after refresh"),
|
|
2514
2577
|
check_run_conclusion: z.string().nullable().describe("success | failure | neutral | null while pending"),
|
|
2515
2578
|
check_run_updated_at: z.string().nullable().describe("ISO timestamp when CI status was last persisted")
|
|
2516
|
-
}
|
|
2579
|
+
})
|
|
2517
2580
|
},
|
|
2518
2581
|
async (args) => {
|
|
2519
2582
|
const data = await apiCall(`/v1/admin/fixes/${args.fixId}/refresh-ci`, { method: "POST" });
|
|
@@ -2526,13 +2589,13 @@ function createMushiServer(config) {
|
|
|
2526
2589
|
title: titleOf("reopen_report"),
|
|
2527
2590
|
description: descOf("reopen_report"),
|
|
2528
2591
|
annotations: annotationsFor("reopen_report"),
|
|
2529
|
-
inputSchema: {
|
|
2592
|
+
inputSchema: z.object({
|
|
2530
2593
|
reportId: z.string().describe("Report UUID to move back to reopened status"),
|
|
2531
2594
|
note: z.string().optional().describe("Operator note recorded on the reopen transition")
|
|
2532
|
-
},
|
|
2533
|
-
outputSchema: {
|
|
2595
|
+
}),
|
|
2596
|
+
outputSchema: z.object({
|
|
2534
2597
|
report: z.unknown().describe("Updated report row with status=reopened")
|
|
2535
|
-
}
|
|
2598
|
+
})
|
|
2536
2599
|
},
|
|
2537
2600
|
async (args) => {
|
|
2538
2601
|
const report = await apiCall(`/v1/sync/reports/${args.reportId}`, {
|
|
@@ -2548,7 +2611,7 @@ function createMushiServer(config) {
|
|
|
2548
2611
|
title: titleOf("transition_status"),
|
|
2549
2612
|
description: descOf("transition_status"),
|
|
2550
2613
|
annotations: annotationsFor("transition_status"),
|
|
2551
|
-
inputSchema: {
|
|
2614
|
+
inputSchema: z.object({
|
|
2552
2615
|
reportId: z.string().describe("Report UUID"),
|
|
2553
2616
|
status: z.enum([
|
|
2554
2617
|
"pending",
|
|
@@ -2567,7 +2630,7 @@ function createMushiServer(config) {
|
|
|
2567
2630
|
"dismissed"
|
|
2568
2631
|
]).describe("Target status (resolved is stored as fixed)"),
|
|
2569
2632
|
reason: z.string().optional().describe("Reason for the transition (audit trail)")
|
|
2570
|
-
}
|
|
2633
|
+
})
|
|
2571
2634
|
},
|
|
2572
2635
|
async (args) => {
|
|
2573
2636
|
const data = await apiCall(`/v1/admin/reports/${args.reportId}`, {
|
|
@@ -2583,9 +2646,9 @@ function createMushiServer(config) {
|
|
|
2583
2646
|
title: titleOf("setup_repo_for_mushi"),
|
|
2584
2647
|
description: descOf("setup_repo_for_mushi"),
|
|
2585
2648
|
annotations: annotationsFor("setup_repo_for_mushi"),
|
|
2586
|
-
inputSchema: {
|
|
2649
|
+
inputSchema: z.object({
|
|
2587
2650
|
projectId: z.string().optional().describe("Project UUID \u2014 defaults to configured project")
|
|
2588
|
-
}
|
|
2651
|
+
})
|
|
2589
2652
|
},
|
|
2590
2653
|
async (args) => {
|
|
2591
2654
|
const pid = args.projectId ?? projectId;
|
|
@@ -2608,12 +2671,12 @@ function createMushiServer(config) {
|
|
|
2608
2671
|
title: titleOf("query_lessons"),
|
|
2609
2672
|
description: descOf("query_lessons"),
|
|
2610
2673
|
annotations: annotationsFor("query_lessons"),
|
|
2611
|
-
inputSchema: {
|
|
2674
|
+
inputSchema: z.object({
|
|
2612
2675
|
diff_text: z.string().describe("The PR diff, code snippet, or description of the change being made."),
|
|
2613
2676
|
max_tokens: z.number().optional().describe("Maximum tokens for returned lessons context (default 3000, max 8000)."),
|
|
2614
2677
|
top_k: z.number().optional().describe("Max number of lessons to return (default 15, max 50)."),
|
|
2615
2678
|
project_id: z.string().optional().describe("Project UUID. Defaults to configured project.")
|
|
2616
|
-
}
|
|
2679
|
+
})
|
|
2617
2680
|
},
|
|
2618
2681
|
async (args) => {
|
|
2619
2682
|
const pid = args.project_id ?? projectId;
|
|
@@ -2635,14 +2698,14 @@ function createMushiServer(config) {
|
|
|
2635
2698
|
title: titleOf("list_lessons"),
|
|
2636
2699
|
description: descOf("list_lessons"),
|
|
2637
2700
|
annotations: annotationsFor("list_lessons"),
|
|
2638
|
-
inputSchema: {
|
|
2701
|
+
inputSchema: z.object({
|
|
2639
2702
|
severity: z.enum(["info", "warn", "critical"]).optional().describe("Filter to one severity level"),
|
|
2640
2703
|
limit: z.number().optional().describe("Max lessons to return (default 50, max 200)"),
|
|
2641
2704
|
project_id: z.string().optional().describe("Project UUID \u2014 defaults to configured project")
|
|
2642
|
-
},
|
|
2643
|
-
outputSchema: {
|
|
2705
|
+
}),
|
|
2706
|
+
outputSchema: z.object({
|
|
2644
2707
|
lessons: z.array(z.unknown()).describe("Promoted lesson rows ordered by frequency")
|
|
2645
|
-
}
|
|
2708
|
+
})
|
|
2646
2709
|
},
|
|
2647
2710
|
async (args) => {
|
|
2648
2711
|
const pid = args.project_id ?? projectId;
|
|
@@ -2654,7 +2717,7 @@ function createMushiServer(config) {
|
|
|
2654
2717
|
return wrappedJsonResult({ lessons }, "lesson text");
|
|
2655
2718
|
}
|
|
2656
2719
|
);
|
|
2657
|
-
server.
|
|
2720
|
+
server.registerResource(
|
|
2658
2721
|
"project_stats",
|
|
2659
2722
|
"project://stats",
|
|
2660
2723
|
{ description: "Report counts, category breakdown, severity distribution" },
|
|
@@ -2668,7 +2731,7 @@ function createMushiServer(config) {
|
|
|
2668
2731
|
]
|
|
2669
2732
|
})
|
|
2670
2733
|
);
|
|
2671
|
-
server.
|
|
2734
|
+
server.registerResource(
|
|
2672
2735
|
"project_settings",
|
|
2673
2736
|
"project://settings",
|
|
2674
2737
|
{
|
|
@@ -2684,7 +2747,7 @@ function createMushiServer(config) {
|
|
|
2684
2747
|
]
|
|
2685
2748
|
})
|
|
2686
2749
|
);
|
|
2687
|
-
server.
|
|
2750
|
+
server.registerResource(
|
|
2688
2751
|
"project_dashboard",
|
|
2689
2752
|
"project://dashboard",
|
|
2690
2753
|
{
|
|
@@ -2706,10 +2769,10 @@ function createMushiServer(config) {
|
|
|
2706
2769
|
title: titleOf("list_top_contributors"),
|
|
2707
2770
|
description: descOf("list_top_contributors"),
|
|
2708
2771
|
annotations: annotationsFor("list_top_contributors"),
|
|
2709
|
-
inputSchema: {
|
|
2772
|
+
inputSchema: z.object({
|
|
2710
2773
|
limit: z.number().int().min(1).max(100).optional().default(10).describe("Max rows to return (default 10, max 100)"),
|
|
2711
2774
|
range: z.enum(["30d", "90d", "all"]).optional().default("30d").describe("Time window for points calculation")
|
|
2712
|
-
}
|
|
2775
|
+
})
|
|
2713
2776
|
},
|
|
2714
2777
|
async ({ limit, range }) => ({
|
|
2715
2778
|
content: [
|
|
@@ -2730,11 +2793,11 @@ function createMushiServer(config) {
|
|
|
2730
2793
|
title: titleOf("award_bonus_points"),
|
|
2731
2794
|
description: descOf("award_bonus_points"),
|
|
2732
2795
|
annotations: annotationsFor("award_bonus_points"),
|
|
2733
|
-
inputSchema: {
|
|
2796
|
+
inputSchema: z.object({
|
|
2734
2797
|
external_user_id: z.string().describe("The host-app user id as passed to Mushi.identify()"),
|
|
2735
2798
|
points: z.number().int().min(1).max(5e4).describe("Bonus points to award (max 50,000 per call)"),
|
|
2736
2799
|
reason: z.string().max(200).describe("Human-readable reason, logged to end_user_activity")
|
|
2737
|
-
}
|
|
2800
|
+
})
|
|
2738
2801
|
},
|
|
2739
2802
|
async ({ external_user_id, points, reason }) => ({
|
|
2740
2803
|
content: [
|
|
@@ -2759,11 +2822,11 @@ function createMushiServer(config) {
|
|
|
2759
2822
|
title: titleOf("set_tier"),
|
|
2760
2823
|
description: descOf("set_tier"),
|
|
2761
2824
|
annotations: annotationsFor("set_tier"),
|
|
2762
|
-
inputSchema: {
|
|
2825
|
+
inputSchema: z.object({
|
|
2763
2826
|
external_user_id: z.string().describe("The host-app user id as passed to Mushi.identify()"),
|
|
2764
2827
|
tier_slug: z.string().describe('Tier slug to assign, e.g. "champion", "contributor", "explorer"'),
|
|
2765
2828
|
reason: z.string().max(200).optional().describe("Optional reason for manual override")
|
|
2766
|
-
}
|
|
2829
|
+
})
|
|
2767
2830
|
},
|
|
2768
2831
|
async ({ external_user_id, tier_slug, reason }) => ({
|
|
2769
2832
|
content: [
|
|
@@ -2782,7 +2845,7 @@ function createMushiServer(config) {
|
|
|
2782
2845
|
]
|
|
2783
2846
|
})
|
|
2784
2847
|
);
|
|
2785
|
-
server.
|
|
2848
|
+
server.registerResource(
|
|
2786
2849
|
"privacy_status",
|
|
2787
2850
|
"privacy://status",
|
|
2788
2851
|
{
|
|
@@ -2798,7 +2861,7 @@ function createMushiServer(config) {
|
|
|
2798
2861
|
]
|
|
2799
2862
|
})
|
|
2800
2863
|
);
|
|
2801
|
-
server.
|
|
2864
|
+
server.registerResource(
|
|
2802
2865
|
"evolution_history",
|
|
2803
2866
|
"evolution://history",
|
|
2804
2867
|
{
|
|
@@ -2820,7 +2883,7 @@ function createMushiServer(config) {
|
|
|
2820
2883
|
]
|
|
2821
2884
|
})
|
|
2822
2885
|
);
|
|
2823
|
-
server.
|
|
2886
|
+
server.registerResource(
|
|
2824
2887
|
"project_integration_health",
|
|
2825
2888
|
"project://integration-health",
|
|
2826
2889
|
{
|
|
@@ -2836,7 +2899,7 @@ function createMushiServer(config) {
|
|
|
2836
2899
|
]
|
|
2837
2900
|
})
|
|
2838
2901
|
);
|
|
2839
|
-
server.
|
|
2902
|
+
server.registerResource(
|
|
2840
2903
|
"inventory_current",
|
|
2841
2904
|
"inventory://current",
|
|
2842
2905
|
{
|
|
@@ -2861,9 +2924,9 @@ function createMushiServer(config) {
|
|
|
2861
2924
|
title: titleOf("activation_status"),
|
|
2862
2925
|
description: descOf("activation_status"),
|
|
2863
2926
|
annotations: annotationsFor("activation_status"),
|
|
2864
|
-
inputSchema: {
|
|
2927
|
+
inputSchema: z.object({
|
|
2865
2928
|
project_id: z.string().optional().describe("Project UUID (defaults to the configured project).")
|
|
2866
|
-
}
|
|
2929
|
+
})
|
|
2867
2930
|
},
|
|
2868
2931
|
async (args) => {
|
|
2869
2932
|
const pid = args.project_id ?? projectId;
|
|
@@ -2871,7 +2934,7 @@ function createMushiServer(config) {
|
|
|
2871
2934
|
return jsonResult(await apiCall(`/v1/admin/activation${qs}`));
|
|
2872
2935
|
}
|
|
2873
2936
|
);
|
|
2874
|
-
server.
|
|
2937
|
+
server.registerResource(
|
|
2875
2938
|
"activation_status",
|
|
2876
2939
|
"mushi://activation",
|
|
2877
2940
|
{
|
|
@@ -2890,10 +2953,12 @@ function createMushiServer(config) {
|
|
|
2890
2953
|
};
|
|
2891
2954
|
}
|
|
2892
2955
|
);
|
|
2893
|
-
server.
|
|
2956
|
+
server.registerPrompt(
|
|
2894
2957
|
"summarize_report_for_fix",
|
|
2895
|
-
|
|
2896
|
-
|
|
2958
|
+
{
|
|
2959
|
+
description: "Turn a Mushi report into a one-line root cause, smallest file set, repro steps, and blast-radius warnings. Use before asking an agent to write the patch.",
|
|
2960
|
+
argsSchema: z.object({ reportId: z.string().describe("The report UUID to summarize") })
|
|
2961
|
+
},
|
|
2897
2962
|
({ reportId }) => ({
|
|
2898
2963
|
messages: [
|
|
2899
2964
|
{
|
|
@@ -2918,10 +2983,12 @@ Lead with the fix. Skip the preamble.`
|
|
|
2918
2983
|
]
|
|
2919
2984
|
})
|
|
2920
2985
|
);
|
|
2921
|
-
server.
|
|
2986
|
+
server.registerPrompt(
|
|
2922
2987
|
"explain_judge_result",
|
|
2923
|
-
|
|
2924
|
-
|
|
2988
|
+
{
|
|
2989
|
+
description: "Turn raw Sonnet-as-Judge scores into ship / iterate / dismiss guidance. Use after a fix attempt has been judged.",
|
|
2990
|
+
argsSchema: z.object({ fixId: z.string().describe("The fix_attempt UUID to explain") })
|
|
2991
|
+
},
|
|
2925
2992
|
({ fixId }) => ({
|
|
2926
2993
|
messages: [
|
|
2927
2994
|
{
|
|
@@ -2942,10 +3009,12 @@ No preamble, no score-by-score recap \u2014 the numbers are in the tool output.`
|
|
|
2942
3009
|
]
|
|
2943
3010
|
})
|
|
2944
3011
|
);
|
|
2945
|
-
server.
|
|
3012
|
+
server.registerPrompt(
|
|
2946
3013
|
"triage_next_steps",
|
|
2947
|
-
|
|
2948
|
-
|
|
3014
|
+
{
|
|
3015
|
+
description: 'Answer "what should I focus on right now?" \u2014 five-item markdown list drawn from the dashboard + recent classified queue.',
|
|
3016
|
+
argsSchema: z.object({})
|
|
3017
|
+
},
|
|
2949
3018
|
() => ({
|
|
2950
3019
|
messages: [
|
|
2951
3020
|
{
|
|
@@ -2965,10 +3034,12 @@ Prefer items that are bottlenecks or critical severity. Skip filler.`
|
|
|
2965
3034
|
]
|
|
2966
3035
|
})
|
|
2967
3036
|
);
|
|
2968
|
-
server.
|
|
3037
|
+
server.registerPrompt(
|
|
2969
3038
|
"mushi_setup",
|
|
2970
|
-
|
|
2971
|
-
|
|
3039
|
+
{
|
|
3040
|
+
description: "Diagnose why Mushi setup is stuck and return the single next command or console step to unblock it.",
|
|
3041
|
+
argsSchema: z.object({})
|
|
3042
|
+
},
|
|
2972
3043
|
() => ({
|
|
2973
3044
|
messages: [
|
|
2974
3045
|
{
|
|
@@ -2998,13 +3069,13 @@ Be specific. No generic advice.`
|
|
|
2998
3069
|
title: titleOf("map_user_stories", TDD_TOOL_CATALOG),
|
|
2999
3070
|
description: descOf("map_user_stories", TDD_TOOL_CATALOG),
|
|
3000
3071
|
annotations: annotationsFor("map_user_stories", TDD_TOOL_CATALOG),
|
|
3001
|
-
inputSchema: {
|
|
3072
|
+
inputSchema: z.object({
|
|
3002
3073
|
projectId: z.string().describe("Project id to map stories for"),
|
|
3003
3074
|
baseUrl: z.string().url().describe("Live app URL to crawl"),
|
|
3004
3075
|
maxPages: z.number().int().min(1).max(50).optional().describe("Max pages to crawl (default 20)"),
|
|
3005
3076
|
provider: z.enum(["firecrawl", "browserbase"]).optional().describe("Crawl provider (default: firecrawl)"),
|
|
3006
3077
|
cursorCloudRefine: z.boolean().optional().describe("Dispatch Cursor Cloud agent to refine and open a PR")
|
|
3007
|
-
}
|
|
3078
|
+
})
|
|
3008
3079
|
},
|
|
3009
3080
|
async ({ projectId: projectId2, baseUrl, maxPages, provider, cursorCloudRefine }) => {
|
|
3010
3081
|
if (!projectId2) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required");
|
|
@@ -3029,9 +3100,9 @@ Be specific. No generic advice.`
|
|
|
3029
3100
|
title: titleOf("get_map_run_status", TDD_TOOL_CATALOG),
|
|
3030
3101
|
description: descOf("get_map_run_status", TDD_TOOL_CATALOG),
|
|
3031
3102
|
annotations: annotationsFor("get_map_run_status", TDD_TOOL_CATALOG),
|
|
3032
|
-
inputSchema: {
|
|
3103
|
+
inputSchema: z.object({
|
|
3033
3104
|
projectId: z.string().describe("Project id")
|
|
3034
|
-
}
|
|
3105
|
+
})
|
|
3035
3106
|
},
|
|
3036
3107
|
async ({ projectId: projectId2 }) => {
|
|
3037
3108
|
const data = await apiCall(`/v1/admin/inventory/${projectId2}/map-runs`);
|
|
@@ -3044,7 +3115,7 @@ Be specific. No generic advice.`
|
|
|
3044
3115
|
title: titleOf("generate_tdd_from_story", TDD_TOOL_CATALOG),
|
|
3045
3116
|
description: descOf("generate_tdd_from_story", TDD_TOOL_CATALOG),
|
|
3046
3117
|
annotations: annotationsFor("generate_tdd_from_story", TDD_TOOL_CATALOG),
|
|
3047
|
-
inputSchema: {
|
|
3118
|
+
inputSchema: z.object({
|
|
3048
3119
|
projectId: z.string().describe("Project UUID that owns the inventory story"),
|
|
3049
3120
|
storyNodeId: z.string().describe(
|
|
3050
3121
|
"User story node id/slug from accepted inventory (from map_user_stories or inventory.yaml)"
|
|
@@ -3052,13 +3123,13 @@ Be specific. No generic advice.`
|
|
|
3052
3123
|
automationMode: z.enum(["auto", "review", "approve"]).optional().describe("Approval gate for the generated qa_story (default review \u2192 pending_review)"),
|
|
3053
3124
|
baseUrl: z.string().url().optional().describe("Override the live app URL the Playwright test should target"),
|
|
3054
3125
|
openPr: z.boolean().optional().describe("Open a draft GitHub PR with the generated spec (default true)")
|
|
3055
|
-
},
|
|
3056
|
-
outputSchema: {
|
|
3126
|
+
}),
|
|
3127
|
+
outputSchema: z.object({
|
|
3057
3128
|
qaStoryId: z.string().describe("UUID of the inserted qa_stories row"),
|
|
3058
3129
|
prUrl: z.string().nullable().describe("GitHub PR URL when openPr=true and GitHub is connected"),
|
|
3059
3130
|
approvalStatus: z.string().describe("pending_review | approved \u2014 follows automationMode and project defaults"),
|
|
3060
3131
|
needsHumanReview: z.boolean().describe("True when the story requires operator approval before scheduled runs")
|
|
3061
|
-
}
|
|
3132
|
+
})
|
|
3062
3133
|
},
|
|
3063
3134
|
async ({ projectId: projectId2, storyNodeId, automationMode, baseUrl, openPr }) => {
|
|
3064
3135
|
if (!projectId2) throw new MushiApiError(400, "MISSING_PROJECT", "projectId is required");
|
|
@@ -3079,9 +3150,9 @@ Be specific. No generic advice.`
|
|
|
3079
3150
|
title: titleOf("improve_qa_story", TDD_TOOL_CATALOG),
|
|
3080
3151
|
description: descOf("improve_qa_story", TDD_TOOL_CATALOG),
|
|
3081
3152
|
annotations: annotationsFor("improve_qa_story", TDD_TOOL_CATALOG),
|
|
3082
|
-
inputSchema: {
|
|
3153
|
+
inputSchema: z.object({
|
|
3083
3154
|
projectId: z.string().optional().describe("Project id (omit to run across all projects)")
|
|
3084
|
-
}
|
|
3155
|
+
})
|
|
3085
3156
|
},
|
|
3086
3157
|
async ({ projectId: projectId2 }) => {
|
|
3087
3158
|
const data = await apiCall("/v1/admin/pdca/improve-qa-stories", {
|
|
@@ -3097,10 +3168,10 @@ Be specific. No generic advice.`
|
|
|
3097
3168
|
title: titleOf("run_qa_story", TDD_TOOL_CATALOG),
|
|
3098
3169
|
description: descOf("run_qa_story", TDD_TOOL_CATALOG),
|
|
3099
3170
|
annotations: annotationsFor("run_qa_story", TDD_TOOL_CATALOG),
|
|
3100
|
-
inputSchema: {
|
|
3171
|
+
inputSchema: z.object({
|
|
3101
3172
|
projectId: z.string().describe("Project id"),
|
|
3102
3173
|
qaStoryId: z.string().describe("qa_story id to run")
|
|
3103
|
-
}
|
|
3174
|
+
})
|
|
3104
3175
|
},
|
|
3105
3176
|
async ({ projectId: projectId2, qaStoryId }) => {
|
|
3106
3177
|
const data = await apiCall(
|
|
@@ -3116,9 +3187,9 @@ Be specific. No generic advice.`
|
|
|
3116
3187
|
title: titleOf("list_byok_keys", TDD_TOOL_CATALOG),
|
|
3117
3188
|
description: descOf("list_byok_keys", TDD_TOOL_CATALOG),
|
|
3118
3189
|
annotations: annotationsFor("list_byok_keys", TDD_TOOL_CATALOG),
|
|
3119
|
-
inputSchema: {
|
|
3190
|
+
inputSchema: z.object({
|
|
3120
3191
|
projectId: z.string().describe("Project id")
|
|
3121
|
-
}
|
|
3192
|
+
})
|
|
3122
3193
|
},
|
|
3123
3194
|
async ({ projectId: projectId2 }) => {
|
|
3124
3195
|
const data = await apiCall(
|
|
@@ -3133,14 +3204,14 @@ Be specific. No generic advice.`
|
|
|
3133
3204
|
title: titleOf("add_byok_key", TDD_TOOL_CATALOG),
|
|
3134
3205
|
description: descOf("add_byok_key", TDD_TOOL_CATALOG),
|
|
3135
3206
|
annotations: annotationsFor("add_byok_key", TDD_TOOL_CATALOG),
|
|
3136
|
-
inputSchema: {
|
|
3207
|
+
inputSchema: z.object({
|
|
3137
3208
|
projectId: z.string().describe("Project id"),
|
|
3138
3209
|
provider: z.enum(["anthropic", "openai", "firecrawl", "browserbase", "cursor"]).describe("Provider slug"),
|
|
3139
3210
|
key: z.string().min(8).max(4096).describe("The API key value to add"),
|
|
3140
3211
|
label: z.string().optional().describe("Human-readable label for this key"),
|
|
3141
3212
|
priority: z.number().int().min(0).max(1e4).optional().describe("Priority for ordering (lower = higher priority)"),
|
|
3142
3213
|
baseUrl: z.string().url().max(2048).optional().describe("Allow-listed OpenAI-compatible HTTPS base URL")
|
|
3143
|
-
}
|
|
3214
|
+
})
|
|
3144
3215
|
},
|
|
3145
3216
|
async ({ projectId: projectId2, provider, key, label, priority, baseUrl }) => {
|
|
3146
3217
|
const data = await apiCall("/v1/admin/byok/keys", {
|
|
@@ -3163,10 +3234,10 @@ Be specific. No generic advice.`
|
|
|
3163
3234
|
title: titleOf("test_byok_key", TDD_TOOL_CATALOG),
|
|
3164
3235
|
description: descOf("test_byok_key", TDD_TOOL_CATALOG),
|
|
3165
3236
|
annotations: annotationsFor("test_byok_key", TDD_TOOL_CATALOG),
|
|
3166
|
-
inputSchema: {
|
|
3237
|
+
inputSchema: z.object({
|
|
3167
3238
|
projectId: z.string().describe("Project id"),
|
|
3168
3239
|
keyId: z.string().uuid().describe("Pooled BYOK key id")
|
|
3169
|
-
}
|
|
3240
|
+
})
|
|
3170
3241
|
},
|
|
3171
3242
|
async ({ keyId }) => {
|
|
3172
3243
|
const data = await apiCall(`/v1/admin/byok/keys/${encodeURIComponent(keyId)}/test`, {
|
|
@@ -3181,10 +3252,10 @@ Be specific. No generic advice.`
|
|
|
3181
3252
|
title: titleOf("remove_byok_key", TDD_TOOL_CATALOG),
|
|
3182
3253
|
description: descOf("remove_byok_key", TDD_TOOL_CATALOG),
|
|
3183
3254
|
annotations: annotationsFor("remove_byok_key", TDD_TOOL_CATALOG),
|
|
3184
|
-
inputSchema: {
|
|
3255
|
+
inputSchema: z.object({
|
|
3185
3256
|
projectId: z.string().describe("Project id"),
|
|
3186
3257
|
keyId: z.string().uuid().describe("Pooled BYOK key UUID from list_byok_keys")
|
|
3187
|
-
}
|
|
3258
|
+
})
|
|
3188
3259
|
},
|
|
3189
3260
|
async ({ keyId }) => {
|
|
3190
3261
|
const data = await apiCall(`/v1/admin/byok/keys/${encodeURIComponent(keyId)}`, {
|
|
@@ -3199,9 +3270,9 @@ Be specific. No generic advice.`
|
|
|
3199
3270
|
title: titleOf("list_pending_review_stories", TDD_TOOL_CATALOG),
|
|
3200
3271
|
description: descOf("list_pending_review_stories", TDD_TOOL_CATALOG),
|
|
3201
3272
|
annotations: annotationsFor("list_pending_review_stories", TDD_TOOL_CATALOG),
|
|
3202
|
-
inputSchema: {
|
|
3273
|
+
inputSchema: z.object({
|
|
3203
3274
|
projectId: z.string().describe("Project id")
|
|
3204
|
-
}
|
|
3275
|
+
})
|
|
3205
3276
|
},
|
|
3206
3277
|
async ({ projectId: projectId2 }) => {
|
|
3207
3278
|
const data = await apiCall(
|
|
@@ -3216,11 +3287,11 @@ Be specific. No generic advice.`
|
|
|
3216
3287
|
title: titleOf("approve_qa_story", TDD_TOOL_CATALOG),
|
|
3217
3288
|
description: descOf("approve_qa_story", TDD_TOOL_CATALOG),
|
|
3218
3289
|
annotations: annotationsFor("approve_qa_story", TDD_TOOL_CATALOG),
|
|
3219
|
-
inputSchema: {
|
|
3290
|
+
inputSchema: z.object({
|
|
3220
3291
|
projectId: z.string().describe("Project id"),
|
|
3221
3292
|
qaStoryId: z.string().describe("QA story id to approve or reject"),
|
|
3222
3293
|
status: z.enum(["approved", "rejected"]).describe("New approval status")
|
|
3223
|
-
}
|
|
3294
|
+
})
|
|
3224
3295
|
},
|
|
3225
3296
|
async ({ projectId: projectId2, qaStoryId, status }) => {
|
|
3226
3297
|
const data = await apiCall(
|
|
@@ -3236,11 +3307,11 @@ Be specific. No generic advice.`
|
|
|
3236
3307
|
title: titleOf("reply_to_reporter", TDD_TOOL_CATALOG),
|
|
3237
3308
|
description: descOf("reply_to_reporter", TDD_TOOL_CATALOG),
|
|
3238
3309
|
annotations: annotationsFor("reply_to_reporter", TDD_TOOL_CATALOG),
|
|
3239
|
-
inputSchema: {
|
|
3310
|
+
inputSchema: z.object({
|
|
3240
3311
|
reportId: z.string().describe("Report id to reply to"),
|
|
3241
3312
|
message: z.string().min(1).max(1e4).describe("Message text to send to the reporter"),
|
|
3242
3313
|
authorName: z.string().optional().describe('Display name for the admin sender (default: "Mushi Admin")')
|
|
3243
|
-
}
|
|
3314
|
+
})
|
|
3244
3315
|
},
|
|
3245
3316
|
async ({ reportId, message, authorName }) => {
|
|
3246
3317
|
const data = await apiCall(`/v1/sync/reports/${reportId}/reply`, {
|
|
@@ -3256,10 +3327,10 @@ Be specific. No generic advice.`
|
|
|
3256
3327
|
title: titleOf("list_qa_story_runs", TDD_TOOL_CATALOG),
|
|
3257
3328
|
description: descOf("list_qa_story_runs", TDD_TOOL_CATALOG),
|
|
3258
3329
|
annotations: annotationsFor("list_qa_story_runs", TDD_TOOL_CATALOG),
|
|
3259
|
-
inputSchema: {
|
|
3330
|
+
inputSchema: z.object({
|
|
3260
3331
|
storyId: z.string().describe("QA story id (uuid)"),
|
|
3261
3332
|
limit: z.number().int().min(1).max(50).optional().default(10).describe("Max runs to return (default 10)")
|
|
3262
|
-
}
|
|
3333
|
+
})
|
|
3263
3334
|
},
|
|
3264
3335
|
async ({ storyId, limit }) => {
|
|
3265
3336
|
const data = await apiCall(
|
|
@@ -3274,10 +3345,10 @@ Be specific. No generic advice.`
|
|
|
3274
3345
|
title: titleOf("get_qa_story_run", TDD_TOOL_CATALOG),
|
|
3275
3346
|
description: descOf("get_qa_story_run", TDD_TOOL_CATALOG),
|
|
3276
3347
|
annotations: annotationsFor("get_qa_story_run", TDD_TOOL_CATALOG),
|
|
3277
|
-
inputSchema: {
|
|
3348
|
+
inputSchema: z.object({
|
|
3278
3349
|
storyId: z.string().describe("QA story id (uuid)"),
|
|
3279
3350
|
runId: z.string().describe("Run id (uuid) to fetch detail for")
|
|
3280
|
-
}
|
|
3351
|
+
})
|
|
3281
3352
|
},
|
|
3282
3353
|
async ({ storyId, runId }) => {
|
|
3283
3354
|
const data = await apiCall(
|
|
@@ -3300,9 +3371,9 @@ Be specific. No generic advice.`
|
|
|
3300
3371
|
title: titleOf("test_notification_channel", TDD_TOOL_CATALOG),
|
|
3301
3372
|
description: descOf("test_notification_channel", TDD_TOOL_CATALOG),
|
|
3302
3373
|
annotations: annotationsFor("test_notification_channel", TDD_TOOL_CATALOG),
|
|
3303
|
-
inputSchema: {
|
|
3374
|
+
inputSchema: z.object({
|
|
3304
3375
|
kind: z.enum(["slack", "discord"]).describe("Notification channel kind to test")
|
|
3305
|
-
}
|
|
3376
|
+
})
|
|
3306
3377
|
},
|
|
3307
3378
|
async ({ kind }) => {
|
|
3308
3379
|
const data = await apiCall(
|
|
@@ -3318,9 +3389,9 @@ Be specific. No generic advice.`
|
|
|
3318
3389
|
title: titleOf("run_fullstack_audit"),
|
|
3319
3390
|
description: descOf("run_fullstack_audit"),
|
|
3320
3391
|
annotations: annotationsFor("run_fullstack_audit"),
|
|
3321
|
-
inputSchema: {
|
|
3392
|
+
inputSchema: z.object({
|
|
3322
3393
|
project_id: z.string().optional().describe("Project ID to audit. Defaults to the configured project.")
|
|
3323
|
-
}
|
|
3394
|
+
})
|
|
3324
3395
|
},
|
|
3325
3396
|
async ({ project_id }) => {
|
|
3326
3397
|
const pid = project_id ?? config.projectId;
|
|
@@ -3338,10 +3409,10 @@ Be specific. No generic advice.`
|
|
|
3338
3409
|
title: titleOf("get_backend_health"),
|
|
3339
3410
|
description: descOf("get_backend_health"),
|
|
3340
3411
|
annotations: annotationsFor("get_backend_health"),
|
|
3341
|
-
inputSchema: {
|
|
3412
|
+
inputSchema: z.object({
|
|
3342
3413
|
project_id: z.string().optional().describe("Project ID. Defaults to the configured project."),
|
|
3343
3414
|
include_logs: z.boolean().optional().describe("Whether to include recent backend error logs (default: true).")
|
|
3344
|
-
}
|
|
3415
|
+
})
|
|
3345
3416
|
},
|
|
3346
3417
|
async ({ project_id, include_logs = true }) => {
|
|
3347
3418
|
const pid = project_id ?? config.projectId;
|
|
@@ -3365,9 +3436,9 @@ Be specific. No generic advice.`
|
|
|
3365
3436
|
title: titleOf("get_usage"),
|
|
3366
3437
|
description: descOf("get_usage"),
|
|
3367
3438
|
annotations: annotationsFor("get_usage"),
|
|
3368
|
-
inputSchema: {
|
|
3439
|
+
inputSchema: z.object({
|
|
3369
3440
|
project_id: z.string().optional().describe("Project ID. Defaults to the configured project.")
|
|
3370
|
-
}
|
|
3441
|
+
})
|
|
3371
3442
|
},
|
|
3372
3443
|
async ({ project_id }) => {
|
|
3373
3444
|
const pid = project_id ?? config.projectId;
|
|
@@ -3382,12 +3453,12 @@ Be specific. No generic advice.`
|
|
|
3382
3453
|
title: titleOf("list_skills"),
|
|
3383
3454
|
description: descOf("list_skills"),
|
|
3384
3455
|
annotations: annotationsFor("list_skills"),
|
|
3385
|
-
inputSchema: {
|
|
3456
|
+
inputSchema: z.object({
|
|
3386
3457
|
category: z.string().optional().describe("Filter by category: workflow, debug, test, audit, enhance, \u2026"),
|
|
3387
3458
|
search: z.string().optional().describe("Free-text search across slug, title, description"),
|
|
3388
3459
|
page: z.number().optional().describe("Page number (default 1)"),
|
|
3389
3460
|
limit: z.number().optional().describe("Max results per page (default 200, max 200)")
|
|
3390
|
-
}
|
|
3461
|
+
})
|
|
3391
3462
|
},
|
|
3392
3463
|
async (args) => {
|
|
3393
3464
|
const qs = new URLSearchParams();
|
|
@@ -3406,9 +3477,9 @@ Be specific. No generic advice.`
|
|
|
3406
3477
|
title: titleOf("get_skill"),
|
|
3407
3478
|
description: descOf("get_skill"),
|
|
3408
3479
|
annotations: annotationsFor("get_skill"),
|
|
3409
|
-
inputSchema: {
|
|
3480
|
+
inputSchema: z.object({
|
|
3410
3481
|
slug: z.string().describe('Skill slug, e.g. "workflow-fix-and-ship"')
|
|
3411
|
-
}
|
|
3482
|
+
})
|
|
3412
3483
|
},
|
|
3413
3484
|
async (args) => {
|
|
3414
3485
|
const data = await apiCall(`/v1/admin/skills/${args.slug}`);
|
|
@@ -3421,14 +3492,14 @@ Be specific. No generic advice.`
|
|
|
3421
3492
|
title: titleOf("start_skill_pipeline"),
|
|
3422
3493
|
description: descOf("start_skill_pipeline"),
|
|
3423
3494
|
annotations: annotationsFor("start_skill_pipeline"),
|
|
3424
|
-
inputSchema: {
|
|
3495
|
+
inputSchema: z.object({
|
|
3425
3496
|
root_skill_slug: z.string().describe('Root skill slug to run, e.g. "workflow-fix-and-ship"'),
|
|
3426
3497
|
report_id: z.string().optional().describe("Report UUID to attach the pipeline to"),
|
|
3427
3498
|
mode: z.enum(["handoff", "cloud"]).optional().describe(
|
|
3428
3499
|
"handoff (default): get context packet for local agent. cloud: auto-dispatch via Cursor Cloud."
|
|
3429
3500
|
),
|
|
3430
3501
|
project_id: z.string().optional().describe("Project UUID. Falls back to the configured project.")
|
|
3431
|
-
}
|
|
3502
|
+
})
|
|
3432
3503
|
},
|
|
3433
3504
|
async (args) => {
|
|
3434
3505
|
const resolvedProjectId = args.project_id ?? projectId;
|
|
@@ -3446,9 +3517,9 @@ Be specific. No generic advice.`
|
|
|
3446
3517
|
title: titleOf("get_pipeline_run"),
|
|
3447
3518
|
description: descOf("get_pipeline_run"),
|
|
3448
3519
|
annotations: annotationsFor("get_pipeline_run"),
|
|
3449
|
-
inputSchema: {
|
|
3520
|
+
inputSchema: z.object({
|
|
3450
3521
|
run_id: z.string().describe("Pipeline run UUID")
|
|
3451
|
-
}
|
|
3522
|
+
})
|
|
3452
3523
|
},
|
|
3453
3524
|
async (args) => {
|
|
3454
3525
|
const data = await apiCall(`/v1/admin/skills/pipelines/${args.run_id}`);
|
|
@@ -3461,14 +3532,14 @@ Be specific. No generic advice.`
|
|
|
3461
3532
|
title: titleOf("checkin_pipeline_step"),
|
|
3462
3533
|
description: descOf("checkin_pipeline_step"),
|
|
3463
3534
|
annotations: annotationsFor("checkin_pipeline_step"),
|
|
3464
|
-
inputSchema: {
|
|
3535
|
+
inputSchema: z.object({
|
|
3465
3536
|
run_id: z.string().describe("Pipeline run UUID"),
|
|
3466
3537
|
step_index: z.number().describe("Step index (0-based)"),
|
|
3467
3538
|
status: z.enum(["running", "passed", "failed", "skipped"]).describe("Step status"),
|
|
3468
3539
|
notes: z.string().optional().describe("Optional notes or output summary"),
|
|
3469
3540
|
pr_url: z.string().optional().describe("PR URL opened during this step"),
|
|
3470
3541
|
agent_ref: z.string().optional().describe("Cursor agentId or external agent reference")
|
|
3471
|
-
}
|
|
3542
|
+
})
|
|
3472
3543
|
},
|
|
3473
3544
|
async (args) => {
|
|
3474
3545
|
const { run_id, step_index, ...body } = args;
|
|
@@ -3485,13 +3556,13 @@ Be specific. No generic advice.`
|
|
|
3485
3556
|
title: titleOf("ask_codebase", CODEBASE_TOOL_CATALOG),
|
|
3486
3557
|
description: descOf("ask_codebase", CODEBASE_TOOL_CATALOG),
|
|
3487
3558
|
annotations: annotationsFor("ask_codebase", CODEBASE_TOOL_CATALOG),
|
|
3488
|
-
inputSchema: {
|
|
3559
|
+
inputSchema: z.object({
|
|
3489
3560
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
3490
3561
|
question: z.string().describe("Plain-English question about the repo"),
|
|
3491
3562
|
thread_id: z.string().optional().describe("Optional thread UUID to continue a conversation"),
|
|
3492
3563
|
file_path: z.string().optional().describe("Optional file path focus"),
|
|
3493
3564
|
symbol_name: z.string().optional().describe("Optional symbol name focus")
|
|
3494
|
-
}
|
|
3565
|
+
})
|
|
3495
3566
|
},
|
|
3496
3567
|
async (args) => {
|
|
3497
3568
|
const pid = args.project_id ?? projectId;
|
|
@@ -3519,12 +3590,12 @@ Be specific. No generic advice.`
|
|
|
3519
3590
|
title: titleOf("get_file_summary", CODEBASE_TOOL_CATALOG),
|
|
3520
3591
|
description: descOf("get_file_summary", CODEBASE_TOOL_CATALOG),
|
|
3521
3592
|
annotations: annotationsFor("get_file_summary", CODEBASE_TOOL_CATALOG),
|
|
3522
|
-
inputSchema: {
|
|
3593
|
+
inputSchema: z.object({
|
|
3523
3594
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
3524
3595
|
file_path: z.string().describe("Indexed file path"),
|
|
3525
3596
|
symbol_name: z.string().optional().describe("Optional symbol name within the file"),
|
|
3526
3597
|
force: z.boolean().optional().describe("Bypass cache and regenerate")
|
|
3527
|
-
}
|
|
3598
|
+
})
|
|
3528
3599
|
},
|
|
3529
3600
|
async (args) => {
|
|
3530
3601
|
const pid = args.project_id ?? projectId;
|
|
@@ -3542,10 +3613,10 @@ Be specific. No generic advice.`
|
|
|
3542
3613
|
title: titleOf("get_codebase_tour", CODEBASE_TOOL_CATALOG),
|
|
3543
3614
|
description: descOf("get_codebase_tour", CODEBASE_TOOL_CATALOG),
|
|
3544
3615
|
annotations: annotationsFor("get_codebase_tour", CODEBASE_TOOL_CATALOG),
|
|
3545
|
-
inputSchema: {
|
|
3616
|
+
inputSchema: z.object({
|
|
3546
3617
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
3547
3618
|
force: z.boolean().optional().describe("Bypass cache and regenerate")
|
|
3548
|
-
}
|
|
3619
|
+
})
|
|
3549
3620
|
},
|
|
3550
3621
|
async (args) => {
|
|
3551
3622
|
const pid = args.project_id ?? projectId;
|
|
@@ -3561,17 +3632,17 @@ Be specific. No generic advice.`
|
|
|
3561
3632
|
title: titleOf("search_codebase", CODEBASE_TOOL_CATALOG),
|
|
3562
3633
|
description: descOf("search_codebase", CODEBASE_TOOL_CATALOG),
|
|
3563
3634
|
annotations: annotationsFor("search_codebase", CODEBASE_TOOL_CATALOG),
|
|
3564
|
-
inputSchema: {
|
|
3635
|
+
inputSchema: z.object({
|
|
3565
3636
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
3566
3637
|
query: z.string().describe("Plain-English search query against indexed source files"),
|
|
3567
3638
|
k: z.number().int().min(1).max(20).optional().describe("Max hits to return (default 8, max 20)"),
|
|
3568
3639
|
scope_prefix: z.string().optional().describe("Optional repo subdirectory prefix to limit search scope")
|
|
3569
|
-
},
|
|
3570
|
-
outputSchema: {
|
|
3640
|
+
}),
|
|
3641
|
+
outputSchema: z.object({
|
|
3571
3642
|
results: z.array(z.unknown()).describe("Ranked file/symbol hits with paths, line ranges, and similarity"),
|
|
3572
3643
|
query: z.string().describe("Normalized query string that was searched"),
|
|
3573
3644
|
mode: z.string().optional().describe("semantic (embeddings) or name (path/symbol match)")
|
|
3574
|
-
}
|
|
3645
|
+
})
|
|
3575
3646
|
},
|
|
3576
3647
|
async (args) => {
|
|
3577
3648
|
const pid = args.project_id ?? projectId;
|
|
@@ -3596,11 +3667,11 @@ Be specific. No generic advice.`
|
|
|
3596
3667
|
title: titleOf("get_codebase_domains", CODEBASE_TOOL_CATALOG),
|
|
3597
3668
|
description: descOf("get_codebase_domains", CODEBASE_TOOL_CATALOG),
|
|
3598
3669
|
annotations: annotationsFor("get_codebase_domains", CODEBASE_TOOL_CATALOG),
|
|
3599
|
-
inputSchema: {
|
|
3670
|
+
inputSchema: z.object({
|
|
3600
3671
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
3601
3672
|
force: z.boolean().optional().describe("Bypass cache and regenerate"),
|
|
3602
3673
|
scope_prefix: z.string().optional().describe("Optional subdirectory scope prefix")
|
|
3603
|
-
}
|
|
3674
|
+
})
|
|
3604
3675
|
},
|
|
3605
3676
|
async (args) => {
|
|
3606
3677
|
const pid = args.project_id ?? projectId;
|
|
@@ -3619,20 +3690,20 @@ Be specific. No generic advice.`
|
|
|
3619
3690
|
title: titleOf("analyze_codebase_impact", CODEBASE_TOOL_CATALOG),
|
|
3620
3691
|
description: descOf("analyze_codebase_impact", CODEBASE_TOOL_CATALOG),
|
|
3621
3692
|
annotations: annotationsFor("analyze_codebase_impact", CODEBASE_TOOL_CATALOG),
|
|
3622
|
-
inputSchema: {
|
|
3693
|
+
inputSchema: z.object({
|
|
3623
3694
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)"),
|
|
3624
3695
|
paths: z.array(z.string()).optional().describe("Changed repo-relative file paths to analyze"),
|
|
3625
3696
|
source: z.enum(["last_push", "compare", "fix"]).optional().describe("Auto-resolve changed paths instead of manual paths"),
|
|
3626
3697
|
compare: z.string().optional().describe("GitHub compare range base...head when source=compare"),
|
|
3627
3698
|
fix_id: z.string().optional().describe("Fix attempt UUID \u2014 uses that PR's changed files when source=fix")
|
|
3628
|
-
},
|
|
3629
|
-
outputSchema: {
|
|
3699
|
+
}),
|
|
3700
|
+
outputSchema: z.object({
|
|
3630
3701
|
changed_paths: z.array(z.string()).describe("Resolved set of changed paths analyzed"),
|
|
3631
3702
|
source: z.string().describe("How changed_paths were resolved (manual, last_push, compare, fix, \u2026)"),
|
|
3632
3703
|
affected_file_paths: z.array(z.string()).describe("Indexed files that import or depend on changed paths"),
|
|
3633
3704
|
affected_node_ids: z.array(z.string()).describe("Codebase graph node ids impacted by the change"),
|
|
3634
3705
|
meta: z.unknown().nullable().optional().describe("Extra resolution metadata when auto-sourced")
|
|
3635
|
-
}
|
|
3706
|
+
})
|
|
3636
3707
|
},
|
|
3637
3708
|
async (args) => {
|
|
3638
3709
|
const pid = args.project_id ?? projectId;
|
|
@@ -3659,9 +3730,9 @@ Be specific. No generic advice.`
|
|
|
3659
3730
|
title: titleOf("analyze_wiki_knowledge", CODEBASE_TOOL_CATALOG),
|
|
3660
3731
|
description: descOf("analyze_wiki_knowledge", CODEBASE_TOOL_CATALOG),
|
|
3661
3732
|
annotations: annotationsFor("analyze_wiki_knowledge", CODEBASE_TOOL_CATALOG),
|
|
3662
|
-
inputSchema: {
|
|
3733
|
+
inputSchema: z.object({
|
|
3663
3734
|
project_id: z.string().optional().describe("Project UUID (defaults to configured project)")
|
|
3664
|
-
}
|
|
3735
|
+
})
|
|
3665
3736
|
},
|
|
3666
3737
|
async (args) => {
|
|
3667
3738
|
const pid = args.project_id ?? projectId;
|
|
@@ -3675,11 +3746,11 @@ Be specific. No generic advice.`
|
|
|
3675
3746
|
{
|
|
3676
3747
|
title: titleOf("use_mushi"),
|
|
3677
3748
|
description: descOf("use_mushi"),
|
|
3678
|
-
inputSchema: {
|
|
3749
|
+
inputSchema: z.object({
|
|
3679
3750
|
intent: z.string().optional().describe(
|
|
3680
3751
|
'What you are trying to accomplish with Mushi, e.g. "fix the top bug", "check project health", "run QA tests", "set up Mushi". Leave blank for a general orientation.'
|
|
3681
3752
|
)
|
|
3682
|
-
},
|
|
3753
|
+
}),
|
|
3683
3754
|
annotations: annotationsFor("use_mushi")
|
|
3684
3755
|
},
|
|
3685
3756
|
async (args) => {
|
|
@@ -3895,23 +3966,31 @@ async function main() {
|
|
|
3895
3966
|
hasProjectId: !!PROJECT_ID,
|
|
3896
3967
|
scopes: SCOPES.join(",")
|
|
3897
3968
|
});
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3969
|
+
let server;
|
|
3970
|
+
const handle = serveStdio(
|
|
3971
|
+
(ctx) => {
|
|
3972
|
+
server = createMushiServer({
|
|
3973
|
+
version: VERSION,
|
|
3974
|
+
apiEndpoint: API_ENDPOINT,
|
|
3975
|
+
apiKey: API_KEY,
|
|
3976
|
+
projectId: PROJECT_ID || void 0,
|
|
3977
|
+
scopes: SCOPES,
|
|
3978
|
+
features: FEATURES
|
|
3979
|
+
});
|
|
3980
|
+
log.debug("[mushi-mcp] server instance created", { era: ctx.era });
|
|
3981
|
+
return server;
|
|
3982
|
+
},
|
|
3983
|
+
{
|
|
3984
|
+
onerror: (err) => log.error("stdio transport error", { err: String(err) })
|
|
3985
|
+
}
|
|
3986
|
+
);
|
|
3908
3987
|
let shuttingDown = false;
|
|
3909
3988
|
let pollTimer;
|
|
3910
3989
|
const shutdown = (exitCode) => {
|
|
3911
3990
|
if (shuttingDown) return;
|
|
3912
3991
|
shuttingDown = true;
|
|
3913
3992
|
if (pollTimer) clearInterval(pollTimer);
|
|
3914
|
-
void
|
|
3993
|
+
void handle.close().finally(() => process.exit(exitCode));
|
|
3915
3994
|
};
|
|
3916
3995
|
setActiveShutdown(shutdown);
|
|
3917
3996
|
process.stdin.on("end", () => shutdown(0));
|
|
@@ -3943,7 +4022,7 @@ async function main() {
|
|
|
3943
4022
|
const data = await res.json();
|
|
3944
4023
|
const updatedAt = data?.data?.updatedAt ?? null;
|
|
3945
4024
|
if (updatedAt && updatedAt !== lastInventoryAt) {
|
|
3946
|
-
if (lastInventoryAt !== null) {
|
|
4025
|
+
if (lastInventoryAt !== null && server) {
|
|
3947
4026
|
await server.server.sendResourceUpdated({ uri: "inventory://current" });
|
|
3948
4027
|
log.info("inventory://current updated \u2014 notified subscribers", { updatedAt });
|
|
3949
4028
|
}
|