@redocly/redoc 0.137.0-next.6 → 0.137.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
- package/dist/client/templates/api-docs/helpers.d.ts +4 -1
- package/dist/client/templates/api-docs/helpers.js +5 -1
- package/dist/client/templates/api-docs/template.js +1 -1
- package/dist/constants/l10n/langs/ar.js +1 -1
- package/dist/constants/l10n/langs/de.js +1 -1
- package/dist/constants/l10n/langs/en.js +1 -1
- package/dist/constants/l10n/langs/es.js +1 -1
- package/dist/constants/l10n/langs/fr.js +1 -1
- package/dist/constants/l10n/langs/hi.js +1 -1
- package/dist/constants/l10n/langs/it.js +1 -1
- package/dist/constants/l10n/langs/ja.js +1 -1
- package/dist/constants/l10n/langs/ko.js +1 -1
- package/dist/constants/l10n/langs/pl.js +1 -1
- package/dist/constants/l10n/langs/pt-BR.js +1 -1
- package/dist/constants/l10n/langs/pt.js +1 -1
- package/dist/constants/l10n/langs/ru.js +1 -1
- package/dist/constants/l10n/langs/uk.js +1 -1
- package/dist/constants/l10n/langs/zh.js +1 -1
- package/dist/server/config/env-config.d.ts +2 -0
- package/dist/server/config/env-schema.d.ts +5 -0
- package/dist/server/config/env-schemas/feature-flags.d.ts +4 -0
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/esbuild/esbuild.js +3 -3
- package/dist/server/esbuild/plugins/mcp-tool-handlers-resolver.js +1 -1
- package/dist/server/plugins/api-docs/options.js +1 -1
- package/dist/server/plugins/{openapi-docs/is-openapi-doc.d.ts → api-docs/utils/is-api-doc.d.ts} +4 -2
- package/dist/server/plugins/api-docs/utils/is-api-doc.js +1 -0
- package/dist/server/plugins/arazzo-docs/arazzo-doc-loader.d.ts +1 -1
- package/dist/server/plugins/arazzo-docs/arazzo-doc-loader.js +1 -1
- package/dist/server/plugins/entitlements/index.js +1 -1
- package/dist/server/plugins/l10n/index.js +1 -1
- package/dist/server/plugins/lifecycle.js +2 -2
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-open-api-ref.js +1 -1
- package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +4 -4
- package/dist/server/plugins/mcp/codemode/code-execution-telemetry.d.ts +3 -1
- package/dist/server/plugins/mcp/codemode/code-execution-telemetry.js +1 -1
- package/dist/server/plugins/mcp/codemode/invoke-tool.js +1 -1
- package/dist/server/plugins/mcp/codemode/prompts.js +1 -1
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.d.ts +1 -1
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.js +9 -3
- package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +1 -1
- package/dist/server/plugins/mcp/codemode/types.d.ts +1 -0
- package/dist/server/plugins/mcp/constants.d.ts +1 -0
- package/dist/server/plugins/mcp/constants.js +1 -1
- package/dist/server/plugins/mcp/custom-tools/extract-tool-definition.d.ts +13 -0
- package/dist/server/plugins/mcp/custom-tools/extract-tool-definition.js +1 -0
- package/dist/server/plugins/mcp/custom-tools/scan-custom-tools.d.ts +6 -0
- package/dist/server/plugins/mcp/custom-tools/scan-custom-tools.js +1 -0
- package/dist/server/plugins/mcp/custom-tools/validate-tool-definition.d.ts +3 -0
- package/dist/server/plugins/mcp/custom-tools/validate-tool-definition.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +2 -0
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +2 -2
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.d.ts +10 -0
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +1 -9
- package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/errors.d.ts +7 -2
- package/dist/server/plugins/mcp/handlers/errors.js +1 -1
- package/dist/server/plugins/mcp/index.js +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.d.ts +2 -2
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/servers/mcp-server.d.ts +2 -11
- package/dist/server/plugins/mcp/servers/mcp-server.js +3 -3
- package/dist/server/plugins/mcp/types.d.ts +29 -3
- package/dist/server/plugins/mcp/utils/available-sandbox-tools.d.ts +4 -0
- package/dist/server/plugins/mcp/utils/available-sandbox-tools.js +1 -0
- package/dist/server/plugins/mcp/utils/find-gated-tool-names.d.ts +2 -3
- package/dist/server/plugins/mcp/utils/find-gated-tool-names.js +1 -1
- package/dist/server/plugins/mcp/utils/mcp-client.d.ts +13 -0
- package/dist/server/plugins/mcp/utils/mcp-client.js +1 -0
- package/dist/server/plugins/mcp/workers/execute-mcp-tool.d.ts +6 -1
- package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
- package/dist/server/plugins/mcp/workers/import-mcp-tool-handlers.d.ts +5 -0
- package/dist/server/plugins/mcp/workers/import-mcp-tool-handlers.js +1 -0
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +6 -11
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
- package/dist/server/plugins/mcp/workers/tool-file-system.d.ts +6 -0
- package/dist/server/plugins/mcp/workers/tool-file-system.js +1 -0
- package/dist/server/sandbox/sandbox.js +2 -2
- package/dist/server/sandbox/utils/returns-from-top-level.d.ts +4 -0
- package/dist/server/sandbox/utils/returns-from-top-level.js +1 -0
- package/dist/server/store.d.ts +1 -0
- package/dist/server/store.js +1 -1
- package/dist/server/types/plugins/common.d.ts +2 -1
- package/dist/server/web-server/routes/resolve-route.js +1 -1
- package/dist/server/web-server/utils/get-request-origin.d.ts +2 -0
- package/dist/server/web-server/utils/get-request-origin.js +1 -1
- package/dist/server/workers/mcp-tool-worker-pool.d.ts +1 -0
- package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
- package/dist/server/workers/mcp-tool-worker.js +1 -1
- package/dist/server/workers/types.d.ts +9 -2
- package/dist/server/workers/worker-pool.d.ts +1 -0
- package/dist/server/workers/worker-pool.js +1 -1
- package/dist/utils/guards/is-plain-object.d.ts +19 -0
- package/dist/utils/guards/is-plain-object.js +1 -0
- package/package.json +8 -11
- package/dist/client/templates/asyncapi-docs/helpers.d.ts +0 -12
- package/dist/client/templates/asyncapi-docs/helpers.js +0 -1
- package/dist/client/templates/asyncapi-docs/template.d.ts +0 -15
- package/dist/client/templates/asyncapi-docs/template.js +0 -9
- package/dist/client/templates/openapi-docs/helpers.d.ts +0 -18
- package/dist/client/templates/openapi-docs/helpers.js +0 -5
- package/dist/client/templates/openapi-docs/template.d.ts +0 -6
- package/dist/client/templates/openapi-docs/template.js +0 -14
- package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.d.ts +0 -9
- package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.js +0 -1
- package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.d.ts +0 -2
- package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.js +0 -1
- package/dist/server/esbuild/plugins/api-docs-module-replacer/index.d.ts +0 -6
- package/dist/server/esbuild/plugins/api-docs-module-replacer/index.js +0 -1
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-check.d.ts +0 -8
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-check.js +0 -1
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-overlay.d.ts +0 -2
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-overlay.js +0 -1
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-use-license-key.d.ts +0 -5
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/empty-use-license-key.js +0 -1
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/index.d.ts +0 -6
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/index.js +0 -1
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/loadAndBundleSpec.mock.d.ts +0 -3
- package/dist/server/esbuild/plugins/openapi-docs-module-replacer/loadAndBundleSpec.mock.js +0 -1
- package/dist/server/plugins/asyncapi-docs/asyncapi-doc-loader.d.ts +0 -18
- package/dist/server/plugins/asyncapi-docs/asyncapi-doc-loader.js +0 -5
- package/dist/server/plugins/asyncapi-docs/get-server-props.d.ts +0 -4
- package/dist/server/plugins/asyncapi-docs/get-server-props.js +0 -1
- package/dist/server/plugins/asyncapi-docs/get-template-path.d.ts +0 -2
- package/dist/server/plugins/asyncapi-docs/get-template-path.js +0 -1
- package/dist/server/plugins/asyncapi-docs/index.d.ts +0 -3
- package/dist/server/plugins/asyncapi-docs/index.js +0 -1
- package/dist/server/plugins/asyncapi-docs/is-asyncapi-doc.d.ts +0 -3
- package/dist/server/plugins/asyncapi-docs/is-asyncapi-doc.js +0 -1
- package/dist/server/plugins/asyncapi-docs/search/get-ai-search-documents.d.ts +0 -9
- package/dist/server/plugins/asyncapi-docs/search/get-ai-search-documents.js +0 -56
- package/dist/server/plugins/asyncapi-docs/search/schema-processor.d.ts +0 -8
- package/dist/server/plugins/asyncapi-docs/search/schema-processor.js +0 -1
- package/dist/server/plugins/asyncapi-docs/search/search-facets.d.ts +0 -8
- package/dist/server/plugins/asyncapi-docs/search/search-facets.js +0 -1
- package/dist/server/plugins/asyncapi-docs/search/search-resolver.d.ts +0 -5
- package/dist/server/plugins/asyncapi-docs/search/search-resolver.js +0 -1
- package/dist/server/plugins/asyncapi-docs/store-definition-bundles.d.ts +0 -4
- package/dist/server/plugins/asyncapi-docs/store-definition-bundles.js +0 -1
- package/dist/server/plugins/graphql-docs/constants.d.ts +0 -2
- package/dist/server/plugins/graphql-docs/constants.js +0 -1
- package/dist/server/plugins/graphql-docs/get-template-path.d.ts +0 -2
- package/dist/server/plugins/graphql-docs/get-template-path.js +0 -1
- package/dist/server/plugins/graphql-docs/graphql-doc-loader.d.ts +0 -17
- package/dist/server/plugins/graphql-docs/graphql-doc-loader.js +0 -1
- package/dist/server/plugins/graphql-docs/index.d.ts +0 -4
- package/dist/server/plugins/graphql-docs/index.js +0 -1
- package/dist/server/plugins/graphql-docs/is-graphql-doc.d.ts +0 -2
- package/dist/server/plugins/graphql-docs/is-graphql-doc.js +0 -1
- package/dist/server/plugins/graphql-docs/search/ai/get-ai-search-document.d.ts +0 -17
- package/dist/server/plugins/graphql-docs/search/ai/get-ai-search-document.js +0 -4
- package/dist/server/plugins/graphql-docs/search/ai/utils.d.ts +0 -14
- package/dist/server/plugins/graphql-docs/search/ai/utils.js +0 -36
- package/dist/server/plugins/graphql-docs/search/search-facets.d.ts +0 -8
- package/dist/server/plugins/graphql-docs/search/search-facets.js +0 -1
- package/dist/server/plugins/graphql-docs/search/search-resolver.d.ts +0 -5
- package/dist/server/plugins/graphql-docs/search/search-resolver.js +0 -1
- package/dist/server/plugins/graphql-docs/spec-download.api.d.ts +0 -3
- package/dist/server/plugins/graphql-docs/spec-download.api.js +0 -1
- package/dist/server/plugins/graphql-docs/template/GraphQLDocs.d.ts +0 -5
- package/dist/server/plugins/graphql-docs/template/GraphQLDocs.js +0 -4
- package/dist/server/plugins/graphql-docs/types.d.ts +0 -40
- package/dist/server/plugins/graphql-docs/types.js +0 -0
- package/dist/server/plugins/openapi-docs/ai-search-indexer.d.ts +0 -14
- package/dist/server/plugins/openapi-docs/ai-search-indexer.js +0 -1
- package/dist/server/plugins/openapi-docs/decorators.d.ts +0 -25
- package/dist/server/plugins/openapi-docs/decorators.js +0 -1
- package/dist/server/plugins/openapi-docs/format-bundle-error.d.ts +0 -6
- package/dist/server/plugins/openapi-docs/format-bundle-error.js +0 -5
- package/dist/server/plugins/openapi-docs/get-server-props.d.ts +0 -4
- package/dist/server/plugins/openapi-docs/get-server-props.js +0 -1
- package/dist/server/plugins/openapi-docs/get-template-path.d.ts +0 -2
- package/dist/server/plugins/openapi-docs/get-template-path.js +0 -1
- package/dist/server/plugins/openapi-docs/index.d.ts +0 -3
- package/dist/server/plugins/openapi-docs/index.js +0 -1
- package/dist/server/plugins/openapi-docs/is-openapi-doc.js +0 -1
- package/dist/server/plugins/openapi-docs/load-definition.d.ts +0 -31
- package/dist/server/plugins/openapi-docs/load-definition.js +0 -3
- package/dist/server/plugins/openapi-docs/openapi-search-builder.d.ts +0 -24
- package/dist/server/plugins/openapi-docs/openapi-search-builder.js +0 -1
- package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.d.ts +0 -18
- package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.js +0 -94
- package/dist/server/plugins/openapi-docs/search/search-facets.d.ts +0 -11
- package/dist/server/plugins/openapi-docs/search/search-facets.js +0 -1
- package/dist/server/plugins/openapi-docs/search/search-resolver.d.ts +0 -5
- package/dist/server/plugins/openapi-docs/search/search-resolver.js +0 -1
- package/dist/server/plugins/openapi-docs/search-indexer.d.ts +0 -17
- package/dist/server/plugins/openapi-docs/search-indexer.js +0 -1
- package/dist/server/plugins/openapi-docs/spec-download.api.d.ts +0 -4
- package/dist/server/plugins/openapi-docs/spec-download.api.js +0 -1
- package/dist/server/plugins/openapi-docs/store-definition-bundles.d.ts +0 -4
- package/dist/server/plugins/openapi-docs/store-definition-bundles.js +0 -1
- package/dist/server/plugins/openapi-docs/types.d.ts +0 -17
- package/dist/server/plugins/openapi-docs/types.js +0 -0
- package/dist/server/plugins/openapi-docs/utils.d.ts +0 -25
- package/dist/server/plugins/openapi-docs/utils.js +0 -1
- /package/dist/client/templates/{openapi-docs → api-docs}/mock-server-config.d.ts +0 -0
- /package/dist/client/templates/{openapi-docs → api-docs}/mock-server-config.js +0 -0
- /package/dist/{server/plugins → markdoc}/helpers/parse-partials.d.ts +0 -0
- /package/dist/{server/plugins → markdoc}/helpers/parse-partials.js +0 -0
- /package/dist/server/plugins/{openapi-docs → api-docs/utils}/ast-utils.d.ts +0 -0
- /package/dist/server/plugins/{openapi-docs → api-docs/utils}/ast-utils.js +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ApiDescriptionInfo, McpToolContext } from '../types.js';
|
|
2
|
+
export declare function getCallableApis(context: McpToolContext): ApiDescriptionInfo[];
|
|
3
|
+
/**
|
|
4
|
+
* Fetch capability at request/worker time is derived purely from the build-time stamps:
|
|
5
|
+
* `fetchEligible` is stamped per API by the lifecycle plugin under `isGatewayCapabilityEnabled`
|
|
6
|
+
* (entitlement + hide checks), and the map arriving here is already RBAC-filtered.
|
|
7
|
+
* No EntitlementsProvider read — this code runs in graphs where the provider is uninitialized.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isFetchCapable(context: McpToolContext): boolean;
|
|
10
|
+
//# sourceMappingURL=callable-apis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function i(e){return Object.values(e.apiDescriptionsMap??{}).filter(t=>t.fetchEligible)}function l(e){return i(e).length>0}export{i as getCallableApis,l as isFetchCapable};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Agent as
|
|
1
|
+
import{Agent as Q}from"undici";import{envConfig as Z}from"../../../../config/env-config.js";import{logger as N}from"../../../../tools/notifiers/logger.js";import{assertUrlAllowed as I}from"./ssrf-guard.js";import{createSsrfSafeLookup as q}from"./ssrf-safe-lookup.js";import{SsrfBlockedError as W}from"./ssrf-blocklist.js";import{GatewayFetchBlockedError as R,GatewayFetchSystemError as ee,GatewayFetchUserError as g}from"./fetch-errors.js";import{redactHeaders as J,redactSecretsFromString as te}from"./redact.js";import{extractUpstreamDetail as re}from"./upstream-detail.js";import{normalizeFetchPath as ne}from"./normalize-path.js";import{reportGatewayFetch as K}from"./fetch-telemetry.js";import{logGatewayFetchAudit as V}from"./fetch-audit.js";const X="x-forwarded-for",oe=3e4,se=1024*1024,ae=new Set([401,403,407]);let C;function ce(){if(!C){const e=Z.isDevelopMode;e&&N.warn("Gateway MCP SSRF guard: loopback upstreams are ALLOWED (develop mode only, never in runtime)."),C=new Q({connect:{lookup:q({allowLoopback:e})}})}return C}function _e({allowedHosts:e,apis:t=[],authorization:r,onAuthRequired:n,fetchImpl:c=fetch,dispatcher:a=ce(),timeoutMs:h=oe,maxResponseBytes:l=se,maxFetchesPerExec:w,clientIp:k}){const f=[...e,...t.flatMap(o=>o.matchers)],$=[...new Set(t.map(o=>o.name).filter(Boolean))].join(", "),m=t.flatMap(o=>Object.values(o.secrets??{})),D=[r,...m.map(o=>o.value)].filter(o=>!!o),x=m.map(o=>o.header);let O=0;return async o=>{const y=o.method??"GET",T=Date.now();let B,b,A,E={},H,_,j;try{if(w!==void 0){const u=Math.max(0,w);if(O+=1,O>u)throw new g(`Outbound fetch budget exceeded (max ${u} fetches per execute); split the work across calls`)}const d=le(o.url,f,$);B=d.hostname,b=ne(d.pathname);const v=t.filter(u=>u.matchers.some(z=>z.test(d.hostname))),s=v.length===1?v[0]:void 0;A=s?.slug;const S=pe(o.securityScheme,s),F=S?[S]:s?ye(s,d.pathname,y):void 0,L=s&&F?Se(s,F):void 0,P=L?s?.secrets?.[L]:void 0,M=be({callerHeaders:o.headers,secret:P,authorization:r,clientIp:k,credentialHeaders:s?.credentialHeaders});E=M.headers,H=P&&!M.callerHeader?L:void 0;const G=new AbortController;j=setTimeout(()=>G.abort(),h);const i=await c(d,{method:y,headers:E,body:o.body,redirect:"manual",signal:G.signal,dispatcher:a});_=i.status;let U="";try{U=await we(i,l)}finally{if(ae.has(i.status)&&s&&n){const u=re(U,i.headers.get("content-type"),D);n({api:s.slug,name:s.name,status:i.status,...L?{scheme:L}:{},...F?.length?{schemes:[...F]}:{},...H?{sentScheme:H}:{},...M.callerHeader?{callerHeader:M.callerHeader}:{},...u?{detail:u}:{}})}}let p=Ae(i.headers);if(fe(i.status)){p=J(p,x);const{location:u}=p;u&&!he(u,d,f)&&delete p.location}return K({host:d.hostname,method:y,outcome:"success",durationMs:Date.now()-T,path:b,api:A,status:i.status,bytes:Buffer.byteLength(U,"utf8")}),V({rawUrl:d.href,method:y,host:d.hostname,outcome:"success",durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:i.status,injectedScheme:H,requestHeaders:E,requestBody:o.body,responseHeaders:p,responseBody:U}),{status:i.status,statusText:i.statusText,ok:i.ok,headers:p,bodyText:U}}catch(d){const{outcome:v,userSafe:s}=ie(d),S=B??(s instanceof R?s.host:void 0)??ue(o.url)??"invalid-url";throw K({host:S,method:y,outcome:v,durationMs:Date.now()-T,path:b,api:A,status:_}),V({rawUrl:o.url,method:y,host:S,outcome:v,durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:_,injectedScheme:H,requestHeaders:E,requestBody:o.body}),s||(N.error(`Gateway MCP fetch failed [${y} ${S}]: ${te(me(d),D)} headers=${JSON.stringify(J(E,x))}`),new ee("Upstream fetch failed due to an internal error"))}finally{j!==void 0&&clearTimeout(j)}}}function de(e){let t=e;for(let r=0;r<5&&t instanceof Error;r++){if(t instanceof g||t instanceof W)return t;t=t.cause}}function ie(e){const t=de(e);return{outcome:t instanceof R||t instanceof W?"blocked":t?"user_error":"system_error",userSafe:t}}function le(e,t,r){try{return I(e,t)}catch(n){throw n instanceof R&&r?new R(`${n.message}. \`fetch\` reaches only the documented hosts of the callable APIs (${r}); other documented APIs can be read through the tools but not called.`,n.host):n}}function ue(e){try{return new URL(e).hostname||void 0}catch{return}}function fe(e){return e>=300&&e<400}function he(e,t,r){try{return!!I(new URL(e,t).href,r)}catch{return!1}}function me(e){if(!(e instanceof Error))return String(e);const t=e.cause;return t instanceof Error?`${e.message}: ${t.message}`:e.message}async function we(e,t){const r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>t)throw Y(t,r);if(!e.body)return"";const n=e.body.getReader(),c=new TextDecoder;let a=0,h="";try{for(;;){const{done:l,value:w}=await n.read();if(l)break;if(a+=w.byteLength,a>t)throw Y(t,a);h+=c.decode(w,{stream:!0})}return h+c.decode()}finally{await n.cancel().catch(()=>{})}}function Y(e,t){return new g(`Response is too large (over ${e} bytes, got ${t}); request less data`)}function ye(e,t,r){const n=e.routes?.find(c=>c.method===r&&c.pattern.test(t));return n?n.schemes:ge(e)}function Se(e,t){const r=t.filter(n=>e.secrets?.[n]);return r.length===0?t[0]:r.reduce((n,c)=>{const a=e.secrets?.[n]?.savedAt??0;return(e.secrets?.[c]?.savedAt??0)>a?c:n})}function pe(e,t){if(e==null)return;if(typeof e!="string")throw new g("securityScheme must be a security scheme name (a string)");if(!t)throw new g("securityScheme cannot be applied: the URL host does not identify exactly one callable API");const r=t.schemePriority??[];if(r.length>0&&!r.includes(e))throw new g(`Unknown securityScheme "${e}" for ${t.name}; valid values: ${r.join(", ")}`);return e}function ge(e){const t=Object.keys(e.secrets??{});if(t.length===0)return e.defaultScheme?[e.defaultScheme]:[];const r=(e.schemePriority??[]).filter(n=>t.includes(n));return[...r,...t.filter(n=>!r.includes(n))]}function be({callerHeaders:e,secret:t,authorization:r,clientIp:n,credentialHeaders:c}){const a={},h=new Set,l=t??(r?{header:"Authorization",value:r}:void 0),w=l?new Set((c??[]).map(f=>f.toLowerCase()).filter(f=>f!==l.header.toLowerCase())):new Set;for(const[f,$]of Object.entries(e??{})){const m=f.toLowerCase();m==="host"||m==="content-length"||m!==X&&(w.has(m)||(h.add(m),a[f]=$))}if(n&&(a[X]=n),!l)return{headers:a};const k=l.header.toLowerCase();return h.has(k)?{headers:a,callerHeader:k}:(a[l.header]=l.value,{headers:a})}function Ae(e){const t={};return e.forEach((r,n)=>{t[n.toLowerCase()]=r}),t}export{_e as buildFetchBridge,ce as getDefaultAgent,we as readCappedBody};
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { McpToolContext } from '../types.js';
|
|
2
2
|
import type { SandboxFetch } from '../codemode/types.js';
|
|
3
3
|
import type { UpstreamAuthRequiredEvent } from './upstream-auth.js';
|
|
4
|
-
export declare function getCallableApis(context: McpToolContext): ApiDescriptionInfo[];
|
|
5
|
-
/**
|
|
6
|
-
* Fetch capability at request/worker time is derived purely from the build-time stamps:
|
|
7
|
-
* `fetchEligible` is stamped per API by the lifecycle plugin under `isGatewayCapabilityEnabled`
|
|
8
|
-
* (entitlement + hide checks), and the map arriving here is already RBAC-filtered.
|
|
9
|
-
* No EntitlementsProvider read — this code runs in graphs where the provider is uninitialized.
|
|
10
|
-
*/
|
|
11
|
-
export declare function isFetchCapable(context: McpToolContext): boolean;
|
|
12
4
|
export declare function buildExecuteHostFetch(context: McpToolContext, onAuthRequired?: (event: UpstreamAuthRequiredEvent) => void): Promise<SandboxFetch>;
|
|
13
5
|
//# sourceMappingURL=fetch-capability.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildAllowedHostMatchers as
|
|
1
|
+
import{getCallableApis as l}from"./callable-apis.js";import{buildAllowedHostMatchers as a}from"./fetch/allowed-hosts.js";import{buildFetchBridge as m}from"./fetch/fetch-bridge.js";import{credentialHeadersOf as o,orderedSchemesOf as c,resolveUpstreamApiAuth as h}from"./upstream-auth-scheme.js";async function f(e,s){const i=await Promise.all(l(e).map(async r=>{const t=await h(e,r.relativePath);return{slug:r.relativePath,name:r.name,matchers:a(r.servers??[]),secrets:e.upstreamSecrets?.[r.relativePath],defaultScheme:t.defaultScheme,routes:t.routes,credentialHeaders:o(t.schemes),schemePriority:c(t.schemes)}}));return m({allowedHosts:a([]),apis:i,authorization:e.upstreamAuthorization,onAuthRequired:s,maxFetchesPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp})}export{f as buildExecuteHostFetch};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as
|
|
1
|
+
import{logger as u}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as N}from"../../../web-server/utils/feedback-ip.js";import{getForwardedOrigin as g,getInternalOrigin as F}from"../../../web-server/utils/get-request-origin.js";import{GATEWAY_FETCH_LIMIT_DEFAULTS as v}from"../../../../constants/common.js";import{isObject as k}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as B}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as L}from"../../../utils/skills/get-skill-url.js";import{createMcpHandler as H}from"@modelcontextprotocol/server";import{createDocsMcpServer as V}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as $,filterGraphqlDescriptionsByRbac as j}from"../utils.js";import{McpClientInputError as G,createMethodNotAllowedError as J,withErrorHandling as K}from"./errors.js";import{constructForbiddenResponse as Y,constructInvalidTokenResponse as z,constructUnauthorizedResponse as W,handleMcpAuth as X}from"../auth/auth-handlers.js";import{shouldHandleMcpAuth as Q}from"../../../utils/rbac/should-handle-mcp-auth.js";import{canAnonymousAccessMcpFeature as Z}from"../../../utils/rbac/can-anonymous-access-mcp-feature.js";import{extractTokenFromAuthHeader as q}from"../utils/jwt.js";import{resolveMcpClient as x}from"../utils/mcp-client.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as ee,SSE_KEEPALIVE_INTERVAL_MS as re}from"../constants.js";import{withPathPrefix as oe}from"@redocly/theme/core/utils";import{PUBLIC_MCP_ROUTE as se}from"@redocly/theme/core/constants/mcp";import{canAccessFeature as ne}from"../../../utils/rbac.js";import{ANONYMOUS_AUTH_DETAILS as ie}from"../../../constants/rbac.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as te,RbacFeatures as ce}from"../../../../constants/common.js";const h="X-Redocly-AI-Metadata";function ae(r){if(r)try{const e=JSON.parse(r);if(k(e))return e;u.warn(`Ignoring ${h} header: not a JSON object.`)}catch{u.warn(`Ignoring ${h} header: invalid JSON.`)}}const pe=async(r,e,t)=>{const n=!!e?.config?.access?.requiresLogin,i=e?.config?.access?.rbac||{},A=t?.props?.config?.mcpMode??"tools",T=t?.props?.config?.gatewayFetchBudgetPerExec??v.budgetPerExec,S=t?.props?.config?.searchIgnoredRoutes??[],s=t,b=!!s?.props?.config?.isPublicEndpoint;let p;const E=r.headers.get("Authorization");if(b)e.user={...ie,email:"",idpAccessToken:void 0,idpId:void 0};else if(Q(n,i)){const{isAuthenticated:d,isTokenValid:l,currentUser:a,accessToken:m}=await X(r,e);if(!d){const c=g(r),f=e.config.mcp?.docs?.publicEndpoint&&Z(i,n)?`${c}${oe(se)}`:void 0;return l===!1?z(c):W(c,f)}a&&(e.user=a),p=m}else E&&(p=q(E||"")??void 0);const I={isAuthenticated:!!e.user?.isAuthenticated,teams:e.user?.teams||[te],claims:e.user?.claims??{}};return ne(ce.MCP,I,i,n)?await K(async()=>{const d=t?.props?.config?.elicitationEnabled??!1;if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need to register it in your MCP client (VS Code, Cursor, Claude Code, etc.) using this URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return J();const l=s?.props?.config?.apiDescriptionsMap||{},a=s?.props?.config?.graphqlDescriptions||[],m=s?.props?.config?.mcpDocsServerName||ee,{config:{mcp:c={}}}=e,f=$(l,e.user,i,n),y=j(a,e.user,i,n),U=e.config.products?Object.values(e.config.products).map(o=>o?.name):[],w=c.docs?.name||m,C=ae(r.headers.get(h)),R=s?.props?.tools||[],_=s?.props?.skillsBaseUrl||g(r),D=B(s?.props?.skills||[],e.user,i,n).map(o=>({slug:o.slug,name:o.name,description:o.description,content:o.content,uri:L(_,o.slug)})),M=await de(r),O={name:w,tools:R,skills:D,context:{...e,accessToken:p,outdir:e.outdir||"",baseUrl:e.baseUrl||g(r),internalBaseUrl:F(r),apiDescriptionsMap:f,graphqlDescriptions:y,products:U,metadata:C,mcpMode:A,elicitationEnabled:d,gatewayFetchBudgetPerExec:T,searchIgnoredRoutes:S,clientIp:N(r),...x(r)}},P=await V({...O,getKv:e.getKv});return await H(async()=>P,{keepAliveMs:re,onerror:o=>u.warn(`MCP handler: ${o.message}`)}).fetch(r,M!==void 0?{parsedBody:M}:void 0)},A):Y()};async function de(r){try{return await r.json()}catch(e){throw new G(e instanceof Error?e.message:String(e),{cause:e})}}var Fe=pe;export{Fe as default};
|
|
@@ -12,9 +12,14 @@ export declare class McpError extends Error {
|
|
|
12
12
|
constructor(code: McpErrorCodeTypes, message: string, data?: unknown, requestId?: string | number | null);
|
|
13
13
|
createErrorResponse(): Response;
|
|
14
14
|
}
|
|
15
|
+
export declare class McpClientInputError extends Error {
|
|
16
|
+
constructor(message: string, options?: {
|
|
17
|
+
cause?: unknown;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
15
20
|
export declare function createMethodNotAllowedError(requestId?: string | number | null): Response;
|
|
16
|
-
export declare function createInternalServerError(error: Error | string, requestId?: string | number | null
|
|
21
|
+
export declare function createInternalServerError(error: Error | string, requestId?: string | number | null): Response;
|
|
17
22
|
export declare function createInvalidRequestError(message?: string, requestId?: string | number | null): Response;
|
|
18
23
|
export declare function createInvalidParamsError(message?: string, requestId?: string | number | null): Response;
|
|
19
|
-
export declare function withErrorHandling<T>(operation: () => Promise<T>,
|
|
24
|
+
export declare function withErrorHandling<T>(operation: () => Promise<T>, mode?: McpMode): Promise<T | Response>;
|
|
20
25
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetry as c}from"../../../telemetry/index.js";import{McpErrorCodes as
|
|
1
|
+
import{telemetry as c}from"../../../telemetry/index.js";import{McpErrorCodes as o,McpServerType as i}from"../constants.js";import{serverAttributes as d}from"../utils/telemetry-attributes.js";class s extends Error{code;data;requestId;constructor(e,t,n,a){super(t),this.name="McpError",this.code=e,this.data=n,this.requestId=a}createErrorResponse(){const e={jsonrpc:"2.0",error:{code:this.code,message:this.message,...this.data?{data:this.data}:{}},id:this.requestId??null},t=p(this.code);return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":"application/json"}})}}class u extends Error{constructor(e,t){super(e,t),this.name="McpClientInputError"}}function p(r){switch(r){case o.InvalidRequest:case o.InvalidParams:return 400;case o.MethodNotFound:return 404;case o.ServerError:return 405;case o.InternalError:default:return 500}}function I(r){return new s(o.ServerError,"Method not allowed",void 0,r).createErrorResponse()}function l(r,e){const t=r instanceof Error?r.message:String(r);return new s(o.InternalError,"Internal server error mcp",t,e).createErrorResponse()}function f(r="Invalid request",e){return new s(o.InvalidRequest,r,void 0,e).createErrorResponse()}function v(r="Invalid parameters",e){return new s(o.InvalidParams,r,void 0,e).createErrorResponse()}async function M(r,e="tools"){try{return await r()}catch(t){return c.sendMcpErrorMessage([{...d(i.Docs),message:t?.message||"",stack:t?.stack||"",error_class:t instanceof u?"client_error":"server_error",mode:e}]),l(t)}}export{u as McpClientInputError,s as McpError,l as createInternalServerError,v as createInvalidParamsError,f as createInvalidRequestError,I as createMethodNotAllowedError,M as withErrorHandling};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fileURLToPath as
|
|
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,12 +1,12 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
1
2
|
import type { McpToolSchema } from '../../../types';
|
|
2
3
|
import type { McpToolContext, SkillMcpResource } from '../types.js';
|
|
3
4
|
import type { KvService } from '@redocly/config';
|
|
4
|
-
import { type McpServerInstance } from './mcp-server.js';
|
|
5
5
|
export declare function createDocsMcpServer({ name, tools, context, skills, getKv, }: {
|
|
6
6
|
name: string;
|
|
7
7
|
tools: McpToolSchema[];
|
|
8
8
|
context: McpToolContext;
|
|
9
9
|
skills?: SkillMcpResource[];
|
|
10
10
|
getKv: () => Promise<KvService>;
|
|
11
|
-
}): Promise<
|
|
11
|
+
}): Promise<McpServer>;
|
|
12
12
|
//# sourceMappingURL=docs-server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as
|
|
1
|
+
import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as M,MCP_TOOL_IS_AVAILABLE_KEY as v}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as k}from"../constants.js";import{isAnonymousSessionToolAvailable as C}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as L,manageApiCredentials as y,manageApiCredentialsSchema as D}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as A}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as w,CODE_MODE_TOOL_NAMES as N,FETCH_TOOL_NAME as x}from"../codemode/constants.js";import{buildCodeModeInstructions as H,buildExecuteDescription as I}from"../codemode/prompts.js";import{toToolListEntries as U}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as F,getActiveCapabilities as P}from"../codemode/capabilities/index.js";import{describeToolsSchema as R,describeTools as z}from"../codemode/tools/describe-tools.js";import{availableSandboxTools as W}from"../utils/available-sandbox-tools.js";import{toRegisterToolConfig as _}from"../utils/tool-registration.js";import{createMcpServer as X,createToolDispatch as Y,extractSerializableContext as $}from"./mcp-server.js";function g(c,r){const o=r.schema;if(C(c))return o;const{sessionHandle:f,...m}=o.properties;return{...o,properties:m}}async function ae({name:c,tools:r,context:o,skills:f=[],getKv:m}){const l=$(o),a=o.mcpMode==="code",s=a?P(o):[],T=s.some(e=>e.id===x),p=a?await W(r.filter(e=>!N.has(e.name)),l):[],b=U(p,s),O=a&&L(o),n=X(c,a?H(T,b):void 0),E={getClientCapabilities:()=>n.server.getClientCapabilities(),getKv:m},d=Y(l,E),u=async e=>{try{return await M.exec(v,[{toolName:e,context:l}],{timeout:1e4})}catch(i){return S.error(`Failed to check MCP tool availability for "${e}": ${i instanceof Error?i.message:String(i)}`),!1}};if(a){const e=[{tool:{...A,description:I(T,b),schema:g(o,A),annotations:F(s)},callback:d(w)},{tool:R(p,s),callback:z(p,u,s,o)}],i=r.find(t=>t.name===k);if(i&&C(o)&&e.push({tool:i,callback:d(i.name)}),O){const t=D(o);e.push({tool:{...t,schema:g(o,t)},callback:y(l,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 n}export{ae as createDocsMcpServer};
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { McpServer
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { McpToolCallback, McpToolContext } from '../types.js';
|
|
3
3
|
import type { KvService } from '@redocly/config';
|
|
4
|
-
export
|
|
5
|
-
server: McpServer;
|
|
6
|
-
transport: WebStandardStreamableHTTPServerTransport;
|
|
7
|
-
cleanup: () => Promise<void>;
|
|
8
|
-
};
|
|
9
|
-
export declare function createMcpServer(name: string, instructions?: string): {
|
|
10
|
-
server: McpServer;
|
|
11
|
-
transport: WebStandardStreamableHTTPServerTransport;
|
|
12
|
-
};
|
|
13
|
-
export declare function connectMcpServer(server: McpServer, transport: WebStandardStreamableHTTPServerTransport): Promise<McpServerInstance>;
|
|
4
|
+
export declare function createMcpServer(name: string, instructions?: string): McpServer;
|
|
14
5
|
export type ToolDispatchDeps = {
|
|
15
6
|
getClientCapabilities: () => {
|
|
16
7
|
elicitation?: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{McpServer as
|
|
1
|
+
import{McpServer as j}from"@modelcontextprotocol/server";import{logger as b}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as D,MCP_TOOL_WORKER_KEY as F}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as K}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as L,stripAuthRequiredMeta as M,upstreamAuthKey as S}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as H,buildSchemeChoiceHint as B,buildUpstreamCredentialFallback as q,buildUpstreamCredentialInputRequired as P,isCredentialElicitationDeclined as $,schemeLabelOf as x}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as T,resolveUpstreamApiAuth as N,schemeChoicesOf as v}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as G,resolveSecretSubject as V}from"../gateway-mcp/subject.js";const W=6e4,E=new Map;function Y(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 pe(e,t){return new j({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function de(e,t){return r=>async(n,s)=>{b.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,c=s.mcpReq.envelope!==void 0,a=i?V(e.user,n.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 K.getSecretsForSubject(m,o)}catch(m){b.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:re(s)};return await D.exec(F,[m],{timeout:W})};let d=await l();const f=L(d);if(f.length>0&&i&&!o)return M({...d,content:[{type:"text",text:G}],isError:!0});if(f.length>0&&i&&o&&t?.getKv){b.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${Q(t)}`);const m=await t.getKv(),h=await X(e,f),k=f.map(_=>Z(_,h)),y=z(u),g=c?await ee(e,s,k,o,m,y,h,t):await te(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 J(e){return!!e?.getClientCapabilities()?.elicitation?.url}function Q(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 X(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await N(e,n));return r}function Z(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??T};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function z(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(S({api:r,scheme:s}));return t}function R(e,t){return e.status===401&&!t.has(S(e))}function A(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?x(r.schemes,n):void 0}function I(e,t){const r=t.get(e.api);return!r||!e.schemes?.length?[]:v(r,e.schemes)}function C(e,t){return I(e,t).length>1}function w(e,t){return e.map(r=>H(r,A(r,t))).join(`
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
3
|
+
`)}function U(e,t,r){const n=e.map(s=>B(s,I(s,r)));return t.length>0&&n.push(w(t,r)),n.join(`
|
|
4
4
|
|
|
5
|
-
`)}function O(e,t,n,
|
|
5
|
+
`)}function O(e,t,r,n,s){const[i,...c]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??T,p=A(i,s);return{subject:r,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:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:c.map(u=>u.name)}}}async function ee(e,t,r,n,s,i,c,a){if($(t.mcpReq.inputResponses))return{kind:"none"};const o=r.filter(l=>R(l,i));if(o.length===0)return{kind:"prependText",text:w(r,c)};const p=o.filter(l=>C(l,c));if(p.length>0){const l=r.filter(d=>!p.includes(d));return{kind:"prependText",text:U(p,l,c)}}const u=O(e,o,n,s,c);return J(a)?{kind:"inputRequired",result:await P(u)}:{kind:"prependText",text:await q(u)}}async function te(e,t,r,n,s,i){const c=t.filter(u=>R(u,s));if(c.length===0)return{kind:"prependText",text:w(t,i)};const a=c.filter(u=>C(u,i));if(a.length>0){const u=t.filter(l=>!a.includes(l));return{kind:"prependText",text:U(a,u,i)}}const o=O(e,c,r,n,i);return{kind:"prependText",text:await Y(`${r}:${S(c[0])}`,()=>q(o))}}function re(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function me(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{pe as createMcpServer,de as createToolDispatch,me 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';
|
|
@@ -79,7 +79,10 @@ export type SemanticSearchResult = {
|
|
|
79
79
|
url: string;
|
|
80
80
|
content: string;
|
|
81
81
|
};
|
|
82
|
-
export type
|
|
82
|
+
export type McpErrorClass = 'tool_error' | 'sandbox_error' | 'client_error' | 'server_error';
|
|
83
|
+
export type McpToolWorkerResponse = CallToolResult & {
|
|
84
|
+
errorClass?: McpErrorClass;
|
|
85
|
+
};
|
|
83
86
|
export type ToolArgs = Record<string, unknown>;
|
|
84
87
|
export type McpToolCallback = ToolCallback<StandardSchemaWithJSON<ToolArgs, ToolArgs>>;
|
|
85
88
|
export type McpToolExtra = {
|
|
@@ -99,10 +102,14 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
|
|
|
99
102
|
elicitationEnabled?: boolean;
|
|
100
103
|
gatewayFetchBudgetPerExec?: number;
|
|
101
104
|
clientIp?: string;
|
|
105
|
+
client?: string;
|
|
106
|
+
clientVersion?: string;
|
|
102
107
|
upstreamSecrets?: UpstreamSecrets;
|
|
103
108
|
searchIgnoredRoutes?: string[];
|
|
109
|
+
internalBaseUrl?: string;
|
|
110
|
+
fs?: McpToolFileSystem;
|
|
104
111
|
};
|
|
105
|
-
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>;
|
|
106
113
|
export type McpToolIsAvailable = (context: McpToolContext) => boolean | Promise<boolean>;
|
|
107
114
|
export type McpToolHandlerExtended<TArgs extends ToolArgs = ToolArgs> = {
|
|
108
115
|
execute: McpToolHandler<TArgs>;
|
|
@@ -114,5 +121,24 @@ export type McpToolExecutionParams = {
|
|
|
114
121
|
context: McpToolContext;
|
|
115
122
|
extra: McpToolExtra;
|
|
116
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;
|
|
117
143
|
export {};
|
|
118
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 {
|
|
3
|
-
type ToolHandlers = Record<string, McpToolHandler | McpToolHandlerExtended>;
|
|
2
|
+
import type { McpToolModuleExport } from '../types.js';
|
|
4
3
|
type ToolModuleLoader = (importPath: string) => Promise<{
|
|
5
|
-
default:
|
|
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
|
|
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};
|
|
@@ -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{
|
|
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};
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
import type { McpMode, McpServerType } from '../types.js';
|
|
1
|
+
import type { McpErrorClass, McpMode, McpServerType } from '../types.js';
|
|
2
2
|
type McpToolEvent = {
|
|
3
3
|
tool: string;
|
|
4
4
|
mode: McpMode;
|
|
5
5
|
serverType: McpServerType;
|
|
6
6
|
durationMs: number;
|
|
7
|
+
client?: string;
|
|
8
|
+
clientVersion?: string;
|
|
7
9
|
};
|
|
8
|
-
|
|
9
|
-
* Who an error belongs to. `tool_error` — the caller asked for something that does not exist or
|
|
10
|
-
* does not validate. `sandbox_error` — the model's own generated code threw in code mode.
|
|
11
|
-
* `server_error` — Redocly code failed. Reported explicitly so consumers never have to infer it
|
|
12
|
-
* from whether a stack trace happens to be attached.
|
|
13
|
-
*/
|
|
14
|
-
export type McpErrorClass = 'tool_error' | 'sandbox_error' | 'server_error';
|
|
15
|
-
export declare function reportMcpToolCalled({ tool, mode, serverType, durationMs, outputLength, }: McpToolEvent & {
|
|
10
|
+
export declare function reportMcpToolCalled({ tool, mode, serverType, durationMs, outputLength, client, clientVersion, }: McpToolEvent & {
|
|
16
11
|
outputLength: number;
|
|
17
12
|
}): void;
|
|
18
13
|
/**
|
|
@@ -21,12 +16,12 @@ export declare function reportMcpToolCalled({ tool, mode, serverType, durationMs
|
|
|
21
16
|
* identifies the invocation. The result body itself is never recorded — a tool can return
|
|
22
17
|
* credentials no pattern will recognise — so only its digest lands here.
|
|
23
18
|
*/
|
|
24
|
-
export declare function logMcpToolCallAudit({ tool, mode, serverType, args, result, errorClass, }: Omit<McpToolEvent, 'durationMs'> & {
|
|
19
|
+
export declare function logMcpToolCallAudit({ tool, mode, serverType, args, result, errorClass, client, clientVersion, }: Omit<McpToolEvent, 'durationMs'> & {
|
|
25
20
|
args: unknown;
|
|
26
21
|
result?: string;
|
|
27
22
|
errorClass?: McpErrorClass;
|
|
28
23
|
}): void;
|
|
29
|
-
export declare function reportMcpToolError({ tool, mode, serverType, durationMs, message, stack, errorClass, }: McpToolEvent & {
|
|
24
|
+
export declare function reportMcpToolError({ tool, mode, serverType, durationMs, message, stack, errorClass, client, clientVersion, }: McpToolEvent & {
|
|
30
25
|
message: string;
|
|
31
26
|
stack?: string;
|
|
32
27
|
errorClass: McpErrorClass;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetry as
|
|
1
|
+
import{telemetry as c}from"../../../telemetry/index.js";import{serverAttributes as d}from"../utils/telemetry-attributes.js";import{EXECUTE_TOOL_NAME as p}from"../codemode/constants.js";import{auditInput as _,auditOutputDigest as f,auditSha256 as g,logAuditRecord as m}from"../audit/audit-log.js";function A({tool:r,mode:t,serverType:o,durationMs:i,outputLength:e,client:s,clientVersion:n}){c.sendMcpToolCalledMessage([{...d(o),tool:r,mode:t,output_length:e,duration_ms:i,client:s,client_version:n}])}function C({tool:r,mode:t,serverType:o,args:i,result:e,errorClass:s,client:n,clientVersion:a}){if(r===p)return;const l=M(i),u=e===void 0?void 0:f(e);m("Record MCP tool call",{tool:r,mode:t,server_type:o,error_class:s,client:n,client_version:a,args_sha256:g(l),args:_(l),result_sha256:u?.sha256,result_bytes:u?.bytes})}function M(r){try{return JSON.stringify(r)??String(r)}catch{return"\xAB[unserializable]\xBB"}}function b({tool:r,mode:t,serverType:o,durationMs:i,message:e,stack:s="",errorClass:n,client:a,clientVersion:l}){c.sendMcpErrorMessage([{...d(o),tool:r,message:e,stack:s,error_class:n,mode:t,duration_ms:i,client:a,client_version:l}])}export{C as logMcpToolCallAudit,A as reportMcpToolCalled,b as reportMcpToolError};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { McpToolFileSystem } from '@redocly/config';
|
|
2
|
+
import type { McpToolContext } from '../types.js';
|
|
3
|
+
export declare function attachToolFileSystem(context: McpToolContext): McpToolContext & {
|
|
4
|
+
fs: McpToolFileSystem;
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=tool-file-system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFile as s,realpath as i}from"node:fs/promises";import{resolve as l,sep as n}from"node:path";function m(r){return{...r,fs:c(r.outdir)}}function c(r){return{async readFile(o){if(!r)throw new Error("Project files are not available in this environment.");const e=await i(r),t=l(e,o.replace(/^\/+/,"")),a=t.startsWith(e+n)?await i(t):t;if(!a.startsWith(e+n))throw new Error(`Invalid file path "${o}".`);return await s(a,"utf8")}}}export{m as attachToolFileSystem};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
1
|
+
import p from"@jitl/quickjs-singlefile-mjs-release-sync";import{newQuickJSWASMModuleFromVariant as _,newVariant as E}from"quickjs-emscripten-core";import{createExecutionBudget as S}from"./utils/execution-budget.js";import{returnsFromTopLevel as A}from"./utils/returns-from-top-level.js";import{DEFAULT_MAX_LIFETIME_MS as y,DEFAULT_TIMEOUT_MS as b,INITIAL_TOTAL_MEMORY_BYTES as h,MAX_ALLOCATION_BYTES as L,MAX_RESULT_BYTES as g,MAX_STACK_SIZE_BYTES as w,MAX_TOTAL_MEMORY_BYTES as x,WASM_PAGE_BYTES as d}from"./constants/sandbox.js";let c;function I(){return c??=_(E(p,{wasmMemory:new WebAssembly.Memory({initial:h/d,maximum:x/d})}))}async function P(t,l={}){const{timeoutMs:m=b,maxLifetimeMs:f=y,setupContext:M}=l,e=(await I()).newContext();let n,i,r;try{e.runtime.setMemoryLimit(L),e.runtime.setMaxStackSize(w),n=S(e,m,f),i=M?.(e,n)??void 0,r=e.unwrapResult(e.evalCode(`(async () => {
|
|
2
2
|
${t}
|
|
3
|
-
})()`));const
|
|
3
|
+
})()`));const o=e.resolvePromise(r);e.runtime.executePendingJobs();const T=await Promise.race([o,n.aborted]),u=e.unwrapResult(T),s=e.dump(u);if(u.dispose(),s===void 0)return{error:A(e,t)?"The code returned undefined: the `return` ran but produced no value. Read fields off the declared return types \u2014 a field name that does not exist reads as undefined \u2014 and do not `return;` or `return undefined`.":"The code returned undefined because nothing was returned. Add a top-level `return`: a value computed inside a function or IIFE is discarded unless you return it, and a promise chain has to be returned to be awaited."};const a=JSON.stringify(s??null).length;return a>g?{error:`Result is too large (${a} bytes); return less data`}:{result:s}}catch(o){return{error:v(o)}}finally{n?.dispose(),r?.dispose();try{i?.()}catch{}try{e.dispose()}catch{c=void 0}}}function v(t){return t instanceof Error?t.message:String(t)}export{P as runInSandbox};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { QuickJSContext } from 'quickjs-emscripten-core';
|
|
2
|
+
/** Whether `code` returns from the guest wrapper itself rather than from a nested function. */
|
|
3
|
+
export declare function returnsFromTopLevel(context: QuickJSContext, code: string): boolean;
|
|
4
|
+
//# sourceMappingURL=returns-from-top-level.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o="return not in a function";function u(r,t){let e;try{e=r.evalCode(t,"return-probe.js",{type:"module",compileOnly:!0})}catch{return!1}if(!e.error)return e.value.dispose(),!1;const n=r.dump(e.error);return e.error.dispose(),String(n?.message??"").includes(o)}export{u as returnsFromTopLevel};
|
package/dist/server/store.d.ts
CHANGED
|
@@ -128,6 +128,7 @@ export declare class Store {
|
|
|
128
128
|
markGatedMcpTools: (toolNames: string[]) => void;
|
|
129
129
|
addSkills: (skills: Skill[]) => void;
|
|
130
130
|
getSkills: () => Skill[];
|
|
131
|
+
removeMcpTools: (names: string[]) => void;
|
|
131
132
|
addMiddleware: (middleware: MiddlewareDetails) => void;
|
|
132
133
|
setResourceResponseHeaders: (resourcePath: string, headers: NonNullable<RedoclyConfig['responseHeaders']>[string]) => void;
|
|
133
134
|
getRouteByFsPath: (relativePath: string) => PageRouteDetails | undefined;
|