@hcu-lab.me/mcp-device 1.0.9 → 1.0.12

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 (506) hide show
  1. package/PRIVACY.md +21 -0
  2. package/README.md +58 -3
  3. package/SECURITY.md +67 -0
  4. package/config/revoked-approvals.json +1 -0
  5. package/control-plane/config/mcp-servers.example.toml +52 -0
  6. package/control-plane/config/mcp-servers.toml +52 -0
  7. package/control-plane/contracts/device-public-contract-v1.json +733 -0
  8. package/control-plane/scripts/GATEWAY-LICENSE.txt +7 -0
  9. package/control-plane/scripts/account-http.mjs +220 -0
  10. package/control-plane/scripts/account-store.mjs +368 -0
  11. package/control-plane/scripts/admin.mjs +68 -0
  12. package/control-plane/scripts/auth-session.mjs +411 -0
  13. package/control-plane/scripts/authenticated-mcp-wrapper.mjs +1281 -0
  14. package/control-plane/scripts/benchmark-command.mjs +9 -0
  15. package/control-plane/scripts/benchmark-mcp-catalog.mjs +174 -0
  16. package/control-plane/scripts/catalog-budget.mjs +87 -0
  17. package/control-plane/scripts/check-device-public-contract.mjs +20 -0
  18. package/control-plane/scripts/custom-tools/index.mjs +221 -0
  19. package/control-plane/scripts/custom-tools/path-utils.mjs +117 -0
  20. package/control-plane/scripts/custom-tools/response-utils.mjs +34 -0
  21. package/control-plane/scripts/dashboard-http.mjs +598 -0
  22. package/control-plane/scripts/device-access-policy.mjs +205 -0
  23. package/control-plane/scripts/device-admin.mjs +43 -0
  24. package/control-plane/scripts/device-audit.mjs +63 -0
  25. package/control-plane/scripts/device-broker.mjs +1461 -0
  26. package/control-plane/scripts/device-execution-tool-definitions.mjs +217 -0
  27. package/control-plane/scripts/device-inventory.mjs +128 -0
  28. package/control-plane/scripts/device-pairing-http.mjs +109 -0
  29. package/control-plane/scripts/device-pairing-store.mjs +245 -0
  30. package/control-plane/scripts/device-public-contract.mjs +165 -0
  31. package/control-plane/scripts/device-release.mjs +95 -0
  32. package/control-plane/scripts/device-secure-transport.mjs +128 -0
  33. package/control-plane/scripts/device-store.mjs +283 -0
  34. package/control-plane/scripts/device-usage.mjs +657 -0
  35. package/control-plane/scripts/embedded-device.mjs +149 -0
  36. package/control-plane/scripts/enduser-ui.mjs +45 -0
  37. package/control-plane/scripts/external-tool-broker.mjs +179 -0
  38. package/control-plane/scripts/oauth-authorization-server.mjs +589 -0
  39. package/control-plane/scripts/operator-dashboard-http.mjs +81 -0
  40. package/control-plane/scripts/project-inspection.mjs +227 -0
  41. package/control-plane/scripts/projects/project-id.mjs +69 -0
  42. package/control-plane/scripts/projects/trusted-roots-projects.mjs +375 -0
  43. package/control-plane/scripts/prompts/index.mjs +60 -0
  44. package/control-plane/scripts/remote-process-sessions.mjs +78 -0
  45. package/control-plane/scripts/remote-tool-result.mjs +9 -0
  46. package/control-plane/scripts/resources/index.mjs +166 -0
  47. package/control-plane/scripts/runtime-profile.mjs +54 -0
  48. package/control-plane/scripts/shell-tool-descriptor.mjs +17 -0
  49. package/control-plane/scripts/skill-source-safety.mjs +46 -0
  50. package/control-plane/scripts/skills/README.md +70 -0
  51. package/control-plane/scripts/skills/_upstream_licenses/anthropic-THIRD_PARTY_NOTICES.md +405 -0
  52. package/control-plane/scripts/skills/_upstream_licenses/hallmark-LICENSE.txt +21 -0
  53. package/control-plane/scripts/skills/_upstream_licenses/ponytail-LICENSE.txt +21 -0
  54. package/control-plane/scripts/skills/_upstream_licenses/stitch-skills-LICENSE.txt +201 -0
  55. package/control-plane/scripts/skills/_upstream_licenses/superpowers-LICENSE.txt +21 -0
  56. package/control-plane/scripts/skills/algorithmic-art/LICENSE.txt +202 -0
  57. package/control-plane/scripts/skills/algorithmic-art/SKILL.md +405 -0
  58. package/control-plane/scripts/skills/algorithmic-art/templates/generator_template.js +223 -0
  59. package/control-plane/scripts/skills/algorithmic-art/templates/viewer.html +599 -0
  60. package/control-plane/scripts/skills/brainstorming/SKILL.md +285 -0
  61. package/control-plane/scripts/skills/brainstorming/scripts/frame-template.html +213 -0
  62. package/control-plane/scripts/skills/brainstorming/scripts/helper.js +167 -0
  63. package/control-plane/scripts/skills/brainstorming/scripts/server.cjs +723 -0
  64. package/control-plane/scripts/skills/brainstorming/scripts/start-server.sh +209 -0
  65. package/control-plane/scripts/skills/brainstorming/scripts/stop-server.sh +120 -0
  66. package/control-plane/scripts/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  67. package/control-plane/scripts/skills/brainstorming/visual-companion.md +299 -0
  68. package/control-plane/scripts/skills/brand-guidelines/LICENSE.txt +202 -0
  69. package/control-plane/scripts/skills/brand-guidelines/SKILL.md +73 -0
  70. package/control-plane/scripts/skills/claude-api/LICENSE.txt +202 -0
  71. package/control-plane/scripts/skills/claude-api/SKILL.md +570 -0
  72. package/control-plane/scripts/skills/claude-api/csharp/claude-api/README.md +362 -0
  73. package/control-plane/scripts/skills/claude-api/csharp/claude-api/batches.md +14 -0
  74. package/control-plane/scripts/skills/claude-api/csharp/claude-api/files-api.md +25 -0
  75. package/control-plane/scripts/skills/claude-api/csharp/claude-api/streaming.md +28 -0
  76. package/control-plane/scripts/skills/claude-api/csharp/claude-api/tool-use.md +164 -0
  77. package/control-plane/scripts/skills/claude-api/curl/examples.md +256 -0
  78. package/control-plane/scripts/skills/claude-api/curl/managed-agents.md +371 -0
  79. package/control-plane/scripts/skills/claude-api/go/claude-api/README.md +188 -0
  80. package/control-plane/scripts/skills/claude-api/go/claude-api/files-api.md +23 -0
  81. package/control-plane/scripts/skills/claude-api/go/claude-api/streaming.md +43 -0
  82. package/control-plane/scripts/skills/claude-api/go/claude-api/tool-use.md +220 -0
  83. package/control-plane/scripts/skills/claude-api/go/managed-agents/README.md +564 -0
  84. package/control-plane/scripts/skills/claude-api/java/claude-api/README.md +238 -0
  85. package/control-plane/scripts/skills/claude-api/java/claude-api/files-api.md +27 -0
  86. package/control-plane/scripts/skills/claude-api/java/claude-api/streaming.md +24 -0
  87. package/control-plane/scripts/skills/claude-api/java/claude-api/tool-use.md +228 -0
  88. package/control-plane/scripts/skills/claude-api/java/managed-agents/README.md +443 -0
  89. package/control-plane/scripts/skills/claude-api/php/claude-api/README.md +174 -0
  90. package/control-plane/scripts/skills/claude-api/php/claude-api/batches.md +15 -0
  91. package/control-plane/scripts/skills/claude-api/php/claude-api/files-api.md +13 -0
  92. package/control-plane/scripts/skills/claude-api/php/claude-api/streaming.md +27 -0
  93. package/control-plane/scripts/skills/claude-api/php/claude-api/tool-use.md +253 -0
  94. package/control-plane/scripts/skills/claude-api/php/managed-agents/README.md +443 -0
  95. package/control-plane/scripts/skills/claude-api/python/claude-api/README.md +565 -0
  96. package/control-plane/scripts/skills/claude-api/python/claude-api/batches.md +198 -0
  97. package/control-plane/scripts/skills/claude-api/python/claude-api/files-api.md +170 -0
  98. package/control-plane/scripts/skills/claude-api/python/claude-api/sdk-upgrade.md +286 -0
  99. package/control-plane/scripts/skills/claude-api/python/claude-api/streaming.md +179 -0
  100. package/control-plane/scripts/skills/claude-api/python/claude-api/tool-use.md +627 -0
  101. package/control-plane/scripts/skills/claude-api/python/managed-agents/README.md +335 -0
  102. package/control-plane/scripts/skills/claude-api/ruby/claude-api/README.md +134 -0
  103. package/control-plane/scripts/skills/claude-api/ruby/claude-api/streaming.md +16 -0
  104. package/control-plane/scripts/skills/claude-api/ruby/claude-api/tool-use.md +41 -0
  105. package/control-plane/scripts/skills/claude-api/ruby/managed-agents/README.md +394 -0
  106. package/control-plane/scripts/skills/claude-api/shared/admin-api.md +179 -0
  107. package/control-plane/scripts/skills/claude-api/shared/agent-design.md +101 -0
  108. package/control-plane/scripts/skills/claude-api/shared/anthropic-cli.md +269 -0
  109. package/control-plane/scripts/skills/claude-api/shared/claude-platform-on-aws.md +59 -0
  110. package/control-plane/scripts/skills/claude-api/shared/cost-optimization.md +233 -0
  111. package/control-plane/scripts/skills/claude-api/shared/error-codes.md +262 -0
  112. package/control-plane/scripts/skills/claude-api/shared/live-sources.md +166 -0
  113. package/control-plane/scripts/skills/claude-api/shared/managed-agents-api-reference.md +455 -0
  114. package/control-plane/scripts/skills/claude-api/shared/managed-agents-client-patterns.md +220 -0
  115. package/control-plane/scripts/skills/claude-api/shared/managed-agents-core.md +359 -0
  116. package/control-plane/scripts/skills/claude-api/shared/managed-agents-environments.md +226 -0
  117. package/control-plane/scripts/skills/claude-api/shared/managed-agents-events.md +290 -0
  118. package/control-plane/scripts/skills/claude-api/shared/managed-agents-memory.md +201 -0
  119. package/control-plane/scripts/skills/claude-api/shared/managed-agents-multiagent.md +260 -0
  120. package/control-plane/scripts/skills/claude-api/shared/managed-agents-onboarding.md +82 -0
  121. package/control-plane/scripts/skills/claude-api/shared/managed-agents-outcomes.md +108 -0
  122. package/control-plane/scripts/skills/claude-api/shared/managed-agents-overview.md +77 -0
  123. package/control-plane/scripts/skills/claude-api/shared/managed-agents-scheduled-deployments.md +156 -0
  124. package/control-plane/scripts/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +282 -0
  125. package/control-plane/scripts/skills/claude-api/shared/managed-agents-tools.md +504 -0
  126. package/control-plane/scripts/skills/claude-api/shared/managed-agents-webhooks.md +143 -0
  127. package/control-plane/scripts/skills/claude-api/shared/model-migration.md +1872 -0
  128. package/control-plane/scripts/skills/claude-api/shared/models.md +142 -0
  129. package/control-plane/scripts/skills/claude-api/shared/platform-availability.md +52 -0
  130. package/control-plane/scripts/skills/claude-api/shared/prompt-audit.md +223 -0
  131. package/control-plane/scripts/skills/claude-api/shared/prompt-caching.md +292 -0
  132. package/control-plane/scripts/skills/claude-api/shared/token-counting.md +56 -0
  133. package/control-plane/scripts/skills/claude-api/shared/tool-use-concepts.md +526 -0
  134. package/control-plane/scripts/skills/claude-api/typescript/claude-api/README.md +405 -0
  135. package/control-plane/scripts/skills/claude-api/typescript/claude-api/batches.md +106 -0
  136. package/control-plane/scripts/skills/claude-api/typescript/claude-api/files-api.md +98 -0
  137. package/control-plane/scripts/skills/claude-api/typescript/claude-api/streaming.md +178 -0
  138. package/control-plane/scripts/skills/claude-api/typescript/claude-api/tool-use.md +586 -0
  139. package/control-plane/scripts/skills/claude-api/typescript/managed-agents/README.md +359 -0
  140. package/control-plane/scripts/skills/dispatching-parallel-agents/SKILL.md +167 -0
  141. package/control-plane/scripts/skills/enhance-prompt/README.md +34 -0
  142. package/control-plane/scripts/skills/enhance-prompt/SKILL.md +204 -0
  143. package/control-plane/scripts/skills/enhance-prompt/references/KEYWORDS.md +114 -0
  144. package/control-plane/scripts/skills/executing-plans/SKILL.md +371 -0
  145. package/control-plane/scripts/skills/executing-plans/scripts/task-done +52 -0
  146. package/control-plane/scripts/skills/executing-plans/scripts/task-start +28 -0
  147. package/control-plane/scripts/skills/extract-design-md/SKILL.md +358 -0
  148. package/control-plane/scripts/skills/extract-design-md/examples/DESIGN.md +210 -0
  149. package/control-plane/scripts/skills/extract-design-md/references/angular.md +122 -0
  150. package/control-plane/scripts/skills/extract-design-md/references/plain-css.md +161 -0
  151. package/control-plane/scripts/skills/extract-design-md/references/react-tailwind.md +157 -0
  152. package/control-plane/scripts/skills/extract-design-md/references/svelte.md +101 -0
  153. package/control-plane/scripts/skills/extract-design-md/references/vue.md +107 -0
  154. package/control-plane/scripts/skills/finishing-a-development-branch/SKILL.md +225 -0
  155. package/control-plane/scripts/skills/frontend-design/LICENSE.txt +177 -0
  156. package/control-plane/scripts/skills/frontend-design/SKILL.md +71 -0
  157. package/control-plane/scripts/skills/hallmark/SKILL.md +558 -0
  158. package/control-plane/scripts/skills/hallmark/references/anti-patterns.md +418 -0
  159. package/control-plane/scripts/skills/hallmark/references/assets.md +406 -0
  160. package/control-plane/scripts/skills/hallmark/references/color.md +95 -0
  161. package/control-plane/scripts/skills/hallmark/references/component-cookbook.md +263 -0
  162. package/control-plane/scripts/skills/hallmark/references/components/c1-outlined-chip.md +12 -0
  163. package/control-plane/scripts/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -0
  164. package/control-plane/scripts/skills/hallmark/references/components/c3-typographic-link.md +8 -0
  165. package/control-plane/scripts/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -0
  166. package/control-plane/scripts/skills/hallmark/references/components/f1-bento-grid.md +20 -0
  167. package/control-plane/scripts/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -0
  168. package/control-plane/scripts/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -0
  169. package/control-plane/scripts/skills/hallmark/references/components/f4-step-sequence.md +11 -0
  170. package/control-plane/scripts/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -0
  171. package/control-plane/scripts/skills/hallmark/references/components/f6-product-card-grid.md +41 -0
  172. package/control-plane/scripts/skills/hallmark/references/components/ft1-mast-headed.md +13 -0
  173. package/control-plane/scripts/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -0
  174. package/control-plane/scripts/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -0
  175. package/control-plane/scripts/skills/hallmark/references/components/ft4-dense-typographic.md +10 -0
  176. package/control-plane/scripts/skills/hallmark/references/components/ft5-statement.md +21 -0
  177. package/control-plane/scripts/skills/hallmark/references/components/ft6-letter-close.md +19 -0
  178. package/control-plane/scripts/skills/hallmark/references/components/ft7-newsletter-first.md +27 -0
  179. package/control-plane/scripts/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -0
  180. package/control-plane/scripts/skills/hallmark/references/components/h1-marquee.md +15 -0
  181. package/control-plane/scripts/skills/hallmark/references/components/h2-split-diptych.md +15 -0
  182. package/control-plane/scripts/skills/hallmark/references/components/h3-quote-led.md +11 -0
  183. package/control-plane/scripts/skills/hallmark/references/components/h4-stat-led.md +14 -0
  184. package/control-plane/scripts/skills/hallmark/references/components/h5-letter-hero.md +11 -0
  185. package/control-plane/scripts/skills/hallmark/references/components/h6-photographic-fold.md +16 -0
  186. package/control-plane/scripts/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -0
  187. package/control-plane/scripts/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -0
  188. package/control-plane/scripts/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -0
  189. package/control-plane/scripts/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -0
  190. package/control-plane/scripts/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -0
  191. package/control-plane/scripts/skills/hallmark/references/components/n11-mega-menu.md +40 -0
  192. package/control-plane/scripts/skills/hallmark/references/components/n12-banner-retract.md +34 -0
  193. package/control-plane/scripts/skills/hallmark/references/components/n13-inline-cmdk-pill.md +39 -0
  194. package/control-plane/scripts/skills/hallmark/references/components/n1b-saas-three-section.md +35 -0
  195. package/control-plane/scripts/skills/hallmark/references/components/n2-floating-chip.md +14 -0
  196. package/control-plane/scripts/skills/hallmark/references/components/n3-side-rail.md +14 -0
  197. package/control-plane/scripts/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -0
  198. package/control-plane/scripts/skills/hallmark/references/components/n5-floating-pill.md +28 -0
  199. package/control-plane/scripts/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -0
  200. package/control-plane/scripts/skills/hallmark/references/components/n7-brutal-slab.md +22 -0
  201. package/control-plane/scripts/skills/hallmark/references/components/n8-terminal-command.md +21 -0
  202. package/control-plane/scripts/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -0
  203. package/control-plane/scripts/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -0
  204. package/control-plane/scripts/skills/hallmark/references/components/s2-hanging.md +13 -0
  205. package/control-plane/scripts/skills/hallmark/references/components/s3-sticky-pinned.md +19 -0
  206. package/control-plane/scripts/skills/hallmark/references/components/s4-inline-no-break.md +11 -0
  207. package/control-plane/scripts/skills/hallmark/references/components/s5-bottom-anchored.md +13 -0
  208. package/control-plane/scripts/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -0
  209. package/control-plane/scripts/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -0
  210. package/control-plane/scripts/skills/hallmark/references/components/t3-single-huge-quote.md +11 -0
  211. package/control-plane/scripts/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -0
  212. package/control-plane/scripts/skills/hallmark/references/contract.md +25 -0
  213. package/control-plane/scripts/skills/hallmark/references/copy.md +182 -0
  214. package/control-plane/scripts/skills/hallmark/references/custom-craft.md +626 -0
  215. package/control-plane/scripts/skills/hallmark/references/custom-theme.md +367 -0
  216. package/control-plane/scripts/skills/hallmark/references/design-md.md +116 -0
  217. package/control-plane/scripts/skills/hallmark/references/export-formats.md +329 -0
  218. package/control-plane/scripts/skills/hallmark/references/floating-nav.md +89 -0
  219. package/control-plane/scripts/skills/hallmark/references/genres/atmospheric.md +69 -0
  220. package/control-plane/scripts/skills/hallmark/references/genres/editorial.md +72 -0
  221. package/control-plane/scripts/skills/hallmark/references/genres/modern-minimal.md +71 -0
  222. package/control-plane/scripts/skills/hallmark/references/genres/playful.md +70 -0
  223. package/control-plane/scripts/skills/hallmark/references/hero-enrichment.md +475 -0
  224. package/control-plane/scripts/skills/hallmark/references/imagery-kit.md +170 -0
  225. package/control-plane/scripts/skills/hallmark/references/interaction-and-states.md +208 -0
  226. package/control-plane/scripts/skills/hallmark/references/layout-and-space.md +112 -0
  227. package/control-plane/scripts/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -0
  228. package/control-plane/scripts/skills/hallmark/references/macrostructures/02-long-document.md +34 -0
  229. package/control-plane/scripts/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -0
  230. package/control-plane/scripts/skills/hallmark/references/macrostructures/04-stat-led.md +34 -0
  231. package/control-plane/scripts/skills/hallmark/references/macrostructures/05-workbench.md +32 -0
  232. package/control-plane/scripts/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -0
  233. package/control-plane/scripts/skills/hallmark/references/macrostructures/07-manifesto.md +32 -0
  234. package/control-plane/scripts/skills/hallmark/references/macrostructures/08-photographic.md +34 -0
  235. package/control-plane/scripts/skills/hallmark/references/macrostructures/09-quote-led.md +32 -0
  236. package/control-plane/scripts/skills/hallmark/references/macrostructures/10-specimen.md +32 -0
  237. package/control-plane/scripts/skills/hallmark/references/macrostructures/11-catalogue.md +23 -0
  238. package/control-plane/scripts/skills/hallmark/references/macrostructures/12-letter.md +23 -0
  239. package/control-plane/scripts/skills/hallmark/references/macrostructures/13-index-first.md +23 -0
  240. package/control-plane/scripts/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -0
  241. package/control-plane/scripts/skills/hallmark/references/macrostructures/15-split-studio.md +23 -0
  242. package/control-plane/scripts/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -0
  243. package/control-plane/scripts/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -0
  244. package/control-plane/scripts/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -0
  245. package/control-plane/scripts/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -0
  246. package/control-plane/scripts/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -0
  247. package/control-plane/scripts/skills/hallmark/references/macrostructures/21-component-playground.md +23 -0
  248. package/control-plane/scripts/skills/hallmark/references/macrostructures.md +89 -0
  249. package/control-plane/scripts/skills/hallmark/references/microinteractions.md +258 -0
  250. package/control-plane/scripts/skills/hallmark/references/motion.md +109 -0
  251. package/control-plane/scripts/skills/hallmark/references/preview-examples.md +49 -0
  252. package/control-plane/scripts/skills/hallmark/references/responsive.md +138 -0
  253. package/control-plane/scripts/skills/hallmark/references/slop-test.md +192 -0
  254. package/control-plane/scripts/skills/hallmark/references/structure.md +160 -0
  255. package/control-plane/scripts/skills/hallmark/references/study.md +509 -0
  256. package/control-plane/scripts/skills/hallmark/references/themes/carnival.md +301 -0
  257. package/control-plane/scripts/skills/hallmark/references/themes/cobalt.md +146 -0
  258. package/control-plane/scripts/skills/hallmark/references/themes/grid.md +161 -0
  259. package/control-plane/scripts/skills/hallmark/references/themes/hum.md +403 -0
  260. package/control-plane/scripts/skills/hallmark/references/themes/lumen.md +478 -0
  261. package/control-plane/scripts/skills/hallmark/references/typography.md +243 -0
  262. package/control-plane/scripts/skills/hallmark/references/upstream/recipes.md +186 -0
  263. package/control-plane/scripts/skills/hallmark/references/upstream/study-examples.md +176 -0
  264. package/control-plane/scripts/skills/hallmark/references/upstream/tokens.css +1221 -0
  265. package/control-plane/scripts/skills/hallmark/references/verbs/audit.md +25 -0
  266. package/control-plane/scripts/skills/hallmark/references/verbs/redesign.md +269 -0
  267. package/control-plane/scripts/skills/human-comms/SKILL.md +29 -0
  268. package/control-plane/scripts/skills/index.mjs +432 -0
  269. package/control-plane/scripts/skills/internal-comms/LICENSE.txt +202 -0
  270. package/control-plane/scripts/skills/internal-comms/SKILL.md +32 -0
  271. package/control-plane/scripts/skills/internal-comms/examples/3p-updates.md +47 -0
  272. package/control-plane/scripts/skills/internal-comms/examples/company-newsletter.md +65 -0
  273. package/control-plane/scripts/skills/internal-comms/examples/faq-answers.md +30 -0
  274. package/control-plane/scripts/skills/internal-comms/examples/general-comms.md +16 -0
  275. package/control-plane/scripts/skills/mcp-adapter.mjs +94 -0
  276. package/control-plane/scripts/skills/mcp-builder/LICENSE.txt +202 -0
  277. package/control-plane/scripts/skills/mcp-builder/SKILL.md +236 -0
  278. package/control-plane/scripts/skills/mcp-builder/reference/evaluation.md +602 -0
  279. package/control-plane/scripts/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  280. package/control-plane/scripts/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  281. package/control-plane/scripts/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  282. package/control-plane/scripts/skills/mcp-builder/scripts/connections.py +151 -0
  283. package/control-plane/scripts/skills/mcp-builder/scripts/evaluation.py +373 -0
  284. package/control-plane/scripts/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  285. package/control-plane/scripts/skills/mcp-builder/scripts/requirements.txt +2 -0
  286. package/control-plane/scripts/skills/ponytail/SKILL.md +120 -0
  287. package/control-plane/scripts/skills/ponytail-audit/SKILL.md +41 -0
  288. package/control-plane/scripts/skills/ponytail-debt/SKILL.md +44 -0
  289. package/control-plane/scripts/skills/ponytail-gain/SKILL.md +50 -0
  290. package/control-plane/scripts/skills/ponytail-help/SKILL.md +71 -0
  291. package/control-plane/scripts/skills/ponytail-review/SKILL.md +57 -0
  292. package/control-plane/scripts/skills/receiving-code-review/SKILL.md +205 -0
  293. package/control-plane/scripts/skills/requesting-code-review/SKILL.md +95 -0
  294. package/control-plane/scripts/skills/requesting-code-review/code-reviewer.md +198 -0
  295. package/control-plane/scripts/skills/skill-creator/LICENSE.txt +202 -0
  296. package/control-plane/scripts/skills/skill-creator/SKILL.md +485 -0
  297. package/control-plane/scripts/skills/skill-creator/agents/analyzer.md +274 -0
  298. package/control-plane/scripts/skills/skill-creator/agents/comparator.md +202 -0
  299. package/control-plane/scripts/skills/skill-creator/agents/grader.md +223 -0
  300. package/control-plane/scripts/skills/skill-creator/assets/eval_review.html +146 -0
  301. package/control-plane/scripts/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  302. package/control-plane/scripts/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  303. package/control-plane/scripts/skills/skill-creator/references/schemas.md +430 -0
  304. package/control-plane/scripts/skills/skill-creator/scripts/__init__.py +0 -0
  305. package/control-plane/scripts/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  306. package/control-plane/scripts/skills/skill-creator/scripts/generate_report.py +326 -0
  307. package/control-plane/scripts/skills/skill-creator/scripts/improve_description.py +247 -0
  308. package/control-plane/scripts/skills/skill-creator/scripts/package_skill.py +136 -0
  309. package/control-plane/scripts/skills/skill-creator/scripts/quick_validate.py +103 -0
  310. package/control-plane/scripts/skills/skill-creator/scripts/run_eval.py +310 -0
  311. package/control-plane/scripts/skills/skill-creator/scripts/run_loop.py +328 -0
  312. package/control-plane/scripts/skills/skill-creator/scripts/utils.py +47 -0
  313. package/control-plane/scripts/skills/slack-gif-creator/LICENSE.txt +202 -0
  314. package/control-plane/scripts/skills/slack-gif-creator/SKILL.md +254 -0
  315. package/control-plane/scripts/skills/slack-gif-creator/core/easing.py +234 -0
  316. package/control-plane/scripts/skills/slack-gif-creator/core/frame_composer.py +176 -0
  317. package/control-plane/scripts/skills/slack-gif-creator/core/gif_builder.py +269 -0
  318. package/control-plane/scripts/skills/slack-gif-creator/core/validators.py +136 -0
  319. package/control-plane/scripts/skills/slack-gif-creator/requirements.txt +4 -0
  320. package/control-plane/scripts/skills/sources.json +401 -0
  321. package/control-plane/scripts/skills/sources.lock.json +416 -0
  322. package/control-plane/scripts/skills/subagent-driven-development/SKILL.md +570 -0
  323. package/control-plane/scripts/skills/subagent-driven-development/implementer-prompt.md +154 -0
  324. package/control-plane/scripts/skills/subagent-driven-development/re-review-prompt.md +115 -0
  325. package/control-plane/scripts/skills/subagent-driven-development/scripts/review-package +53 -0
  326. package/control-plane/scripts/skills/subagent-driven-development/scripts/sdd-workspace +82 -0
  327. package/control-plane/scripts/skills/subagent-driven-development/scripts/task-brief +43 -0
  328. package/control-plane/scripts/skills/subagent-driven-development/task-reviewer-prompt.md +207 -0
  329. package/control-plane/scripts/skills/systematic-debugging/CREATION-LOG.md +119 -0
  330. package/control-plane/scripts/skills/systematic-debugging/SKILL.md +283 -0
  331. package/control-plane/scripts/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  332. package/control-plane/scripts/skills/systematic-debugging/condition-based-waiting.md +115 -0
  333. package/control-plane/scripts/skills/systematic-debugging/defense-in-depth.md +122 -0
  334. package/control-plane/scripts/skills/systematic-debugging/find-polluter.sh +72 -0
  335. package/control-plane/scripts/skills/systematic-debugging/root-cause-tracing.md +169 -0
  336. package/control-plane/scripts/skills/systematic-debugging/test-academic.md +14 -0
  337. package/control-plane/scripts/skills/systematic-debugging/test-pressure-1.md +58 -0
  338. package/control-plane/scripts/skills/systematic-debugging/test-pressure-2.md +68 -0
  339. package/control-plane/scripts/skills/systematic-debugging/test-pressure-3.md +69 -0
  340. package/control-plane/scripts/skills/test-driven-development/SKILL.md +330 -0
  341. package/control-plane/scripts/skills/test-driven-development/writing-good-tests.md +198 -0
  342. package/control-plane/scripts/skills/theme-factory/LICENSE.txt +202 -0
  343. package/control-plane/scripts/skills/theme-factory/SKILL.md +59 -0
  344. package/control-plane/scripts/skills/theme-factory/theme-showcase.pdf +0 -0
  345. package/control-plane/scripts/skills/theme-factory/themes/arctic-frost.md +19 -0
  346. package/control-plane/scripts/skills/theme-factory/themes/botanical-garden.md +19 -0
  347. package/control-plane/scripts/skills/theme-factory/themes/desert-rose.md +19 -0
  348. package/control-plane/scripts/skills/theme-factory/themes/forest-canopy.md +19 -0
  349. package/control-plane/scripts/skills/theme-factory/themes/golden-hour.md +19 -0
  350. package/control-plane/scripts/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  351. package/control-plane/scripts/skills/theme-factory/themes/modern-minimalist.md +19 -0
  352. package/control-plane/scripts/skills/theme-factory/themes/ocean-depths.md +19 -0
  353. package/control-plane/scripts/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  354. package/control-plane/scripts/skills/theme-factory/themes/tech-innovation.md +19 -0
  355. package/control-plane/scripts/skills/using-git-worktrees/SKILL.md +167 -0
  356. package/control-plane/scripts/skills/verification-before-completion/SKILL.md +120 -0
  357. package/control-plane/scripts/skills/web-artifacts-builder/LICENSE.txt +202 -0
  358. package/control-plane/scripts/skills/web-artifacts-builder/SKILL.md +74 -0
  359. package/control-plane/scripts/skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  360. package/control-plane/scripts/skills/web-artifacts-builder/scripts/init-artifact.sh +322 -0
  361. package/control-plane/scripts/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  362. package/control-plane/scripts/skills/webapp-testing/LICENSE.txt +202 -0
  363. package/control-plane/scripts/skills/webapp-testing/SKILL.md +96 -0
  364. package/control-plane/scripts/skills/webapp-testing/examples/console_logging.py +35 -0
  365. package/control-plane/scripts/skills/webapp-testing/examples/element_discovery.py +40 -0
  366. package/control-plane/scripts/skills/webapp-testing/examples/static_html_automation.py +33 -0
  367. package/control-plane/scripts/skills/webapp-testing/scripts/with_server.py +106 -0
  368. package/control-plane/scripts/skills/writing-plans/SKILL.md +192 -0
  369. package/control-plane/scripts/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  370. package/control-plane/scripts/skills/writing-skills/SKILL.md +681 -0
  371. package/control-plane/scripts/skills/writing-skills/anthropic-best-practices.md +1150 -0
  372. package/control-plane/scripts/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  373. package/control-plane/scripts/skills/writing-skills/graphviz-conventions.dot +172 -0
  374. package/control-plane/scripts/skills/writing-skills/persuasion-principles.md +187 -0
  375. package/control-plane/scripts/skills/writing-skills/render-graphs.js +169 -0
  376. package/control-plane/scripts/skills/writing-skills/testing-skills-with-subagents.md +384 -0
  377. package/control-plane/scripts/smoke-mcp-schemas.mjs +30 -0
  378. package/control-plane/scripts/surface-config.mjs +45 -0
  379. package/control-plane/scripts/sync-skills.mjs +370 -0
  380. package/control-plane/scripts/tool-metrics.mjs +74 -0
  381. package/control-plane/scripts/tool-risk.mjs +156 -0
  382. package/control-plane/scripts/tool-surface-stability.mjs +38 -0
  383. package/control-plane/scripts/upstreams/catalog-cache.mjs +28 -0
  384. package/control-plane/scripts/upstreams/config.mjs +158 -0
  385. package/control-plane/scripts/upstreams/diagnostics.mjs +21 -0
  386. package/control-plane/scripts/upstreams/http-client.mjs +67 -0
  387. package/control-plane/scripts/upstreams/manager.mjs +535 -0
  388. package/control-plane/scripts/upstreams/names.mjs +55 -0
  389. package/control-plane/scripts/upstreams/presets.mjs +60 -0
  390. package/control-plane/scripts/upstreams/resource-uri.mjs +29 -0
  391. package/control-plane/scripts/upstreams/stdio-client.mjs +73 -0
  392. package/control-plane/scripts/workspace-registry.mjs +147 -0
  393. package/dist/context/authorization.d.ts +5 -0
  394. package/dist/context/authorization.js +70 -0
  395. package/dist/context/capture.d.ts +46 -0
  396. package/dist/context/capture.js +187 -0
  397. package/dist/context/cli.d.ts +47 -0
  398. package/dist/context/cli.js +287 -0
  399. package/dist/context/device-adapter.d.ts +102 -0
  400. package/dist/context/device-adapter.js +79 -0
  401. package/dist/context/gateway.d.ts +354 -0
  402. package/dist/context/gateway.js +50 -0
  403. package/dist/context/graph.d.ts +63 -0
  404. package/dist/context/graph.js +214 -0
  405. package/dist/context/importer.d.ts +8 -0
  406. package/dist/context/importer.js +69 -0
  407. package/dist/context/indexer.d.ts +14 -0
  408. package/dist/context/indexer.js +57 -0
  409. package/dist/context/migrations/index.d.ts +4 -0
  410. package/dist/context/migrations/index.js +87 -0
  411. package/dist/context/redact.d.ts +15 -0
  412. package/dist/context/redact.js +43 -0
  413. package/dist/context/repositories.d.ts +9 -0
  414. package/dist/context/repositories.js +45 -0
  415. package/dist/context/search.d.ts +63 -0
  416. package/dist/context/search.js +207 -0
  417. package/dist/context/service.d.ts +278 -0
  418. package/dist/context/service.js +160 -0
  419. package/dist/context/store.d.ts +134 -0
  420. package/dist/context/store.js +722 -0
  421. package/dist/context/text.d.ts +4 -0
  422. package/dist/context/text.js +14 -0
  423. package/dist/context/tool-contract.d.ts +534 -0
  424. package/dist/context/tool-contract.js +45 -0
  425. package/dist/device/core.d.ts +29 -0
  426. package/dist/device/core.js +66 -0
  427. package/dist/device/device.d.ts +5 -0
  428. package/dist/device/device.js +94 -37
  429. package/dist/device/gateway-channel.d.ts +8 -1
  430. package/dist/device/gateway-channel.js +51 -3
  431. package/dist/device/gateway-tool-adapter.d.ts +11 -3
  432. package/dist/device/gateway-tool-adapter.js +141 -98
  433. package/dist/device/official-trust.d.ts +12 -0
  434. package/dist/device/official-trust.js +25 -1
  435. package/dist/device/runtime-owner.js +9 -1
  436. package/dist/distribution.d.ts +4 -0
  437. package/dist/distribution.js +8 -0
  438. package/dist/handlers/filesystem-handlers.js +53 -37
  439. package/dist/handlers/search-handlers.d.ts +1 -0
  440. package/dist/handlers/search-handlers.js +51 -1
  441. package/dist/log-palace/cli.d.ts +7 -0
  442. package/dist/log-palace/cli.js +89 -0
  443. package/dist/log-palace/formats.d.ts +26 -0
  444. package/dist/log-palace/formats.js +126 -0
  445. package/dist/log-palace/store.d.ts +129 -0
  446. package/dist/log-palace/store.js +856 -0
  447. package/dist/mcp-device.d.ts +1 -1
  448. package/dist/mcp-device.js +28 -6
  449. package/dist/npm-scripts/remote.js +1 -0
  450. package/dist/platform/activity-journal.d.ts +16 -0
  451. package/dist/platform/activity-journal.js +68 -0
  452. package/dist/platform/cli.d.ts +1 -0
  453. package/dist/platform/cli.js +300 -0
  454. package/dist/platform/coordination-lock.d.ts +45 -0
  455. package/dist/platform/coordination-lock.js +233 -0
  456. package/dist/platform/device-runtime.d.ts +16 -0
  457. package/dist/platform/device-runtime.js +83 -0
  458. package/dist/platform/knowledge-contract.d.ts +46 -0
  459. package/dist/platform/knowledge-contract.js +1 -0
  460. package/dist/platform/knowledge-mcp.d.ts +29 -0
  461. package/dist/platform/knowledge-mcp.js +95 -0
  462. package/dist/platform/knowledge-router.d.ts +64 -0
  463. package/dist/platform/knowledge-router.js +320 -0
  464. package/dist/platform/plugin-child.d.ts +1 -0
  465. package/dist/platform/plugin-child.js +115 -0
  466. package/dist/platform/plugin-contract.d.ts +76 -0
  467. package/dist/platform/plugin-contract.js +53 -0
  468. package/dist/platform/plugin-driver.d.ts +8 -0
  469. package/dist/platform/plugin-driver.js +443 -0
  470. package/dist/platform/plugin-host.d.ts +88 -0
  471. package/dist/platform/plugin-host.js +817 -0
  472. package/dist/platform/plugin-policy.d.ts +3 -0
  473. package/dist/platform/plugin-policy.js +29 -0
  474. package/dist/platform/plugin-services.d.ts +14 -0
  475. package/dist/platform/plugin-services.js +32 -0
  476. package/dist/platform/process-identity.d.ts +9 -0
  477. package/dist/platform/process-identity.js +68 -0
  478. package/dist/platform/runtime-lease.d.ts +4 -0
  479. package/dist/platform/runtime-lease.js +58 -0
  480. package/dist/platform/runtime-root.d.ts +9 -0
  481. package/dist/platform/runtime-root.js +61 -0
  482. package/dist/platform/state-backup.d.ts +92 -0
  483. package/dist/platform/state-backup.js +399 -0
  484. package/dist/plugins/reference/plugin.d.ts +3 -0
  485. package/dist/plugins/reference/plugin.js +13 -0
  486. package/dist/search-manager.d.ts +6 -0
  487. package/dist/search-manager.js +123 -0
  488. package/dist/server.d.ts +13 -0
  489. package/dist/server.js +7 -3
  490. package/dist/terminal-manager.d.ts +16 -0
  491. package/dist/terminal-manager.js +137 -42
  492. package/dist/tool-dispatcher.d.ts +11 -0
  493. package/dist/tool-dispatcher.js +228 -0
  494. package/dist/tools/edit.js +72 -1
  495. package/dist/tools/filesystem.d.ts +1 -1
  496. package/dist/tools/filesystem.js +2 -2
  497. package/dist/tools/improved-process-tools.js +91 -108
  498. package/dist/tools/schemas.d.ts +94 -2
  499. package/dist/tools/schemas.js +20 -6
  500. package/dist/types.d.ts +8 -0
  501. package/dist/utils/output-budget.d.ts +6 -0
  502. package/dist/utils/output-budget.js +15 -0
  503. package/dist/version.d.ts +1 -1
  504. package/dist/version.js +1 -1
  505. package/package.json +29 -6
  506. package/skills/mcp-device-context/SKILL.md +40 -0
@@ -0,0 +1,535 @@
1
+ import { loadExternalMcpConfig } from './config.mjs';
2
+ import { createStdioUpstreamClient } from './stdio-client.mjs';
3
+ import { createHttpUpstreamClient } from './http-client.mjs';
4
+ import { createCatalogSnapshot, createCatalogState } from './catalog-cache.mjs';
5
+ import { toExternalToolName, toExternalPromptName, assertNoNameCollision } from './names.mjs';
6
+ import { encodeUpstreamResourceUri, isExternalResourceUri, parseExternalResourceUri, toExternalResourceUri } from './resource-uri.mjs';
7
+ import { diagnosticsResource, summarizeDiagnostics } from './diagnostics.mjs';
8
+ import { selectExternalCatalog } from '../catalog-budget.mjs';
9
+
10
+ function safeError(error) {
11
+ return String(error?.message || error || '').slice(0, 1000);
12
+ }
13
+
14
+ function upstreamToolMeta(server, upstreamName) {
15
+ return { upstreamId: server.id, upstreamToolName: upstreamName, transport: server.transport, source: 'external-mcp' };
16
+ }
17
+
18
+ function upstreamPromptMeta(server, upstreamName) {
19
+ return { upstreamId: server.id, upstreamPromptName: upstreamName, transport: server.transport, source: 'external-mcp' };
20
+ }
21
+
22
+ function upstreamResourceMeta(server, upstreamUri) {
23
+ return { upstreamId: server.id, upstreamUri, transport: server.transport, source: 'external-mcp' };
24
+ }
25
+
26
+ function timeout(ms, label) {
27
+ return new Promise(resolve => {
28
+ setTimeout(() => resolve({ timedOut: true, label }), Math.max(0, ms));
29
+ });
30
+ }
31
+
32
+ export async function closeClientWithTimeout(client, defaultShutdownTimeoutMs = 5000) {
33
+ const result = await Promise.race([
34
+ client.close().then(() => ({ ok: true })).catch(error => ({ ok: false, error: safeError(error) })),
35
+ timeout(client.config?.shutdownTimeoutMs ?? defaultShutdownTimeoutMs, `upstream ${client.id} close`)
36
+ ]);
37
+ if (result?.timedOut) {
38
+ console.log(`[external-mcp] ${client.id} close timed out`);
39
+ client.kill?.('SIGTERM');
40
+ if (typeof client.isRunning === 'function') {
41
+ const killTimer = setTimeout(() => {
42
+ if (client.isRunning?.()) client.kill?.('SIGKILL');
43
+ }, 1000);
44
+ killTimer.unref?.();
45
+ }
46
+ }
47
+ if (result?.error) console.log(`[external-mcp] ${client.id} close failed: ${result.error}`);
48
+ }
49
+
50
+ async function safeList(server, kind, fn, emptyResult = {}) {
51
+ try {
52
+ return { ok: true, result: await fn(), error: null };
53
+ } catch (error) {
54
+ return { ok: false, result: emptyResult, error: `${kind}: ${safeError(error)}` };
55
+ }
56
+ }
57
+
58
+ function hasCapability(client, capability) {
59
+ return Boolean(client?.capabilities?.[capability]);
60
+ }
61
+
62
+ function skippedList(emptyResult = {}) {
63
+ return { ok: true, result: emptyResult, error: null, skipped: true };
64
+ }
65
+
66
+ function addServerStatus(statuses, server, patch) {
67
+ const previous = statuses.get(server.id) || {};
68
+ statuses.set(server.id, {
69
+ enabled: true,
70
+ available: previous.available ?? true,
71
+ transport: server.transport,
72
+ startedAt: previous.startedAt || null,
73
+ toolCount: previous.toolCount || 0,
74
+ resourceCount: previous.resourceCount || 0,
75
+ resourceTemplateCount: previous.resourceTemplateCount || 0,
76
+ promptCount: previous.promptCount || 0,
77
+ lastError: previous.lastError || null,
78
+ lastRefreshError: previous.lastRefreshError || null,
79
+ lastCatalogRefreshAt: previous.lastCatalogRefreshAt || null,
80
+ ...patch
81
+ });
82
+ }
83
+
84
+ export async function buildExternalCatalog({ servers, clients, localToolNames = [], localPromptNames = [], generation = 0, statuses = new Map(), externalConfig = {} }) {
85
+ const snapshot = createCatalogSnapshot({ generation, builtAt: new Date().toISOString() });
86
+ const toolNames = new Set(localToolNames);
87
+ const promptNames = new Set(localPromptNames);
88
+ const resourceUris = new Set();
89
+ const serverDiagnostics = new Map();
90
+
91
+ for (const server of servers) {
92
+ const client = clients.get(server.id);
93
+ if (!client) {
94
+ const previous = statuses.get(server.id);
95
+ const error = previous?.lastError || 'External MCP upstream unavailable';
96
+ serverDiagnostics.set(server.id, { error });
97
+ addServerStatus(statuses, server, { available: false, lastRefreshError: error, lastError: error });
98
+ continue;
99
+ }
100
+
101
+ const supportsResources = hasCapability(client, 'resources');
102
+ const supportsPrompts = hasCapability(client, 'prompts');
103
+ const [toolList, resourceList, templateList, promptList] = await Promise.all([
104
+ safeList(server, 'tools/list', () => client.listTools(), { tools: [] }),
105
+ supportsResources ? safeList(server, 'resources/list', () => client.listResources(), { resources: [] }) : skippedList({ resources: [] }),
106
+ supportsResources ? safeList(server, 'resources/templates/list', () => client.listResourceTemplates(), { resourceTemplates: [] }) : skippedList({ resourceTemplates: [] }),
107
+ supportsPrompts ? safeList(server, 'prompts/list', () => client.listPrompts(), { prompts: [] }) : skippedList({ prompts: [] })
108
+ ]);
109
+
110
+ const errors = [toolList, resourceList, templateList, promptList].filter(item => !item.ok).map(item => item.error);
111
+ if (errors.length > 0) {
112
+ const error = errors.join('; ');
113
+ serverDiagnostics.set(server.id, { error });
114
+ addServerStatus(statuses, server, {
115
+ available: true,
116
+ lastRefreshError: error,
117
+ lastError: error,
118
+ lastCatalogRefreshAt: snapshot.builtAt
119
+ });
120
+ throw new Error(`External MCP catalog refresh failed for ${server.id}: ${error}`);
121
+ } else {
122
+ serverDiagnostics.set(server.id, { error: null });
123
+ }
124
+
125
+ for (const tool of toolList.result.tools || []) {
126
+ const exposedName = toExternalToolName(server.toolPrefix, tool.name);
127
+ assertNoNameCollision(exposedName, toolNames, 'tool');
128
+ const exposed = {
129
+ ...tool,
130
+ name: exposedName,
131
+ _meta: {
132
+ ...(tool._meta || {}),
133
+ upstream: upstreamToolMeta(server, tool.name)
134
+ }
135
+ };
136
+ snapshot.tools.push(exposed);
137
+ snapshot.toolRoutes.set(exposedName, { serverId: server.id, upstreamToolName: tool.name, tool: exposed });
138
+ }
139
+
140
+ for (const resource of resourceList.result.resources || []) {
141
+ const exposedUri = toExternalResourceUri(server.id, resource.uri);
142
+ if (resourceUris.has(exposedUri)) throw new Error(`External MCP resource URI collision: ${exposedUri}`);
143
+ resourceUris.add(exposedUri);
144
+ snapshot.resources.push({
145
+ ...resource,
146
+ uri: exposedUri,
147
+ _meta: { ...(resource._meta || {}), upstream: upstreamResourceMeta(server, resource.uri) }
148
+ });
149
+ snapshot.resourceRoutes.set(exposedUri, { serverId: server.id, upstreamUri: resource.uri });
150
+ }
151
+
152
+ const upstreamTemplates = templateList.result.resourceTemplates || [];
153
+ if (upstreamTemplates.length > 0) {
154
+ snapshot.resourceTemplates.push({
155
+ uriTemplate: `external-mcp://${server.id}/{encodedUpstreamUri}`,
156
+ name: `${server.id} external resource`,
157
+ description: `Read an encoded upstream resource URI from ${server.id}. Upstream templates are listed in _meta.upstream.resourceTemplates.`,
158
+ mimeType: 'application/octet-stream',
159
+ _meta: {
160
+ upstream: {
161
+ upstreamId: server.id,
162
+ source: 'external-mcp',
163
+ routeFormat: `external-mcp://${server.id}/<base64url-upstream-uri>`,
164
+ resourceTemplates: upstreamTemplates.map(template => ({
165
+ name: template.name || null,
166
+ uriTemplate: template.uriTemplate,
167
+ mimeType: template.mimeType || null,
168
+ description: template.description || null,
169
+ encodedTemplate: encodeUpstreamResourceUri(template.uriTemplate)
170
+ }))
171
+ }
172
+ }
173
+ });
174
+ }
175
+
176
+ for (const prompt of promptList.result.prompts || []) {
177
+ const exposedName = toExternalPromptName(server.toolPrefix, prompt.name);
178
+ assertNoNameCollision(exposedName, promptNames, 'prompt');
179
+ snapshot.prompts.push({
180
+ ...prompt,
181
+ name: exposedName,
182
+ _meta: { ...(prompt._meta || {}), upstream: upstreamPromptMeta(server, prompt.name) }
183
+ });
184
+ snapshot.promptRoutes.set(exposedName, { serverId: server.id, upstreamPromptName: prompt.name });
185
+ }
186
+
187
+ addServerStatus(statuses, server, {
188
+ available: true,
189
+ toolCount: (toolList.result.tools || []).length,
190
+ resourceCount: (resourceList.result.resources || []).length,
191
+ resourceTemplateCount: upstreamTemplates.length,
192
+ promptCount: (promptList.result.prompts || []).length,
193
+ lastError: errors.length ? errors.join('; ') : null,
194
+ lastRefreshError: errors.length ? errors.join('; ') : null,
195
+ lastCatalogRefreshAt: snapshot.builtAt
196
+ });
197
+ }
198
+
199
+ snapshot.diagnostics = Object.fromEntries(serverDiagnostics.entries());
200
+ snapshot.exposure = selectExternalCatalog(snapshot.tools, externalConfig, servers);
201
+ return snapshot;
202
+ }
203
+
204
+ function serverSignature(server) {
205
+ return JSON.stringify({
206
+ transport: server.transport,
207
+ toolPrefix: server.toolPrefix,
208
+ command: server.command,
209
+ args: server.args || [],
210
+ cwd: server.cwd,
211
+ url: server.url,
212
+ bearerTokenEnv: server.bearerTokenEnv,
213
+ startupTimeoutMs: server.startupTimeoutMs,
214
+ shutdownTimeoutMs: server.shutdownTimeoutMs
215
+ });
216
+ }
217
+
218
+ function catalogKeys(snapshot) {
219
+ const exposedTools = snapshot.exposure?.eagerTools ?? snapshot.tools ?? [];
220
+ return {
221
+ tools: exposedTools.map(item => item.name).sort().join('\n'),
222
+ resources: (snapshot.resources || []).map(item => item.uri).sort().join('\n') + '\n' +
223
+ (snapshot.resourceTemplates || []).map(item => item.uriTemplate).sort().join('\n'),
224
+ prompts: (snapshot.prompts || []).map(item => item.name).sort().join('\n')
225
+ };
226
+ }
227
+
228
+ export async function createExternalMcpManager({
229
+ env = process.env,
230
+ repoRoot = process.cwd(),
231
+ localToolNames = [],
232
+ localPromptNames = [],
233
+ onCatalogChanged = async () => {},
234
+ clientFactory = null
235
+ } = {}) {
236
+ let config = await loadExternalMcpConfig({ env, repoRoot });
237
+ let servers = config.servers;
238
+ let clients = new Map();
239
+ let statuses = new Map();
240
+ const createClient = clientFactory || (async server => server.transport === 'stdio'
241
+ ? await createStdioUpstreamClient(server)
242
+ : await createHttpUpstreamClient(server));
243
+
244
+ async function markFailureIn(statusMap, configValue, server, error) {
245
+ addServerStatus(statusMap, server, {
246
+ available: false,
247
+ startedAt: null,
248
+ toolCount: 0,
249
+ resourceCount: 0,
250
+ resourceTemplateCount: 0,
251
+ promptCount: 0,
252
+ lastError: safeError(error),
253
+ lastRefreshError: safeError(error)
254
+ });
255
+ if (configValue.external.fail_gateway_on_startup_error) throw error;
256
+ }
257
+
258
+ async function startServerInto(server, clientMap, statusMap, configValue, { allowUnavailable = true } = {}) {
259
+ try {
260
+ const client = await createClient(server);
261
+ clientMap.set(server.id, client);
262
+ addServerStatus(statusMap, server, {
263
+ enabled: true,
264
+ available: true,
265
+ startedAt: new Date().toISOString(),
266
+ lastError: null,
267
+ lastRefreshError: null
268
+ });
269
+ return client;
270
+ } catch (error) {
271
+ console.log(`[external-mcp] ${server.id} unavailable: ${safeError(error)}`);
272
+ await markFailureIn(statusMap, configValue, server, error);
273
+ if (!allowUnavailable) throw error;
274
+ return null;
275
+ }
276
+ }
277
+
278
+ async function closeStartedClients() {
279
+ await Promise.all([...clients.values()].map(client => closeClientWithTimeout(client, config.external.shutdown_timeout_ms)));
280
+ clients.clear();
281
+ }
282
+
283
+ try {
284
+ for (const server of servers) await startServerInto(server, clients, statuses, config);
285
+ } catch (error) {
286
+ await closeStartedClients();
287
+ throw error;
288
+ }
289
+
290
+ const catalogState = createCatalogState();
291
+ const knownExternalToolNames = new Set();
292
+ const knownExternalPromptNames = new Set();
293
+
294
+ async function commitRefresh({ notify = true } = {}) {
295
+ const nextGeneration = catalogState.generation + 1;
296
+ const candidateStatuses = new Map(statuses);
297
+ const candidate = await buildExternalCatalog({
298
+ servers,
299
+ clients,
300
+ localToolNames,
301
+ localPromptNames,
302
+ generation: nextGeneration,
303
+ statuses: candidateStatuses,
304
+ externalConfig: config.external
305
+ });
306
+ for (const [id, status] of candidateStatuses.entries()) statuses.set(id, status);
307
+ const previous = catalogState.snapshot;
308
+ catalogState.snapshot = candidate;
309
+ catalogState.generation = nextGeneration;
310
+ catalogState.lastRefreshAt = candidate.builtAt;
311
+ catalogState.lastRefreshError = null;
312
+ for (const tool of candidate.tools) knownExternalToolNames.add(tool.name);
313
+ for (const prompt of candidate.prompts) knownExternalPromptNames.add(prompt.name);
314
+ for (const server of servers) {
315
+ const status = statuses.get(server.id);
316
+ console.log(`[external-mcp] ${server.id} catalog tools=${status?.toolCount || 0} resources=${status?.resourceCount || 0} prompts=${status?.promptCount || 0}`);
317
+ }
318
+ if (notify) {
319
+ const before = catalogKeys(previous);
320
+ const after = catalogKeys(candidate);
321
+ const changes = {
322
+ toolsChanged: before.tools !== after.tools,
323
+ resourcesChanged: before.resources !== after.resources,
324
+ promptsChanged: before.prompts !== after.prompts
325
+ };
326
+ if (changes.toolsChanged || changes.resourcesChanged || changes.promptsChanged) {
327
+ await onCatalogChanged(changes);
328
+ }
329
+ }
330
+ return candidate;
331
+ }
332
+
333
+ async function refreshCatalog(options = {}) {
334
+ if (catalogState.refreshInFlight) return await catalogState.refreshInFlight;
335
+ catalogState.refreshInFlight = (async () => {
336
+ try {
337
+ return await commitRefresh(options);
338
+ } catch (error) {
339
+ catalogState.lastRefreshError = safeError(error);
340
+ return catalogState.snapshot;
341
+ } finally {
342
+ catalogState.refreshInFlight = null;
343
+ }
344
+ })();
345
+ return await catalogState.refreshInFlight;
346
+ }
347
+
348
+ await refreshCatalog({ notify: false });
349
+ if (catalogState.lastRefreshError && config.external.fail_gateway_on_startup_error) {
350
+ await closeStartedClients();
351
+ throw new Error(catalogState.lastRefreshError);
352
+ }
353
+
354
+ async function snapshotForCatalogList() {
355
+ const mode = config.external.catalog_cache;
356
+ if (mode === 'startup') return catalogState.snapshot;
357
+ if (mode === 'none') return await refreshCatalog({ notify: false });
358
+ const last = catalogState.lastRefreshAt ? Date.parse(catalogState.lastRefreshAt) : 0;
359
+ if (Date.now() - last <= config.external.catalog_cache_ttl_ms) return catalogState.snapshot;
360
+ return await refreshCatalog({ notify: false });
361
+ }
362
+
363
+ function currentSnapshot() {
364
+ return catalogState.snapshot;
365
+ }
366
+
367
+ async function reconcile(nextConfig) {
368
+ const resolvedConfig = nextConfig || await loadExternalMcpConfig({ env, repoRoot });
369
+ if (catalogState.refreshInFlight) await catalogState.refreshInFlight;
370
+
371
+ const previousServers = servers;
372
+ const previousClients = clients;
373
+ const previousStatuses = statuses;
374
+ const previousSnapshot = catalogState.snapshot;
375
+ const previousGeneration = catalogState.generation;
376
+ const previousById = new Map(previousServers.map(server => [server.id, server]));
377
+ const nextServers = resolvedConfig.servers;
378
+ const nextById = new Map(nextServers.map(server => [server.id, server]));
379
+ const candidateClients = new Map();
380
+ const candidateStatuses = new Map(previousStatuses);
381
+ const stagedClients = [];
382
+ let candidate;
383
+
384
+ try {
385
+ for (const next of nextServers) {
386
+ const previous = previousById.get(next.id);
387
+ const unchanged = previous && serverSignature(previous) === serverSignature(next);
388
+ const committedClient = previousClients.get(next.id);
389
+ if (unchanged && committedClient) {
390
+ candidateClients.set(next.id, committedClient);
391
+ continue;
392
+ }
393
+ const staged = await startServerInto(next, candidateClients, candidateStatuses, resolvedConfig, { allowUnavailable: false });
394
+ if (staged) stagedClients.push(staged);
395
+ }
396
+
397
+ for (const previous of previousServers) {
398
+ if (nextById.has(previous.id)) continue;
399
+ const prior = candidateStatuses.get(previous.id) || {};
400
+ candidateStatuses.set(previous.id, {
401
+ ...prior,
402
+ enabled: false,
403
+ available: false,
404
+ toolCount: 0,
405
+ resourceCount: 0,
406
+ resourceTemplateCount: 0,
407
+ promptCount: 0,
408
+ lastError: null,
409
+ lastRefreshError: null
410
+ });
411
+ }
412
+
413
+ candidate = await buildExternalCatalog({
414
+ servers: nextServers,
415
+ clients: candidateClients,
416
+ localToolNames,
417
+ localPromptNames,
418
+ generation: previousGeneration + 1,
419
+ statuses: candidateStatuses,
420
+ externalConfig: resolvedConfig.external
421
+ });
422
+ } catch (error) {
423
+ await Promise.all(stagedClients.map(client => closeClientWithTimeout(client, resolvedConfig.external.shutdown_timeout_ms)));
424
+ catalogState.lastRefreshError = safeError(error);
425
+ throw new Error(`External MCP reconcile failed; committed topology preserved: ${safeError(error)}`);
426
+ }
427
+
428
+ config = resolvedConfig;
429
+ servers = nextServers;
430
+ clients = candidateClients;
431
+ statuses = candidateStatuses;
432
+ catalogState.snapshot = candidate;
433
+ catalogState.generation = candidate.generation;
434
+ catalogState.lastRefreshAt = candidate.builtAt;
435
+ catalogState.lastRefreshError = null;
436
+ for (const tool of candidate.tools) knownExternalToolNames.add(tool.name);
437
+ for (const prompt of candidate.prompts) knownExternalPromptNames.add(prompt.name);
438
+
439
+ const retiredClients = [];
440
+ for (const [id, client] of previousClients.entries()) {
441
+ if (candidateClients.get(id) !== client) retiredClients.push(client);
442
+ }
443
+ await Promise.all(retiredClients.map(client => closeClientWithTimeout(client, resolvedConfig.external.shutdown_timeout_ms)));
444
+
445
+ const before = catalogKeys(previousSnapshot);
446
+ const after = catalogKeys(candidate);
447
+ const changes = {
448
+ toolsChanged: before.tools !== after.tools,
449
+ resourcesChanged: before.resources !== after.resources,
450
+ promptsChanged: before.prompts !== after.prompts
451
+ };
452
+ if (changes.toolsChanged || changes.resourcesChanged || changes.promptsChanged) {
453
+ await Promise.resolve(onCatalogChanged(changes)).catch(error => {
454
+ console.log(`[external-mcp] catalog notification failed: ${safeError(error)}`);
455
+ });
456
+ }
457
+ return candidate;
458
+ }
459
+
460
+ function diagnosticsList() {
461
+ return [
462
+ { uri: 'external-mcp://_diagnostics/status', name: 'External MCP diagnostics', mimeType: 'application/json' },
463
+ ...[...statuses.keys()].map(id => ({ uri: `external-mcp://${id}/status`, name: `External MCP ${id} status`, mimeType: 'application/json' }))
464
+ ];
465
+ }
466
+
467
+ return {
468
+ get config() { return config; },
469
+ async listAllToolsUnfiltered() {
470
+ const snapshot = await snapshotForCatalogList();
471
+ return [...(snapshot.exposure?.eagerTools ?? snapshot.tools)];
472
+ },
473
+ async listToolsForProfile() {
474
+ const snapshot = await snapshotForCatalogList();
475
+ return [...(snapshot.exposure?.eagerTools ?? snapshot.tools)];
476
+ },
477
+ getCachedTools() { return [...currentSnapshot().tools]; },
478
+ isEagerToolName(name) {
479
+ const snapshot = currentSnapshot();
480
+ return (snapshot.exposure?.eagerTools ?? snapshot.tools).some(tool => tool.name === name);
481
+ },
482
+ hasTool(name) { return currentSnapshot().toolRoutes.has(name); },
483
+ isExternalToolName(name) { return currentSnapshot().toolRoutes.has(name) || knownExternalToolNames.has(name); },
484
+ isExternalPromptName(name) { return currentSnapshot().promptRoutes.has(name) || knownExternalPromptNames.has(name); },
485
+ assertToolAllowedForProfile(name) {
486
+ return currentSnapshot().toolRoutes.has(name);
487
+ },
488
+ async callTool(name, args = {}) {
489
+ const route = currentSnapshot().toolRoutes.get(name);
490
+ if (!route) throw new Error(`Unknown external MCP tool: ${name}`);
491
+ const client = clients.get(route.serverId);
492
+ if (!client) throw new Error(`External MCP upstream unavailable: ${route.serverId}`);
493
+ return await client.callTool({ name: route.upstreamToolName, arguments: args });
494
+ },
495
+ async listResources() {
496
+ return [...diagnosticsList(), ...(await snapshotForCatalogList()).resources];
497
+ },
498
+ async listResourceTemplates() { return [...(await snapshotForCatalogList()).resourceTemplates]; },
499
+ async readResource(uri) {
500
+ if (!isExternalResourceUri(uri)) throw new Error(`Unsupported external MCP resource URI: ${uri}`);
501
+ const parsed = parseExternalResourceUri(uri);
502
+ if (parsed.diagnostics && parsed.serverId === '_diagnostics') return diagnosticsResource(uri, summarizeDiagnostics(statuses, catalogState, config));
503
+ if (parsed.diagnostics) return diagnosticsResource(uri, statuses.get(parsed.serverId) || { enabled: false, available: false, lastError: 'Unknown upstream' });
504
+ const route = currentSnapshot().resourceRoutes.get(uri) || { serverId: parsed.serverId, upstreamUri: parsed.upstreamUri };
505
+ const client = clients.get(route.serverId);
506
+ if (!client) throw new Error(`External MCP upstream unavailable: ${route.serverId}`);
507
+ const result = await client.readResource({ uri: route.upstreamUri });
508
+ return {
509
+ ...result,
510
+ contents: (result.contents || []).map(content => ({
511
+ ...content,
512
+ uri,
513
+ _meta: { ...(content._meta || {}), upstream: { upstreamId: route.serverId, upstreamUri: route.upstreamUri, source: 'external-mcp' } }
514
+ }))
515
+ };
516
+ },
517
+ async listPrompts() { return [...(await snapshotForCatalogList()).prompts]; },
518
+ hasPrompt(name) { return currentSnapshot().promptRoutes.has(name); },
519
+ async getPrompt(name, args = {}) {
520
+ const route = currentSnapshot().promptRoutes.get(name);
521
+ if (!route) throw new Error(`Unknown external MCP prompt: ${name}`);
522
+ const client = clients.get(route.serverId);
523
+ if (!client) throw new Error(`External MCP upstream unavailable: ${route.serverId}`);
524
+ return await client.getPrompt({ name: route.upstreamPromptName, arguments: args });
525
+ },
526
+ getDiagnostics() { return summarizeDiagnostics(statuses, catalogState, config); },
527
+ reconcile,
528
+ async shutdown() {
529
+ await Promise.all([...clients.values()].map(client => closeClientWithTimeout(client, config.external.shutdown_timeout_ms)));
530
+ },
531
+ _refreshForTests: refreshCatalog,
532
+ _reconcileForTests: reconcile,
533
+ _catalogStateForTests: catalogState
534
+ };
535
+ }
@@ -0,0 +1,55 @@
1
+ const ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/;
2
+ const RESERVED_TOOL_PREFIXES = new Set(['custom']);
3
+
4
+ export function validateUpstreamId(id, label = 'upstream id') {
5
+ const value = String(id ?? '').trim();
6
+ if (!ID_PATTERN.test(value)) {
7
+ throw new Error(`Invalid ${label}: ${id}. Expected ${ID_PATTERN}.`);
8
+ }
9
+ if (value.includes('..') || /[\\/]/.test(value)) {
10
+ throw new Error(`Invalid ${label}: ${id}. Path separators and dot-dot are not allowed.`);
11
+ }
12
+ return value;
13
+ }
14
+
15
+ export function validateExternalToolPrefix(prefix, label = 'tool prefix') {
16
+ const value = validateUpstreamId(prefix, label);
17
+ if (RESERVED_TOOL_PREFIXES.has(value)) {
18
+ throw new Error(`Invalid ${label}: ${value}. This prefix is reserved for local gateway tools.`);
19
+ }
20
+ return value;
21
+ }
22
+
23
+ export function normalizeCapabilityName(name) {
24
+ const raw = String(name ?? '').trim().toLowerCase();
25
+ const normalized = raw.replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '').replace(/_+/g, '_');
26
+ return normalized || 'unnamed';
27
+ }
28
+
29
+ function stripDuplicatePrefix(prefix, capabilityName) {
30
+ const normalizedPrefix = normalizeCapabilityName(validateUpstreamId(prefix, 'capability prefix'));
31
+ const normalizedName = normalizeCapabilityName(capabilityName);
32
+ const marker = `${normalizedPrefix}_`;
33
+ if (normalizedName.startsWith(marker) && normalizedName.length > marker.length) {
34
+ return normalizedName.slice(marker.length);
35
+ }
36
+ return normalizedName;
37
+ }
38
+
39
+ export function toExternalToolName(serverPrefix, upstreamToolName) {
40
+ const prefix = validateUpstreamId(serverPrefix, 'tool prefix');
41
+ return `${prefix}_${stripDuplicatePrefix(prefix, upstreamToolName)}`;
42
+ }
43
+
44
+ export function toExternalPromptName(serverPrefix, upstreamPromptName) {
45
+ const prefix = validateUpstreamId(serverPrefix, 'prompt prefix');
46
+ return `${prefix}_${stripDuplicatePrefix(prefix, upstreamPromptName)}`;
47
+ }
48
+
49
+ export function assertNoNameCollision(name, seen, kind = 'capability') {
50
+ if (seen.has(name)) {
51
+ throw new Error(`External MCP ${kind} name collision: ${name}`);
52
+ }
53
+ seen.add(name);
54
+ return name;
55
+ }
@@ -0,0 +1,60 @@
1
+ import os from 'node:os';
2
+
3
+ export function normalizeRunnerCommand(runner, platform = process.platform) {
4
+ const value = String(runner ?? '').trim().toLowerCase();
5
+ if (!value) return undefined;
6
+ if (value === 'npx') return platform === 'win32' ? 'npx.cmd' : 'npx';
7
+ throw new Error(`Unsupported MCP runner: ${runner}`);
8
+ }
9
+
10
+ export function expandPlaceholders(value, { repoRoot = process.cwd(), cwd, home = os.homedir(), env = process.env } = {}) {
11
+ if (typeof value !== 'string') return value;
12
+ return value.replace(/\$\{([^}]+)\}/g, (match, name) => {
13
+ if (name === 'repoRoot') return repoRoot;
14
+ if (name === 'home') return home;
15
+ if (name === 'cwd') return cwd || repoRoot;
16
+ if (name.startsWith('env:')) {
17
+ const envName = name.slice(4);
18
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(envName)) throw new Error(`Invalid env placeholder: ${match}`);
19
+ return env[envName] || '';
20
+ }
21
+ return match;
22
+ });
23
+ }
24
+
25
+ function hasExplicitArgs(serverRaw) {
26
+ return Object.prototype.hasOwnProperty.call(serverRaw, 'args');
27
+ }
28
+
29
+ function withPresetDefaults(serverRaw, defaults) {
30
+ return { ...defaults, ...serverRaw, preset: serverRaw.preset };
31
+ }
32
+
33
+ export function expandMcpPreset(id, serverRaw = {}, context = {}) {
34
+ const preset = String(serverRaw.preset || '').trim().toLowerCase();
35
+ if (!preset) return { ...serverRaw };
36
+ const runnerCommand = normalizeRunnerCommand(serverRaw.runner || 'npx', context.platform);
37
+ const explicitArgs = hasExplicitArgs(serverRaw);
38
+
39
+ if (preset === 'eslint') {
40
+ return withPresetDefaults(serverRaw, {
41
+ transport: 'stdio',
42
+ command: serverRaw.command || runnerCommand,
43
+ args: explicitArgs ? serverRaw.args : ['-y', '@eslint/mcp@latest'],
44
+ cwd: serverRaw.cwd || '${repoRoot}',
45
+ startup_timeout_ms: 30000,
46
+ shutdown_timeout_ms: 5000,
47
+ tool_prefix: id
48
+ });
49
+ }
50
+
51
+ if (preset === 'context7') {
52
+ return withPresetDefaults(serverRaw, {
53
+ transport: 'http',
54
+ url: 'https://mcp.context7.com/mcp',
55
+ tool_prefix: id
56
+ });
57
+ }
58
+
59
+ throw new Error(`Unknown MCP preset for ${id}: ${serverRaw.preset}`);
60
+ }
@@ -0,0 +1,29 @@
1
+ const SCHEME = 'external-mcp://';
2
+
3
+ export function encodeUpstreamResourceUri(upstreamUri) {
4
+ return Buffer.from(String(upstreamUri ?? ''), 'utf8').toString('base64url');
5
+ }
6
+
7
+ export function decodeUpstreamResourceUri(encoded) {
8
+ return Buffer.from(String(encoded ?? ''), 'base64url').toString('utf8');
9
+ }
10
+
11
+ export function toExternalResourceUri(serverId, upstreamUri) {
12
+ return `${SCHEME}${encodeURIComponent(serverId)}/${encodeUpstreamResourceUri(upstreamUri)}`;
13
+ }
14
+
15
+ export function isExternalResourceUri(uri) {
16
+ return String(uri || '').startsWith(SCHEME);
17
+ }
18
+
19
+ export function parseExternalResourceUri(uri) {
20
+ const text = String(uri || '');
21
+ if (!isExternalResourceUri(text)) throw new Error(`Not an external MCP resource URI: ${uri}`);
22
+ const match = text.match(/^external-mcp:\/\/([^/]+)\/(.+)$/);
23
+ if (!match) throw new Error(`Invalid external MCP resource URI: ${uri}`);
24
+ const serverId = decodeURIComponent(match[1]);
25
+ if (serverId === '_diagnostics') return { diagnostics: true, serverId, upstreamUri: 'status' };
26
+ const encoded = match[2].replace(/[?#].*$/, '');
27
+ if (encoded === 'status') return { diagnostics: true, serverId, upstreamUri: 'status' };
28
+ return { diagnostics: false, serverId, upstreamUri: decodeUpstreamResourceUri(encoded) };
29
+ }