dominds 1.19.2 → 1.19.3

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.
Files changed (186) hide show
  1. package/dist/cli/team-definition-audit.d.ts +2 -1
  2. package/dist/cli/team-definition-audit.js +20 -8
  3. package/dist/cli/validate-team-def.js +3 -3
  4. package/dist/docs/mcp-support.md +11 -0
  5. package/dist/docs/mcp-support.zh.md +7 -0
  6. package/dist/docs/team_mgmt-toolset.md +5 -2
  7. package/dist/docs/team_mgmt-toolset.zh.md +4 -2
  8. package/dist/docs/tool-availability-protocol.md +4 -2
  9. package/dist/mcp/config.d.ts +1 -0
  10. package/dist/mcp/config.js +16 -0
  11. package/dist/mcp/supervisor.d.ts +7 -1
  12. package/dist/mcp/supervisor.js +298 -16
  13. package/dist/minds/load.js +5 -0
  14. package/dist/minds/system-prompt.d.ts +1 -0
  15. package/dist/minds/system-prompt.js +14 -6
  16. package/dist/tools/builtins.js +2 -0
  17. package/dist/tools/env.js +10 -58
  18. package/dist/tools/manual/render.js +4 -0
  19. package/dist/tools/mcp.d.ts +1 -0
  20. package/dist/tools/mcp.js +55 -5
  21. package/dist/tools/prompts/mcp_admin/en/errors.md +0 -14
  22. package/dist/tools/prompts/mcp_admin/en/index.md +5 -3
  23. package/dist/tools/prompts/mcp_admin/en/principles.md +11 -5
  24. package/dist/tools/prompts/mcp_admin/en/scenarios.md +19 -3
  25. package/dist/tools/prompts/mcp_admin/en/tools.md +85 -21
  26. package/dist/tools/prompts/mcp_admin/zh/errors.md +0 -14
  27. package/dist/tools/prompts/mcp_admin/zh/index.md +5 -3
  28. package/dist/tools/prompts/mcp_admin/zh/principles.md +11 -5
  29. package/dist/tools/prompts/mcp_admin/zh/scenarios.md +19 -3
  30. package/dist/tools/prompts/mcp_admin/zh/tools.md +85 -21
  31. package/dist/tools/prompts/os/en/errors.md +0 -28
  32. package/dist/tools/prompts/os/en/scenarios.md +1 -1
  33. package/dist/tools/prompts/os/en/tools.md +8 -17
  34. package/dist/tools/prompts/os/zh/errors.md +0 -28
  35. package/dist/tools/prompts/os/zh/scenarios.md +1 -1
  36. package/dist/tools/prompts/os/zh/tools.md +8 -17
  37. package/dist/tools/registry.d.ts +5 -0
  38. package/dist/tools/team_mgmt-mcp-manual.d.ts +2 -2
  39. package/dist/tools/team_mgmt-mcp-manual.js +57 -16
  40. package/dist/tools/team_mgmt.js +4 -4
  41. package/package.json +3 -3
  42. package/webapp/dist/assets/{_basePickBy-B7M9Q0Fa.js → _basePickBy-Dnh413xT.js} +3 -3
  43. package/webapp/dist/assets/_basePickBy-Dnh413xT.js.map +1 -0
  44. package/webapp/dist/assets/{_baseUniq-DAeYoL6j.js → _baseUniq-DWzYqpN_.js} +2 -2
  45. package/webapp/dist/assets/_baseUniq-DWzYqpN_.js.map +1 -0
  46. package/webapp/dist/assets/{arc-Bh4nDbNR.js → arc-vfBkNCOx.js} +2 -2
  47. package/webapp/dist/assets/arc-vfBkNCOx.js.map +1 -0
  48. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-CxqmdsIm.js → architectureDiagram-VXUJARFQ-DiUEBXOa.js} +8 -26
  49. package/webapp/dist/assets/architectureDiagram-VXUJARFQ-DiUEBXOa.js.map +1 -0
  50. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-CxIWLtpt.js → blockDiagram-VD42YOAC-BqK1KM2m.js} +170 -187
  51. package/webapp/dist/assets/blockDiagram-VD42YOAC-BqK1KM2m.js.map +1 -0
  52. package/webapp/dist/assets/{c4Diagram-IC4MRINW-1qErOIgG.js → c4Diagram-YG6GDRKO-ClHNu1Uo.js} +4 -4
  53. package/webapp/dist/assets/c4Diagram-YG6GDRKO-ClHNu1Uo.js.map +1 -0
  54. package/webapp/dist/assets/{channel-DkgZHNUe.js → channel-BbWLVc8W.js} +2 -2
  55. package/webapp/dist/assets/channel-BbWLVc8W.js.map +1 -0
  56. package/webapp/dist/assets/{chunk-4BX2VUAB-BmdMbU9v.js → chunk-4BX2VUAB-CItdSmZH.js} +2 -2
  57. package/webapp/dist/assets/chunk-4BX2VUAB-CItdSmZH.js.map +1 -0
  58. package/webapp/dist/assets/{chunk-55IACEB6-D6LDTDBy.js → chunk-55IACEB6-DSCX9WCf.js} +2 -2
  59. package/webapp/dist/assets/chunk-55IACEB6-DSCX9WCf.js.map +1 -0
  60. package/webapp/dist/assets/{chunk-WL4C6EOR-B-Pk44be.js → chunk-B4BG7PRW-5CRXFeD9.js} +121 -171
  61. package/webapp/dist/assets/chunk-B4BG7PRW-5CRXFeD9.js.map +1 -0
  62. package/webapp/dist/assets/{chunk-NQ4KR5QH-wlvxalE3.js → chunk-DI55MBZ5-CRMf6XZu.js} +7 -9
  63. package/webapp/dist/assets/chunk-DI55MBZ5-CRMf6XZu.js.map +1 -0
  64. package/webapp/dist/assets/{chunk-FMBD7UC4-C-BdCe4C.js → chunk-FMBD7UC4-BJ1vT2se.js} +2 -2
  65. package/webapp/dist/assets/chunk-FMBD7UC4-BJ1vT2se.js.map +1 -0
  66. package/webapp/dist/assets/{chunk-KX2RTZJC-CA7sDJO5.js → chunk-QN33PNHL-CGyezTSD.js} +2 -2
  67. package/webapp/dist/assets/chunk-QN33PNHL-CGyezTSD.js.map +1 -0
  68. package/webapp/dist/assets/{chunk-QZHKN3VN-Bo1VMcph.js → chunk-QZHKN3VN-9xs15j8C.js} +2 -2
  69. package/webapp/dist/assets/chunk-QZHKN3VN-9xs15j8C.js.map +1 -0
  70. package/webapp/dist/assets/{chunk-JSJVCQXG-WA_BLIm9.js → chunk-TZMSLE5B-D2g6Tj7Z.js} +6 -14
  71. package/webapp/dist/assets/chunk-TZMSLE5B-D2g6Tj7Z.js.map +1 -0
  72. package/webapp/dist/assets/{classDiagram-VBA2DB6C-BqKuyb49.js → classDiagram-2ON5EDUG-BQFGGJNm.js} +6 -7
  73. package/webapp/dist/assets/classDiagram-2ON5EDUG-BQFGGJNm.js.map +1 -0
  74. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-BqKuyb49.js → classDiagram-v2-WZHVMYZB-BQFGGJNm.js} +6 -7
  75. package/webapp/dist/assets/classDiagram-v2-WZHVMYZB-BQFGGJNm.js.map +1 -0
  76. package/webapp/dist/assets/{clone-BX5z8WVZ.js → clone-DOfPd4cz.js} +2 -2
  77. package/webapp/dist/assets/clone-DOfPd4cz.js.map +1 -0
  78. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-B-s11SgN.js → cose-bilkent-S5V4N54A-BYN-vqm8.js} +2 -2
  79. package/webapp/dist/assets/cose-bilkent-S5V4N54A-BYN-vqm8.js.map +1 -0
  80. package/webapp/dist/assets/cytoscape.esm-Bm8DJGmZ.js.map +1 -1
  81. package/webapp/dist/assets/{dagre-KLK3FWXG-DmQFV2qK.js → dagre-6UL2VRFP-ClEaFABE.js} +7 -7
  82. package/webapp/dist/assets/dagre-6UL2VRFP-ClEaFABE.js.map +1 -0
  83. package/webapp/dist/assets/defaultLocale-B2RvLBDe.js.map +1 -1
  84. package/webapp/dist/assets/{diagram-E7M64L7V-QRaBfST8.js → diagram-PSM6KHXK-CM4hLE_0.js} +10 -10
  85. package/webapp/dist/assets/diagram-PSM6KHXK-CM4hLE_0.js.map +1 -0
  86. package/webapp/dist/assets/{diagram-IFDJBPK2-lrWn1Obo.js → diagram-QEK2KX5R-BZjGFX-2.js} +8 -9
  87. package/webapp/dist/assets/diagram-QEK2KX5R-BZjGFX-2.js.map +1 -0
  88. package/webapp/dist/assets/{diagram-P4PSJMXO-sTU7Hh-Y.js → diagram-S2PKOQOG-Bvw01OOG.js} +8 -8
  89. package/webapp/dist/assets/diagram-S2PKOQOG-Bvw01OOG.js.map +1 -0
  90. package/webapp/dist/assets/{erDiagram-INFDFZHY-Cx6jc9Wq.js → erDiagram-Q2GNP2WA-ctHu5zQL.js} +75 -96
  91. package/webapp/dist/assets/erDiagram-Q2GNP2WA-ctHu5zQL.js.map +1 -0
  92. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-DfGI49Dz.js → flowDiagram-NV44I4VS-m7ofIhri.js} +81 -98
  93. package/webapp/dist/assets/flowDiagram-NV44I4VS-m7ofIhri.js.map +1 -0
  94. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-nrcHWWaM.js → ganttDiagram-JELNMOA3-D9wS5Veb.js} +3 -28
  95. package/webapp/dist/assets/ganttDiagram-JELNMOA3-D9wS5Veb.js.map +1 -0
  96. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-D8ivAqd6.js → gitGraphDiagram-V2S2FVAM-B86qqJx7.js} +46 -38
  97. package/webapp/dist/assets/gitGraphDiagram-V2S2FVAM-B86qqJx7.js.map +1 -0
  98. package/webapp/dist/assets/graph-u844GGQC.js +425 -0
  99. package/webapp/dist/assets/graph-u844GGQC.js.map +1 -0
  100. package/webapp/dist/assets/{index-DZFkLLVz.css → index-BGdI3lWA.css} +1 -1
  101. package/webapp/dist/assets/{index--fy89xGh.js → index-tinPEZoH.js} +1059 -1034
  102. package/webapp/dist/assets/{index--fy89xGh.js.map → index-tinPEZoH.js.map} +1 -1
  103. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-PIoZHr7s.js → infoDiagram-HS3SLOUP-DwRPUctP.js} +7 -7
  104. package/webapp/dist/assets/infoDiagram-HS3SLOUP-DwRPUctP.js.map +1 -0
  105. package/webapp/dist/assets/init-ZxktEp_H.js.map +1 -1
  106. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-C2qidjQ5.js → journeyDiagram-XKPGCS4Q-B91ZO-ec.js} +5 -5
  107. package/webapp/dist/assets/journeyDiagram-XKPGCS4Q-B91ZO-ec.js.map +1 -0
  108. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-Du0TC8WS.js → kanban-definition-3W4ZIXB7-CoogrZ07.js} +3 -5
  109. package/webapp/dist/assets/kanban-definition-3W4ZIXB7-CoogrZ07.js.map +1 -0
  110. package/webapp/dist/assets/{layout-VmEo1OEB.js → layout-BrzQmqFJ.js} +5 -5
  111. package/webapp/dist/assets/layout-BrzQmqFJ.js.map +1 -0
  112. package/webapp/dist/assets/{linear-B662YHAc.js → linear-C6H7K9Zy.js} +2 -2
  113. package/webapp/dist/assets/linear-C6H7K9Zy.js.map +1 -0
  114. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-D7arZj95.js → mindmap-definition-VGOIOE7T-UDHZQkNZ.js} +5 -7
  115. package/webapp/dist/assets/mindmap-definition-VGOIOE7T-UDHZQkNZ.js.map +1 -0
  116. package/webapp/dist/assets/ordinal-CxptdPJm.js.map +1 -1
  117. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-DvjPP4PA.js → pieDiagram-ADFJNKIX-M81uyQ1J.js} +8 -8
  118. package/webapp/dist/assets/pieDiagram-ADFJNKIX-M81uyQ1J.js.map +1 -0
  119. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-B_JUGMj_.js → quadrantDiagram-AYHSOK5B-ClzIh9Gb.js} +3 -3
  120. package/webapp/dist/assets/quadrantDiagram-AYHSOK5B-ClzIh9Gb.js.map +1 -0
  121. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-DF0mpvE3.js → requirementDiagram-UZGBJVZJ-DLK3A-pn.js} +6 -16
  122. package/webapp/dist/assets/requirementDiagram-UZGBJVZJ-DLK3A-pn.js.map +1 -0
  123. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-CoXlxv00.js → sankeyDiagram-TZEHDZUN-CYqju8I1.js} +2 -2
  124. package/webapp/dist/assets/sankeyDiagram-TZEHDZUN-CYqju8I1.js.map +1 -0
  125. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-DYqT5Pg7.js → sequenceDiagram-WL72ISMW-2guv6eOd.js} +201 -601
  126. package/webapp/dist/assets/sequenceDiagram-WL72ISMW-2guv6eOd.js.map +1 -0
  127. package/webapp/dist/assets/{stateDiagram-RAJIS63D-D9b1mN8-.js → stateDiagram-FKZM4ZOC-iujqSp0X.js} +9 -9
  128. package/webapp/dist/assets/stateDiagram-FKZM4ZOC-iujqSp0X.js.map +1 -0
  129. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-DNzgudL_.js → stateDiagram-v2-4FDKWEC3-BxzY81ky.js} +5 -5
  130. package/webapp/dist/assets/stateDiagram-v2-4FDKWEC3-BxzY81ky.js.map +1 -0
  131. package/webapp/dist/assets/{timeline-definition-YZTLITO2-CkyKUY7A.js → timeline-definition-IT6M3QCI-DjCFSC8d.js} +3 -3
  132. package/webapp/dist/assets/timeline-definition-IT6M3QCI-DjCFSC8d.js.map +1 -0
  133. package/webapp/dist/assets/{treemap-KZPCXAKY-CZd09kF-.js → treemap-GDKQZRPO-iaBzDWCP.js} +24 -37
  134. package/webapp/dist/assets/treemap-GDKQZRPO-iaBzDWCP.js.map +1 -0
  135. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-BRwRloPc.js → xychartDiagram-PRI3JC2R-R6Jl1c89.js} +4 -4
  136. package/webapp/dist/assets/xychartDiagram-PRI3JC2R-R6Jl1c89.js.map +1 -0
  137. package/webapp/dist/index.html +2 -2
  138. package/webapp/dist/assets/_basePickBy-B7M9Q0Fa.js.map +0 -1
  139. package/webapp/dist/assets/_baseUniq-DAeYoL6j.js.map +0 -1
  140. package/webapp/dist/assets/arc-Bh4nDbNR.js.map +0 -1
  141. package/webapp/dist/assets/architectureDiagram-2XIMDMQ5-CxqmdsIm.js.map +0 -1
  142. package/webapp/dist/assets/blockDiagram-WCTKOSBZ-CxIWLtpt.js.map +0 -1
  143. package/webapp/dist/assets/c4Diagram-IC4MRINW-1qErOIgG.js.map +0 -1
  144. package/webapp/dist/assets/channel-DkgZHNUe.js.map +0 -1
  145. package/webapp/dist/assets/chunk-4BX2VUAB-BmdMbU9v.js.map +0 -1
  146. package/webapp/dist/assets/chunk-55IACEB6-D6LDTDBy.js.map +0 -1
  147. package/webapp/dist/assets/chunk-FMBD7UC4-C-BdCe4C.js.map +0 -1
  148. package/webapp/dist/assets/chunk-JSJVCQXG-WA_BLIm9.js.map +0 -1
  149. package/webapp/dist/assets/chunk-KX2RTZJC-CA7sDJO5.js.map +0 -1
  150. package/webapp/dist/assets/chunk-NQ4KR5QH-wlvxalE3.js.map +0 -1
  151. package/webapp/dist/assets/chunk-QZHKN3VN-Bo1VMcph.js.map +0 -1
  152. package/webapp/dist/assets/chunk-WL4C6EOR-B-Pk44be.js.map +0 -1
  153. package/webapp/dist/assets/classDiagram-VBA2DB6C-BqKuyb49.js.map +0 -1
  154. package/webapp/dist/assets/classDiagram-v2-RAHNMMFH-BqKuyb49.js.map +0 -1
  155. package/webapp/dist/assets/clone-BX5z8WVZ.js.map +0 -1
  156. package/webapp/dist/assets/cose-bilkent-S5V4N54A-B-s11SgN.js.map +0 -1
  157. package/webapp/dist/assets/dagre-KLK3FWXG-DmQFV2qK.js.map +0 -1
  158. package/webapp/dist/assets/diagram-E7M64L7V-QRaBfST8.js.map +0 -1
  159. package/webapp/dist/assets/diagram-IFDJBPK2-lrWn1Obo.js.map +0 -1
  160. package/webapp/dist/assets/diagram-P4PSJMXO-sTU7Hh-Y.js.map +0 -1
  161. package/webapp/dist/assets/erDiagram-INFDFZHY-Cx6jc9Wq.js.map +0 -1
  162. package/webapp/dist/assets/flowDiagram-PKNHOUZH-DfGI49Dz.js.map +0 -1
  163. package/webapp/dist/assets/ganttDiagram-A5KZAMGK-nrcHWWaM.js.map +0 -1
  164. package/webapp/dist/assets/gitGraphDiagram-K3NZZRJ6-D8ivAqd6.js.map +0 -1
  165. package/webapp/dist/assets/graph-R5G-y8tB.js +0 -782
  166. package/webapp/dist/assets/graph-R5G-y8tB.js.map +0 -1
  167. package/webapp/dist/assets/infoDiagram-LFFYTUFH-PIoZHr7s.js.map +0 -1
  168. package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-oCM-LYk1.js +0 -966
  169. package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-oCM-LYk1.js.map +0 -1
  170. package/webapp/dist/assets/journeyDiagram-4ABVD52K-C2qidjQ5.js.map +0 -1
  171. package/webapp/dist/assets/kanban-definition-K7BYSVSG-Du0TC8WS.js.map +0 -1
  172. package/webapp/dist/assets/layout-VmEo1OEB.js.map +0 -1
  173. package/webapp/dist/assets/linear-B662YHAc.js.map +0 -1
  174. package/webapp/dist/assets/mindmap-definition-YRQLILUH-D7arZj95.js.map +0 -1
  175. package/webapp/dist/assets/pieDiagram-SKSYHLDU-DvjPP4PA.js.map +0 -1
  176. package/webapp/dist/assets/quadrantDiagram-337W2JSQ-B_JUGMj_.js.map +0 -1
  177. package/webapp/dist/assets/requirementDiagram-Z7DCOOCP-DF0mpvE3.js.map +0 -1
  178. package/webapp/dist/assets/sankeyDiagram-WA2Y5GQK-CoXlxv00.js.map +0 -1
  179. package/webapp/dist/assets/sequenceDiagram-2WXFIKYE-DYqT5Pg7.js.map +0 -1
  180. package/webapp/dist/assets/stateDiagram-RAJIS63D-D9b1mN8-.js.map +0 -1
  181. package/webapp/dist/assets/stateDiagram-v2-FVOUBMTO-DNzgudL_.js.map +0 -1
  182. package/webapp/dist/assets/timeline-definition-YZTLITO2-CkyKUY7A.js.map +0 -1
  183. package/webapp/dist/assets/treemap-KZPCXAKY-CZd09kF-.js.map +0 -1
  184. package/webapp/dist/assets/vennDiagram-LZ73GAT5-BxVF5Olo.js +0 -2487
  185. package/webapp/dist/assets/vennDiagram-LZ73GAT5-BxVF5Olo.js.map +0 -1
  186. package/webapp/dist/assets/xychartDiagram-JWTSCODW-BRwRloPc.js.map +0 -1
@@ -40,12 +40,14 @@ exports.getMcpDeclaredServerRuntimeStatuses = getMcpDeclaredServerRuntimeStatuse
40
40
  exports.startMcpSupervisor = startMcpSupervisor;
41
41
  exports.stopMcpSupervisor = stopMcpSupervisor;
42
42
  exports.requestMcpServerRestart = requestMcpServerRestart;
43
+ exports.requestMcpServerDisable = requestMcpServerDisable;
43
44
  exports.requestMcpConfigReload = requestMcpConfigReload;
44
45
  exports.buildHttpHeaders = buildHttpHeaders;
45
46
  const time_1 = require("@longrun-ai/kernel/utils/time");
46
47
  const fs = __importStar(require("fs"));
47
48
  const node_crypto_1 = require("node:crypto");
48
49
  const path = __importStar(require("path"));
50
+ const yaml_1 = __importStar(require("yaml"));
49
51
  const log_1 = require("../log");
50
52
  const persistence_1 = require("../persistence");
51
53
  const problems_1 = require("../problems");
@@ -151,6 +153,7 @@ class McpServerDispatch {
151
153
  for (const rt of this.leasesByDialogKey.values()) {
152
154
  rt.requestStop({ forceKillAfterMs: 3000 });
153
155
  }
156
+ this.leasesByDialogKey.clear();
154
157
  for (const [dialogKey, init] of this.leaseInitByDialogKey.entries()) {
155
158
  this.canceledLeaseDialogs.add(dialogKey);
156
159
  void init
@@ -159,6 +162,7 @@ class McpServerDispatch {
159
162
  // ignore
160
163
  });
161
164
  }
165
+ this.leaseInitByDialogKey.clear();
162
166
  }
163
167
  async callToolForDialog(dlg, mcpToolName, args) {
164
168
  const serverId = this.serverId;
@@ -323,6 +327,13 @@ function getMcpDeclaredServerRuntimeStatuses() {
323
327
  errorText: catalogEntry.configErrorText,
324
328
  };
325
329
  }
330
+ if (catalogEntry?.disabled) {
331
+ return {
332
+ serverId,
333
+ transport: catalogEntry.transport,
334
+ status: 'disabled',
335
+ };
336
+ }
326
337
  if (serverStateById.has(serverId)) {
327
338
  return {
328
339
  serverId,
@@ -435,6 +446,27 @@ function requestMcpServerRestart(serverId) {
435
446
  });
436
447
  });
437
448
  }
449
+ function requestMcpServerDisable(serverId) {
450
+ return new Promise((resolve) => {
451
+ reloadChain = reloadChain
452
+ .then(async () => {
453
+ try {
454
+ const res = await disableServerNow(serverId);
455
+ resolve(res);
456
+ }
457
+ catch (err) {
458
+ const errorText = err instanceof Error ? err.message : String(err);
459
+ log.warn(`MCP server disable failed`, err, { serverId });
460
+ resolve({ ok: false, errorText });
461
+ }
462
+ })
463
+ .catch((err) => {
464
+ const errorText = err instanceof Error ? err.message : String(err);
465
+ log.warn(`MCP server disable enqueue failed`, err, { serverId });
466
+ resolve({ ok: false, errorText });
467
+ });
468
+ });
469
+ }
438
470
  function requestMcpConfigReload(reason = 'manual') {
439
471
  const normalizedReason = reason.trim() === '' ? 'manual' : reason.trim();
440
472
  return new Promise((resolve) => {
@@ -554,7 +586,7 @@ async function reloadNow(reason) {
554
586
  const code = isRecord(err) && 'code' in err ? err.code : undefined;
555
587
  if (code === 'ENOENT') {
556
588
  // Deletion is treated as empty config.
557
- await applyWorkspaceConfig({ version: 1, servers: {} }, [], [], [], `missing file (${reason})`);
589
+ await applyWorkspaceConfig({ version: 1, servers: {} }, [], [], [], [], null, `missing file (${reason})`);
558
590
  clearWorkspaceConfigProblem();
559
591
  await reconcileMcpManualProblemsForRuntime([], null);
560
592
  return;
@@ -572,10 +604,19 @@ async function reloadNow(reason) {
572
604
  return;
573
605
  }
574
606
  clearWorkspaceConfigProblem();
575
- await applyWorkspaceConfig(parsed.config, parsed.invalidServers, parsed.serverIdsInYamlOrder, parsed.validServerIdsInYamlOrder, reason);
607
+ await applyWorkspaceConfig(parsed.config, parsed.invalidServers, parsed.serverIdsInYamlOrder, parsed.validServerIdsInYamlOrder, parsed.disabledServerIdsInYamlOrder, rawText, reason);
576
608
  await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, rawText);
577
609
  }
578
610
  async function restartServerNow(serverId) {
611
+ let removedPlaceholder = false;
612
+ const notifyPlaceholderRemovalOnFailure = (trigger) => {
613
+ if (!removedPlaceholder)
614
+ return;
615
+ (0, tool_availability_updates_1.notifyToolAvailabilityRegistryMaybeChanged)({
616
+ reason: 'registry_changed',
617
+ trigger,
618
+ });
619
+ };
579
620
  let rawText;
580
621
  try {
581
622
  rawText = await fs.promises.readFile(MCP_YAML_PATH, 'utf8');
@@ -592,23 +633,51 @@ async function restartServerNow(serverId) {
592
633
  upsertWorkspaceConfigProblem(`Failed to read ${MCP_YAML_PATH}: ${String(err)}`);
593
634
  return { ok: false, errorText: `Failed to read ${MCP_YAML_PATH}: ${String(err)}` };
594
635
  }
595
- const parsed = (0, config_1.parseMcpYaml)(rawText);
636
+ let activeRawText = rawText;
637
+ let parsed = (0, config_1.parseMcpYaml)(activeRawText);
596
638
  if (!parsed.ok) {
597
639
  await reconcileMcpManualProblemsForRuntime([], null);
598
640
  upsertWorkspaceConfigProblem(parsed.errorText);
599
641
  return { ok: false, errorText: parsed.errorText };
600
642
  }
601
643
  clearWorkspaceConfigProblem();
644
+ const disabledServer = parsed.serverIdsInYamlOrder.includes(serverId) &&
645
+ parsed.invalidServers.every((s) => s.serverId !== serverId) &&
646
+ parsed.config.servers[serverId] === undefined;
647
+ if (disabledServer) {
648
+ const enableRes = setServerEnabledInMcpYaml(rawText, serverId, true);
649
+ if (!enableRes.ok) {
650
+ await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, rawText);
651
+ return { ok: false, errorText: enableRes.errorText };
652
+ }
653
+ if (enableRes.changed) {
654
+ await fs.promises.writeFile(MCP_YAML_PATH, enableRes.rawText, 'utf8');
655
+ lastSeenMcpYamlSig = await readMcpYamlSig();
656
+ removedPlaceholder = unregisterMcpToolsetPlaceholder(serverId) || removedPlaceholder;
657
+ }
658
+ activeRawText = enableRes.rawText;
659
+ parsed = (0, config_1.parseMcpYaml)(activeRawText);
660
+ if (!parsed.ok) {
661
+ clearDeclaredServerRuntimeCatalog();
662
+ await reconcileMcpManualProblemsForRuntime([], null);
663
+ upsertWorkspaceConfigProblem(parsed.errorText);
664
+ notifyPlaceholderRemovalOnFailure(`mcp:restart:${serverId}:parse-failed`);
665
+ return { ok: false, errorText: parsed.errorText };
666
+ }
667
+ clearWorkspaceConfigProblem();
668
+ }
602
669
  const invalid = parsed.invalidServers.find((s) => s.serverId === serverId);
603
670
  if (invalid) {
604
- replaceDeclaredServerRuntimeCatalog(parsed.config, parsed.invalidServers, parsed.serverIdsInYamlOrder);
605
- await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, rawText);
671
+ replaceDeclaredServerRuntimeCatalog(parsed.config, parsed.invalidServers, parsed.serverIdsInYamlOrder, parsed.disabledServerIdsInYamlOrder);
672
+ await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, activeRawText);
606
673
  upsertMcpServerConfigInvalidProblem(serverId, invalid.errorText);
674
+ notifyPlaceholderRemovalOnFailure(`mcp:restart:${serverId}:config-invalid`);
607
675
  return { ok: false, errorText: invalid.errorText };
608
676
  }
609
677
  const serverCfg = parsed.config.servers[serverId];
610
678
  if (!serverCfg) {
611
- await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, rawText);
679
+ await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, activeRawText);
680
+ notifyPlaceholderRemovalOnFailure(`mcp:restart:${serverId}:not-configured`);
612
681
  return {
613
682
  ok: false,
614
683
  errorText: `MCP server '${serverId}' is not configured in ${MCP_YAML_PATH}`,
@@ -618,25 +687,28 @@ async function restartServerNow(serverId) {
618
687
  const fingerprint = fingerprintServerConfig(serverCfg);
619
688
  const existing = serverStateById.get(serverId);
620
689
  const runtimeLeaseChanged = existing !== undefined;
621
- replaceDeclaredServerRuntimeCatalog(parsed.config, parsed.invalidServers, parsed.serverIdsInYamlOrder);
690
+ replaceDeclaredServerRuntimeCatalog(parsed.config, parsed.invalidServers, parsed.serverIdsInYamlOrder, parsed.disabledServerIdsInYamlOrder);
691
+ if (!existing) {
692
+ removedPlaceholder = unregisterMcpToolsetPlaceholder(serverId) || removedPlaceholder;
693
+ }
622
694
  const res = await tryBuildServerState(serverCfg, desiredToolsetName, fingerprint);
623
695
  if (!res.ok) {
624
- await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, rawText);
696
+ await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, activeRawText);
625
697
  upsertDeclaredServerRuntimeError(serverId, res.errorText);
626
698
  upsertMcpServerRuntimeUnavailableProblem(serverId, res.errorText, res.detailTextI18n);
699
+ notifyPlaceholderRemovalOnFailure(`mcp:restart:${serverId}:runtime-unavailable`);
627
700
  return { ok: false, errorText: res.errorText };
628
701
  }
629
702
  clearDeclaredServerRuntimeError(serverId);
630
703
  (0, problems_1.removeProblemsByPrefix)(`${problemPrefixForServer(serverId)}server_error`);
631
704
  if (existing) {
632
- unregisterServer(existing);
633
- existing.dispatch.requestStop();
705
+ stopLoadedServer(serverId);
634
706
  }
635
707
  registerServer(res.state);
636
708
  serverStateById.set(serverId, res.state);
637
709
  (0, problems_1.reconcileProblemsByPrefix)(problemPrefixForServer(serverId), res.state.problems);
638
710
  reorderMcpToolsetsInRegistry(parsed.serverIdsInYamlOrder);
639
- await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, rawText);
711
+ await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, activeRawText);
640
712
  (0, tool_availability_updates_1.notifyToolAvailabilityRegistryMaybeChanged)({
641
713
  reason: 'registry_changed',
642
714
  trigger: `mcp:restart:${serverId}`,
@@ -646,6 +718,119 @@ async function restartServerNow(serverId) {
646
718
  }
647
719
  return { ok: true };
648
720
  }
721
+ async function disableServerNow(serverId) {
722
+ const stoppedExisting = stopLoadedServer(serverId);
723
+ let rawText;
724
+ try {
725
+ rawText = await fs.promises.readFile(MCP_YAML_PATH, 'utf8');
726
+ }
727
+ catch (err) {
728
+ const code = isRecord(err) && 'code' in err ? err.code : undefined;
729
+ if (stoppedExisting) {
730
+ (0, tool_availability_updates_1.notifyToolAvailabilityRegistryMaybeChanged)({
731
+ reason: 'registry_changed',
732
+ trigger: `mcp:disable:${serverId}:read-failed`,
733
+ });
734
+ (0, tool_availability_updates_1.notifyToolAvailabilityRuntimeLeaseChanged)(`mcp:disable:${serverId}:read-failed`);
735
+ }
736
+ if (code === 'ENOENT') {
737
+ return { ok: false, errorText: `Cannot disable '${serverId}': ${MCP_YAML_PATH} is missing` };
738
+ }
739
+ return { ok: false, errorText: `Failed to read ${MCP_YAML_PATH}: ${String(err)}` };
740
+ }
741
+ const disableRes = setServerEnabledInMcpYaml(rawText, serverId, false);
742
+ if (!disableRes.ok) {
743
+ if (stoppedExisting) {
744
+ (0, tool_availability_updates_1.notifyToolAvailabilityRegistryMaybeChanged)({
745
+ reason: 'registry_changed',
746
+ trigger: `mcp:disable:${serverId}:disable-failed`,
747
+ });
748
+ (0, tool_availability_updates_1.notifyToolAvailabilityRuntimeLeaseChanged)(`mcp:disable:${serverId}:disable-failed`);
749
+ }
750
+ return { ok: false, errorText: disableRes.errorText };
751
+ }
752
+ if (disableRes.changed) {
753
+ await fs.promises.writeFile(MCP_YAML_PATH, disableRes.rawText, 'utf8');
754
+ lastSeenMcpYamlSig = await readMcpYamlSig();
755
+ }
756
+ const parsed = (0, config_1.parseMcpYaml)(disableRes.rawText);
757
+ if (!parsed.ok) {
758
+ clearDeclaredServerRuntimeCatalog();
759
+ await reconcileMcpManualProblemsForRuntime([], null);
760
+ upsertWorkspaceConfigProblem(parsed.errorText);
761
+ if (stoppedExisting) {
762
+ (0, tool_availability_updates_1.notifyToolAvailabilityRegistryMaybeChanged)({
763
+ reason: 'registry_changed',
764
+ trigger: `mcp:disable:${serverId}:parse-failed`,
765
+ });
766
+ (0, tool_availability_updates_1.notifyToolAvailabilityRuntimeLeaseChanged)(`mcp:disable:${serverId}:parse-failed`);
767
+ }
768
+ return { ok: false, errorText: parsed.errorText };
769
+ }
770
+ clearWorkspaceConfigProblem();
771
+ await applyWorkspaceConfig(parsed.config, parsed.invalidServers, parsed.serverIdsInYamlOrder, parsed.validServerIdsInYamlOrder, parsed.disabledServerIdsInYamlOrder, disableRes.rawText, `mcp_disable:${serverId}`);
772
+ await reconcileMcpManualProblemsForRuntime(parsed.serverIdsInYamlOrder, disableRes.rawText);
773
+ if (stoppedExisting) {
774
+ (0, tool_availability_updates_1.notifyToolAvailabilityRuntimeLeaseChanged)(`mcp:disable:${serverId}`);
775
+ }
776
+ return { ok: true };
777
+ }
778
+ function setServerEnabledInMcpYaml(rawText, serverId, enabled) {
779
+ const doc = yaml_1.default.parseDocument(rawText, { prettyErrors: true });
780
+ if (doc.errors.length > 0) {
781
+ return { ok: false, errorText: doc.errors.map((e) => String(e)).join('\n') };
782
+ }
783
+ const parsed = doc.toJS();
784
+ if (!isRecord(parsed)) {
785
+ return { ok: false, errorText: `Invalid mcp.yaml: expected object at mcp.yaml root` };
786
+ }
787
+ if (parsed.version !== 1) {
788
+ return { ok: false, errorText: `Invalid mcp.yaml: expected version: 1` };
789
+ }
790
+ const servers = parsed.servers;
791
+ const server = isRecord(servers) ? servers[serverId] : undefined;
792
+ if (!isRecord(server)) {
793
+ return {
794
+ ok: false,
795
+ errorText: `MCP server '${serverId}' is not configured in ${MCP_YAML_PATH}`,
796
+ };
797
+ }
798
+ const currentEnabled = server.enabled;
799
+ if (currentEnabled !== undefined && typeof currentEnabled !== 'boolean') {
800
+ return {
801
+ ok: false,
802
+ errorText: `Invalid mcp.yaml: servers.${serverId}.enabled must be a boolean`,
803
+ };
804
+ }
805
+ if (currentEnabled === enabled) {
806
+ return { ok: true, rawText, changed: false };
807
+ }
808
+ const serverNode = doc.getIn(['servers', serverId], true);
809
+ if (!(0, yaml_1.isMap)(serverNode)) {
810
+ return {
811
+ ok: false,
812
+ errorText: `Invalid mcp.yaml: servers.${serverId} must be an object`,
813
+ };
814
+ }
815
+ const existingEnabledPair = serverNode.items.find((pair) => (0, yaml_1.isScalar)(pair.key) && pair.key.value === 'enabled');
816
+ if (existingEnabledPair) {
817
+ existingEnabledPair.value = doc.createNode(enabled);
818
+ }
819
+ else {
820
+ serverNode.items.unshift(doc.createPair('enabled', enabled));
821
+ }
822
+ return { ok: true, rawText: String(doc), changed: true };
823
+ }
824
+ function stopLoadedServer(serverId) {
825
+ const existing = serverStateById.get(serverId);
826
+ if (!existing)
827
+ return false;
828
+ unregisterServer(existing);
829
+ existing.dispatch.requestStop();
830
+ serverStateById.delete(serverId);
831
+ (0, problems_1.reconcileProblemsByPrefix)(problemPrefixForServer(serverId), []);
832
+ return true;
833
+ }
649
834
  async function reconcileMcpManualProblemsForRuntime(serverIdsInYamlOrder, rawText) {
650
835
  const manualInfo = rawText === null ? (0, manual_problems_1.emptyMcpToolsetManualByServer)() : (0, manual_problems_1.parseMcpManualByServer)(rawText);
651
836
  await (0, manual_problems_1.reconcileMcpToolsetManualProblems)({
@@ -711,13 +896,15 @@ function upsertMcpToolCallProblem(args) {
711
896
  const hintLines = workLanguage === 'zh'
712
897
  ? [
713
898
  '建议排查:',
714
- `- 先释放租约:mcp_release({"serverId":"${args.serverId}"})`,
899
+ `- 如果需要全局重建该 MCP server,直接调用 mcp_restart({"serverId":"${args.serverId}"});它成功后会清理旧 runtime 的全部 lease`,
900
+ `- 如果只想丢弃当前对话的连接,再调用 mcp_release({"serverId":"${args.serverId}"})`,
715
901
  `- 重新打开/关闭浏览器窗口,避免 Playwright persistent context 残留`,
716
902
  `- 查看 ${MCP_YAML_PATH} 是否已加载且配置正确(Problems 面板 / 后端日志)`,
717
903
  ]
718
904
  : [
719
905
  'Suggested checks:',
720
- `- Release the lease first: mcp_release({"serverId":"${args.serverId}"})`,
906
+ `- To rebuild this MCP server globally, call mcp_restart({"serverId":"${args.serverId}"}) directly; a successful restart clears all leases on the old runtime`,
907
+ `- To discard only this dialog's connection, call mcp_release({"serverId":"${args.serverId}"})`,
721
908
  `- Close/reopen browser windows to avoid leftover Playwright persistent contexts`,
722
909
  `- Verify ${MCP_YAML_PATH} is loaded and valid (Problems panel / backend logs)`,
723
910
  ];
@@ -746,12 +933,13 @@ function upsertMcpToolCallProblem(args) {
746
933
  function clearMcpToolCallProblem(serverId) {
747
934
  (0, problems_1.removeProblemsByPrefix)(`${MCP_TOOL_CALL_PROBLEM_PREFIX}${sanitizePathSegment(serverId)}`);
748
935
  }
749
- async function applyWorkspaceConfig(config, invalidServers, serverIdsInYamlOrder, validServerIdsInYamlOrder, reason) {
936
+ async function applyWorkspaceConfig(config, invalidServers, serverIdsInYamlOrder, validServerIdsInYamlOrder, disabledServerIdsInYamlOrder, rawText, reason) {
750
937
  log.info(`Applying MCP rtws config (${reason})`);
751
- replaceDeclaredServerRuntimeCatalog(config, invalidServers, serverIdsInYamlOrder);
938
+ replaceDeclaredServerRuntimeCatalog(config, invalidServers, serverIdsInYamlOrder, disabledServerIdsInYamlOrder);
752
939
  let runtimeLeaseChanged = false;
753
940
  const invalidIds = new Set(invalidServers.map((s) => s.serverId));
754
941
  const desiredIds = new Set([...Object.keys(config.servers), ...invalidIds]);
942
+ const declaredIds = new Set(serverIdsInYamlOrder);
755
943
  // Remove deleted servers first.
756
944
  for (const [serverId, state] of serverStateById.entries()) {
757
945
  if (desiredIds.has(serverId))
@@ -762,8 +950,18 @@ async function applyWorkspaceConfig(config, invalidServers, serverIdsInYamlOrder
762
950
  serverStateById.delete(serverId);
763
951
  (0, problems_1.reconcileProblemsByPrefix)(problemPrefixForServer(serverId), []);
764
952
  }
953
+ // Remove disabled/deleted MCP placeholders that are no longer declared.
954
+ for (const [toolsetName, owner] of Array.from(toolsetOwnerByName.entries())) {
955
+ if (owner.kind !== 'mcp')
956
+ continue;
957
+ if (declaredIds.has(owner.serverId))
958
+ continue;
959
+ (0, registry_1.unregisterToolset)(toolsetName);
960
+ toolsetOwnerByName.delete(toolsetName);
961
+ }
765
962
  // Surface invalid server config errors (while keeping last-known-good runtimes registered).
766
963
  for (const s of invalidServers) {
964
+ unregisterMcpToolsetPlaceholder(s.serverId);
767
965
  upsertMcpServerConfigInvalidProblem(s.serverId, s.errorText);
768
966
  }
769
967
  // Apply desired servers independently (deterministic order).
@@ -775,6 +973,9 @@ async function applyWorkspaceConfig(config, invalidServers, serverIdsInYamlOrder
775
973
  const fingerprint = fingerprintServerConfig(serverCfg);
776
974
  const existing = serverStateById.get(serverId);
777
975
  if (!existing || existing.configFingerprint !== fingerprint) {
976
+ if (!existing) {
977
+ unregisterMcpToolsetPlaceholder(serverId);
978
+ }
778
979
  const res = await tryBuildServerState(serverCfg, desiredToolsetName, fingerprint);
779
980
  if (!res.ok) {
780
981
  upsertDeclaredServerRuntimeError(serverId, res.errorText);
@@ -827,6 +1028,11 @@ async function applyWorkspaceConfig(config, invalidServers, serverIdsInYamlOrder
827
1028
  if (!changed)
828
1029
  break;
829
1030
  }
1031
+ const manualInfo = rawText === null ? (0, manual_problems_1.emptyMcpToolsetManualByServer)() : (0, manual_problems_1.parseMcpManualByServer)(rawText);
1032
+ for (const serverId of disabledServerIdsInYamlOrder) {
1033
+ (0, problems_1.reconcileProblemsByPrefix)(problemPrefixForServer(serverId), []);
1034
+ registerDisabledServerToolset(serverId, manualInfo);
1035
+ }
830
1036
  reorderMcpToolsetsInRegistry(serverIdsInYamlOrder);
831
1037
  (0, tool_availability_updates_1.notifyToolAvailabilityRegistryMaybeChanged)({
832
1038
  reason: 'registry_changed',
@@ -849,7 +1055,7 @@ function clearDeclaredServerRuntimeCatalog() {
849
1055
  declaredServerIdsInYamlOrder = [];
850
1056
  declaredServerRuntimeCatalogById.clear();
851
1057
  }
852
- function replaceDeclaredServerRuntimeCatalog(config, invalidServers, serverIdsInYamlOrder) {
1058
+ function replaceDeclaredServerRuntimeCatalog(config, invalidServers, serverIdsInYamlOrder, disabledServerIdsInYamlOrder) {
853
1059
  const previousRuntimeErrors = new Map();
854
1060
  for (const [serverId, entry] of declaredServerRuntimeCatalogById.entries()) {
855
1061
  if (typeof entry.runtimeErrorText === 'string' && entry.runtimeErrorText.trim() !== '') {
@@ -858,7 +1064,15 @@ function replaceDeclaredServerRuntimeCatalog(config, invalidServers, serverIdsIn
858
1064
  }
859
1065
  declaredServerIdsInYamlOrder = [...serverIdsInYamlOrder];
860
1066
  declaredServerRuntimeCatalogById.clear();
1067
+ const disabledIds = new Set(disabledServerIdsInYamlOrder);
861
1068
  for (const serverId of serverIdsInYamlOrder) {
1069
+ if (disabledIds.has(serverId)) {
1070
+ declaredServerRuntimeCatalogById.set(serverId, {
1071
+ transport: 'unknown',
1072
+ disabled: true,
1073
+ });
1074
+ continue;
1075
+ }
862
1076
  const cfg = config.servers[serverId];
863
1077
  if (!cfg)
864
1078
  continue;
@@ -945,6 +1159,74 @@ function registerServer(state) {
945
1159
  });
946
1160
  toolsetOwnerByName.set(state.toolsetName, { kind: 'mcp', serverId: state.serverId });
947
1161
  }
1162
+ function registerDisabledServerToolset(serverId, manualInfo) {
1163
+ const existingToolset = registry_1.toolsetsRegistry.get(serverId);
1164
+ const existingOwner = toolsetOwnerByName.get(serverId);
1165
+ if (existingToolset && (!existingOwner || existingOwner.serverId !== serverId)) {
1166
+ upsertMcpServerConfigInvalidProblem(serverId, `Toolset name collision: ${serverId}`);
1167
+ return;
1168
+ }
1169
+ (0, registry_1.registerToolset)(serverId, []);
1170
+ const manual = manualInfo.manualByServerId.get(serverId);
1171
+ const manualSpec = manual?.contentFile
1172
+ ? (0, spec_1.buildMcpManualSpec)(manual.contentFile)
1173
+ : {
1174
+ topics: ['index'],
1175
+ warnOnMissing: false,
1176
+ includeSchemaToolsSection: false,
1177
+ };
1178
+ const inlineManual = manual ? renderInlineMcpToolsetManual(manual) : '';
1179
+ const disabledNoticeEn = [
1180
+ `This MCP server is configured but disabled in \`.minds/mcp.yaml\` (\`enabled: false\`).`,
1181
+ `It intentionally exposes zero tools until an MCP administrator enables it with \`mcp_restart({"serverId":"${serverId}"})\`.`,
1182
+ inlineManual,
1183
+ ]
1184
+ .filter((part) => part.trim() !== '')
1185
+ .join('\n\n');
1186
+ const disabledNoticeZh = [
1187
+ `该 MCP server 已在 \`.minds/mcp.yaml\` 中配置,但当前为禁用状态(\`enabled: false\`)。`,
1188
+ `它会刻意暴露为 0 工具的 toolset;需要 MCP 排障/管理员用 \`mcp_restart({"serverId":"${serverId}"})\` 启用后才会加载工具。`,
1189
+ inlineManual,
1190
+ ]
1191
+ .filter((part) => part.trim() !== '')
1192
+ .join('\n\n');
1193
+ (0, registry_1.setToolsetMeta)(serverId, {
1194
+ source: 'mcp',
1195
+ descriptionI18n: {
1196
+ en: `MCP server: ${serverId} (disabled)`,
1197
+ zh: `MCP 服务器:${serverId}(已禁用)`,
1198
+ },
1199
+ manualNoticeI18n: {
1200
+ en: disabledNoticeEn,
1201
+ zh: disabledNoticeZh,
1202
+ },
1203
+ ...(manualSpec !== undefined ? { manualSpec } : {}),
1204
+ });
1205
+ toolsetOwnerByName.set(serverId, { kind: 'mcp', serverId });
1206
+ }
1207
+ function renderInlineMcpToolsetManual(manual) {
1208
+ const parts = [];
1209
+ if (manual.content) {
1210
+ parts.push(manual.content);
1211
+ }
1212
+ for (const section of manual.sections) {
1213
+ parts.push(`#### ${section.title}\n\n${section.content}`);
1214
+ }
1215
+ return parts.join('\n\n');
1216
+ }
1217
+ function unregisterMcpToolsetPlaceholder(serverId) {
1218
+ if (serverStateById.has(serverId))
1219
+ return false;
1220
+ const owner = toolsetOwnerByName.get(serverId);
1221
+ if (owner?.kind !== 'mcp' || owner.serverId !== serverId)
1222
+ return false;
1223
+ const tools = registry_1.toolsetsRegistry.get(serverId);
1224
+ if (tools && tools.length > 0)
1225
+ return false;
1226
+ (0, registry_1.unregisterToolset)(serverId);
1227
+ toolsetOwnerByName.delete(serverId);
1228
+ return true;
1229
+ }
948
1230
  function unregisterServer(state) {
949
1231
  // Unregister toolset first so Team.Member.listTools doesn't resolve stale tools.
950
1232
  if (toolsetOwnerByName.get(state.toolsetName)?.serverId === state.serverId) {
@@ -116,6 +116,11 @@ function buildAgentMcpToolsetRuntimeNotices(params) {
116
116
  notices.push({
117
117
  toolsetName,
118
118
  transport: runtimeStatus?.transport ?? 'unknown',
119
+ status: runtimeStatus?.status === 'disabled'
120
+ ? 'disabled'
121
+ : runtimeStatus?.status === 'config_invalid'
122
+ ? 'config_invalid'
123
+ : 'temporarily_unavailable',
119
124
  errorText: runtimeStatus?.errorText,
120
125
  });
121
126
  }
@@ -22,6 +22,7 @@ export type BuildSystemPromptInput = {
22
22
  export type McpToolsetRuntimeNotice = Readonly<{
23
23
  toolsetName: string;
24
24
  transport: 'stdio' | 'streamable_http' | 'invalid' | 'unknown';
25
+ status: 'temporarily_unavailable' | 'config_invalid' | 'disabled';
25
26
  errorText?: string;
26
27
  }>;
27
28
  export declare function formatMcpToolsetRuntimeNote(language: LanguageCode, notices: readonly McpToolsetRuntimeNotice[]): string;
@@ -312,24 +312,32 @@ function formatMcpToolsetRuntimeNote(language, notices) {
312
312
  return '';
313
313
  const lines = language === 'zh'
314
314
  ? [
315
- '以下 MCP toolset 已配置给你,且在 `.minds/mcp.yaml` 中有声明,但当前没有加载进运行时工具注册表。',
316
- '请将它们视为“当前暂时不可达”的运行时情况,例如 stdio transport 进程暂时启动失败,或 streamable HTTP transport 当前无法连接;这不代表你的权限被撤销,也不应视为系统级功能降级。',
315
+ '以下 MCP toolset 已配置给你,且在 `.minds/mcp.yaml` 中有声明,但当前不提供可调用的运行时 MCP 工具。',
316
+ '其中有些可能是暂时不可达(例如 stdio transport 进程启动失败,或 streamable HTTP transport 当前无法连接),有些可能是被明确禁用;这不代表你的权限被撤销,也不应视为系统级功能降级。',
317
317
  ...notices.map((notice) => {
318
+ if (notice.status === 'disabled') {
319
+ return `- \`${notice.toolsetName}\`:状态=已禁用;这是一个已配置但当前刻意暴露为 0 工具的 MCP toolset。如任务依赖它,请按团队职责速查表联系 MCP 排障/管理员处理。`;
320
+ }
318
321
  const reason = typeof notice.errorText === 'string' && notice.errorText.trim() !== ''
319
322
  ? `;最近错误:${notice.errorText}`
320
323
  : '';
321
- return `- \`${notice.toolsetName}\`:transport=${formatTransportLabel(language, notice.transport)};状态=暂时不可达${reason}`;
324
+ const status = notice.status === 'config_invalid' ? '配置无效' : '暂时不可达';
325
+ return `- \`${notice.toolsetName}\`:transport=${formatTransportLabel(language, notice.transport)};状态=${status}${reason}`;
322
326
  }),
323
327
  '若当前任务依赖这些能力,应明确说明对应 MCP toolset 眼下不可用,并优先继续使用其余可用工具/路径推进。',
324
328
  ]
325
329
  : [
326
- 'The following MCP toolsets are assigned to you and declared in `.minds/mcp.yaml`, but they are not currently loaded into the runtime tool registry.',
327
- 'Treat this as a temporary runtime-availability condition, for example a stdio transport process failing to start right now, or a streamable HTTP transport being unreachable right now. This does not mean your permission was revoked, and it should not be treated as a system-level capability downgrade.',
330
+ 'The following MCP toolsets are assigned to you and declared in `.minds/mcp.yaml`, but they do not currently provide callable runtime MCP tools.',
331
+ 'Some may be temporarily unavailable (for example a stdio transport process failing to start right now, or a streamable HTTP transport being unreachable right now), and some may be explicitly disabled. This does not mean your permission was revoked, and it should not be treated as a system-level capability downgrade.',
328
332
  ...notices.map((notice) => {
333
+ if (notice.status === 'disabled') {
334
+ return `- \`${notice.toolsetName}\`: status=disabled; this is a configured MCP toolset intentionally exposed with zero tools. If the task depends on it, use the team responsibility quick table to contact the MCP troubleshooter or administrator.`;
335
+ }
329
336
  const reason = typeof notice.errorText === 'string' && notice.errorText.trim() !== ''
330
337
  ? `; latest error: ${notice.errorText}`
331
338
  : '';
332
- return `- \`${notice.toolsetName}\`: transport=${formatTransportLabel(language, notice.transport)}; status=temporarily unavailable${reason}`;
339
+ const status = notice.status === 'config_invalid' ? 'config invalid' : 'temporarily unavailable';
340
+ return `- \`${notice.toolsetName}\`: transport=${formatTransportLabel(language, notice.transport)}; status=${status}${reason}`;
333
341
  }),
334
342
  'If the current task depends on one of these capabilities, say that the corresponding MCP toolset is unavailable right now and continue with other available tools or paths first.',
335
343
  ];
@@ -81,6 +81,7 @@ function manualSpecFor(toolsetId) {
81
81
  // MCP tools (local testing/ops)
82
82
  (0, registry_1.registerTool)(mcp_1.mcpRestartTool);
83
83
  (0, registry_1.registerTool)(mcp_1.mcpReleaseTool);
84
+ (0, registry_1.registerTool)(mcp_1.mcpDisableTool);
84
85
  // Memory tools
85
86
  (0, registry_1.registerTool)(mem_1.addPersonalMemoryTool);
86
87
  (0, registry_1.registerTool)(mem_1.dropPersonalMemoryTool);
@@ -169,6 +170,7 @@ for (const tool of team_mgmt_1.teamMgmtTools) {
169
170
  (0, registry_1.registerToolset)('mcp_admin', [
170
171
  mcp_1.mcpRestartTool,
171
172
  mcp_1.mcpReleaseTool,
173
+ mcp_1.mcpDisableTool,
172
174
  env_1.envGetTool,
173
175
  env_1.envSetTool,
174
176
  env_1.envUnsetTool,