@redocly/reef 0.137.0-next.5 → 0.137.0-next.7

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 (273) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/api-schemas/otel-traces.d.ts +1359 -0
  3. package/dist/api-schemas/otel-traces.js +1 -0
  4. package/dist/cli/stats/collectors/asyncapi/index.d.ts +3 -0
  5. package/dist/cli/stats/collectors/asyncapi/index.js +1 -0
  6. package/dist/cli/stats/collectors/extension-sampling.d.ts +44 -0
  7. package/dist/cli/stats/collectors/extension-sampling.js +1 -0
  8. package/dist/cli/stats/collectors/openapi/index.js +1 -1
  9. package/dist/cli/stats/collectors/prepare-stats-walk.d.ts +10 -0
  10. package/dist/cli/stats/collectors/prepare-stats-walk.js +1 -0
  11. package/dist/cli/stats/collectors/run-stats-collector.d.ts +24 -0
  12. package/dist/cli/stats/collectors/run-stats-collector.js +1 -0
  13. package/dist/cli/stats/index.js +1 -1
  14. package/dist/client/app/hooks/useMcpData.d.ts +1 -0
  15. package/dist/client/app/hooks/useMcpData.js +1 -1
  16. package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
  17. package/dist/client/providers/hooks.js +1 -1
  18. package/dist/client/providers/post-message/PostMessageProvider.js +1 -1
  19. package/dist/client/templates/api-docs/helpers.d.ts +4 -1
  20. package/dist/client/templates/api-docs/helpers.js +5 -1
  21. package/dist/client/templates/api-docs/template.js +1 -1
  22. package/dist/constants/l10n/langs/ar.js +1 -1
  23. package/dist/constants/l10n/langs/de.js +1 -1
  24. package/dist/constants/l10n/langs/en.js +1 -1
  25. package/dist/constants/l10n/langs/es.js +1 -1
  26. package/dist/constants/l10n/langs/fr.js +1 -1
  27. package/dist/constants/l10n/langs/hi.js +1 -1
  28. package/dist/constants/l10n/langs/it.js +1 -1
  29. package/dist/constants/l10n/langs/ja.js +1 -1
  30. package/dist/constants/l10n/langs/ko.js +1 -1
  31. package/dist/constants/l10n/langs/pl.js +1 -1
  32. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  33. package/dist/constants/l10n/langs/pt.js +1 -1
  34. package/dist/constants/l10n/langs/ru.js +1 -1
  35. package/dist/constants/l10n/langs/uk.js +1 -1
  36. package/dist/constants/l10n/langs/zh.js +1 -1
  37. package/dist/server/config/env-config.d.ts +2 -0
  38. package/dist/server/config/env-schema.d.ts +5 -0
  39. package/dist/server/config/env-schemas/feature-flags.d.ts +4 -0
  40. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  41. package/dist/server/constants/mcp.d.ts +5 -0
  42. package/dist/server/constants/mcp.js +1 -0
  43. package/dist/server/constants/rbac.d.ts +3 -0
  44. package/dist/server/constants/rbac.js +1 -0
  45. package/dist/server/esbuild/esbuild.js +3 -3
  46. package/dist/server/esbuild/plugins/mcp-tool-handlers-resolver.js +1 -1
  47. package/dist/server/plugins/api-docs/options.js +1 -1
  48. package/dist/server/plugins/api-docs/search/get-ai-search-documents.js +9 -9
  49. package/dist/server/plugins/api-docs/search/search-indexer.js +1 -1
  50. package/dist/server/plugins/{openapi-docs/is-openapi-doc.d.ts → api-docs/utils/is-api-doc.d.ts} +4 -2
  51. package/dist/server/plugins/api-docs/utils/is-api-doc.js +1 -0
  52. package/dist/server/plugins/arazzo-docs/arazzo-doc-loader.d.ts +1 -1
  53. package/dist/server/plugins/arazzo-docs/arazzo-doc-loader.js +1 -1
  54. package/dist/server/plugins/entitlements/index.js +1 -1
  55. package/dist/server/plugins/l10n/index.js +1 -1
  56. package/dist/server/plugins/lifecycle.js +2 -2
  57. package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.js +1 -1
  58. package/dist/server/plugins/markdown/attribute-resolvers/resolve-open-api-ref.js +1 -1
  59. package/dist/server/plugins/mcp/auth/auth-handlers.d.ts +1 -2
  60. package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
  61. package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +4 -4
  62. package/dist/server/plugins/mcp/codemode/code-execution-telemetry.d.ts +3 -1
  63. package/dist/server/plugins/mcp/codemode/code-execution-telemetry.js +1 -1
  64. package/dist/server/plugins/mcp/codemode/invoke-tool.js +1 -1
  65. package/dist/server/plugins/mcp/codemode/prompts.js +1 -1
  66. package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.d.ts +1 -1
  67. package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.js +9 -3
  68. package/dist/server/plugins/mcp/codemode/tools/describe-tools.d.ts +1 -1
  69. package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -1
  70. package/dist/server/plugins/mcp/codemode/tools/execute-schema.js +1 -1
  71. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
  72. package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -2
  73. package/dist/server/plugins/mcp/codemode/types.d.ts +1 -0
  74. package/dist/server/plugins/mcp/constants.d.ts +1 -1
  75. package/dist/server/plugins/mcp/constants.js +1 -1
  76. package/dist/server/plugins/mcp/custom-tools/extract-tool-definition.d.ts +13 -0
  77. package/dist/server/plugins/mcp/custom-tools/extract-tool-definition.js +1 -0
  78. package/dist/server/plugins/mcp/custom-tools/scan-custom-tools.d.ts +6 -0
  79. package/dist/server/plugins/mcp/custom-tools/scan-custom-tools.js +1 -0
  80. package/dist/server/plugins/mcp/custom-tools/validate-tool-definition.d.ts +3 -0
  81. package/dist/server/plugins/mcp/custom-tools/validate-tool-definition.js +1 -0
  82. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +2 -0
  83. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  84. package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +2 -2
  85. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -1
  86. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
  87. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
  88. package/dist/server/plugins/mcp/gateway-mcp/callable-apis.d.ts +10 -0
  89. package/dist/server/plugins/mcp/gateway-mcp/callable-apis.js +1 -0
  90. package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +3 -2
  91. package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +5 -4
  92. package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -1
  93. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.d.ts +2 -1
  94. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.js +1 -1
  95. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
  96. package/dist/server/plugins/mcp/gateway-mcp/fetch/upstream-detail.d.ts +7 -0
  97. package/dist/server/plugins/mcp/gateway-mcp/fetch/upstream-detail.js +1 -0
  98. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +1 -9
  99. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
  100. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +6 -0
  101. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -1
  102. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  103. package/dist/server/plugins/mcp/handlers/errors.d.ts +6 -1
  104. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  105. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  106. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +1 -1
  107. package/dist/server/plugins/mcp/handlers/mcp-credentials-page.d.ts +6 -0
  108. package/dist/server/plugins/mcp/handlers/mcp-credentials-page.js +50 -42
  109. package/dist/server/plugins/mcp/index.d.ts +0 -2
  110. package/dist/server/plugins/mcp/index.js +1 -1
  111. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  112. package/dist/server/plugins/mcp/servers/mcp-server.js +3 -3
  113. package/dist/server/plugins/mcp/types.d.ts +30 -3
  114. package/dist/server/plugins/mcp/utils/available-sandbox-tools.d.ts +4 -0
  115. package/dist/server/plugins/mcp/utils/available-sandbox-tools.js +1 -0
  116. package/dist/server/plugins/mcp/utils/find-gated-tool-names.d.ts +2 -3
  117. package/dist/server/plugins/mcp/utils/find-gated-tool-names.js +1 -1
  118. package/dist/server/plugins/mcp/utils/mcp-client.d.ts +13 -0
  119. package/dist/server/plugins/mcp/utils/mcp-client.js +1 -0
  120. package/dist/server/plugins/mcp/utils/tool-registration.d.ts +17 -0
  121. package/dist/server/plugins/mcp/utils/tool-registration.js +1 -0
  122. package/dist/server/plugins/mcp/workers/execute-mcp-tool.d.ts +6 -1
  123. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  124. package/dist/server/plugins/mcp/workers/import-mcp-tool-handlers.d.ts +5 -0
  125. package/dist/server/plugins/mcp/workers/import-mcp-tool-handlers.js +1 -0
  126. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +6 -11
  127. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
  128. package/dist/server/plugins/mcp/workers/tool-file-system.d.ts +6 -0
  129. package/dist/server/plugins/mcp/workers/tool-file-system.js +1 -0
  130. package/dist/server/sandbox/sandbox.js +2 -2
  131. package/dist/server/sandbox/utils/returns-from-top-level.d.ts +4 -0
  132. package/dist/server/sandbox/utils/returns-from-top-level.js +1 -0
  133. package/dist/server/store.d.ts +1 -0
  134. package/dist/server/store.js +1 -1
  135. package/dist/server/types/plugins/common.d.ts +3 -1
  136. package/dist/server/utils/rbac/can-anonymous-access-mcp-feature.d.ts +3 -0
  137. package/dist/server/utils/rbac/can-anonymous-access-mcp-feature.js +1 -0
  138. package/dist/server/utils/rbac/should-handle-mcp-auth.d.ts +2 -0
  139. package/dist/server/utils/rbac/should-handle-mcp-auth.js +1 -0
  140. package/dist/server/utils/rbac.js +1 -1
  141. package/dist/server/web-server/auth.js +3 -3
  142. package/dist/server/web-server/handle-api-route-request.js +1 -1
  143. package/dist/server/web-server/routes/error.js +1 -1
  144. package/dist/server/web-server/routes/helpers/resolve-ui-locales-for-idp-login.js +1 -1
  145. package/dist/server/web-server/routes/index.js +1 -1
  146. package/dist/server/web-server/routes/mcp-routes/agent-card.js +1 -1
  147. package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
  148. package/dist/server/web-server/routes/otel/otel.js +1 -1
  149. package/dist/server/web-server/routes/page-data.js +1 -1
  150. package/dist/server/web-server/routes/resolve-route.js +1 -1
  151. package/dist/server/web-server/utils/get-request-origin.d.ts +2 -0
  152. package/dist/server/web-server/utils/get-request-origin.js +1 -1
  153. package/dist/server/web-server/utils/prepare-list-response.d.ts +0 -4
  154. package/dist/server/web-server/utils/prepare-list-response.js +1 -1
  155. package/dist/server/web-server/utils.d.ts +1 -1
  156. package/dist/server/web-server/utils.js +1 -1
  157. package/dist/server/workers/mcp-tool-worker-pool.d.ts +1 -0
  158. package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
  159. package/dist/server/workers/mcp-tool-worker.js +1 -1
  160. package/dist/server/workers/types.d.ts +9 -2
  161. package/dist/server/workers/worker-pool.d.ts +1 -0
  162. package/dist/server/workers/worker-pool.js +1 -1
  163. package/dist/types/global-data.d.ts +1 -0
  164. package/dist/utils/guards/is-plain-object.d.ts +19 -0
  165. package/dist/utils/guards/is-plain-object.js +1 -0
  166. package/package.json +6 -9
  167. package/dist/client/templates/asyncapi-docs/helpers.d.ts +0 -12
  168. package/dist/client/templates/asyncapi-docs/helpers.js +0 -1
  169. package/dist/client/templates/asyncapi-docs/template.d.ts +0 -15
  170. package/dist/client/templates/asyncapi-docs/template.js +0 -9
  171. package/dist/client/templates/openapi-docs/helpers.d.ts +0 -18
  172. package/dist/client/templates/openapi-docs/helpers.js +0 -5
  173. package/dist/client/templates/openapi-docs/template.d.ts +0 -6
  174. package/dist/client/templates/openapi-docs/template.js +0 -14
  175. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.d.ts +0 -9
  176. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.js +0 -1
  177. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.d.ts +0 -2
  178. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.js +0 -1
  179. package/dist/server/esbuild/plugins/api-docs-module-replacer/index.d.ts +0 -6
  180. package/dist/server/esbuild/plugins/api-docs-module-replacer/index.js +0 -1
  181. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-check.d.ts +0 -8
  182. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-check.js +0 -1
  183. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-overlay.d.ts +0 -2
  184. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-overlay.js +0 -1
  185. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-use-license-key.d.ts +0 -5
  186. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-use-license-key.js +0 -1
  187. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/index.d.ts +0 -6
  188. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/index.js +0 -1
  189. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/loadAndBundleSpec.mock.d.ts +0 -3
  190. package/dist/server/esbuild/plugins/openapi-docs-module-replacer/loadAndBundleSpec.mock.js +0 -1
  191. package/dist/server/plugins/asyncapi-docs/asyncapi-doc-loader.d.ts +0 -18
  192. package/dist/server/plugins/asyncapi-docs/asyncapi-doc-loader.js +0 -5
  193. package/dist/server/plugins/asyncapi-docs/get-server-props.d.ts +0 -4
  194. package/dist/server/plugins/asyncapi-docs/get-server-props.js +0 -1
  195. package/dist/server/plugins/asyncapi-docs/get-template-path.d.ts +0 -2
  196. package/dist/server/plugins/asyncapi-docs/get-template-path.js +0 -1
  197. package/dist/server/plugins/asyncapi-docs/index.d.ts +0 -3
  198. package/dist/server/plugins/asyncapi-docs/index.js +0 -1
  199. package/dist/server/plugins/asyncapi-docs/is-asyncapi-doc.d.ts +0 -3
  200. package/dist/server/plugins/asyncapi-docs/is-asyncapi-doc.js +0 -1
  201. package/dist/server/plugins/asyncapi-docs/search/get-ai-search-documents.d.ts +0 -9
  202. package/dist/server/plugins/asyncapi-docs/search/get-ai-search-documents.js +0 -56
  203. package/dist/server/plugins/asyncapi-docs/search/schema-processor.d.ts +0 -8
  204. package/dist/server/plugins/asyncapi-docs/search/schema-processor.js +0 -1
  205. package/dist/server/plugins/asyncapi-docs/search/search-facets.d.ts +0 -8
  206. package/dist/server/plugins/asyncapi-docs/search/search-facets.js +0 -1
  207. package/dist/server/plugins/asyncapi-docs/search/search-resolver.d.ts +0 -5
  208. package/dist/server/plugins/asyncapi-docs/search/search-resolver.js +0 -1
  209. package/dist/server/plugins/asyncapi-docs/store-definition-bundles.d.ts +0 -4
  210. package/dist/server/plugins/asyncapi-docs/store-definition-bundles.js +0 -1
  211. package/dist/server/plugins/graphql-docs/constants.d.ts +0 -2
  212. package/dist/server/plugins/graphql-docs/constants.js +0 -1
  213. package/dist/server/plugins/graphql-docs/get-template-path.d.ts +0 -2
  214. package/dist/server/plugins/graphql-docs/get-template-path.js +0 -1
  215. package/dist/server/plugins/graphql-docs/graphql-doc-loader.d.ts +0 -17
  216. package/dist/server/plugins/graphql-docs/graphql-doc-loader.js +0 -1
  217. package/dist/server/plugins/graphql-docs/index.d.ts +0 -4
  218. package/dist/server/plugins/graphql-docs/index.js +0 -1
  219. package/dist/server/plugins/graphql-docs/is-graphql-doc.d.ts +0 -2
  220. package/dist/server/plugins/graphql-docs/is-graphql-doc.js +0 -1
  221. package/dist/server/plugins/graphql-docs/search/ai/get-ai-search-document.d.ts +0 -17
  222. package/dist/server/plugins/graphql-docs/search/ai/get-ai-search-document.js +0 -4
  223. package/dist/server/plugins/graphql-docs/search/ai/utils.d.ts +0 -14
  224. package/dist/server/plugins/graphql-docs/search/ai/utils.js +0 -36
  225. package/dist/server/plugins/graphql-docs/search/search-facets.d.ts +0 -8
  226. package/dist/server/plugins/graphql-docs/search/search-facets.js +0 -1
  227. package/dist/server/plugins/graphql-docs/search/search-resolver.d.ts +0 -5
  228. package/dist/server/plugins/graphql-docs/search/search-resolver.js +0 -1
  229. package/dist/server/plugins/graphql-docs/spec-download.api.d.ts +0 -3
  230. package/dist/server/plugins/graphql-docs/spec-download.api.js +0 -1
  231. package/dist/server/plugins/graphql-docs/template/GraphQLDocs.d.ts +0 -5
  232. package/dist/server/plugins/graphql-docs/template/GraphQLDocs.js +0 -4
  233. package/dist/server/plugins/graphql-docs/types.d.ts +0 -40
  234. package/dist/server/plugins/graphql-docs/types.js +0 -0
  235. package/dist/server/plugins/openapi-docs/ai-search-indexer.d.ts +0 -14
  236. package/dist/server/plugins/openapi-docs/ai-search-indexer.js +0 -1
  237. package/dist/server/plugins/openapi-docs/decorators.d.ts +0 -25
  238. package/dist/server/plugins/openapi-docs/decorators.js +0 -1
  239. package/dist/server/plugins/openapi-docs/format-bundle-error.d.ts +0 -6
  240. package/dist/server/plugins/openapi-docs/format-bundle-error.js +0 -5
  241. package/dist/server/plugins/openapi-docs/get-server-props.d.ts +0 -4
  242. package/dist/server/plugins/openapi-docs/get-server-props.js +0 -1
  243. package/dist/server/plugins/openapi-docs/get-template-path.d.ts +0 -2
  244. package/dist/server/plugins/openapi-docs/get-template-path.js +0 -1
  245. package/dist/server/plugins/openapi-docs/index.d.ts +0 -3
  246. package/dist/server/plugins/openapi-docs/index.js +0 -1
  247. package/dist/server/plugins/openapi-docs/is-openapi-doc.js +0 -1
  248. package/dist/server/plugins/openapi-docs/load-definition.d.ts +0 -31
  249. package/dist/server/plugins/openapi-docs/load-definition.js +0 -3
  250. package/dist/server/plugins/openapi-docs/openapi-search-builder.d.ts +0 -24
  251. package/dist/server/plugins/openapi-docs/openapi-search-builder.js +0 -1
  252. package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.d.ts +0 -18
  253. package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.js +0 -94
  254. package/dist/server/plugins/openapi-docs/search/search-facets.d.ts +0 -11
  255. package/dist/server/plugins/openapi-docs/search/search-facets.js +0 -1
  256. package/dist/server/plugins/openapi-docs/search/search-resolver.d.ts +0 -5
  257. package/dist/server/plugins/openapi-docs/search/search-resolver.js +0 -1
  258. package/dist/server/plugins/openapi-docs/search-indexer.d.ts +0 -17
  259. package/dist/server/plugins/openapi-docs/search-indexer.js +0 -1
  260. package/dist/server/plugins/openapi-docs/spec-download.api.d.ts +0 -4
  261. package/dist/server/plugins/openapi-docs/spec-download.api.js +0 -1
  262. package/dist/server/plugins/openapi-docs/store-definition-bundles.d.ts +0 -4
  263. package/dist/server/plugins/openapi-docs/store-definition-bundles.js +0 -1
  264. package/dist/server/plugins/openapi-docs/types.d.ts +0 -17
  265. package/dist/server/plugins/openapi-docs/types.js +0 -0
  266. package/dist/server/plugins/openapi-docs/utils.d.ts +0 -25
  267. package/dist/server/plugins/openapi-docs/utils.js +0 -1
  268. /package/dist/client/templates/{openapi-docs → api-docs}/mock-server-config.d.ts +0 -0
  269. /package/dist/client/templates/{openapi-docs → api-docs}/mock-server-config.js +0 -0
  270. /package/dist/{server/plugins → markdoc}/helpers/parse-partials.d.ts +0 -0
  271. /package/dist/{server/plugins → markdoc}/helpers/parse-partials.js +0 -0
  272. /package/dist/server/plugins/{openapi-docs → api-docs/utils}/ast-utils.d.ts +0 -0
  273. /package/dist/server/plugins/{openapi-docs → api-docs/utils}/ast-utils.js +0 -0
@@ -1 +1 @@
1
- import{secretStore as u}from"../gateway-mcp/secret-store.js";import{rejectCredential as k}from"../gateway-mcp/credential-validation.js";import{buildAllowedHostMatchers as P}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as A}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as R,getDefaultAgent as j}from"../gateway-mcp/fetch/fetch-bridge.js";import{logger as O}from"../../../tools/notifiers/logger.js";import{clearedPage as v,formPage as C,notFoundPage as N,successPage as y}from"./mcp-credentials-page.js";const m={"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","X-Frame-Options":"DENY","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; form-action 'self'"},I=3e4,D=64*1024;let x=fetch;function Q(e){x=e}const F=async(e,r)=>{const t=await r.getKv();if(e.method==="GET"){const n=new URL(e.url).searchParams.get("token")??"",o=await u.peekElicitation(t,n);return o?new Response(C(o,n),{status:200,headers:m}):f()}if(e.method==="POST"){const n=await e.formData(),o=d(n,"token"),s=d(n,"mode")||"token";return s==="multi"?B(t,n,o):s==="client-credentials"?G(t,n,o):s==="clear"?U(t,o):M(t,n,o)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function M(e,r,t){const n=d(r,"secret").trim(),o=await u.peekElicitation(e,t);if(!o)return f();const s=k(o.auth,n);if(s)return p(o,t,s);const l=await u.consumeElicitation(e,t);return l?(await u.setSecret(e,l.subject,l.api,l.scheme,S(l.auth,n)),new Response(y(l),{status:200,headers:m})):f()}async function U(e,r){const t=await u.consumeElicitation(e,r);return t?(await u.deleteSecret(e,t.subject,t.api,t.scheme),new Response(v(t),{status:200,headers:m})):f()}async function B(e,r,t){const n=await u.peekElicitation(e,t);if(!n?.schemes||n.schemes.length<=1)return f();const o=n.schemes,s=[];for(let a=0;a<o.length;a++){const i=o[a];if(i.hasExistingSecret&&d(r,`remove__${a}`)){s.push({kind:"remove",scheme:i.name});continue}const h=d(r,`secret__${a}`).trim();if(i.auth.kind==="oauth2ClientCredentials"){const E=d(r,`client_id__${a}`).trim(),_=d(r,`client_secret__${a}`).trim();if(h){const b=k(i.auth,h);if(b)return p(n,t,`${i.name}: ${b}`);s.push({kind:"set",scheme:i.name,secret:S(i.auth,h)})}else if(E&&_)s.push({kind:"exchange",scheme:i.name,auth:i.auth,clientId:E,clientSecret:_});else if(E||_)return p(n,t,`${i.name}: enter both the client ID and the client secret, or leave both blank.`);continue}if(!h)continue;const w=k(i.auth,h);if(w)return p(n,t,`${i.name}: ${w}`);s.push({kind:"set",scheme:i.name,secret:S(i.auth,h)})}if(s.length===0)return p(n,t,"Fill in at least one credential, or check a box to remove one, before saving.");const l=[];for(const a of s){if(a.kind!=="exchange"){l.push(a);continue}const i=await $(a.auth,a.clientId,a.clientSecret);if(!i.ok)return T(n,t,i.reason,a.scheme);l.push({kind:"set",scheme:a.scheme,secret:i.secret})}const c=await u.consumeElicitation(e,t);if(!c)return f();for(const a of l)a.kind==="remove"?await u.deleteSecret(e,c.subject,c.api,a.scheme):await u.setSecret(e,c.subject,c.api,a.scheme,a.secret);return new Response(y(c),{status:200,headers:m})}async function G(e,r,t){const n=d(r,"client_id").trim(),o=d(r,"client_secret").trim(),s=await u.peekElicitation(e,t);if(!s||s.auth.kind!=="oauth2ClientCredentials")return f();if(!n||!o)return p(s,t,"Enter both the client ID and the client secret before saving.");const l=await $(s.auth,n,o);if(!l.ok)return T(s,t,l.reason);const c=await u.consumeElicitation(e,t);return c?(await u.setSecret(e,c.subject,c.api,c.scheme,l.secret),new Response(y(c),{status:200,headers:m})):f()}async function $(e,r,t){try{const n=P([{url:e.tokenUrl}]),o=A(e.tokenUrl,n),s=new AbortController,l=setTimeout(()=>s.abort(),I);let c;try{c=await x(o,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:r,client_secret:t}),redirect:"manual",signal:s.signal,dispatcher:j()})}finally{clearTimeout(l)}if(!c.ok)return g(`token endpoint returned ${c.status}`);let a;try{a=await R(c,D)}catch{return g("token response exceeded the size cap")}let i;try{i=JSON.parse(a)}catch{return g("token response was not valid JSON")}const h=typeof i=="object"&&i!==null&&"access_token"in i?i.access_token:void 0,w=typeof h=="string"?h.trim():"";return w?{ok:!0,secret:{header:"Authorization",value:`Bearer ${w}`}}:g("token response had no access_token")}catch(n){return g(n instanceof Error?n.message:String(n))}}function g(e){return{ok:!1,reason:e}}function T(e,r,t,n){return O.warn(`gateway oauth2 client_credentials exchange failed for ${e.api}: ${t}`),p(e,r,`${n?`${n}: we`:"We"} could not exchange those client credentials for a token. Check the client ID and secret, then try again.`)}function d(e,r){const t=e.get(r);return typeof t=="string"?t:""}function p(e,r,t){return new Response(C(e,r,t),{status:400,headers:m})}function f(){return new Response(N(),{status:404,headers:m})}function S(e,r){return e.kind==="apiKey"?{header:e.header,value:r}:e.kind==="cookie"?{header:"Cookie",value:`${e.name}=${r}`}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:H(r)}:{header:"Authorization",value:r}}function H(e){const r=e.trim();return r.toLowerCase().startsWith("bearer")?r:`Bearer ${r}`}var V=F;export{V as default,Q as setCredentialsFetchImpl};
1
+ import{secretStore as u}from"../gateway-mcp/secret-store.js";import{rejectCredential as y}from"../gateway-mcp/credential-validation.js";import{buildAllowedHostMatchers as R}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as j}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as v,getDefaultAgent as O}from"../gateway-mcp/fetch/fetch-bridge.js";import{logger as N}from"../../../tools/notifiers/logger.js";import{clearedPage as F,formPage as x,multiOutcomePage as I,notFoundPage as D,successPage as $}from"./mcp-credentials-page.js";const w={"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","X-Frame-Options":"DENY","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; form-action 'self'"},M=3e4,U=64*1024;let P=fetch;function q(e){P=e}const B=async(e,i)=>{const t=await i.getKv();if(e.method==="GET"){const n=new URL(e.url).searchParams.get("token")??"",o=await u.peekElicitation(t,n);return o?new Response(x(o,n),{status:200,headers:w}):m()}if(e.method==="POST"){const n=await e.formData(),o=d(n,"token"),a=d(n,"mode")||"token";return a==="multi"?z(t,n,o):a==="client-credentials"?K(t,n,o):a==="clear"?H(t,o):G(t,n,o)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function G(e,i,t){const n=d(i,"secret").trim(),o=await u.peekElicitation(e,t);if(!o)return m();const a=y(o.auth,n);if(a)return h(o,t,a);const l=await u.consumeElicitation(e,t);return l?(await u.setSecret(e,l.subject,l.api,l.scheme,E(l.auth,n)),new Response($(l),{status:200,headers:w})):m()}async function H(e,i){const t=await u.consumeElicitation(e,i);return t?(await u.deleteSecret(e,t.subject,t.api,t.scheme),new Response(F(t),{status:200,headers:w})):m()}async function z(e,i,t){const n=await u.peekElicitation(e,t);if(!n?.schemes||n.schemes.length<=1)return m();const o=n.schemes,a=[];for(let r=0;r<o.length;r++){const s=o[r],p=d(i,`secret__${r}`).trim(),S=d(i,`client_id__${r}`).trim(),b=d(i,`client_secret__${r}`).trim();if(s.hasExistingSecret&&d(i,`remove__${r}`)){if(p||S||b)return h(n,t,`${s.name}: enter a new value or tick "Remove the stored credential", not both.`);a.push({kind:"remove",scheme:s.name});continue}if(s.auth.kind==="oauth2ClientCredentials"){if(p){const C=y(s.auth,p);if(C)return h(n,t,`${s.name}: ${C}`);a.push({kind:"set",scheme:s.name,secret:E(s.auth,p)})}else if(S&&b)a.push({kind:"exchange",scheme:s.name,auth:s.auth,clientId:S,clientSecret:b});else if(S||b)return h(n,t,`${s.name}: enter both the client ID and the client secret, or leave both blank.`);continue}if(!p)continue;const _=y(s.auth,p);if(_)return h(n,t,`${s.name}: ${_}`);a.push({kind:"set",scheme:s.name,secret:E(s.auth,p)})}if(a.length===0)return h(n,t,"Fill in at least one credential, or check a box to remove one, before saving.");const l=[];for(const r of a){if(r.kind!=="exchange"){l.push(r);continue}const s=await T(r.auth,r.clientId,r.clientSecret);if(!s.ok)return A(n,t,s.reason,r.scheme);l.push({kind:"set",scheme:r.scheme,secret:s.secret})}const c=await u.consumeElicitation(e,t);if(!c)return m();for(const r of l)r.kind==="remove"?await u.deleteSecret(e,c.subject,c.api,r.scheme):await u.setSecret(e,c.subject,c.api,r.scheme,r.secret);const k=await u.getSecretsForSubject(e,c.subject),f={saved:l.filter(r=>r.kind==="set").map(r=>r.scheme),removed:l.filter(r=>r.kind==="remove").map(r=>r.scheme),stored:Object.keys(k[c.api]??{})};return new Response(I(c,f),{status:200,headers:w})}async function K(e,i,t){const n=d(i,"client_id").trim(),o=d(i,"client_secret").trim(),a=await u.peekElicitation(e,t);if(!a||a.auth.kind!=="oauth2ClientCredentials")return m();if(!n||!o)return h(a,t,"Enter both the client ID and the client secret before saving.");const l=await T(a.auth,n,o);if(!l.ok)return A(a,t,l.reason);const c=await u.consumeElicitation(e,t);return c?(await u.setSecret(e,c.subject,c.api,c.scheme,l.secret),new Response($(c),{status:200,headers:w})):m()}async function T(e,i,t){try{const n=R([{url:e.tokenUrl}]),o=j(e.tokenUrl,n),a=new AbortController,l=setTimeout(()=>a.abort(),M);let c;try{c=await P(o,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:i,client_secret:t}),redirect:"manual",signal:a.signal,dispatcher:O()})}finally{clearTimeout(l)}if(!c.ok)return g(`token endpoint returned ${c.status}`);let k;try{k=await v(c,U)}catch{return g("token response exceeded the size cap")}let f;try{f=JSON.parse(k)}catch{return g("token response was not valid JSON")}const r=typeof f=="object"&&f!==null&&"access_token"in f?f.access_token:void 0,s=typeof r=="string"?r.trim():"";return s?{ok:!0,secret:{header:"Authorization",value:`Bearer ${s}`}}:g("token response had no access_token")}catch(n){return g(n instanceof Error?n.message:String(n))}}function g(e){return{ok:!1,reason:e}}function A(e,i,t,n){return N.warn(`gateway oauth2 client_credentials exchange failed for ${e.api}: ${t}`),h(e,i,`${n?`${n}: we`:"We"} could not exchange those client credentials for a token. Check the client ID and secret, then try again.`)}function d(e,i){const t=e.get(i);return typeof t=="string"?t:""}function h(e,i,t){return new Response(x(e,i,t),{status:400,headers:w})}function m(){return new Response(D(),{status:404,headers:w})}function E(e,i){return e.kind==="apiKey"?{header:e.header,value:i}:e.kind==="cookie"?{header:"Cookie",value:`${e.name}=${i}`}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:X(i)}:{header:"Authorization",value:i}}function X(e){const i=e.trim();return i.toLowerCase().startsWith("bearer")?i:`Bearer ${i}`}var ee=B;export{ee as default,q as setCredentialsFetchImpl};
@@ -1,6 +1,12 @@
1
1
  import type { ElicitationTarget } from '../gateway-mcp/secret-store.js';
2
2
  export declare function formPage(target: ElicitationTarget, token: string, error?: string): string;
3
3
  export declare function clearedPage(target: ElicitationTarget): string;
4
+ export type MultiOutcome = {
5
+ saved: readonly string[];
6
+ removed: readonly string[];
7
+ stored: readonly string[];
8
+ };
9
+ export declare function multiOutcomePage(target: ElicitationTarget, outcome: MultiOutcome): string;
4
10
  export declare function successPage(target: ElicitationTarget): string;
5
11
  export declare function notFoundPage(): string;
6
12
  //# sourceMappingURL=mcp-credentials-page.d.ts.map
@@ -1,4 +1,4 @@
1
- import{ELICITATION_TTL_MS as p}from"../gateway-mcp/secret-store.js";const h=6,f=`<svg class="logo" width="193" height="56" viewBox="0 0 193 56" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Redocly">
1
+ import{ELICITATION_TTL_MS as m}from"../gateway-mcp/secret-store.js";const f=6,b=`<svg class="logo" width="193" height="56" viewBox="0 0 193 56" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Redocly">
2
2
  <g clip-path="url(#redocly-logo-clip)">
3
3
  <path d="M84.3634 40.7533H80.0357L73.199 30.9849H69.8119V40.8155H66.1738V14.5592H76.3353C78.9067 14.5592 80.9139 15.368 82.2308 16.9857C83.5483 18.5412 84.1756 20.5322 84.1756 22.8343C84.1756 25.0119 83.6107 26.7541 82.4193 28.3095C81.2902 29.865 79.5339 30.7361 77.2134 30.8605L84.3634 40.7533ZM69.8743 17.8568V27.6251H76.2098C79.22 27.6251 80.5999 25.4475 80.5999 22.7098C80.5999 20.0344 79.22 17.7945 76.3353 17.7945H69.8743V17.8568Z" fill="currentColor"/>
4
4
  <path d="M103.117 33.225H88.5654C89.0042 36.1492 91.2623 38.078 94.3355 38.078C96.5312 38.078 98.5384 37.0203 99.4789 35.3403C99.8553 35.4648 100.357 35.7137 101.047 35.9626L102.553 36.4603C101.047 39.5091 97.9111 41.1889 94.2731 41.1889C91.701 41.1889 89.506 40.3179 87.6873 38.638C85.931 36.8959 85.1152 34.7182 85.1152 31.9184C85.1152 29.1185 85.9934 26.9409 87.6873 25.2609C89.4436 23.5188 91.6386 22.71 94.2731 22.71C96.8445 22.71 98.9771 23.581 100.608 25.2609C102.302 26.9409 103.18 29.1807 103.18 31.9184C103.117 32.5405 103.117 32.9139 103.117 33.225ZM99.6674 30.4873C99.228 27.563 97.0954 25.7587 94.21 25.7587C91.1999 25.7587 88.9418 27.6252 88.5654 30.4873H99.6674Z" fill="currentColor"/>
@@ -13,7 +13,7 @@ import{ELICITATION_TTL_MS as p}from"../gateway-mcp/secret-store.js";const h=6,f=
13
13
  <path d="M28.5385 16.6127H44.4703C45.3484 16.6127 46.0383 15.9282 46.0383 15.0572C46.0383 14.1861 45.3484 13.5017 44.4703 13.5017H28.5385C27.6604 13.5017 26.9705 14.1861 26.9705 15.0572C26.9077 15.8661 27.6604 16.6127 28.5385 16.6127Z" fill="currentColor"/>
14
14
  </g>
15
15
  <defs><clipPath id="redocly-logo-clip"><rect width="193" height="56" fill="white"/></clipPath></defs>
16
- </svg>`;function n(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function s(e){return`<!doctype html>
16
+ </svg>`;function r(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function s(e){return`<!doctype html>
17
17
  <html lang="en">
18
18
  <head>
19
19
  <meta charset="utf-8">
@@ -66,7 +66,9 @@ body{font-family:var(--font);margin:0;min-height:100vh;display:flex;align-items:
66
66
  .logo{color:var(--brand);height:28px;width:auto;display:block;margin:0 0 1.5rem}
67
67
  h1{font-size:1.25rem;line-height:1.3;font-weight:600;margin:0 0 .5rem;letter-spacing:-.01em}
68
68
  .section{margin-top:1.5rem;padding-top:1.5rem;border-top:1px solid var(--border)}
69
- .section h2{font-size:.9375rem;font-weight:600;margin:0 0 .5rem}
69
+ .section h2{font-size:.9375rem;font-weight:600;margin:0 0 .5rem;display:flex;align-items:center;gap:.5rem}
70
+ .badge{font-size:.6875rem;font-weight:600;line-height:1;padding:.25rem .5rem;border-radius:999px;border:1px solid var(--border-strong);color:var(--text-muted);background:var(--code-bg)}
71
+ .badge.stored{color:var(--action);border-color:var(--action)}
70
72
  p{margin:.75rem 0 0}
71
73
  p.hint{color:var(--text-muted);font-size:.8125rem;line-height:1.45}
72
74
  p.error{margin:1rem 0 0;padding:.75rem;border:1px solid var(--error-border);border-radius:6px;background:var(--error-bg);color:var(--error-text);font-size:.8125rem;line-height:1.45}
@@ -86,22 +88,22 @@ label.check input{width:auto;margin:0}
86
88
  footer{margin-top:1.5rem;padding-top:1rem;border-top:1px solid var(--border);font-size:.75rem;color:var(--text-muted);text-align:center;line-height:1.45}
87
89
  </style>
88
90
  </head>
89
- <body><main class="card">${f}${e}</main></body>
90
- </html>`}function l(e){return`<h1>\u{1F512} ${n(e)}</h1>`}function d(){return"<footer>Secured by Redocly &middot; Credentials never enter the AI conversation</footer>"}function c(){return`<p class="hint">This link expires ${Math.round(p/6e4)} minutes after it was issued. If it stops working, request a new one in your AI client.</p>`}function u({name:e,schemeLabel:t,schemes:o}){return o&&o.length>1?e:t?`${e} (${t})`:e}function b(e){return`
91
+ <body><main class="card">${b}${e}</main></body>
92
+ </html>`}function l(e){return`<h1>\u{1F512} ${r(e)}</h1>`}function d(){return"<footer>Secured by Redocly &middot; Credentials never enter the AI conversation</footer>"}function c(){return`<p class="hint">This link expires ${Math.round(m/6e4)} minutes after it was issued. If it stops working, request a new one in your AI client.</p>`}function p({name:e,schemeLabel:t,schemes:o}){return o&&o.length>1?e:t?`${e} (${t})`:e}function g(e){return`
91
93
  <div class="section">
92
94
  <h2>Remove stored credentials</h2>
93
95
  <p class="hint">This API already has credentials stored. Enter new credentials to replace them, or remove them to make calls anonymous again.</p>
94
96
  <form method="post" action="/mcp/credentials" autocomplete="off">
95
- <input type="hidden" name="token" value="${n(e)}">
97
+ <input type="hidden" name="token" value="${r(e)}">
96
98
  <input type="hidden" name="mode" value="clear">
97
99
  <button class="danger" type="submit">Remove credentials</button>
98
100
  </form>
99
- </div>`}function H(e,t,o){const r=o?`<p class="error">${n(o)}</p>`:"";if(e.schemes&&e.schemes.length>1)return x(e,e.schemes,t,r);const a=e.hasExistingSecret?b(t):"",i=u(e);switch(e.auth.kind){case"bearer":return C(i,t,a,r);case"apiKey":return g(i,t,e.auth.header,a,r);case"cookie":return v(i,t,e.auth.name,a,r);case"oauth2ClientCredentials":return y(i,t,e.auth.scopes,a,r);default:return $(i,t,a,r)}}function C(e,t,o,r){return s(`
101
+ </div>`}function M(e,t,o){const n=o?`<p class="error">${r(o)}</p>`:"";if(e.schemes&&e.schemes.length>1)return k(e,e.schemes,t,n);const a=e.hasExistingSecret?g(t):"",i=p(e);switch(e.auth.kind){case"bearer":return C(i,t,a,n);case"apiKey":return v(i,t,e.auth.header,a,n);case"cookie":return y(i,t,e.auth.name,a,n);case"oauth2ClientCredentials":return $(i,t,e.auth.scopes,a,n);default:return x(i,t,a,n)}}function C(e,t,o,n){return s(`
100
102
  ${l(`Credentials for ${e}`)}
101
- ${r}
103
+ ${n}
102
104
  <p class="hint">Encrypted and visible only to you for 24 hours (anonymous) or 30 days (signed in).<br />Sent to the API as the <code>Authorization header</code>. It never passes through the AI conversation.</p>
103
105
  <form method="post" action="/mcp/credentials" autocomplete="off">
104
- <input type="hidden" name="token" value="${n(t)}">
106
+ <input type="hidden" name="token" value="${r(t)}">
105
107
  <input type="hidden" name="mode" value="token">
106
108
  <label for="secret">API token</label>
107
109
  <input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
@@ -110,41 +112,41 @@ ${r}
110
112
  </form>
111
113
  ${o}
112
114
  ${c()}
113
- ${d()}`)}function g(e,t,o,r,a){return s(`
115
+ ${d()}`)}function v(e,t,o,n,a){return s(`
114
116
  ${l(`Credentials for ${e}`)}
115
117
  ${a}
116
- <p class="hint">Encrypted and visible only to you for 24 hours (anonymous) or 30 days (signed in).<br />Sent to the API as the <code>${n(o)}</code> header. It never passes through the AI conversation.</p>
118
+ <p class="hint">Encrypted and visible only to you for 24 hours (anonymous) or 30 days (signed in).<br />Sent to the API as the <code>${r(o)}</code> header. It never passes through the AI conversation.</p>
117
119
  <form method="post" action="/mcp/credentials" autocomplete="off">
118
- <input type="hidden" name="token" value="${n(t)}">
120
+ <input type="hidden" name="token" value="${r(t)}">
119
121
  <input type="hidden" name="mode" value="token">
120
- <label for="secret">${n(o)} value</label>
122
+ <label for="secret">${r(o)} value</label>
121
123
  <input type="password" id="secret" name="secret" placeholder="value" required autofocus>
122
124
  <button type="submit">Save credentials</button>
123
125
  </form>
124
- ${r}
126
+ ${n}
125
127
  ${c()}
126
- ${d()}`)}function v(e,t,o,r,a){return s(`
128
+ ${d()}`)}function y(e,t,o,n,a){return s(`
127
129
  ${l(`Credentials for ${e}`)}
128
130
  ${a}
129
- <p class="hint">Encrypted and visible only to you for 24 hours (anonymous) or 30 days (signed in).<br />Sent to the API as the <code>${n(o)}</code> cookie. It never passes through the AI conversation.</p>
131
+ <p class="hint">Encrypted and visible only to you for 24 hours (anonymous) or 30 days (signed in).<br />Sent to the API as the <code>${r(o)}</code> cookie. It never passes through the AI conversation.</p>
130
132
  <form method="post" action="/mcp/credentials" autocomplete="off">
131
- <input type="hidden" name="token" value="${n(t)}">
133
+ <input type="hidden" name="token" value="${r(t)}">
132
134
  <input type="hidden" name="mode" value="token">
133
- <label for="secret">${n(o)} cookie value</label>
135
+ <label for="secret">${r(o)} cookie value</label>
134
136
  <input type="password" id="secret" name="secret" placeholder="value" required autofocus>
135
- <p class="hint">Paste only the value. It's sent as <code>${n(o)}=&lt;value&gt;</code>.</p>
137
+ <p class="hint">Paste only the value. It's sent as <code>${r(o)}=&lt;value&gt;</code>.</p>
136
138
  <button type="submit">Save credentials</button>
137
139
  </form>
138
- ${r}
140
+ ${n}
139
141
  ${c()}
140
- ${d()}`)}function y(e,t,o,r,a){const i=o.length>0?o.map(n).join(", "):"default scopes";return s(`
142
+ ${d()}`)}function $(e,t,o,n,a){const i=o.length>0?o.map(r).join(", "):"default scopes";return s(`
141
143
  ${l(`Credentials for ${e}`)}
142
144
  ${a}
143
145
  <p class="hint">Paste your token, or provide your OAuth2 client credentials.</p>
144
146
  <div class="section">
145
147
  <h2>I have a token</h2>
146
148
  <form method="post" action="/mcp/credentials" autocomplete="off">
147
- <input type="hidden" name="token" value="${n(t)}">
149
+ <input type="hidden" name="token" value="${r(t)}">
148
150
  <input type="hidden" name="mode" value="token">
149
151
  <label for="secret">API token</label>
150
152
  <input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
@@ -156,7 +158,7 @@ ${a}
156
158
  <h2>Exchange client credentials</h2>
157
159
  <p class="hint">We request a token from the API on your behalf. Scopes: ${i}.</p>
158
160
  <form method="post" action="/mcp/credentials" autocomplete="off">
159
- <input type="hidden" name="token" value="${n(t)}">
161
+ <input type="hidden" name="token" value="${r(t)}">
160
162
  <input type="hidden" name="mode" value="client-credentials">
161
163
  <label for="client_id">Client ID</label>
162
164
  <input type="text" id="client_id" name="client_id" required>
@@ -165,14 +167,14 @@ ${a}
165
167
  <button type="submit">Exchange &amp; save</button>
166
168
  </form>
167
169
  </div>
168
- ${r}
170
+ ${n}
169
171
  ${c()}
170
- ${d()}`)}function $(e,t,o,r){return s(`
172
+ ${d()}`)}function x(e,t,o,n){return s(`
171
173
  ${l(`Credentials for ${e}`)}
172
- ${r}
174
+ ${n}
173
175
  <p class="hint">The value is stored and encrypted only for you for 24 hours (anonymous) or 30 days (signed in).<br />It is sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
174
176
  <form method="post" action="/mcp/credentials" autocomplete="off">
175
- <input type="hidden" name="token" value="${n(t)}">
177
+ <input type="hidden" name="token" value="${r(t)}">
176
178
  <input type="hidden" name="mode" value="token">
177
179
  <label for="secret">Authorization header value</label>
178
180
  <input type="password" id="secret" name="secret" placeholder="Bearer &lt;your token&gt;" required autofocus>
@@ -180,38 +182,44 @@ ${r}
180
182
  </form>
181
183
  ${o}
182
184
  ${c()}
183
- ${d()}`)}function x(e,t,o,r){const a=t.map((i,m)=>k(i,m)).join(`
185
+ ${d()}`)}function k(e,t,o,n){const a=t.map((i,u)=>w(i,u)).join(`
184
186
  `);return s(`
185
187
  ${l(`Credentials for ${e.name}`)}
186
- ${r}
188
+ ${n}
187
189
  <p class="hint">This API accepts more than one kind of credential. Fill in the one(s) you have and leave the rest blank - each value is stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent straight to the API. It never passes through the AI conversation.</p>
188
190
  <form method="post" action="/mcp/credentials" autocomplete="off">
189
- <input type="hidden" name="token" value="${n(o)}">
191
+ <input type="hidden" name="token" value="${r(o)}">
190
192
  <input type="hidden" name="mode" value="multi">
191
193
  ${a}
192
194
  <button type="submit">Save credentials</button>
193
195
  </form>
194
196
  ${c()}
195
- ${d()}`)}function k(e,t){const o=A(e.auth),r=e.label?`<p class="hint">${n(e.label)}</p>`:"",a=_(e.operations),i=e.hasExistingSecret?`<label class="check"><input type="checkbox" name="remove__${t}" value="1"> Remove the stored credential</label>`:"";return`
197
+ ${d()}`)}function w(e,t){const o=P(e.auth),n=e.label?`<p class="hint">${r(e.label)}</p>`:"",a=_(e.operations),i=e.hasExistingSecret?`<label class="check"><input type="checkbox" name="remove__${t}" value="1"> Remove the stored credential</label>`:"",u=e.hasExistingSecret?'<span class="badge stored">Stored</span>':'<span class="badge">Not set</span>';return`
196
198
  <div class="section">
197
- <h2>${n(e.name)}</h2>
198
- <p class="hint">Sent to the API as the <code>${n(o.code)}</code> ${o.suffix}.</p>
199
- ${r}
199
+ <h2>${r(e.name)} ${u}</h2>
200
+ <p class="hint">Sent to the API as the <code>${r(o.code)}</code> ${o.suffix}.</p>
201
+ ${n}
200
202
  ${a}
201
- ${w(e.auth,t)}
203
+ ${I(e.auth,t)}
202
204
  ${i}
203
- </div>`}function w(e,t){const o=`secret__${t}`;if(e.kind==="oauth2ClientCredentials"){const a=e.scopes.length>0?e.scopes.map(n).join(", "):"default scopes";return`<label for="${o}">API token</label>
205
+ </div>`}function I(e,t){const o=`secret__${t}`;if(e.kind==="oauth2ClientCredentials"){const a=e.scopes.length>0?e.scopes.map(r).join(", "):"default scopes";return`<label for="${o}">API token</label>
204
206
  <input type="password" id="${o}" name="${o}" placeholder="paste a token you already have">
205
207
  <p class="hint">Or exchange client credentials for one (scopes: ${a}). We add <code>Bearer</code> automatically.</p>
206
208
  <label for="client_id__${t}">Client ID</label>
207
209
  <input type="text" id="client_id__${t}" name="client_id__${t}">
208
210
  <label for="client_secret__${t}">Client secret</label>
209
- <input type="password" id="client_secret__${t}" name="client_secret__${t}">`}const r=I(e);return`<label for="${o}">${n(r)}</label>
210
- <input type="password" id="${o}" name="${o}" placeholder="value">`}function I(e){switch(e.kind){case"apiKey":return`${e.header} value`;case"cookie":return`${e.name} cookie value`;case"bearer":return"API token";default:return"Authorization header value"}}function A(e){switch(e.kind){case"apiKey":return{code:e.header,suffix:"header"};case"cookie":return{code:e.name,suffix:"cookie"};case"bearer":return{code:"Authorization",suffix:"header (bearer token)"};case"oauth2ClientCredentials":return{code:"Authorization",suffix:"header (OAuth2 bearer token)"};default:return{code:"Authorization",suffix:"header"}}}function _(e){if(!e||e.length===0)return"";const t=e.slice(0,h).map(n).join(", "),o=e.length-h,r=o>0?`, and ${o} more`:"";return`<p class="hint">Used by ${t}${r}.</p>`}function M(e){return s(`
211
+ <input type="password" id="client_secret__${t}" name="client_secret__${t}">`}const n=A(e);return`<label for="${o}">${r(n)}</label>
212
+ <input type="password" id="${o}" name="${o}" placeholder="value">`}function A(e){switch(e.kind){case"apiKey":return`${e.header} value`;case"cookie":return`${e.name} cookie value`;case"bearer":return"API token";default:return"Authorization header value"}}function P(e){switch(e.kind){case"apiKey":return{code:e.header,suffix:"header"};case"cookie":return{code:e.name,suffix:"cookie"};case"bearer":return{code:"Authorization",suffix:"header (bearer token)"};case"oauth2ClientCredentials":return{code:"Authorization",suffix:"header (OAuth2 bearer token)"};default:return{code:"Authorization",suffix:"header"}}}function _(e){if(!e||e.length===0)return"";const t=e.slice(0,f).map(r).join(", "),o=e.length-f,n=o>0?`, and ${o} more`:"";return`<p class="hint">Used by ${t}${n}.</p>`}function S(e){return s(`
211
213
  ${l("Credentials removed")}
212
- <p>Credentials for ${n(u(e))} are removed. Calls to the API are anonymous again until you add new credentials.</p>
213
- ${d()}`)}function S(e){return s(`
214
+ <p>Credentials for ${r(p(e))} are removed. Calls to the API are anonymous again until you add new credentials.</p>
215
+ ${d()}`)}function z(e,t){const o=t.saved.length===0?"Credentials removed":t.removed.length===0?"Credentials saved":"Credentials updated",n=[t.saved.length>0?`<p>Saved: ${h(t.saved)}.</p>`:"",t.removed.length>0?`<p>Removed: ${h(t.removed)}.</p>`:"",t.stored.length>0?`<p>${r(e.name)} now has stored credentials for ${h(t.stored)}.</p>`:`<p>${r(e.name)} has no stored credentials. Calls to the API are anonymous until you add new ones.</p>`];return s(`
216
+ ${l(o)}
217
+ ${n.join(`
218
+ `)}
219
+ <p>Retry in your AI client, or confirm any prompt it left open. You can close this tab.</p>
220
+ <p class="hint">This link is single-use and is now spent. To change anything, request a new one in your AI client.</p>
221
+ ${d()}`)}function h(e){return e.map(t=>`<code>${r(t)}</code>`).join(", ")}function L(e){return s(`
214
222
  ${l("Credentials saved")}
215
- <p>Credentials for ${n(u(e))} are saved. Retry in your AI client, or confirm any prompt it left open. You can close this tab.</p>
223
+ <p>Credentials for ${r(p(e))} are saved. Retry in your AI client, or confirm any prompt it left open. You can close this tab.</p>
216
224
  <p class="hint">This link is single-use and is now spent. To change anything, request a new one in your AI client.</p>
217
- ${d()}`)}function z(){return s(`${l("Link expired")}<p>This credentials link is invalid, already used, or older than ${Math.round(p/6e4)} minutes. Retry in your AI client to get a fresh link.</p>${d()}`)}export{M as clearedPage,H as formPage,z as notFoundPage,S as successPage};
225
+ ${d()}`)}function T(){return s(`${l("Link expired")}<p>This credentials link is invalid, already used, or older than ${Math.round(m/6e4)} minutes. Retry in your AI client to get a fresh link.</p>${d()}`)}export{S as clearedPage,M as formPage,z as multiOutcomePage,T as notFoundPage,L as successPage};
@@ -1,6 +1,4 @@
1
1
  import type { LifecyclePluginInstance } from '../../types';
2
- export declare const MCP_DOCS_SERVER_HANDLER_ID = "mcp-docs-server-handler";
3
- export declare const MCP_CREDENTIALS_HANDLER_ID = "mcp-credentials-handler";
4
2
  export declare function mcpServerPlugin(): Promise<LifecyclePluginInstance>;
5
3
  export default mcpServerPlugin;
6
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- import{fileURLToPath as G}from"node:url";import{dirname as q,join as p}from"node:path";import{logger as l}from"../../tools/notifiers/logger.js";import{reporter as I}from"../../tools/notifiers/reporter.js";import{isDefined as N}from"../../../utils/guards/is-defined.js";import{bundledOpenApiDocumentsToMcpOpenApi as H,bundledGraphqlDocumentsToMcpOpenApi as U,buildGraphqlDescriptions as j,collectIgnoredRoutes as x,filterIgnoredApiDescriptions as _,getCleanedUpApiDescriptions as F,isMcpInRedirects as B}from"./utils.js";import{getMcpMode as V,isMcpElicitationEnabled as k}from"./utils/mode.js";import{findGatedToolNames as J}from"./utils/find-gated-tool-names.js";import{getDefaultToolSchemas as W}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as X}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as $,isGatewayEligible as z}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as K}from"./gateway-mcp/rate-limit/limits.js";import{telemetryTraceStep as Q}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as v,MCP_NOT_ALLOWED_TEMPLATE_ID as Y}from"./constants.js";const y="mcp-docs-server-handler",Z="/mcp",A="mcp-credentials-handler",ee="/mcp/credentials",m=q(G(import.meta.url));async function te(){let o=!1;return{id:"mcp",async processContent(t,r){o||await Q("com.redocly.build.plugin.mcp",async a=>{const n=H(await t.loadApiDocuments(r)),f=U(await t.loadApiDocuments(r)),s=await r.getConfig(),{mcp:i,redirects:d}=s;if(a?.setAttribute("config",JSON.stringify(i||{})),!(i?.hide||i?.docs?.hide)&&(B(d)&&await I.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),t.createTemplate(Y,"@redocly/theme/layouts/McpNotAllowed"),!i?.docs?.hide)){l.info("Configuring MCP servers...");const g=p(m,"./handlers/docs-mcp-handler.js"),c=i?.docs?.ignore||[],h=F(_(n,c)),u=!!s?.access?.requiresLogin,D=s?.access?.rbac||{},R=$(i),M=new Map;for(const e of h){const L=e.definition.info?.title||"",w=e.definition.info?.version||"";M.set(e.relativePath,{name:L,description:typeof e.definition.info?.description=="string"?e.definition.info.description:"",version:w,servers:e.definition.servers||[],relativePath:e.relativePath,...R&&z(e.definition.info,e.relativePath,D)?{fetchEligible:!0}:{}})}const E=j(_(f,c)),T=Object.values(s.products||{}).map(e=>e?.name).filter(N),b=s.l10n?.locales?.map(e=>e.code)??r.fs.localeFolders,C=V(),P=k(),{budgetPerExec:S}=K(),O=W({products:T,locales:b,requiresLogin:u,rbac:D,hasGraphqlApis:E.length>0,elicitationEnabled:P});t.addMcpTools(p(m,"./docs-mcp/tools/index.js"),O),C==="code"&&t.addMcpTools(p(m,"./codemode/tools/execute.js"),[X]),await oe({actions:t,handlerPath:g,apiDescriptionsMap:Object.fromEntries(M),graphqlDescriptions:E,mcpConfig:i,mcpMode:C,elicitationEnabled:P,gatewayFetchBudgetPerExec:S}),o=!0}})},async afterRoutesCreated(t,r){const a=await r.getConfig(),{mcp:n}=a;t.markGatedMcpTools(await J(t.getMcpTools())),t.setGlobalData({mcpData:{docs:{enabled:!n?.hide&&!n?.docs?.hide,name:n?.docs?.name||v}}})}}}var De=te;async function oe({actions:o,handlerPath:t,apiDescriptionsMap:r,graphqlDescriptions:a,mcpConfig:n,mcpMode:f,elicitationEnabled:s,gatewayFetchBudgetPerExec:i}){if(o.createRequestHandler(y,t),o.addApiRoute({slug:Z,requestHandlerId:y,httpMethod:"all",getStaticData:async(d,g)=>{const c=x(g.getAllRoutes(),n?.docs?.ignore||[]);return c.length>0&&l.verbose(`mcp.docs.ignore: hiding ${c.length} page routes from MCP search`),{props:{config:{apiDescriptionsMap:r,graphqlDescriptions:a,mcpDocsServerName:n?.docs?.name||v,mcpMode:f,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,searchIgnoredRoutes:c},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:h,...u})=>u)}}}}),l.info("Registered Docs MCP Server endpoint at /mcp"),s){const d=p(m,"./handlers/mcp-credentials-handler.js");o.createRequestHandler(A,d),o.addApiRoute({slug:ee,requestHandlerId:A,httpMethod:"all",getStaticData:async()=>({props:{}})}),l.info("Registered MCP credentials endpoint at /mcp/credentials")}}export{A as MCP_CREDENTIALS_HANDLER_ID,y as MCP_DOCS_SERVER_HANDLER_ID,De as default,te as mcpServerPlugin};
1
+ import{fileURLToPath as F}from"node:url";import{dirname as $,join as M}from"node:path";import{MCP_ROUTE as k,PUBLIC_MCP_ROUTE as D}from"@redocly/theme/core/constants/mcp";import{logger as c}from"../../tools/notifiers/logger.js";import{reporter as B}from"../../tools/notifiers/reporter.js";import{isDefined as x}from"../../../utils/guards/is-defined.js";import{canAnonymousAccessMcpFeature as P}from"../../utils/rbac/can-anonymous-access-mcp-feature.js";import{shouldHandleMcpAuth as R}from"../../utils/rbac/should-handle-mcp-auth.js";import{MCP_CREDENTIALS_HANDLER_ID as _,MCP_CREDENTIALS_ROUTE as V,MCP_DOCS_SERVER_HANDLER_ID as T,MCP_NOT_ALLOWED_TEMPLATE_ID as J}from"../../constants/mcp.js";import{bundledOpenApiDocumentsToMcpOpenApi as W,bundledGraphqlDocumentsToMcpOpenApi as X,buildGraphqlDescriptions as z,collectIgnoredRoutes as K,filterIgnoredApiDescriptions as S,getCleanedUpApiDescriptions as Q,isMcpInRedirects as Y}from"./utils.js";import{getMcpMode as O,isMcpElicitationEnabled as Z,isMcpGatewayEnabled as ee}from"./utils/mode.js";import{findGatedToolNames as te}from"./utils/find-gated-tool-names.js";import{getDefaultToolSchemas as oe}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as ie}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as re,isGatewayEligible as se}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as ne}from"./gateway-mcp/rate-limit/limits.js";import{resetCustomMcpTools as ae,scanCustomMcpTools as ce}from"./custom-tools/scan-custom-tools.js";import{telemetryTraceStep as pe}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as w}from"./constants.js";const b=$(F(import.meta.url));async function le(){let o;const p={registeredToolNames:[]};let l=0,d=!1;return{id:"mcp",async processContent(e,n){await pe("com.redocly.build.plugin.mcp",async s=>{const i=await n.getConfig(),{mcp:r,redirects:g}=i;if(s?.setAttribute("config",JSON.stringify(r||{})),s?.setAttribute("mcpMode",O()),s?.setAttribute("mcpGateway",String(ee())),r?.hide||r?.docs?.hide){ae(e,p);return}Y(g)&&await B.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),e.createTemplate(J,"@redocly/theme/layouts/McpNotAllowed");const u=!!i?.access?.requiresLogin,a=i?.access?.rbac||{},E=O(),h=Z(),{budgetPerExec:f}=ne();if(!o){c.info("Configuring MCP servers...");const C=W(await e.loadApiDocuments(n)),L=X(await e.loadApiDocuments(n)),v=r?.docs?.ignore||[],q=Q(S(C,v)),I=re(r),A=new Map;for(const t of q){const j=t.definition.info?.title||"",U=t.definition.info?.version||"";A.set(t.relativePath,{name:j,description:typeof t.definition.info?.description=="string"?t.definition.info.description:"",version:U,servers:t.definition.servers||[],relativePath:t.relativePath,...I&&se(t.definition.info,t.relativePath,a)?{fetchEligible:!0}:{}})}const y=z(S(L,v)),G=Object.values(i.products||{}).map(t=>t?.name).filter(x),N=i.l10n?.locales?.map(t=>t.code)??n.fs.localeFolders,H=oe({products:G,locales:N,requiresLogin:u,rbac:a,hasGraphqlApis:y.length>0,elicitationEnabled:h,hasCallableApis:A.values().some(t=>t.fetchEligible)});e.addMcpTools(M(b,"./docs-mcp/tools/index.js"),H),E==="code"&&e.addMcpTools(M(b,"./codemode/tools/execute.js"),[ie]),o={apiDescriptionsMap:Object.fromEntries(A),graphqlDescriptions:y}}const m=await ce(e,n,p);s?.setAttribute("customToolsCount",String(m)),m!==l&&(l=m,m>0&&c.info(`Registered ${m} custom MCP tool${m===1?"":"s"} from @mcp folders`)),await me({actions:e,handlerPath:M(b,"./handlers/docs-mcp-handler.js"),apiDescriptionsMap:o.apiDescriptionsMap,graphqlDescriptions:o.graphqlDescriptions,mcpConfig:r,mcpMode:E,elicitationEnabled:h,gatewayFetchBudgetPerExec:f,requiresLogin:u,rbacConfig:a}),d||(c.info("Registered Docs MCP Server endpoint at /mcp"),d=!0)})},async afterRoutesCreated(e,n){const s=await n.getConfig(),{mcp:i}=s,r=!i?.hide&&!i?.docs?.hide;e.markGatedMcpTools(await te(e.getMcpTools())),e.setGlobalData({mcpData:{docs:{enabled:r,name:i?.docs?.name||w,publicEndpoint:r&&de(i,s)}}})}}}var Le=le;function de(o,p){const l=!!p.access?.requiresLogin,d=p.access?.rbac||{};return!!o?.docs?.publicEndpoint&&R(l,d)&&P(d,l)}async function me({actions:o,handlerPath:p,apiDescriptionsMap:l,graphqlDescriptions:d,mcpConfig:e,mcpMode:n,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,requiresLogin:r,rbacConfig:g}){o.createRequestHandler(T,p);const u=a=>async(E,h)=>{const f=K(h.getAllRoutes(),e?.docs?.ignore||[]);return f.length>0&&c.verbose(`mcp.docs.ignore: hiding ${f.length} page routes from MCP search`),{props:{config:{apiDescriptionsMap:l,graphqlDescriptions:d,mcpDocsServerName:e?.docs?.name||w,mcpMode:n,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,searchIgnoredRoutes:f,...a?{isPublicEndpoint:a}:{}},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:m,...C})=>C)}}};if(o.addApiRoute({slug:k,requestHandlerId:T,httpMethod:"all",getStaticData:u(!1)}),e?.docs?.publicEndpoint&&(R(r,g)?P(g,r)?(o.addApiRoute({slug:D,requestHandlerId:T,httpMethod:"all",getStaticData:u(!0)}),c.verbose(`Registered public Docs MCP Server endpoint at ${D}`)):c.info(`mcp.docs.publicEndpoint is enabled, but anonymous users are denied the MCP feature (rbac.features.mcp or requiresLogin) - skipping ${D}.`):c.info(`mcp.docs.publicEndpoint is enabled, but the project has no protected content - /mcp already serves anonymous users, skipping ${D}.`)),s){const a=M(b,"./handlers/mcp-credentials-handler.js");o.createRequestHandler(_,a),o.addApiRoute({slug:V,requestHandlerId:_,httpMethod:"all",getStaticData:async()=>({props:{}})}),c.verbose("Registered MCP credentials endpoint at /mcp/credentials")}}export{Le as default,le as mcpServerPlugin};
@@ -1 +1 @@
1
- import{fromJsonSchema as A}from"@modelcontextprotocol/server";import{logger as b}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as g,MCP_TOOL_IS_AVAILABLE_KEY as M}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as L}from"../constants.js";import{isAnonymousSessionToolAvailable as T}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as v,manageApiCredentials as D,manageApiCredentialsSchema as y}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as I}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as O,DESCRIBE_TOOLS_TOOL_NAME as N,CODE_MODE_TOOL_NAMES as H,FETCH_TOOL_NAME as k}from"../codemode/constants.js";import{buildCodeModeInstructions as w,buildExecuteDescription as x,DESCRIBE_TOOLS_DESCRIPTION as F}from"../codemode/prompts.js";import{toToolListEntries as R}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as P,getActiveCapabilities as B}from"../codemode/capabilities/index.js";import{describeToolsSchema as U,describeTools as z}from"../codemode/tools/describe-tools.js";import{mcpJsonSchemaValidator as J}from"../utils/json-schema-validator.js";import{connectMcpServer as V,createMcpServer as X,createToolDispatch as Y,extractSerializableContext as $}from"./mcp-server.js";function K(r){const t=I.schema;if(T(r))return t;const{sessionHandle:i,...m}=t.properties;return{...t,properties:m}}function W(r,t){const i=t.schema;if(T(r))return i;const{sessionHandle:m,...p}=i.properties;return{...i,properties:p}}async function me({name:r,tools:t,context:i,skills:m=[],getKv:p}){const s=i.mcpMode==="code",a=s?B(i):[],E=a.some(e=>e.id===k),l=s?t.filter(e=>!H.has(e.name)):[],u=R(l,a),_=s&&v(i),{server:n,transport:C}=X(r,s?w(E,u):void 0),c=e=>A(e,J),d=$(i),S={getClientCapabilities:()=>n.server.getClientCapabilities(),getKv:p},f=Y(d,S),h=async e=>{try{return await g.exec(M,[{toolName:e,context:d}],{timeout:1e4})}catch(o){return b.error(`Failed to check MCP tool availability for "${e}": ${o instanceof Error?o.message:String(o)}`),!1}};if(s){n.registerTool(O,{description:x(E,u),inputSchema:c(K(i)),annotations:P(a)},f(O)),n.registerTool(N,{description:F,inputSchema:c(U(l,a))},z(l,h,a,i));const e=t.find(o=>o.name===L);if(e&&T(i)&&n.registerTool(e.name,{description:e.description,inputSchema:c(e.schema),annotations:e.annotations??{title:e.name}},f(e.name)),_){const o=y(i);n.registerTool(o.name,{description:o.description,inputSchema:c(W(i,o)),annotations:o.annotations??{title:o.name}},D(d,S))}}else await Promise.all(t.map(async e=>{const o=n.registerTool(e.name,{description:e.description,inputSchema:c(e.schema),annotations:e.annotations||{title:e.name}},f(e.name));await h(e.name)||o.disable()}));for(const e of m)n.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return V(n,C)}export{me as createDocsMcpServer};
1
+ import{logger as M}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as v,MCP_TOOL_IS_AVAILABLE_KEY as k}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as L}from"../constants.js";import{isAnonymousSessionToolAvailable as C}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as y,manageApiCredentials as D,manageApiCredentialsSchema as w}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as A}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as N,CODE_MODE_TOOL_NAMES as x,FETCH_TOOL_NAME as H}from"../codemode/constants.js";import{buildCodeModeInstructions as I,buildExecuteDescription as U}from"../codemode/prompts.js";import{toToolListEntries as F}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as P,getActiveCapabilities as R}from"../codemode/capabilities/index.js";import{describeToolsSchema as z,describeTools as W}from"../codemode/tools/describe-tools.js";import{availableSandboxTools as X}from"../utils/available-sandbox-tools.js";import{toRegisterToolConfig as _}from"../utils/tool-registration.js";import{connectMcpServer as Y,createMcpServer as $,createToolDispatch as B,extractSerializableContext as K}from"./mcp-server.js";function g(l,r){const o=r.schema;if(C(l))return o;const{sessionHandle:f,...m}=o.properties;return{...o,properties:m}}async function ne({name:l,tools:r,context:o,skills:f=[],getKv:m}){const c=K(o),a=o.mcpMode==="code",s=a?R(o):[],T=s.some(e=>e.id===H),p=a?await X(r.filter(e=>!x.has(e.name)),c):[],b=F(p,s),O=a&&y(o),{server:n,transport:S}=$(l,a?I(T,b):void 0),E={getClientCapabilities:()=>n.server.getClientCapabilities(),getKv:m},d=B(c,E),u=async e=>{try{return await v.exec(k,[{toolName:e,context:c}],{timeout:1e4})}catch(i){return M.error(`Failed to check MCP tool availability for "${e}": ${i instanceof Error?i.message:String(i)}`),!1}};if(a){const e=[{tool:{...A,description:U(T,b),schema:g(o,A),annotations:P(s)},callback:d(N)},{tool:z(p,s),callback:W(p,u,s,o)}],i=r.find(t=>t.name===L);if(i&&C(o)&&e.push({tool:i,callback:d(i.name)}),O){const t=w(o);e.push({tool:{...t,schema:g(o,t)},callback:D(c,E)})}for(const{tool:t,callback:h}of e)n.registerTool(t.name,_(t),h)}else await Promise.all(r.map(async e=>{const i=n.registerTool(e.name,_(e),d(e.name));await u(e.name)||i.disable()}));for(const e of f)n.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return Y(n,S)}export{ne as createDocsMcpServer};
@@ -1,5 +1,5 @@
1
- import{McpServer as L,WebStandardStreamableHTTPServerTransport as j}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as D,MCP_TOOL_WORKER_KEY as K}from"../../../workers/mcp-tool-worker-pool.js";import{SSE_KEEPALIVE_INTERVAL_MS as x}from"../constants.js";import{secretStore as F}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as H,stripAuthRequiredMeta as M,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as P,buildSchemeChoiceHint as v,buildUpstreamCredentialFallback as T,buildUpstreamCredentialInputRequired as $,isCredentialElicitationDeclined as N,schemeLabelOf as B}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as q,resolveUpstreamApiAuth as G,schemeChoicesOf as W}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as V,resolveSecretSubject as Y}from"../gateway-mcp/subject.js";const J=6e4,E=new Map;function Q(e,t){const r=E.get(e);if(r)return r;const n=t().finally(()=>{E.delete(e)});return E.set(e,n),n}function fe(e,t){const r=new L({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}}),n=new j({keepAliveMs:x,sessionIdGenerator:void 0});return{server:r,transport:n}}async function he(e,t){return await e.connect(t),{server:e,transport:t,cleanup:async()=>{t.close()}}}function ge(e,t){return r=>async(n,s)=>{S.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,c=s.mcpReq.envelope!==void 0,o=i?Y(e.user,n.sessionHandle):{kind:"anonymous"},a=o.kind==="resolved"?o.subject:void 0;if(o.kind==="invalid")return{content:[{type:"text",text:o.message}],isError:!0};const p=async()=>{if(!(!i||!a||!t?.getKv))try{const m=await t.getKv();return await F.getSecretsForSubject(m,a)}catch(m){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let u;const l=async()=>{u=await p();const m={toolName:r,args:n,context:{...e,upstreamSecrets:u},extra:ie(s)};return await D.exec(K,[m],{timeout:J})};let d=await l();const f=H(d);if(f.length>0&&i&&!a)return M({...d,content:[{type:"text",text:V}],isError:!0});if(f.length>0&&i&&a&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${Z(t)}`);const m=await t.getKv(),h=await z(e,f),k=f.map(U=>ee(U,h)),y=te(u),g=c?await re(e,s,k,a,m,y,h,t):await ne(e,k,a,m,y,h);switch(g.kind){case"inputRequired":return g.result;case"retry":d=await l();break;case"prependText":d={...d,content:[{type:"text",text:g.text},...d.content],isError:!0};break;case"none":break}}return M(d)}}function X(e){return!!e?.getClientCapabilities()?.elicitation?.url}function Z(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}async function z(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await G(e,n));return r}function ee(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??q};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function te(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(b({api:r,scheme:s}));return t}function A(e,t){return e.status===401&&!t.has(b(e))}function I(e,t){const r=t.get(e.api);return r&&e.scheme?B(r.schemes,e.scheme):void 0}function R(e,t){const r=t.get(e.api);return!r||!e.schemes?.length?[]:W(r,e.schemes)}function _(e,t){return R(e,t).length>1}function w(e,t){return e.map(r=>P(r,I(r,t))).join(`
1
+ import{McpServer as L,WebStandardStreamableHTTPServerTransport as j}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as D,MCP_TOOL_WORKER_KEY as K}from"../../../workers/mcp-tool-worker-pool.js";import{SSE_KEEPALIVE_INTERVAL_MS as F}from"../constants.js";import{secretStore as H}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as P,stripAuthRequiredMeta as M,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as v,buildSchemeChoiceHint as B,buildUpstreamCredentialFallback as T,buildUpstreamCredentialInputRequired as $,isCredentialElicitationDeclined as x,schemeLabelOf as N}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as q,resolveUpstreamApiAuth as V,schemeChoicesOf as G}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as W,resolveSecretSubject as Y}from"../gateway-mcp/subject.js";const J=6e4,E=new Map;function Q(e,t){const n=E.get(e);if(n)return n;const r=t().finally(()=>{E.delete(e)});return E.set(e,r),r}function fe(e,t){const n=new L({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}}),r=new j({keepAliveMs:F,sessionIdGenerator:void 0});return{server:n,transport:r}}async function he(e,t){return await e.connect(t),{server:e,transport:t,cleanup:async()=>{t.close()}}}function ge(e,t){return n=>async(r,s)=>{S.info(`MCP tool called: ${n}`);const i=e.elicitationEnabled??!1,c=s.mcpReq.envelope!==void 0,a=i?Y(e.user,r.sessionHandle):{kind:"anonymous"},o=a.kind==="resolved"?a.subject:void 0;if(a.kind==="invalid")return{content:[{type:"text",text:a.message}],isError:!0};const p=async()=>{if(!(!i||!o||!t?.getKv))try{const m=await t.getKv();return await H.getSecretsForSubject(m,o)}catch(m){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let u;const l=async()=>{u=await p();const m={toolName:n,args:r,context:{...e,upstreamSecrets:u},extra:ie(s)};return await D.exec(K,[m],{timeout:J})};let d=await l();const f=P(d);if(f.length>0&&i&&!o)return M({...d,content:[{type:"text",text:W}],isError:!0});if(f.length>0&&i&&o&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${Z(t)}`);const m=await t.getKv(),h=await z(e,f),k=f.map(O=>ee(O,h)),y=te(u),g=c?await ne(e,s,k,o,m,y,h,t):await re(e,k,o,m,y,h);switch(g.kind){case"inputRequired":return g.result;case"retry":d=await l();break;case"prependText":d={...d,content:[{type:"text",text:g.text},...d.content],isError:!0};break;case"none":break}}return M(d)}}function X(e){return!!e?.getClientCapabilities()?.elicitation?.url}function Z(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const n=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return n.length>0?n.join("+"):"none"}async function z(e,t){const n=new Map;for(const r of new Set(t.map(s=>s.api)))n.set(r,await V(e,r));return n}function ee(e,t){const n=t.get(e.api);if(!n)return{...e,scheme:e.scheme??q};const r=e.scheme&&n.schemes[e.scheme]?e.scheme:n.defaultScheme;return{...e,scheme:r}}function te(e){const t=new Set;for(const[n,r]of Object.entries(e??{}))for(const s of Object.keys(r))t.add(b({api:n,scheme:s}));return t}function A(e,t){return e.status===401&&!t.has(b(e))}function I(e,t){const n=t.get(e.api),r=e.sentScheme??e.scheme;return n&&r?N(n.schemes,r):void 0}function R(e,t){const n=t.get(e.api);return!n||!e.schemes?.length?[]:G(n,e.schemes)}function _(e,t){return R(e,t).length>1}function w(e,t){return e.map(n=>v(n,I(n,t))).join(`
2
2
 
3
- `)}function C(e,t,r){const n=e.map(s=>v(s,R(s,r)));return t.length>0&&n.push(w(t,r)),n.join(`
3
+ `)}function C(e,t,n){const r=e.map(s=>B(s,R(s,n)));return t.length>0&&r.push(w(t,n)),r.join(`
4
4
 
5
- `)}function O(e,t,r,n,s){const[i,...c]=t,o=s.get(i.api),a=i.scheme??o?.defaultScheme??q,p=I(i,s);return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:a,...p?{schemeLabel:p}:{}},auth:o?.schemes[a]??{kind:"raw"},...o?{apiAuth:o}:{},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,otherApiNames:c.map(u=>u.name)}}}async function re(e,t,r,n,s,i,c,o){if(N(t.mcpReq.inputResponses))return{kind:"none"};const a=r.filter(l=>A(l,i));if(a.length===0)return{kind:"prependText",text:w(r,c)};const p=a.filter(l=>_(l,c));if(p.length>0){const l=r.filter(d=>!p.includes(d));return{kind:"prependText",text:C(p,l,c)}}const u=O(e,a,n,s,c);return X(o)?{kind:"inputRequired",result:await $(u)}:{kind:"prependText",text:await T(u)}}async function ne(e,t,r,n,s,i){const c=t.filter(u=>A(u,s));if(c.length===0)return{kind:"prependText",text:w(t,i)};const o=c.filter(u=>_(u,i));if(o.length>0){const u=t.filter(l=>!o.includes(l));return{kind:"prependText",text:C(o,u,i)}}const a=O(e,c,r,n,i);return{kind:"prependText",text:await Q(`${r}:${b(c[0])}`,()=>T(a))}}function ie(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function Se(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes}}export{he as connectMcpServer,fe as createMcpServer,ge as createToolDispatch,Se as extractSerializableContext};
5
+ `)}function U(e,t,n,r,s){const[i,...c]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??q,p=I(i,s);return{subject:n,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:o,...p?{schemeLabel:p}:{}},auth:a?.schemes[o]??{kind:"raw"},...a?{apiAuth:a}:{},kv:r,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:c.map(u=>u.name)}}}async function ne(e,t,n,r,s,i,c,a){if(x(t.mcpReq.inputResponses))return{kind:"none"};const o=n.filter(l=>A(l,i));if(o.length===0)return{kind:"prependText",text:w(n,c)};const p=o.filter(l=>_(l,c));if(p.length>0){const l=n.filter(d=>!p.includes(d));return{kind:"prependText",text:C(p,l,c)}}const u=U(e,o,r,s,c);return X(a)?{kind:"inputRequired",result:await $(u)}:{kind:"prependText",text:await T(u)}}async function re(e,t,n,r,s,i){const c=t.filter(u=>A(u,s));if(c.length===0)return{kind:"prependText",text:w(t,i)};const a=c.filter(u=>_(u,i));if(a.length>0){const u=t.filter(l=>!a.includes(l));return{kind:"prependText",text:C(a,u,i)}}const o=U(e,c,n,r,i);return{kind:"prependText",text:await Q(`${n}:${b(c[0])}`,()=>T(o))}}function ie(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function Se(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,client:e.client,clientVersion:e.clientVersion,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,fs:void 0}}export{he as connectMcpServer,fe as createMcpServer,ge as createToolDispatch,Se as extractSerializableContext};
@@ -1,4 +1,4 @@
1
- import type { ApiFunctionsContext, ApiFunctionsContextMethods, PageStaticData } from '@redocly/config';
1
+ import type { ApiFunctionsContext, ApiFunctionsContextMethods, McpToolDefinition, McpToolFileSystem, McpToolJsonValue, PageStaticData } from '@redocly/config';
2
2
  import type { AuthInfo, CallToolResult, RequestId, RequestMeta, StandardSchemaWithJSON, ToolCallback } from '@modelcontextprotocol/server';
3
3
  import type { OpenAPIPath, OpenAPIServer, OpenAPIOperation } from '@redocly/api-docs';
4
4
  import type { McpErrorCodes, McpServerType } from './constants';
@@ -29,6 +29,7 @@ export type McpDocsStaticDataPropsConfig = {
29
29
  elicitationEnabled: boolean;
30
30
  gatewayFetchBudgetPerExec: number;
31
31
  searchIgnoredRoutes?: string[];
32
+ isPublicEndpoint?: boolean;
32
33
  };
33
34
  export type McpDocsStaticData = PageStaticData & {
34
35
  props: {
@@ -78,7 +79,10 @@ export type SemanticSearchResult = {
78
79
  url: string;
79
80
  content: string;
80
81
  };
81
- export type McpToolWorkerResponse = CallToolResult;
82
+ export type McpErrorClass = 'tool_error' | 'sandbox_error' | 'client_error' | 'server_error';
83
+ export type McpToolWorkerResponse = CallToolResult & {
84
+ errorClass?: McpErrorClass;
85
+ };
82
86
  export type ToolArgs = Record<string, unknown>;
83
87
  export type McpToolCallback = ToolCallback<StandardSchemaWithJSON<ToolArgs, ToolArgs>>;
84
88
  export type McpToolExtra = {
@@ -98,10 +102,14 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
98
102
  elicitationEnabled?: boolean;
99
103
  gatewayFetchBudgetPerExec?: number;
100
104
  clientIp?: string;
105
+ client?: string;
106
+ clientVersion?: string;
101
107
  upstreamSecrets?: UpstreamSecrets;
102
108
  searchIgnoredRoutes?: string[];
109
+ internalBaseUrl?: string;
110
+ fs?: McpToolFileSystem;
103
111
  };
104
- export type McpToolHandler<TArgs extends ToolArgs = ToolArgs> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse>;
112
+ export type McpToolHandler<TArgs extends ToolArgs = ToolArgs> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse | McpToolJsonValue>;
105
113
  export type McpToolIsAvailable = (context: McpToolContext) => boolean | Promise<boolean>;
106
114
  export type McpToolHandlerExtended<TArgs extends ToolArgs = ToolArgs> = {
107
115
  execute: McpToolHandler<TArgs>;
@@ -113,5 +121,24 @@ export type McpToolExecutionParams = {
113
121
  context: McpToolContext;
114
122
  extra: McpToolExtra;
115
123
  };
124
+ export type CustomMcpToolsState = {
125
+ registeredToolNames: string[];
126
+ };
127
+ export type ToolDefinitionValidationResult = {
128
+ ok: true;
129
+ schema: McpToolSchema;
130
+ } | {
131
+ ok: false;
132
+ errors: string[];
133
+ };
134
+ export type ToolFileDefaultExport = Partial<McpToolDefinition> | null | undefined;
135
+ export type McpToolModuleGetter = () => Promise<{
136
+ default: McpToolModuleExport;
137
+ }>;
138
+ export type McpToolMapExport = Record<string, McpToolHandler | McpToolHandlerExtended | undefined>;
139
+ export type McpToolFileExport = McpToolHandlerExtended & {
140
+ description: string;
141
+ };
142
+ export type McpToolModuleExport = McpToolMapExport | McpToolFileExport;
116
143
  export {};
117
144
  //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,4 @@
1
+ import type { McpToolSchema } from '../../../types';
2
+ import type { McpToolContext } from '../types.js';
3
+ export declare function availableSandboxTools(candidates: McpToolSchema[], context: McpToolContext): Promise<McpToolSchema[]>;
4
+ //# sourceMappingURL=available-sandbox-tools.d.ts.map
@@ -0,0 +1 @@
1
+ import{logger as i}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as a,MCP_TOOL_AVAILABILITY_KEY as m}from"../../../workers/mcp-tool-worker-pool.js";async function p(o,t){if(o.length===0)return o;const l=o.map(r=>r.name);let e;try{e=await a.exec(m,[{toolNames:l,context:t}],{timeout:1e4})}catch(r){return i.error(`Failed to resolve MCP tool availability: ${r instanceof Error?r.message:String(r)}`),o}return!e||typeof e!="object"?o:o.filter(r=>e[r.name]!==!1)}export{p as availableSandboxTools};
@@ -1,8 +1,7 @@
1
1
  import type { McpToolRegistration } from '../../../types';
2
- import type { McpToolHandler, McpToolHandlerExtended } from '../types.js';
3
- type ToolHandlers = Record<string, McpToolHandler | McpToolHandlerExtended>;
2
+ import type { McpToolModuleExport } from '../types.js';
4
3
  type ToolModuleLoader = (importPath: string) => Promise<{
5
- default: ToolHandlers;
4
+ default: McpToolModuleExport;
6
5
  }>;
7
6
  /**
8
7
  * Names of the tools whose handler declares an `isAvailable` predicate — the ones the live
@@ -1 +1 @@
1
- const r=t=>import(t);async function f(t,o=r){const n=[];for(const{name:a,importPath:i}of t){const e=await c(i,o);(!e||s(e[a]))&&n.push(a)}return n}async function c(t,o){try{const{default:n}=await o(t);return n}catch{return}}function s(t){return typeof t=="object"&&typeof t.isAvailable=="function"}export{f as findGatedToolNames};
1
+ import{resolveToolHandler as l}from"../workers/execute-mcp-tool.js";const s=t=>import(t);async function d(t,o=s){const n=[];for(const{name:e,importPath:r,hasAvailabilityGate:a}of t){if(a!==void 0){a&&n.push(e);continue}const i=await c(r,o);(!i||f(l(i,e)))&&n.push(e)}return n}async function c(t,o){try{const{default:n}=await o(t);return n}catch{return}}function f(t){return typeof t=="object"&&typeof t.isAvailable=="function"}export{d as findGatedToolNames};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Both markers are parenthesised so neither can collide with a real client: a name is built out
3
+ * of `[a-z0-9._-]`, which cannot produce a bracket.
4
+ */
5
+ export declare function resolveMcpClient(request: Request): {
6
+ client: string;
7
+ clientVersion?: string;
8
+ };
9
+ export declare function parseUserAgent(userAgent: string | null | undefined): {
10
+ client: string;
11
+ clientVersion?: string;
12
+ };
13
+ //# sourceMappingURL=mcp-client.d.ts.map
@@ -0,0 +1 @@
1
+ const o="(none)",r="(unparsed)",N=40,i=/^[A-Za-z0-9._\- ]+/,c=/\s+([0-9]\S*).*$/,l=/^[/\s]+v?([0-9][^\s;,)]*)/;function a(e){return E(e.headers.get("user-agent"))}function E(e){if(e==null)return{client:o};const n=i.exec(e)?.[0]??"",t=n.replace(c,"").trim();if(!t)return{client:r};const s=c.exec(n)?.[1]??l.exec(e.slice(n.length))?.[1];return{client:t.replace(/\s+/g,"-").toLowerCase().slice(0,40),clientVersion:s?.slice(0,40)}}export{E as parseUserAgent,a as resolveMcpClient};
@@ -0,0 +1,17 @@
1
+ import type { McpToolSchema } from '../../../types';
2
+ import type { ToolArgs } from '../types.js';
3
+ export declare function normalizeToolDisplayName(tool: McpToolSchema): McpToolSchema;
4
+ /** The `registerTool` config for a tool schema, with its input schema compiled for validation. */
5
+ export declare function toRegisterToolConfig(tool: McpToolSchema): {
6
+ title: string | undefined;
7
+ description: string;
8
+ inputSchema: import("@modelcontextprotocol/server").StandardSchemaWithJSON<ToolArgs, ToolArgs>;
9
+ annotations: {
10
+ title?: string | undefined;
11
+ readOnlyHint?: boolean | undefined;
12
+ destructiveHint?: boolean | undefined;
13
+ idempotentHint?: boolean | undefined;
14
+ openWorldHint?: boolean | undefined;
15
+ } | undefined;
16
+ };
17
+ //# sourceMappingURL=tool-registration.d.ts.map
@@ -0,0 +1 @@
1
+ import{fromJsonSchema as a}from"@modelcontextprotocol/server";import{mcpJsonSchemaValidator as r}from"./json-schema-validator.js";function m(t){const n=t.title??t.annotations?.title;return n?{...t,title:n,annotations:{...t.annotations,title:n}}:t}function p(t){const{title:n,description:o,schema:i,annotations:e}=m(t);return{title:n,description:o,inputSchema:a(i,r),annotations:e}}export{m as normalizeToolDisplayName,p as toRegisterToolConfig};
@@ -1,4 +1,9 @@
1
- import type { McpToolExecutionParams, McpToolWorkerResponse } from '../types.js';
1
+ import type { McpToolContext, McpToolExecutionParams, McpToolHandler, McpToolHandlerExtended, McpToolModuleExport, McpToolWorkerResponse } from '../types.js';
2
2
  export declare function executeMcpTool(params: McpToolExecutionParams): Promise<McpToolWorkerResponse>;
3
+ export declare function resolveToolHandler(moduleDefault: McpToolModuleExport, toolName: string): McpToolHandler | McpToolHandlerExtended | undefined;
3
4
  export declare function isMcpToolAvailable(params: Omit<McpToolExecutionParams, 'args' | 'extra'>): Promise<boolean>;
5
+ export declare function mcpToolAvailability(params: {
6
+ toolNames: string[];
7
+ context: McpToolContext;
8
+ }): Promise<Record<string, boolean>>;
4
9
  //# sourceMappingURL=execute-mcp-tool.d.ts.map
@@ -1 +1 @@
1
- import{telemetry as h}from"../../../telemetry/index.js";import{mcpToolHandlers as y}from"../../../../client/mcp-tool-handlers-entry.js";import{McpServerType as c}from"../constants.js";import{EXECUTE_TOOL_NAME as T}from"../codemode/constants.js";import{logMcpToolCallAudit as M,reportMcpToolCalled as C,reportMcpToolError as u}from"./mcp-tool-telemetry.js";function E(e){return e.content.map(o=>o.type==="text"?o.text:"")}async function j(e){h.initialize();const{toolName:o,args:a,context:l,extra:r}=e,n=l?.mcpMode??"tools",s=performance.now();try{const t=y[o];if(!t)throw new Error(`Unknown MCP tool: ${o}`);const{default:x}=await t(),i=x[o];if(!i)throw new Error(`MCP tool module does not export a handler for "${o}". Expected \`export default { '${o}': handler }\`.`);const f=await(typeof i=="function"?i:i.execute)(a,l,r);if(!v(f))throw new Error(`MCP tool "${o}" returned an invalid result.`);const m=Math.round(performance.now()-s),p=f.isError?o===T?"sandbox_error":"tool_error":void 0,d=E(f),w=d.join("");return M({tool:o,mode:n,serverType:c.Docs,args:a,result:w,errorClass:p}),p?u({tool:o,message:d.join(" "),mode:n,serverType:c.Docs,durationMs:m,errorClass:p}):C({tool:o,mode:n,serverType:c.Docs,durationMs:m,outputLength:w.length}),f}catch(t){throw M({tool:o,mode:n,serverType:c.Docs,args:a,errorClass:"server_error"}),u({tool:o,message:t instanceof Error?t.message:String(t),mode:n,serverType:c.Docs,durationMs:Math.round(performance.now()-s),stack:t instanceof Error&&t.stack||"",errorClass:"server_error"}),t}}function v(e){return!e||typeof e!="object"?!1:Array.isArray(e.content)}async function P(e){h.initialize();const{toolName:o,context:a}=e,l=performance.now();try{const r=y[o];if(!r)return!1;const{default:n}=await r(),s=n[o];return s?typeof s=="object"&&typeof s.isAvailable=="function"?await s.isAvailable(a):!0:!1}catch(r){throw u({tool:o,message:"Failed to check if MCP tool is available: "+(r instanceof Error?r.message:String(r)),mode:a?.mcpMode??"tools",serverType:c.Docs,durationMs:Math.round(performance.now()-l),stack:r instanceof Error&&r.stack||"",errorClass:"server_error"}),r}}export{j as executeMcpTool,P as isMcpToolAvailable};
1
+ import{telemetry as h}from"../../../telemetry/index.js";import{McpServerType as c}from"../constants.js";import{EXECUTE_TOOL_NAME as w}from"../codemode/constants.js";import{isPlainObject as f}from"../../../../utils/guards/is-plain-object.js";import{logMcpToolCallAudit as g,reportMcpToolCalled as _,reportMcpToolError as u}from"./mcp-tool-telemetry.js";import{attachToolFileSystem as E}from"./tool-file-system.js";import{importMcpToolHandlers as S}from"./import-mcp-tool-handlers.js";function A(e){return e.content.map(t=>t.type==="text"?t.text:"")}async function J(e){h.initialize();const{toolName:t,args:o,extra:s}=e,r=E(e.context),n=r?.mcpMode??"tools",a={client:r?.client,clientVersion:r?.clientVersion},d=performance.now();try{const i=await M(t);if(!i)throw new Error(`MCP tool "${t}" is not registered or its module does not export a handler for "${t}". Expected \`export default { '${t}': handler }\` or a single tool definition with \`description\` and \`execute\` as the default export.`);const C=typeof i=="function"?i:i.execute,l=P(t,await C(o,r,s),n),m=Math.round(performance.now()-d),{errorClass:y}=l;delete l.errorClass;const p=l.isError?y??(t===w?"sandbox_error":"tool_error"):void 0,v=t===w&&y==="tool_error",x=A(l),T=x.join("");return g({tool:t,mode:n,serverType:c.Docs,args:o,result:T,errorClass:p,...a}),p?v||u({tool:t,message:x.join(" "),mode:n,serverType:c.Docs,durationMs:m,errorClass:p,...a}):_({tool:t,mode:n,serverType:c.Docs,durationMs:m,outputLength:T.length,...a}),l}catch(i){throw g({tool:t,mode:n,serverType:c.Docs,args:o,errorClass:"server_error",...a}),u({tool:t,message:i instanceof Error?i.message:String(i),mode:n,serverType:c.Docs,durationMs:Math.round(performance.now()-d),stack:i instanceof Error&&i.stack||"",errorClass:"server_error",...a}),i}}function b(e){return"execute"in e&&typeof e.execute=="function"&&"description"in e&&typeof e.description=="string"}async function M(e){const t=(await S())[e];if(!t)return;const{default:o}=await t();return O(o,e)}function O(e,t){return b(e)?e:e[t]}function P(e,t,o){if(L(t))return t;if(typeof t=="string")return{content:[{type:"text",text:t}]};let s;try{s=JSON.stringify(t)}catch(n){throw new Error(`MCP tool "${e}" returned a value that cannot be serialized to JSON: `+(n instanceof Error?n.message:String(n)))}if(s===void 0)throw new Error(`MCP tool "${e}" returned an invalid result.`);const r=o==="code"?JSON.parse(s):void 0;return f(r)?{content:[{type:"text",text:s}],structuredContent:r}:{content:[{type:"text",text:s}]}}const k=new Set(["text","image","audio","resource","resource_link"]);function L(e){if(!f(e))return!1;const{content:t}=e;return Array.isArray(t)&&t.every(o=>f(o)&&k.has(o.type))}async function j(e){h.initialize();const{toolName:t}=e,o=E(e.context),s=performance.now();try{const r=await M(t);return r?typeof r=="object"&&typeof r.isAvailable=="function"?await r.isAvailable(o):!0:!1}catch(r){throw u({tool:t,message:"Failed to check if MCP tool is available: "+(r instanceof Error?r.message:String(r)),mode:o?.mcpMode??"tools",serverType:c.Docs,durationMs:Math.round(performance.now()-s),stack:r instanceof Error&&r.stack||"",errorClass:"server_error",client:o?.client,clientVersion:o?.clientVersion}),r}}async function F(e){const{toolNames:t,context:o}=e,s=await Promise.all(t.map(r=>j({toolName:r,context:o}).catch(()=>!1)));return Object.fromEntries(t.map((r,n)=>[r,s[n]]))}export{J as executeMcpTool,j as isMcpToolAvailable,F as mcpToolAvailability,O as resolveToolHandler};
@@ -0,0 +1,5 @@
1
+ import type { McpToolModuleGetter } from '../types.js';
2
+ type McpToolHandlers = Record<string, McpToolModuleGetter | undefined>;
3
+ export declare function importMcpToolHandlers(): Promise<McpToolHandlers>;
4
+ export {};
5
+ //# sourceMappingURL=import-mcp-tool-handlers.d.ts.map
@@ -0,0 +1 @@
1
+ import{stat as e}from"node:fs/promises";import{join as i}from"node:path";import{pathToFileURL as m}from"node:url";import{envConfig as a}from"../../../config/env-config.js";import{workerBaseDir as s}from"../../../workers/worker-pool.js";let t;async function y(){if(a.isRuntimeMode)return(await import("../../../../client/mcp-tool-handlers-entry.js")).mcpToolHandlers;const o=i(s,"mcp-tool-handlers-entry.js"),{mtimeMs:r}=await e(o);if(t?.mtimeMs!==r){const n=await import(`${m(o).href}?${r}`);t={mtimeMs:r,handlers:n.mcpToolHandlers}}return t.handlers}export{y as importMcpToolHandlers};