@redocly/realm 0.135.0 → 0.136.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli/build/analytics/collect-analytics.js +1 -1
  3. package/dist/cli/build/analytics/collectors/get-skills-usage.d.ts +3 -0
  4. package/dist/cli/build/analytics/collectors/get-skills-usage.js +1 -0
  5. package/dist/client/templates/openapi-docs/helpers.js +1 -1
  6. package/dist/constants/common.d.ts +8 -0
  7. package/dist/constants/common.js +1 -1
  8. package/dist/server/config/env-config.d.ts +2 -0
  9. package/dist/server/config/env-schema.d.ts +5 -0
  10. package/dist/server/config/env-schemas/feature-flags.d.ts +4 -0
  11. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  12. package/dist/server/constants/plugins/search.d.ts +1 -2
  13. package/dist/server/constants/plugins/search.js +1 -1
  14. package/dist/server/esbuild/plugins/on-rebuild.js +1 -1
  15. package/dist/server/fs/fs.js +1 -1
  16. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.js +1 -1
  17. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/arazzo-entities-extractor.js +1 -1
  18. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.js +1 -1
  19. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.js +2 -2
  20. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
  21. package/dist/server/plugins/config-parser/loaders/redocly-config-loader.js +1 -1
  22. package/dist/server/plugins/lifecycle.js +2 -2
  23. package/dist/server/plugins/mcp/{docs-mcp/codemode → codemode}/build-tool-type-declarations.d.ts +1 -1
  24. package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.d.ts +4 -0
  25. package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +4 -0
  26. package/dist/server/plugins/mcp/codemode/capabilities/index.d.ts +3 -0
  27. package/dist/server/plugins/mcp/codemode/capabilities/index.js +1 -0
  28. package/dist/server/plugins/mcp/codemode/capabilities/registry.d.ts +4 -0
  29. package/dist/server/plugins/mcp/codemode/capabilities/registry.js +1 -0
  30. package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +13 -0
  31. package/dist/server/plugins/mcp/codemode/capabilities/utils.d.ts +13 -0
  32. package/dist/server/plugins/mcp/codemode/capabilities/utils.js +7 -0
  33. package/dist/server/plugins/mcp/codemode/constants.d.ts +5 -0
  34. package/dist/server/plugins/mcp/codemode/constants.js +1 -0
  35. package/dist/server/plugins/mcp/codemode/invoke-tool.d.ts +4 -0
  36. package/dist/server/plugins/mcp/codemode/invoke-tool.js +1 -0
  37. package/dist/server/plugins/mcp/codemode/prompts.d.ts +6 -0
  38. package/dist/server/plugins/mcp/codemode/prompts.js +4 -0
  39. package/dist/server/plugins/mcp/codemode/sandbox/sandbox-polyfills.d.ts +3 -0
  40. package/dist/server/plugins/mcp/codemode/sandbox/sandbox-polyfills.js +100 -0
  41. package/dist/server/plugins/mcp/{docs-mcp/codemode → codemode/sandbox}/sandbox.d.ts +1 -1
  42. package/dist/server/plugins/mcp/codemode/sandbox/sandbox.js +15 -0
  43. package/dist/server/plugins/mcp/codemode/tools/describe-tools.d.ts +7 -0
  44. package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -0
  45. package/dist/server/plugins/mcp/codemode/tools/execute-schema.d.ts +5 -0
  46. package/dist/server/plugins/mcp/codemode/tools/execute-schema.js +1 -0
  47. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -0
  48. package/dist/server/plugins/mcp/codemode/types.d.ts +24 -0
  49. package/dist/server/plugins/mcp/codemode/types.js +0 -0
  50. package/dist/server/plugins/mcp/constants.d.ts +2 -0
  51. package/dist/server/plugins/mcp/constants.js +1 -1
  52. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +0 -4
  53. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  54. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
  55. package/dist/server/plugins/mcp/docs-mcp/utils.js +1 -1
  56. package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +30 -0
  57. package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -0
  58. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.d.ts +13 -0
  59. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.js +1 -0
  60. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +12 -0
  61. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -0
  62. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.d.ts +9 -0
  63. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -0
  64. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +6 -0
  65. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -0
  66. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  67. package/dist/server/plugins/mcp/handlers/errors.d.ts +3 -21
  68. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  69. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  70. package/dist/server/plugins/mcp/index.js +1 -1
  71. package/dist/server/plugins/mcp/servers/docs-server.d.ts +5 -10
  72. package/dist/server/plugins/mcp/servers/docs-server.js +1 -3
  73. package/dist/server/plugins/mcp/servers/mcp-server.d.ts +18 -0
  74. package/dist/server/plugins/mcp/servers/mcp-server.js +1 -0
  75. package/dist/server/plugins/mcp/types.d.ts +23 -8
  76. package/dist/server/plugins/mcp/utils/mode.d.ts +7 -0
  77. package/dist/server/plugins/mcp/utils/mode.js +1 -0
  78. package/dist/server/plugins/mcp/utils/xmcp-utils.d.ts +12 -60
  79. package/dist/server/plugins/mcp/utils/xmcp-utils.js +1 -1
  80. package/dist/server/plugins/mcp/utils.d.ts +8 -0
  81. package/dist/server/plugins/mcp/utils.js +1 -1
  82. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  83. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +15 -3
  84. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
  85. package/dist/server/plugins/openapi-docs/index.js +1 -1
  86. package/dist/server/plugins/search/engines/search-engine.d.ts +2 -1
  87. package/dist/server/plugins/search/index.js +1 -1
  88. package/dist/server/plugins/skills/discover-skills.d.ts +17 -0
  89. package/dist/server/plugins/skills/discover-skills.js +1 -0
  90. package/dist/server/plugins/skills/index.d.ts +3 -0
  91. package/dist/server/plugins/skills/index.js +1 -0
  92. package/dist/server/plugins/skills/utils/parse-skill.d.ts +18 -0
  93. package/dist/server/plugins/skills/utils/parse-skill.js +1 -0
  94. package/dist/server/plugins/sso/index.js +1 -1
  95. package/dist/server/store.d.ts +4 -0
  96. package/dist/server/store.js +1 -1
  97. package/dist/server/types/plugins/common.d.ts +3 -0
  98. package/dist/server/types/plugins/search.d.ts +0 -1
  99. package/dist/server/types/plugins/skills.d.ts +16 -0
  100. package/dist/server/types/plugins/skills.js +0 -0
  101. package/dist/server/utils/cookie.d.ts +3 -0
  102. package/dist/server/utils/cookie.js +1 -1
  103. package/dist/server/utils/skills/can-access-skill.d.ts +9 -0
  104. package/dist/server/utils/skills/can-access-skill.js +1 -0
  105. package/dist/server/utils/skills/get-accessible-skills.d.ts +5 -0
  106. package/dist/server/utils/skills/get-accessible-skills.js +1 -0
  107. package/dist/server/utils/skills/get-skill-url.d.ts +2 -0
  108. package/dist/server/utils/skills/get-skill-url.js +1 -0
  109. package/dist/server/web-server/auth.js +4 -4
  110. package/dist/server/web-server/middleware/corsMiddleware.d.ts +1 -0
  111. package/dist/server/web-server/middleware/corsMiddleware.js +1 -1
  112. package/dist/server/web-server/middleware/ensureSearchData.js +1 -1
  113. package/dist/server/web-server/routes/auth.js +1 -1
  114. package/dist/server/web-server/routes/catalog/helpers/create-entity-schema.d.ts +305 -256
  115. package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.d.ts +46 -39
  116. package/dist/server/web-server/routes/health.js +1 -1
  117. package/dist/server/web-server/routes/index.js +1 -1
  118. package/dist/server/web-server/routes/mcp-routes/a2a.d.ts +10 -0
  119. package/dist/server/web-server/routes/mcp-routes/a2a.js +1 -0
  120. package/dist/server/web-server/routes/mcp-routes/agent-card.d.ts +4 -0
  121. package/dist/server/web-server/routes/mcp-routes/agent-card.js +1 -0
  122. package/dist/server/web-server/routes/mcp-routes/constants.d.ts +14 -0
  123. package/dist/server/web-server/routes/mcp-routes/constants.js +1 -0
  124. package/dist/server/web-server/routes/mcp-routes/mcp-routes.d.ts +1 -1
  125. package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
  126. package/dist/server/web-server/routes/mcp-routes/mcp-server-card.d.ts +4 -0
  127. package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -0
  128. package/dist/server/web-server/routes/mcp-routes/types.d.ts +34 -0
  129. package/dist/server/web-server/routes/mcp-routes/types.js +0 -0
  130. package/dist/server/web-server/routes/mcp-routes/utils/build-agent-card.d.ts +10 -0
  131. package/dist/server/web-server/routes/mcp-routes/utils/build-agent-card.js +1 -0
  132. package/dist/server/web-server/routes/page-data.js +1 -1
  133. package/dist/server/web-server/routes/skills/build-skills-index.d.ts +4 -0
  134. package/dist/server/web-server/routes/skills/build-skills-index.js +1 -0
  135. package/dist/server/web-server/routes/skills/constants.d.ts +4 -0
  136. package/dist/server/web-server/routes/skills/constants.js +1 -0
  137. package/dist/server/web-server/routes/skills/skill-markdown.d.ts +4 -0
  138. package/dist/server/web-server/routes/skills/skill-markdown.js +1 -0
  139. package/dist/server/web-server/routes/skills/skills-index.d.ts +4 -0
  140. package/dist/server/web-server/routes/skills/skills-index.js +1 -0
  141. package/dist/server/web-server/routes/skills/skills-routes.d.ts +4 -0
  142. package/dist/server/web-server/routes/skills/skills-routes.js +1 -0
  143. package/dist/server/web-server/routes/skills/types.d.ts +12 -0
  144. package/dist/server/web-server/routes/skills/types.js +0 -0
  145. package/dist/server/web-server/utils/resolve-public-base-url.d.ts +4 -0
  146. package/dist/server/web-server/utils/resolve-public-base-url.js +1 -0
  147. package/dist/server/web-server/utils.js +1 -1
  148. package/dist/server/workers/api-routes-worker-pool.js +1 -1
  149. package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
  150. package/dist/server/workers/scorecards-worker-pool.js +1 -1
  151. package/dist/server/workers/worker-pool.d.ts +1 -0
  152. package/dist/server/workers/worker-pool.js +1 -1
  153. package/package.json +9 -9
  154. package/dist/server/plugins/mcp/docs-mcp/codemode/prompts.d.ts +0 -5
  155. package/dist/server/plugins/mcp/docs-mcp/codemode/prompts.js +0 -4
  156. package/dist/server/plugins/mcp/docs-mcp/codemode/sandbox.js +0 -7
  157. package/dist/server/plugins/mcp/docs-mcp/codemode/types.d.ts +0 -9
  158. package/dist/server/plugins/mcp/docs-mcp/tools/execute.js +0 -1
  159. package/dist/server/plugins/mcp/mode.d.ts +0 -9
  160. package/dist/server/plugins/mcp/mode.js +0 -1
  161. /package/dist/server/plugins/mcp/{docs-mcp/codemode → codemode}/build-tool-type-declarations.js +0 -0
  162. /package/dist/server/plugins/mcp/{docs-mcp/codemode → codemode/capabilities}/types.js +0 -0
  163. /package/dist/server/plugins/mcp/{docs-mcp → codemode}/tools/execute.d.ts +0 -0
@@ -0,0 +1,4 @@
1
+ import{getCallableApis as a,isFetchCapable as s}from"../../../gateway-mcp/fetch-capability.js";import{FETCH_TOOL_NAME as i}from"../../constants.js";const l=["```ts","/**"," * Call a documented API. Only the callable APIs' documented hosts are reachable."," * Responses cap at 1 MiB and redirects are not followed."," */","declare function fetch(url: string, init?: {"," method?: string;"," /** `content-type` is set automatically for URLSearchParams/FormData unless you set one. */"," headers?: Record<string, string>;"," /** string \xB7 URLSearchParams (\u2192 application/x-www-form-urlencoded) \xB7 FormData (\u2192 multipart/form-data) */"," body?: string | URLSearchParams | FormData;","}): Promise<{"," status: number;"," statusText: string;"," ok: boolean;"," headers: { get(name: string): string | null };"," json(): Promise<unknown>;"," text(): Promise<string>;","}>;","```"].join(`
2
+ `),c=["Example - List the write endpoints of an API and call one of them with `fetch`:","","```ts","const { items } = await tools.listApis({ filter: 'billing' });","const { endpoints } = await tools.getEndpoints({ name: items[0].name });","const ep = endpoints.find((e) => e.method === 'POST' && e.path.includes('invoices'));","const info = await tools.getEndpointInfo({ name: items[0].name, path: ep.path, method: ep.method });","const url = (info.servers?.[0]?.url ?? '') + ep.path;","try {"," const res = await fetch(url, { method: 'POST', body: JSON.stringify({ /* fields from info */ }) });"," return res.ok ? await res.json() : { status: res.status, error: await res.text() };","} catch (error) {"," return { error: error instanceof Error ? error.message : String(error), endpointId: info };","}","```"].join(`
3
+ `);function d(r){const t=new Map;for(const{name:e,version:n}of r){if(!e)continue;const o=t.get(e)??[];n&&o.push(n),t.set(e,o)}return[...t.entries()].map(([e,n])=>n.length>1?`${e} (${n.map(o=>`v${o}`).join(", ")})`:e).join(", ")}const f={id:i,isActive:s,annotations:{readOnlyHint:!1,destructiveHint:!0,openWorldHint:!0},renderSection(r){const t=d(a(r));return["## `fetch` \u2014 call the documented APIs","",l,"","Always call `getEndpointInfo` before `fetch` for the exact URL, required parameters, and body shape. Never guess.","",`Callable APIs (their documented hosts are reachable via \`fetch\`): ${t}`,"",c].join(`
4
+ `)}};export{l as FETCH_DECLARATION,f as fetchCapability};
@@ -0,0 +1,3 @@
1
+ export type { SandboxCapability } from './types.js';
2
+ export { composeExecuteAnnotations, getActiveCapabilities, renderDescribeToolsOutput, } from './utils.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ import{composeExecuteAnnotations as o,getActiveCapabilities as i,renderDescribeToolsOutput as r}from"./utils.js";export{o as composeExecuteAnnotations,i as getActiveCapabilities,r as renderDescribeToolsOutput};
@@ -0,0 +1,4 @@
1
+ import type { SandboxCapability } from './types.js';
2
+ /** Every sandbox capability, in the order their sections appear in describe-tools output. */
3
+ export declare const ALL_CAPABILITIES: readonly SandboxCapability[];
4
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ import{fetchCapability as t}from"./fetch/index.js";const i=[t];export{i as ALL_CAPABILITIES};
@@ -0,0 +1,13 @@
1
+ import type { ToolAnnotations } from '@redocly/mcp-typescript-sdk/types.js';
2
+ import type { McpToolContext } from '../../types.js';
3
+ /** A capability is a per-request-gated global the code-mode sandbox exposes beyond the schema-driven `tools.*` surface. */
4
+ export type SandboxCapability = {
5
+ id: string;
6
+ /** Whether this capability is live for THIS request (RBAC/config/flag-dependent). */
7
+ isActive(context: McpToolContext): boolean;
8
+ /** How this capability changes `execute`'s MCP annotations when active. */
9
+ annotations: Partial<ToolAnnotations>;
10
+ /** The self-contained `describe-tools` section for this capability: heading, TS declaration, guidance, and example. */
11
+ renderSection(context: McpToolContext): string;
12
+ };
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,13 @@
1
+ import type { ToolAnnotations } from '@redocly/mcp-typescript-sdk/types.js';
2
+ import type { McpToolSchema } from '../../../../types';
3
+ import type { McpToolContext } from '../../types.js';
4
+ import type { SandboxCapability } from './types.js';
5
+ export declare function getActiveCapabilities(context: McpToolContext): SandboxCapability[];
6
+ /** `execute`'s annotations = the read-only base with every active capability's delta merged over it. */
7
+ export declare function composeExecuteAnnotations(active: SandboxCapability[]): ToolAnnotations;
8
+ /**
9
+ * The describe-tools output: the tool signatures, the always-present
10
+ * `execute` args note, then one self-contained section per selected capability.
11
+ */
12
+ export declare function renderDescribeToolsOutput(tools: McpToolSchema[], capabilities: SandboxCapability[], context: McpToolContext): string;
13
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1,7 @@
1
+ import{buildToolTypeDeclarations as i}from"../build-tool-type-declarations.js";import{EXECUTE_BASE_ANNOTATIONS as c}from"../tools/execute-schema.js";import{EXECUTE_ARGS_NOTE as p,USAGE_NOTES as s}from"../prompts.js";import{ALL_CAPABILITIES as u}from"./registry.js";function T(o){return u.filter(t=>t.isActive(o))}function m(o){return o.reduce((t,e)=>({...t,...e.annotations}),{...c})}function l(o,t,e){const n=[];o.length>0&&n.push(`## Sandbox tools
2
+
3
+ ${i(o)}
4
+
5
+ ${s}`),n.push(p);for(const r of t)n.push(r.renderSection(e));return n.join(`
6
+
7
+ `)}export{m as composeExecuteAnnotations,T as getActiveCapabilities,l as renderDescribeToolsOutput};
@@ -0,0 +1,5 @@
1
+ export declare const EXECUTE_TOOL_NAME = "execute";
2
+ export declare const DESCRIBE_TOOLS_TOOL_NAME = "describe-tools";
3
+ export declare const FETCH_TOOL_NAME = "fetch";
4
+ export declare const CODE_MODE_TOOL_NAMES: ReadonlySet<string>;
5
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ const e="execute",t="describe-tools",E="fetch",O=new Set([e,t]);export{O as CODE_MODE_TOOL_NAMES,t as DESCRIBE_TOOLS_TOOL_NAME,e as EXECUTE_TOOL_NAME,E as FETCH_TOOL_NAME};
@@ -0,0 +1,4 @@
1
+ import type { McpToolContext, McpToolExtra } from '../types.js';
2
+ /** Call a registered MCP tool from inside the sandbox and return its parsed result. */
3
+ export declare function invokeTool(toolName: string, input: unknown, context: McpToolContext, extra: McpToolExtra): Promise<unknown>;
4
+ //# sourceMappingURL=invoke-tool.d.ts.map
@@ -0,0 +1 @@
1
+ import{executeMcpTool as i}from"../workers/execute-mcp-tool.js";async function p(t,r,n,c){const e=await i({toolName:t,args:r,context:n,extra:c}),o=u(e);if(e.isError)throw new Error(o);return s(o)}function u(t){return t.content.filter(r=>r.type==="text").map(r=>r.text).join("")}function s(t){try{return JSON.parse(t)}catch{return t}}export{p as invokeTool};
@@ -0,0 +1,6 @@
1
+ export declare const EXECUTE_ARGS_NOTE = "Both `execute` arguments are required: `code` (the JavaScript to run; return a value to receive it) and `description` (a short human-readable summary of what the code does).";
2
+ export declare function buildExecuteDescription(hasFetch: boolean): string;
3
+ export declare const DESCRIBE_TOOLS_DESCRIPTION: string;
4
+ export declare function buildCodeModeInstructions(hasFetch: boolean): string;
5
+ export declare const USAGE_NOTES = "Types named `OpenApi\u2026` are the standard OpenAPI Specification objects.";
6
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1,4 @@
1
+ const t="Both `execute` arguments are required: `code` (the JavaScript to run; return a value to receive it) and `description` (a short human-readable summary of what the code does).";function o(e){return["Run JavaScript in a sandbox against the documentation tools on the global `tools` object.",e?"The only extra globals are `tools` and `fetch` - there is no `console`, `setTimeout`, `require`, or Node.js API; all other I/O goes through `tools`.":"The only extra global is `tools` - there is no `fetch`, `console`, `setTimeout`, `require`, or Node.js API; all I/O goes through `tools`.","","Workflow - minimize round-trips; one `describe-tools` call plus one `execute` call covers most requests:","1. Analyze the request and decide which sandbox tools it needs (every tool name is listed in the `describe-tools` input schema / description).","2. Call `describe-tools` with those names to get their exact TypeScript signatures. NEVER call `execute` with guessed method names, parameter names, or enum values.","3. Batch everything into a SINGLE script: chain tool calls, pass one call's output into the next, process results in plain JavaScript, and `return` only what the request needs.","",...e?["Example - list the Billing API endpoints and call one of them:","","```ts","const { items } = await tools.listApis({ filter: 'billing' });","const { endpoints } = await tools.getEndpoints({ name: items[0].name });","const ep = endpoints.find((e) => e.method === 'POST' && e.path.includes('invoices'));","const info = await tools.getEndpointInfo({ name: items[0].name, path: ep.path, method: ep.method });","const url = (info.servers?.[0]?.url ?? '') + ep.path;","try {"," const res = await fetch(url, { method: 'POST', body: JSON.stringify({ /* fields from info */ }) });"," return res.ok ? await res.json() : { status: res.status, error: await res.text() };","} catch (error) {"," return { error: error instanceof Error ? error.message : String(error), endpointId: info };","}","```"]:["Example - list the write endpoints of an API:","","```ts","const { items } = await tools.listApis({ filter: 'billing' });","const { endpoints } = await tools.getEndpoints({ name: items[0].name });","const writes = endpoints.filter((e) => e.method !== 'GET');","return { api: items[0].name, writes: writes.map((e) => `${e.method} ${e.path}`) };","```"]].join(`
2
+ `)}const s=["Get the exact TypeScript signatures of the sandbox tools available to `execute`.","Analyze the user request first, then pass `tools` with only the tool names the request needs (every name is listed in this input schema / description); omit `tools` only when you cannot tell which tools apply.","Always call this before your first `execute` and never guess signatures. Request every tool the task may need in ONE call instead of calling this repeatedly."].join(`
3
+ `);function n(e){return["This server exposes documentation tools (API discovery, endpoint details, security schemes, full-text search) through two tools:","- `describe-tools` returns the exact TypeScript signatures of the sandbox tools.","- `execute` runs JavaScript that calls those tools on the global `tools` object.","Workflow: analyze the request, call `describe-tools` once with only the tool names it needs, then batch everything into a single `execute` script. Minimize round-trips and never guess tool signatures.",e?"The sandbox also has a global `fetch` that can call the documented APIs (allow-listed hosts only). Include `fetch` in your `describe-tools` call to get its contract and the list of callable APIs.":""].join(`
4
+ `)}const i="Types named `OpenApi\u2026` are the standard OpenAPI Specification objects.";export{s as DESCRIBE_TOOLS_DESCRIPTION,t as EXECUTE_ARGS_NOTE,i as USAGE_NOTES,n as buildCodeModeInstructions,o as buildExecuteDescription};
@@ -0,0 +1,3 @@
1
+ export declare const SANDBOX_POLYFILLS = "\n const URLSearchParams = class URLSearchParams {\n constructor(init) {\n this._params = [];\n if (typeof init === 'string') {\n const str = init.startsWith('?') ? init.slice(1) : init;\n for (const pair of (str ? str.split('&') : [])) {\n const eq = pair.indexOf('=');\n const k = eq >= 0 ? pair.slice(0, eq) : pair;\n const v = eq >= 0 ? pair.slice(eq + 1) : '';\n if (k) this._params.push([decodeURIComponent(k), decodeURIComponent(v)]);\n }\n } else if (init != null && typeof init === 'object') {\n for (const [k, v] of Object.entries(init)) this._params.push([k, String(v)]);\n }\n }\n append(key, value) { this._params.push([String(key), String(value)]); }\n set(key, value) {\n const k = String(key), v = String(value);\n this._params = this._params.filter(([pk]) => pk !== k);\n this._params.push([k, v]);\n }\n get(key) { return (this._params.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }\n getAll(key) { return this._params.filter(([k]) => k === String(key)).map(([, v]) => v); }\n has(key) { return this._params.some(([k]) => k === String(key)); }\n delete(key) { this._params = this._params.filter(([k]) => k !== String(key)); }\n entries() { return this._params.values(); }\n [Symbol.iterator]() { return this._params.values(); }\n toString() {\n return this._params\n .map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(v))\n .join('&');\n }\n };\n globalThis.URLSearchParams = URLSearchParams;\n\n const FormData = class FormData {\n constructor() { this._fields = []; }\n append(key, value) { this._fields.push([String(key), String(value)]); }\n set(key, value) {\n const k = String(key), v = String(value);\n this._fields = this._fields.filter(([fk]) => fk !== k);\n this._fields.push([k, v]);\n }\n get(key) { return (this._fields.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }\n has(key) { return this._fields.some(([k]) => k === String(key)); }\n delete(key) { this._fields = this._fields.filter(([k]) => k !== String(key)); }\n entries() { return this._fields.values(); }\n [Symbol.iterator]() { return this._fields.values(); }\n };\n globalThis.FormData = FormData;\n";
2
+ export declare const SANDBOX_FETCH_SETUP = "\n const hostFetch = globalThis.__fetch;\n delete globalThis.__fetch;\n globalThis.fetch = (url, init = {}) => {\n let body;\n let autoContentType;\n if (init.body instanceof URLSearchParams) {\n body = init.body.toString();\n autoContentType = 'application/x-www-form-urlencoded';\n } else if (init.body instanceof FormData) {\n const boundary = '----FormBoundary' + Math.random().toString(36).slice(2);\n body = init.body._fields\n .map(([k, v]) =>\n '--' + boundary + '\\r\\nContent-Disposition: form-data; name=\"' + k + '\"\\r\\n\\r\\n' + v,\n )\n .join('\\r\\n') + '\\r\\n--' + boundary + '--';\n autoContentType = 'multipart/form-data; boundary=' + boundary;\n } else if (init.body != null && typeof init.body !== 'string') {\n throw new TypeError('fetch body must be a string, URLSearchParams, or FormData');\n } else {\n body = init.body ?? undefined;\n }\n const callerHeaders = init.headers;\n const hasContentType = callerHeaders != null && Object.keys(callerHeaders).some(\n (k) => k.toLowerCase() === 'content-type',\n );\n const headers = autoContentType && !hasContentType\n ? Object.assign({ 'content-type': autoContentType }, callerHeaders)\n : callerHeaders;\n return hostFetch(JSON.stringify({ url: String(url), method: init.method, headers, body }))\n .then((json) => {\n const res = JSON.parse(json);\n const resHeaders = res.headers || {};\n return {\n status: res.status,\n statusText: res.statusText,\n ok: res.ok,\n headers: {\n get: (name) => {\n const value = resHeaders[String(name).toLowerCase()];\n return value === undefined ? null : value;\n },\n },\n json: () => Promise.resolve(JSON.parse(res.bodyText)),\n text: () => Promise.resolve(res.bodyText),\n };\n });\n };\n";
3
+ //# sourceMappingURL=sandbox-polyfills.d.ts.map
@@ -0,0 +1,100 @@
1
+ const e=`
2
+ const URLSearchParams = class URLSearchParams {
3
+ constructor(init) {
4
+ this._params = [];
5
+ if (typeof init === 'string') {
6
+ const str = init.startsWith('?') ? init.slice(1) : init;
7
+ for (const pair of (str ? str.split('&') : [])) {
8
+ const eq = pair.indexOf('=');
9
+ const k = eq >= 0 ? pair.slice(0, eq) : pair;
10
+ const v = eq >= 0 ? pair.slice(eq + 1) : '';
11
+ if (k) this._params.push([decodeURIComponent(k), decodeURIComponent(v)]);
12
+ }
13
+ } else if (init != null && typeof init === 'object') {
14
+ for (const [k, v] of Object.entries(init)) this._params.push([k, String(v)]);
15
+ }
16
+ }
17
+ append(key, value) { this._params.push([String(key), String(value)]); }
18
+ set(key, value) {
19
+ const k = String(key), v = String(value);
20
+ this._params = this._params.filter(([pk]) => pk !== k);
21
+ this._params.push([k, v]);
22
+ }
23
+ get(key) { return (this._params.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }
24
+ getAll(key) { return this._params.filter(([k]) => k === String(key)).map(([, v]) => v); }
25
+ has(key) { return this._params.some(([k]) => k === String(key)); }
26
+ delete(key) { this._params = this._params.filter(([k]) => k !== String(key)); }
27
+ entries() { return this._params.values(); }
28
+ [Symbol.iterator]() { return this._params.values(); }
29
+ toString() {
30
+ return this._params
31
+ .map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(v))
32
+ .join('&');
33
+ }
34
+ };
35
+ globalThis.URLSearchParams = URLSearchParams;
36
+
37
+ const FormData = class FormData {
38
+ constructor() { this._fields = []; }
39
+ append(key, value) { this._fields.push([String(key), String(value)]); }
40
+ set(key, value) {
41
+ const k = String(key), v = String(value);
42
+ this._fields = this._fields.filter(([fk]) => fk !== k);
43
+ this._fields.push([k, v]);
44
+ }
45
+ get(key) { return (this._fields.find(([k]) => k === String(key)) ?? [undefined, null])[1]; }
46
+ has(key) { return this._fields.some(([k]) => k === String(key)); }
47
+ delete(key) { this._fields = this._fields.filter(([k]) => k !== String(key)); }
48
+ entries() { return this._fields.values(); }
49
+ [Symbol.iterator]() { return this._fields.values(); }
50
+ };
51
+ globalThis.FormData = FormData;
52
+ `,t=`
53
+ const hostFetch = globalThis.__fetch;
54
+ delete globalThis.__fetch;
55
+ globalThis.fetch = (url, init = {}) => {
56
+ let body;
57
+ let autoContentType;
58
+ if (init.body instanceof URLSearchParams) {
59
+ body = init.body.toString();
60
+ autoContentType = 'application/x-www-form-urlencoded';
61
+ } else if (init.body instanceof FormData) {
62
+ const boundary = '----FormBoundary' + Math.random().toString(36).slice(2);
63
+ body = init.body._fields
64
+ .map(([k, v]) =>
65
+ '--' + boundary + '\\r\\nContent-Disposition: form-data; name="' + k + '"\\r\\n\\r\\n' + v,
66
+ )
67
+ .join('\\r\\n') + '\\r\\n--' + boundary + '--';
68
+ autoContentType = 'multipart/form-data; boundary=' + boundary;
69
+ } else if (init.body != null && typeof init.body !== 'string') {
70
+ throw new TypeError('fetch body must be a string, URLSearchParams, or FormData');
71
+ } else {
72
+ body = init.body ?? undefined;
73
+ }
74
+ const callerHeaders = init.headers;
75
+ const hasContentType = callerHeaders != null && Object.keys(callerHeaders).some(
76
+ (k) => k.toLowerCase() === 'content-type',
77
+ );
78
+ const headers = autoContentType && !hasContentType
79
+ ? Object.assign({ 'content-type': autoContentType }, callerHeaders)
80
+ : callerHeaders;
81
+ return hostFetch(JSON.stringify({ url: String(url), method: init.method, headers, body }))
82
+ .then((json) => {
83
+ const res = JSON.parse(json);
84
+ const resHeaders = res.headers || {};
85
+ return {
86
+ status: res.status,
87
+ statusText: res.statusText,
88
+ ok: res.ok,
89
+ headers: {
90
+ get: (name) => {
91
+ const value = resHeaders[String(name).toLowerCase()];
92
+ return value === undefined ? null : value;
93
+ },
94
+ },
95
+ json: () => Promise.resolve(JSON.parse(res.bodyText)),
96
+ text: () => Promise.resolve(res.bodyText),
97
+ };
98
+ });
99
+ };
100
+ `;export{t as SANDBOX_FETCH_SETUP,e as SANDBOX_POLYFILLS};
@@ -1,3 +1,3 @@
1
- import type { RunInSandboxOptions, SandboxResult, SandboxTool } from './types.js';
1
+ import type { RunInSandboxOptions, SandboxResult, SandboxTool } from '../types.js';
2
2
  export declare function runInSandbox(code: string, tools: Record<string, SandboxTool>, options?: RunInSandboxOptions): Promise<SandboxResult>;
3
3
  //# sourceMappingURL=sandbox.d.ts.map
@@ -0,0 +1,15 @@
1
+ import P from"@jitl/quickjs-singlefile-mjs-release-sync";import{newQuickJSWASMModuleFromVariant as A,shouldInterruptAfterDeadline as j}from"quickjs-emscripten-core";import{SANDBOX_FETCH_SETUP as J,SANDBOX_POLYFILLS as N}from"./sandbox-polyfills.js";const B=1e4,C=64*1024*1024,L=256*1024,y=100,$=1024*1024,I=1024*1024,R=1024*1024;let v;function x(){return v??=A(P)}function F(t,r){const u=t.map(l=>`${JSON.stringify(l)}: (input) => invoke(${JSON.stringify(l)}, JSON.stringify(input ?? {})).then(JSON.parse)`).join(", ");return`(() => {
2
+ const invoke = globalThis.__invoke;
3
+ delete globalThis.__invoke;${r?N+J:""}
4
+ const tools = Object.freeze({ ${u} });
5
+ globalThis.tools = new Proxy(tools, {
6
+ get(target, prop) {
7
+ if (typeof prop !== 'string' || prop in target || prop === 'then' || prop === 'toJSON') {
8
+ return target[prop];
9
+ }
10
+ throw new TypeError('Unknown tool "' + prop + '". Available tools: ' + Object.keys(target).join(', '));
11
+ },
12
+ });
13
+ })();`}async function H(t,r,u={}){const{timeoutMs:i=B,hostFetch:l}=u,T=new Set;let b=0,_=0;const e=(await x()).newContext();let c,h=()=>{};const k=new Promise((o,a)=>{h=()=>a(new Error(`Execution timed out after ${i}ms`))}),O=()=>e.runtime.setInterruptHandler(j(Date.now()+i)),w=()=>{clearTimeout(c),c=setTimeout(h,i)},E=(o,a,g,d)=>{X(e,o,(...p)=>{const f=p.map(s=>e.getString(s)),n=e.newPromise();return T.add(n),_++,clearTimeout(c),Promise.resolve().then(()=>a(f)).then(s=>{if(!e.alive)return;const S=JSON.stringify(s??null);S.length>g?e.newError(d(S.length)).consume(n.reject):e.newString(S).consume(n.resolve)},s=>{e.alive&&e.newError(M(s)).consume(n.reject)}),n.settled.then(()=>{e.alive&&(O(),--_===0&&w(),e.runtime.executePendingJobs())}),n.handle})};let m;try{e.runtime.setMemoryLimit(C),e.runtime.setMaxStackSize(L),O(),w();const o=()=>{if(++b>y)throw new Error(`Exceeded the limit of ${y} tool calls`)};E("__invoke",([n,s])=>(o(),r[n](JSON.parse(s))),$,n=>`Tool output is too large (${n} bytes); request narrower data instead`),l&&E("__fetch",([n])=>(o(),l(JSON.parse(n))),I,n=>`Response is too large (${n} bytes); request less data`),Y(e,F(Object.keys(r),!!l)),m=e.unwrapResult(e.evalCode(`(async () => {
14
+ ${t}
15
+ })()`));const a=e.resolvePromise(m);e.runtime.executePendingJobs();const g=await Promise.race([a,k]),d=e.unwrapResult(g),p=e.dump(d);d.dispose();const f=JSON.stringify(p??null).length;return f>R?{error:`Result is too large (${f} bytes); return less data`}:{result:p}}catch(o){return{error:M(o)}}finally{clearTimeout(c),m?.dispose();for(const o of T)o.alive&&o.dispose();try{e.dispose()}catch{v=void 0}}}function X(t,r,u){t.newFunction(r,u).consume(i=>t.setProp(t.global,r,i))}function Y(t,r){t.unwrapResult(t.evalCode(r)).dispose()}function M(t){return t instanceof Error?t.message:String(t)}export{H as runInSandbox};
@@ -0,0 +1,7 @@
1
+ import type { ToolCallback } from '@redocly/mcp-typescript-sdk/server/mcp.js';
2
+ import type { McpToolSchema } from '../../../../types';
3
+ import type { McpToolContext } from '../../types.js';
4
+ import { type SandboxCapability } from '../capabilities/index.js';
5
+ export declare function describeToolsSchema(tools: McpToolSchema[], capabilities: SandboxCapability[]): Record<string, unknown>;
6
+ export declare function describeTools(tools: McpToolSchema[], isToolAvailable: (toolName: string) => Promise<boolean>, capabilities: SandboxCapability[], context: McpToolContext): ToolCallback<Record<string, unknown>>;
7
+ //# sourceMappingURL=describe-tools.d.ts.map
@@ -0,0 +1 @@
1
+ import{renderDescribeToolsOutput as w}from"../capabilities/index.js";import{sanitizeToolName as o}from"../build-tool-type-declarations.js";function g(i,l){const n=[...new Set([...i.map(s=>o(s.name)),...l.map(s=>o(s.id))])];return{type:"object",required:[],additionalProperties:!1,properties:{tools:{type:"array",description:`Tool names to describe: ${n.join(", ")}. Omit to describe everything.`,items:{type:"string"},nullable:!0}}}}function v(i,l,n,s){const r=new Map(i.map(t=>[o(t.name),t])),c=new Map(n.map(t=>[o(t.id),t]));return async t=>{const a=[...new Set((t.tools??[]).map(o))],p=a.length===0,m=a.filter(e=>!r.has(e)&&!c.has(e));if(m.length>0){const e=[...r.keys(),...c.keys()];throw new Error(`Unknown tool(s): ${m.join(", ")}. Valid tools: ${e.join(", ")}.`)}const u=p?n:n.filter(e=>a.includes(o(e.id))),d=p?i:a.filter(e=>r.has(e)).map(e=>r.get(e)),y=await Promise.all(d.map(e=>l(e.name))),f=d.filter((e,b)=>y[b]);return{content:[{type:"text",text:w(f,u,s)}]}}}export{v as describeTools,g as describeToolsSchema};
@@ -0,0 +1,5 @@
1
+ import type { ToolAnnotations } from '@redocly/mcp-typescript-sdk/types.js';
2
+ import type { McpToolSchema } from '../../../../types';
3
+ export declare const EXECUTE_BASE_ANNOTATIONS: ToolAnnotations;
4
+ export declare const EXECUTE_TOOL_SCHEMA: McpToolSchema;
5
+ //# sourceMappingURL=execute-schema.d.ts.map
@@ -0,0 +1 @@
1
+ import{EXECUTE_TOOL_NAME as e}from"../constants.js";import{buildExecuteDescription as t}from"../prompts.js";const i={title:"Execute code",readOnlyHint:!0,openWorldHint:!1},n={name:e,description:t(!1),annotations:i,schema:{type:"object",required:["code","description"],additionalProperties:!1,properties:{code:{type:"string",description:"JavaScript to run in the sandbox. Return a value to receive it as the result.",minLength:1},description:{type:"string",description:"A short, human-readable summary of what this code does.",minLength:1}}}};export{i as EXECUTE_BASE_ANNOTATIONS,n as EXECUTE_TOOL_SCHEMA};
@@ -0,0 +1 @@
1
+ import{mcpToolHandlers as a}from"../../../../../client/mcp-tool-handlers-entry.js";import{isMcpToolAvailable as l}from"../../workers/execute-mcp-tool.js";import{buildExecuteHostFetch as c,isFetchCapable as m}from"../../gateway-mcp/fetch-capability.js";import{CODE_MODE_TOOL_NAMES as f,EXECUTE_TOOL_NAME as p}from"../constants.js";import{sanitizeToolName as u}from"../build-tool-type-declarations.js";import{invokeTool as d}from"../invoke-tool.js";import{runInSandbox as T}from"../sandbox/sandbox.js";const b=async(e,t,i)=>{const o=await E(t,i),s=m(t)?{hostFetch:c(t)}:{},{result:r,error:n}=await T(e.code,o,s);return{content:[{type:"text",text:JSON.stringify({result:r,error:n})}],isError:n!==void 0}};async function E(e,t){const i={};for(const o of Object.keys(a))f.has(o)||!await l({toolName:o,context:e}).catch(()=>!1)||(i[u(o)]=r=>d(o,r,e,t));return i}var M={[p]:b};export{M as default};
@@ -0,0 +1,24 @@
1
+ export type SandboxTool = (input: unknown) => Promise<unknown> | unknown;
2
+ export type SandboxFetchRequest = {
3
+ url: string;
4
+ method?: string;
5
+ headers?: Record<string, string>;
6
+ body?: string;
7
+ };
8
+ export type SandboxFetchResponse = {
9
+ status: number;
10
+ statusText: string;
11
+ ok: boolean;
12
+ headers: Record<string, string>;
13
+ bodyText: string;
14
+ };
15
+ export type SandboxFetch = (request: SandboxFetchRequest) => Promise<SandboxFetchResponse>;
16
+ export type SandboxResult = {
17
+ result?: unknown;
18
+ error?: string;
19
+ };
20
+ export type RunInSandboxOptions = {
21
+ timeoutMs?: number;
22
+ hostFetch?: SandboxFetch;
23
+ };
24
+ //# sourceMappingURL=types.d.ts.map
File without changes
@@ -8,8 +8,10 @@ export declare const McpErrorCodes: {
8
8
  readonly MethodNotFound: -32601;
9
9
  readonly InvalidParams: -32602;
10
10
  };
11
+ export declare const MCP_PROTOCOL_VERSION = "2025-06-18";
11
12
  export declare const DEFAULT_CONNECTION_TIMEOUT_MS = 30000;
12
13
  export declare const SSE_KEEPALIVE_INTERVAL_MS = 15000;
13
14
  export declare const MAX_DOCUMENTS_PER_CATEGORY = 3;
14
15
  export declare const MCP_NOT_ALLOWED_TEMPLATE_ID = "mcp-not-allowed";
16
+ export declare const DEFAULT_DOCS_MCP_SERVER_NAME = "Docs MCP server";
15
17
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- const o={Docs:"docs"},r={InternalError:-32603,ServerError:-32e3,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602},e=3e4,t=15e3,E=3,_="mcp-not-allowed";export{e as DEFAULT_CONNECTION_TIMEOUT_MS,E as MAX_DOCUMENTS_PER_CATEGORY,_ as MCP_NOT_ALLOWED_TEMPLATE_ID,r as McpErrorCodes,o as McpServerType,t as SSE_KEEPALIVE_INTERVAL_MS};
1
+ const o={Docs:"docs"},r={InternalError:-32603,ServerError:-32e3,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602},E="2025-06-18",e=3e4,t=15e3,_=3,s="mcp-not-allowed",c="Docs MCP server";export{e as DEFAULT_CONNECTION_TIMEOUT_MS,c as DEFAULT_DOCS_MCP_SERVER_NAME,_ as MAX_DOCUMENTS_PER_CATEGORY,s as MCP_NOT_ALLOWED_TEMPLATE_ID,E as MCP_PROTOCOL_VERSION,r as McpErrorCodes,o as McpServerType,t as SSE_KEEPALIVE_INTERVAL_MS};
@@ -1,8 +1,4 @@
1
1
  import type { McpToolSchema } from '../../../types';
2
- export declare const EXECUTE_TOOL_NAME = "execute";
3
- export declare const EXECUTE_TOOL_SCHEMA: McpToolSchema;
4
- export declare const DESCRIBE_TOOLS_TOOL_NAME = "describe-tools";
5
- export declare const CODE_MODE_TOOL_NAMES: ReadonlySet<string>;
6
2
  export declare function getDefaultToolSchemas(config: {
7
3
  products?: string[];
8
4
  locales?: string[];
@@ -1 +1 @@
1
- import{shouldHandleMcpAuth as d}from"../auth/auth-handlers.js";import{EXECUTE_DESCRIPTION as h}from"./codemode/prompts.js";import{GRAPHQL_TYPE_KINDS as o}from"./tools/graphql/types.js";const p=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD","TRACE"],t={type:"string",nullable:!0},n={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},r={codemodeType:"OpenApiServer[]"},s={codemodeType:"OpenApiSecurityRequirement[]"},l={codemodeType:"Record<string, OpenApiSecurityScheme>"},y={codemodeType:"OpenApiDocument"},g={codemodeType:"OpenApiOperation & { path: string; method: string }"},c="execute",j={name:c,description:h,schema:{type:"object",required:["code","description"],additionalProperties:!1,properties:{code:{type:"string",description:"JavaScript to run in the sandbox. Return a value to receive it as the result.",minLength:1},description:{type:"string",description:"A short, human-readable summary of what this code does (shown to users in place of the raw call).",minLength:1}}}},f="describe-tools",I=new Set([c,f]),b={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"API name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of APIs per page. Default is 300",minimum:1,default:300,nullable:!0}}},a={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0}}},S={type:"object",required:["name","path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...p,...p.map(e=>e.toLowerCase())],minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0}}},v={type:"object",required:[],additionalProperties:!1,properties:{}};function w(e){const i=[{name:"list-apis",description:"Lists available APIs with their context and purpose",schema:b,annotations:{title:"List APIs",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:t,version:t,servers:r}}},...n}}},{name:"get-endpoints",description:"Get all endpoints for a specific API",schema:a,annotations:{title:"Get Endpoints",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoints:{type:"array",items:{type:"object",properties:{path:{type:"string"},method:{type:"string"},summary:t,description:t,security:s}}}}}},{name:"get-endpoint-info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:S,annotations:{title:"Get Endpoint Info",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoint:g,globalSecurity:s,securitySchemes:l}}},{name:"get-security-schemes",description:"Get the security schemes for a specific API",schema:a,annotations:{title:"Get Security Schemes",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:t,version:t,securitySchemes:l,security:s}}},{name:"get-full-api-description",description:"Get the complete OpenAPI description",schema:a,annotations:{title:"Get Full API Description",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},definition:y}}},P(e.products,e.locales)];return d(e.requiresLogin,e.rbac)&&i.push({name:"whoami",description:"Get information about the currently authenticated user",schema:v,annotations:{title:"Who Am I",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{email:{type:"string"},name:{type:"string"},subject:{type:"string"},clientId:{type:"string"},scope:{type:"string"},issuedAt:{type:"string"},expiresAt:{type:"string"}}}}),e.hasGraphqlApis&&i.push(...O()),i}const H={type:"object",required:[],additionalProperties:!1,properties:{filter:{type:"string",description:"GraphQL schema name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},L={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},kind:{type:"string",description:"Optional: return only a single category of schema members",enum:[...o],nullable:!0},filter:{type:"string",description:'Optional: only members whose name contains this substring (e.g. "book")',minLength:1,nullable:!0},referencesType:{type:"string",description:'Optional: only members that reference this type directly or transitively (via return, field, argument, union-member or input-field types). Finds cross-cutting members that never name it \u2014 e.g. referencesType "Book" surfaces a search query returning a union that includes Book.',minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},T={type:"object",required:["name","type"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},type:{type:"string",description:"Name of the type, operation, or directive",minLength:1},includeReferencedTypes:{type:"boolean",description:"Also include the SDL of every type referenced transitively. Gives the whole subgraph at once, but can be large for highly-connected types.",default:!1,nullable:!0}}},A={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function O(){return[{name:"list-graphql-apis",description:"Lists available GraphQL schemas with their context and purpose",schema:H,annotations:{title:"List GraphQL APIs",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:t}}},...n}}},{name:"get-graphql-type-list",description:'List all operations and types in a GraphQL schema as a flat, paginated list. Each item is tagged with its kind (query, object, enum, \u2026) and carries a one-line description; operations also include their return type and argument signature \u2014 use it to decide which members to fetch in detail. Narrow the result with `kind` (one category), `filter` (member-name substring, e.g. "book"), or `referencesType` (only members that use a given type, directly or transitively) to explore a domain cheaply instead of pulling the full schema.',schema:L,annotations:{title:"Get GraphQL Type List",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:{type:"string"},items:{type:"array",items:{type:"object",properties:{kind:{type:"string",enum:o},name:{type:"string"},description:t,type:{type:"string"},args:{type:"string"}}}},...n}}},{name:"get-graphql-type",description:"Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Set includeReferencedTypes to also pull in every type it references transitively \u2014 the full structural subgraph in one call, ideal for complete exploration of an entity (e.g. Book and all the types it touches). That traversal only follows what the target depends on; to go the other direction and find the members that use a type, call get-graphql-type-list with `referencesType`.",schema:T,annotations:{title:"Get GraphQL Type",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",description:"Get the complete GraphQL schema as SDL \u2014 the whole type graph in one call. Returns everything, so it can be very large and token-expensive for big schemas; prefer get-graphql-type-list (filter/paginate) plus targeted get-graphql-type calls, and reach for this only for small schemas or when you truly need the full SDL.",schema:A,annotations:{title:"Get GraphQL Schema",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function P(e,i){const u=e&&e.length>0,m=i&&i.length>0;return{name:"search",description:"Search across the documentation to fetch relevant content for a given query",schema:{type:"object",required:["query"],additionalProperties:!1,properties:{query:{type:"string",description:"Search query. Should be a single word or that phrase that is presented in a documentation.",minLength:1},...u?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:e,nullable:!0}}:{},...m?{locale:{type:"string",description:"Optional locale code to filter search results by documentation language (e.g. 'en', 'ja'). Use the locale matching the language of the user's request. Defaults to the project's default locale.",enum:i,nullable:!0}}:{}}},annotations:{title:"Search Documentation",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}export{I as CODE_MODE_TOOL_NAMES,f as DESCRIBE_TOOLS_TOOL_NAME,c as EXECUTE_TOOL_NAME,j as EXECUTE_TOOL_SCHEMA,w as getDefaultToolSchemas};
1
+ import{shouldHandleMcpAuth as m}from"../auth/auth-handlers.js";import{GRAPHQL_TYPE_KINDS as o}from"./tools/graphql/types.js";const p=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD","TRACE"],t={type:"string",nullable:!0},n={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},r={codemodeType:"OpenApiServer[]"},s={codemodeType:"OpenApiSecurityRequirement[]"},l={codemodeType:"Record<string, OpenApiSecurityScheme>"},d={codemodeType:"OpenApiDocument"},h={codemodeType:"OpenApiOperation & { path: string; method: string }"},y={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"API name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of APIs per page. Default is 300",minimum:1,default:300,nullable:!0}}},a={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0}}},g={type:"object",required:["name","path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...p,...p.map(e=>e.toLowerCase())],minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0}}},f={type:"object",required:[],additionalProperties:!1,properties:{}};function q(e){const i=[{name:"list-apis",description:"Lists available APIs with their context and purpose",schema:y,annotations:{title:"List APIs",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:t,version:t,servers:r}}},...n}}},{name:"get-endpoints",description:"Get all endpoints for a specific API",schema:a,annotations:{title:"Get Endpoints",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoints:{type:"array",items:{type:"object",properties:{path:{type:"string"},method:{type:"string"},summary:t,description:t,security:s}}}}}},{name:"get-endpoint-info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:g,annotations:{title:"Get Endpoint Info",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoint:h,globalSecurity:s,securitySchemes:l}}},{name:"get-security-schemes",description:"Get the security schemes for a specific API",schema:a,annotations:{title:"Get Security Schemes",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:t,version:t,securitySchemes:l,security:s}}},{name:"get-full-api-description",description:"Get the complete OpenAPI description",schema:a,annotations:{title:"Get Full API Description",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},definition:d}}},P(e.products,e.locales)];return m(e.requiresLogin,e.rbac)&&i.push({name:"whoami",description:"Get information about the currently authenticated user",schema:f,annotations:{title:"Who Am I",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{email:{type:"string"},name:{type:"string"},subject:{type:"string"},clientId:{type:"string"},scope:{type:"string"},issuedAt:{type:"string"},expiresAt:{type:"string"}}}}),e.hasGraphqlApis&&i.push(...L()),i}const b={type:"object",required:[],additionalProperties:!1,properties:{filter:{type:"string",description:"GraphQL schema name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},S={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},kind:{type:"string",description:"Optional: return only a single category of schema members",enum:[...o],nullable:!0},filter:{type:"string",description:'Optional: only members whose name contains this substring (e.g. "book")',minLength:1,nullable:!0},referencesType:{type:"string",description:'Optional: only members that reference this type directly or transitively (via return, field, argument, union-member or input-field types). Finds cross-cutting members that never name it \u2014 e.g. referencesType "Book" surfaces a search query returning a union that includes Book.',minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},H={type:"object",required:["name","type"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},type:{type:"string",description:"Name of the type, operation, or directive",minLength:1},includeReferencedTypes:{type:"boolean",description:"Also include the SDL of every type referenced transitively. Gives the whole subgraph at once, but can be large for highly-connected types.",default:!1,nullable:!0}}},v={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function L(){return[{name:"list-graphql-apis",description:"Lists available GraphQL schemas with their context and purpose",schema:b,annotations:{title:"List GraphQL APIs",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:t}}},...n}}},{name:"get-graphql-type-list",description:'List all operations and types in a GraphQL schema as a flat, paginated list. Each item is tagged with its kind (query, object, enum, \u2026) and carries a one-line description; operations also include their return type and argument signature \u2014 use it to decide which members to fetch in detail. Narrow the result with `kind` (one category), `filter` (member-name substring, e.g. "book"), or `referencesType` (only members that use a given type, directly or transitively) to explore a domain cheaply instead of pulling the full schema.',schema:S,annotations:{title:"Get GraphQL Type List",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:{type:"string"},items:{type:"array",items:{type:"object",properties:{kind:{type:"string",enum:o},name:{type:"string"},description:t,type:{type:"string"},args:{type:"string"}}}},...n}}},{name:"get-graphql-type",description:"Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Set includeReferencedTypes to also pull in every type it references transitively \u2014 the full structural subgraph in one call, ideal for complete exploration of an entity (e.g. Book and all the types it touches). That traversal only follows what the target depends on; to go the other direction and find the members that use a type, call get-graphql-type-list with `referencesType`.",schema:H,annotations:{title:"Get GraphQL Type",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",description:"Get the complete GraphQL schema as SDL \u2014 the whole type graph in one call. Returns everything, so it can be very large and token-expensive for big schemas; prefer get-graphql-type-list (filter/paginate) plus targeted get-graphql-type calls, and reach for this only for small schemas or when you truly need the full SDL.",schema:v,annotations:{title:"Get GraphQL Schema",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function P(e,i){const c=e&&e.length>0,u=i&&i.length>0;return{name:"search",description:"Search across the documentation to fetch relevant content for a given query",schema:{type:"object",required:["query"],additionalProperties:!1,properties:{query:{type:"string",description:"Search query. Should be a single word or that phrase that is presented in a documentation.",minLength:1},...c?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:e,nullable:!0}}:{},...u?{locale:{type:"string",description:"Optional locale code to filter search results by documentation language (e.g. 'en', 'ja'). Use the locale matching the language of the user's request. Defaults to the project's default locale.",enum:i,nullable:!0}}:{}}},annotations:{title:"Search Documentation",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}export{q as getDefaultToolSchemas};
@@ -1 +1 @@
1
- import{filterApiDescriptionsByName as f}from"../../utils.js";const x=async(a,l)=>{const{filter:i,page:n=1,limit:e=300}=a;let t=Object.values(l.apiDescriptionsMap);i&&(t=f(t,i));const s=(n-1)*e,o=s+e,r=Math.ceil(t.length/e),c=t.length;return t=t.slice(s,o),t.length===0?{content:[{type:"text",text:"No APIs available"}]}:{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:g,...p})=>p),limit:e,total:c,page:n,totalPages:r})}]}};var m={"list-apis":x};export{m as default};
1
+ import{filterApiDescriptionsByName as f}from"../../utils.js";const g=async(l,a)=>{const{filter:i,page:n=1,limit:e=300}=l;let t=Object.values(a.apiDescriptionsMap);i&&(t=f(t,i));const s=(n-1)*e,o=s+e,c=Math.ceil(t.length/e),r=t.length;return t=t.slice(s,o),t.length===0?{content:[{type:"text",text:"No APIs available"}]}:{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:h,fetchEligible:x,...p})=>p),limit:e,total:r,page:n,totalPages:c})}]}};var u={"list-apis":g};export{u as default};
@@ -1 +1 @@
1
- function $(e,o,s){if(!o)return;const n=o.toLowerCase();if(s)return e[`${n}@${s}`];const t=Object.values(e).filter(({name:r})=>r.toLowerCase()===n);if(t.length){if(t.length>1){const r=t.map(({version:c})=>c||"(no version)").join(", ");throw new Error(`Multiple versions of "${o}" found: ${r}. Specify a version to disambiguate.`)}return t[0]}}function v(e,o){return Object.values(e).filter(({name:s})=>s.toLowerCase().includes(o.toLowerCase()))}function d(e,o){if(!o||!e?.startsWith("#/"))return;const s=e.slice(2).split("/");let n=o;for(const t of s)if(typeof n=="object"&&n!==null&&t in n)n=n[t];else return;return n}function l({schema:e,definition:o,visitedRefs:s=new Set,maxDepth:n=50,currentDepth:t=0}){if(!e)return;if(t>=n)return{type:"object",description:`Maximum resolution depth exceeded (${n})`};if("$ref"in e&&e.$ref){if(s.has(e.$ref))return{type:"object",description:`Circular reference detected: ${e.$ref}`,"x-circular-ref":e.$ref};const f=new Set(s);f.add(e.$ref);const u=d(e.$ref,o);return u?l({schema:u,definition:o,visitedRefs:f,maxDepth:n,currentDepth:t+1}):{type:"object",description:`Could not resolve reference: ${e.$ref}`,"x-unresolved-ref":e.$ref}}const r={...e};if(r.properties){const f={};for(const[u,i]of Object.entries(r.properties)){const p=l({schema:i,definition:o,visitedRefs:new Set(s),maxDepth:n,currentDepth:t+1});f[u]=p||i}r.properties=f}if(r.items&&typeof r.items=="object")if(Array.isArray(r.items))r.items=r.items.map(f=>l({schema:f,definition:o,visitedRefs:new Set(s),maxDepth:n,currentDepth:t+1})||f);else{const f=l({schema:r.items,definition:o,visitedRefs:new Set(s),maxDepth:n,currentDepth:t+1});f&&(r.items=f)}return["allOf","anyOf","oneOf"].forEach(f=>{const u=r[f];Array.isArray(u)&&(r[f]=u.reduce((i,p)=>{const m=l({schema:p,definition:o,visitedRefs:new Set(s),maxDepth:n,currentDepth:t+1});return m&&i.push(m),i},[]))}),r}function h({pathParams:e,opParams:o,definition:s}){return[...e,...o].reduce((n,t)=>{if(!t)return n;if("$ref"in t&&t.$ref){const r=d(t.$ref,s);return r&&n.push({...r,schema:"schema"in r&&r.schema?l({schema:r.schema,definition:s}):void 0}),n}return n.push({...t,schema:"schema"in t&&t.schema?l({schema:t.schema,definition:s}):void 0}),n},[])}function a(e,o){const s={...e};if(e.example!==void 0&&(s.example=e.example),!e.examples)return s;const n={};for(const[t,r]of Object.entries(e.examples))if("$ref"in r){const c=d(r.$ref,o);c&&(n[t]=c)}else n[t]=r;return s.examples=n,s}function w(e,o){if(!e)return;const s="$ref"in e&&e.$ref?d(e.$ref,o):e;if(!s)return;const n={...s};if("content"in s&&s.content){const t={};for(const[r,c]of Object.entries(s.content))t[r]={...a(c,o),schema:c.schema?l({schema:c.schema,definition:o}):void 0};n.content=t}return n}function x(e,o){return Object.entries(e).reduce((s,[n,t])=>{const r="$ref"in t&&t.$ref?d(t.$ref,o):t;if(!r)return s;const c={...r};if("content"in r&&r.content){const f={};for(const[u,i]of Object.entries(r.content))f[u]={...a(i,o),schema:i.schema?l({schema:i.schema,definition:o}):void 0};c.content=f}return s[n]=c,s},{})}export{v as filterApiDescriptionsByName,$ as findApiDescriptionByNameAndVersion,h as resolveParameters,d as resolveRef,w as resolveRequestBody,x as resolveResponses,l as resolveSchemaRefs};
1
+ function v(t,o,n){if(!o)return;const s=o.toLowerCase(),r=Object.values(t).filter(({name:i})=>i.toLowerCase()===s);if(r.length===0)return;const e=n?r.filter(i=>i.version===n):r;if(e.length===0)return;if(e.length===1)return e[0];if(new Set(e.map(({version:i})=>i||"")).size>1){const i=e.map(({version:d})=>d||"(no version)").join(", ");throw new Error(`Multiple versions of "${o}" found: ${i}. Specify a version to disambiguate.`)}const c=e.map(({relativePath:i})=>i||"(unknown path)").join(", "),u=e[0].version?` at version "${e[0].version}"`:"";throw new Error(`Multiple APIs are titled "${o}"${u} (${c}). Give them a distinct info.title or info.version so they can be addressed individually.`)}function $(t,o){return Object.values(t).filter(({name:n})=>n.toLowerCase().includes(o.toLowerCase()))}function a(t,o){if(!o||!t?.startsWith("#/"))return;const n=t.slice(2).split("/");let s=o;for(const r of n)if(typeof s=="object"&&s!==null&&r in s)s=s[r];else return;return s}function l({schema:t,definition:o,visitedRefs:n=new Set,maxDepth:s=50,currentDepth:r=0}){if(!t)return;if(r>=s)return{type:"object",description:`Maximum resolution depth exceeded (${s})`};if("$ref"in t&&t.$ref){if(n.has(t.$ref))return{type:"object",description:`Circular reference detected: ${t.$ref}`,"x-circular-ref":t.$ref};const c=new Set(n);c.add(t.$ref);const u=a(t.$ref,o);return u?l({schema:u,definition:o,visitedRefs:c,maxDepth:s,currentDepth:r+1}):{type:"object",description:`Could not resolve reference: ${t.$ref}`,"x-unresolved-ref":t.$ref}}const e={...t};if(e.properties){const c={};for(const[u,i]of Object.entries(e.properties)){const d=l({schema:i,definition:o,visitedRefs:new Set(n),maxDepth:s,currentDepth:r+1});c[u]=d||i}e.properties=c}if(e.items&&typeof e.items=="object")if(Array.isArray(e.items))e.items=e.items.map(c=>l({schema:c,definition:o,visitedRefs:new Set(n),maxDepth:s,currentDepth:r+1})||c);else{const c=l({schema:e.items,definition:o,visitedRefs:new Set(n),maxDepth:s,currentDepth:r+1});c&&(e.items=c)}return["allOf","anyOf","oneOf"].forEach(c=>{const u=e[c];Array.isArray(u)&&(e[c]=u.reduce((i,d)=>{const p=l({schema:d,definition:o,visitedRefs:new Set(n),maxDepth:s,currentDepth:r+1});return p&&i.push(p),i},[]))}),e}function h({pathParams:t,opParams:o,definition:n}){return[...t,...o].reduce((s,r)=>{if(!r)return s;if("$ref"in r&&r.$ref){const e=a(r.$ref,n);return e&&s.push({...e,schema:"schema"in e&&e.schema?l({schema:e.schema,definition:n}):void 0}),s}return s.push({...r,schema:"schema"in r&&r.schema?l({schema:r.schema,definition:n}):void 0}),s},[])}function m(t,o){const n={...t};if(t.example!==void 0&&(n.example=t.example),!t.examples)return n;const s={};for(const[r,e]of Object.entries(t.examples))if("$ref"in e){const f=a(e.$ref,o);f&&(s[r]=f)}else s[r]=e;return n.examples=s,n}function w(t,o){if(!t)return;const n="$ref"in t&&t.$ref?a(t.$ref,o):t;if(!n)return;const s={...n};if("content"in n&&n.content){const r={};for(const[e,f]of Object.entries(n.content))r[e]={...m(f,o),schema:f.schema?l({schema:f.schema,definition:o}):void 0};s.content=r}return s}function b(t,o){return Object.entries(t).reduce((n,[s,r])=>{const e="$ref"in r&&r.$ref?a(r.$ref,o):r;if(!e)return n;const f={...e};if("content"in e&&e.content){const c={};for(const[u,i]of Object.entries(e.content))c[u]={...m(i,o),schema:i.schema?l({schema:i.schema,definition:o}):void 0};f.content=c}return n[s]=f,n},{})}export{$ as filterApiDescriptionsByName,v as findApiDescriptionByNameAndVersion,h as resolveParameters,a as resolveRef,w as resolveRequestBody,b as resolveResponses,l as resolveSchemaRefs};
@@ -0,0 +1,30 @@
1
+ import type { OpenAPIDefinition } from '@redocly/openapi-docs';
2
+ import type { OpenAPIMcp } from '@redocly/openapi-docs/lib/types/open-api.js';
3
+ import type { RbacConfig } from '@redocly/config';
4
+ type GatewayVisibility = {
5
+ hide?: boolean;
6
+ docs?: {
7
+ hide?: boolean;
8
+ ignore?: readonly string[];
9
+ };
10
+ gateway?: {
11
+ hide?: boolean;
12
+ };
13
+ };
14
+ /** Whether the gateway fetch capability is on: the feature flag plus none of mcp/docs/gateway hidden. */
15
+ export declare function isGatewayCapabilityEnabled(mcp: GatewayVisibility | undefined): boolean;
16
+ /** Whether an API is eligible for the gateway (fetch-capable `execute` + `/mcp` advertisement). */
17
+ export declare function isGatewayEligible(info: OpenAPIDefinition['info'] | undefined, relativePath: string, rbacConfig: RbacConfig): boolean;
18
+ /**
19
+ * Whether an API docs page advertises the `/mcp` endpoint via an injected root-level x-mcp:
20
+ * the capability is on, the author has not provided their own x-mcp servers, and the API is
21
+ * both gateway-eligible and part of the Docs MCP catalog.
22
+ */
23
+ export declare function shouldAdvertiseGatewayXMcp(definition: (OpenAPIDefinition & {
24
+ 'x-mcp'?: {
25
+ servers?: unknown[];
26
+ };
27
+ }) | undefined, relativePath: string, rbacConfig: RbacConfig, mcpConfig: GatewayVisibility | undefined): boolean;
28
+ export declare function buildGatewayXMcp(url: string): OpenAPIMcp;
29
+ export {};
30
+ //# sourceMappingURL=eligibility.d.ts.map
@@ -0,0 +1 @@
1
+ import{join as r}from"node:path";import{PUBLIC_API_DEFINITIONS_FOLDER as s}from"../../../constants/common.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as a}from"../../../../constants/common.js";import{canDownloadApiDefinition as n}from"../../../utils/rbac.js";import{MCP_PROTOCOL_VERSION as p}from"../constants.js";import{isApiIncludedInDocsMcp as l}from"../utils.js";import{isMcpGatewayEnabled as c}from"../utils/mode.js";import{isDefinitionHidden as f,hasGatewayConfig as m}from"../utils/xmcp-utils.js";function u(o){return c()&&!o?.hide&&!o?.docs?.hide&&!o?.gateway?.hide}function d(o,e,i){return f(o,"gateway")?!1:n(r(s,e),i,!1,{isAuthenticated:!1,teams:[a]})||m(o)}function D(o,e,i,t){return u(t)&&!o?.["x-mcp"]?.servers?.length&&d(o?.info,e,i)&&l(e,o,t)}function M(o){return{protocolVersion:p,capabilities:{tools:{}},servers:[{url:o}],tools:[],resources:[],prompts:[]}}export{M as buildGatewayXMcp,u as isGatewayCapabilityEnabled,d as isGatewayEligible,D as shouldAdvertiseGatewayXMcp};
@@ -0,0 +1,13 @@
1
+ import type { OpenAPIServer } from '@redocly/openapi-docs/lib/types/open-api.js';
2
+ /**
3
+ * Build case-insensitive host matchers from an API's server URL templates (plus any
4
+ * configured extra hosts). A server URL host may contain server-variable placeholders
5
+ * (e.g. a tenant `{subdomain}`); each placeholder expands to its `enum` values, or - when
6
+ * free-form - to one DNS label plus any fixed parent domain carried by the variable's
7
+ * `default`. So `{subdomain}.dealpos.com` matches `acme.dealpos.com`, and a whole-host
8
+ * `{subdomain}` defaulting to `acme.dealpos.net` matches `<tenant>.dealpos.net`, but neither
9
+ * matches `a.b.dealpos.com`, the bare parent domain, or an unrelated host.
10
+ */
11
+ export declare function buildAllowedHostMatchers(servers?: readonly OpenAPIServer[], extraHosts?: readonly string[]): RegExp[];
12
+ export declare function isHostAllowed(host: string, matchers: readonly RegExp[]): boolean;
13
+ //# sourceMappingURL=allowed-hosts.d.ts.map
@@ -0,0 +1 @@
1
+ const i=/\{([^}]+)\}/g;function m(n=[],e=[]){const t=[];for(const r of n){const o=u(r);o&&t.push(o)}for(const r of e){const o=h(r);o&&t.push(o)}return t}function p(n,e){return e.some(t=>t.test(n))}function u(n){const e=f(n.url);if(!e)return null;let t="",r=0;for(const o of e.matchAll(i)){const[c,l]=o;t+=s(e.slice(r,o.index)),t+=a(n.variables?.[l]),r=o.index+c.length}return t+=s(e.slice(r)),t.includes("\\.")?new RegExp(`^${t}$`,"i"):null}function a(n){const e=n?.enum?.filter(Boolean);if(e&&e.length>0)return`(?:${e.map(s).join("|")})`;const t=n?.default?.split(".").slice(1).join(".");return t?`[^.]+\\.${s(t)}`:"[^.]+"}function h(n){const e=n.trim().toLowerCase();return e?e.startsWith("*.")?new RegExp(`^[^.]+\\.${s(e.slice(2))}$`,"i"):new RegExp(`^${s(e)}$`,"i"):null}function f(n){if(!n)return null;const t=n.replace(/^[a-z][a-z0-9+.-]*:\/\//i,"").split(/[/?#]/,1)[0];return t&&(t.includes("@")?t.slice(t.lastIndexOf("@")+1):t).replace(/:(?:\d+|\{[^}]+\})$/,"")||null}function s(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}export{m as buildAllowedHostMatchers,p as isHostAllowed};
@@ -0,0 +1,12 @@
1
+ import type { SandboxFetch } from '../../codemode/types.js';
2
+ type FetchBridgeOptions = {
3
+ allowedHosts: readonly RegExp[];
4
+ authorization?: string;
5
+ fetchImpl?: typeof fetch;
6
+ timeoutMs?: number;
7
+ maxResponseBytes?: number;
8
+ };
9
+ /** Build the host-side `fetch` the gateway sandbox calls. */
10
+ export declare function buildFetchBridge({ allowedHosts, authorization, fetchImpl, timeoutMs, maxResponseBytes }: FetchBridgeOptions): SandboxFetch;
11
+ export {};
12
+ //# sourceMappingURL=fetch-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ import{assertUrlAllowed as f}from"./ssrf-guard.js";const b=3e4,w=1024*1024;function m({allowedHosts:t,authorization:e,fetchImpl:o=fetch,timeoutMs:n=b,maxResponseBytes:s=w}){return async r=>{const a=f(r.url,t),d=g(r.headers,e),c=new AbortController,u=setTimeout(()=>c.abort(),n);try{const i=await o(a,{method:r.method??"GET",headers:d,body:r.body,redirect:"manual",signal:c.signal}),h=await y(i,s);return{status:i.status,statusText:i.statusText,ok:i.ok,headers:T(i.headers),bodyText:h}}finally{clearTimeout(u)}}}async function y(t,e){const o=Number(t.headers.get("content-length"));if(Number.isFinite(o)&&o>e)throw l(e,o);if(!t.body)return"";const n=t.body.getReader(),s=new TextDecoder;let r=0,a="";try{for(;;){const{done:d,value:c}=await n.read();if(d)break;if(r+=c.byteLength,r>e)throw l(e,r);a+=s.decode(c,{stream:!0})}return a+s.decode()}finally{await n.cancel().catch(()=>{})}}function l(t,e){return new Error(`Response is too large (over ${t} bytes, got ${e}); request less data`)}function g(t,e){const o={};let n=!1;for(const[s,r]of Object.entries(t??{})){const a=s.toLowerCase();a==="host"||a==="content-length"||(a==="authorization"&&(n=!0),o[s]=r)}return e&&!n&&(o.Authorization=e),o}function T(t){const e={};return t.forEach((o,n)=>{e[n.toLowerCase()]=o}),e}export{m as buildFetchBridge};
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Validate an outbound request URL against an API's host allow-list before the gateway fetches it.
3
+ *
4
+ * Returns the parsed URL on success; throws with a clear message otherwise.
5
+ */
6
+ export declare function assertUrlAllowed(rawUrl: string, matchers: readonly RegExp[]): URL;
7
+ /** True for loopback, private, link-local, unspecified, or otherwise internal addresses. */
8
+ export declare function isBlockedAddress(host: string): boolean;
9
+ //# sourceMappingURL=ssrf-guard.d.ts.map
@@ -0,0 +1 @@
1
+ import{isHostAllowed as f}from"./allowed-hosts.js";function c(e,r){let t;try{t=new URL(e)}catch{throw new Error(`Invalid URL: ${e}`)}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new Error(`Only http(s) URLs are allowed, got ${t.protocol}`);const n=o(t.hostname);if(u(n)||!f(n,r))throw new Error(`Host "${n}" is not allowed`);return t}function u(e){const r=o(e.toLowerCase());return r==="localhost"||r.endsWith(".localhost")?!0:i(r)?s(r):r.includes(":")?l(r):!1}function o(e){return e.replace(/^\[|\]$/g,"")}function i(e){return/^\d{1,3}(\.\d{1,3}){3}$/.test(e)}function s(e){const[r,t]=e.split(".").map(Number);return r===0||r===10||r===127||r===169&&t===254||r===172&&t>=16&&t<=31||r===192&&t===168||r===100&&t>=64&&t<=127}function l(e){if(e==="::1"||e==="::")return!0;const r=e.match(/::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/);if(r)return s(r[1]);const t=parseInt(e.split(":")[0],16);return Number.isNaN(t)?!1:t>=65152&&t<=65215||t>=64512&&t<=65023}export{c as assertUrlAllowed,u as isBlockedAddress};
@@ -0,0 +1,6 @@
1
+ import type { ApiDescriptionInfo, McpToolContext } from '../types.js';
2
+ import type { SandboxFetch } from '../codemode/types.js';
3
+ export declare function getCallableApis(context: McpToolContext): ApiDescriptionInfo[];
4
+ export declare function isFetchCapable(context: McpToolContext): boolean;
5
+ export declare function buildExecuteHostFetch(context: McpToolContext): SandboxFetch;
6
+ //# sourceMappingURL=fetch-capability.d.ts.map
@@ -0,0 +1 @@
1
+ import{isGatewayCapabilityEnabled as a}from"./eligibility.js";import{buildAllowedHostMatchers as l}from"./fetch/allowed-hosts.js";import{buildFetchBridge as s}from"./fetch/fetch-bridge.js";function i(t){return Object.values(t.apiDescriptionsMap??{}).filter(e=>e.fetchEligible)}function u(t){const e=t.config?.mcp;return a(e)&&i(t).length>0}function f(t){const e=t.config?.mcp,o=i(t).flatMap(r=>r.servers??[]);return s({allowedHosts:l(o,e?.gateway?.allowedHosts),authorization:t.upstreamAuthorization})}export{f as buildExecuteHostFetch,i as getCallableApis,u as isFetchCapable};
@@ -1 +1 @@
1
- import{toFetchResponse as b,toReqRes as N}from"fetch-to-node";import{logger as m}from"../../../tools/notifiers/logger.js";import{isObject as k}from"../../../../utils/guards/is-object.js";import{createDocsMcpServer as O}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as U,filterGraphqlDescriptionsByRbac as E}from"../utils.js";import{createMethodNotAllowedError as H,withErrorHandling as I}from"./errors.js";import{attachSseKeepalive as j}from"./sse-keepalive.js";import{McpServerType as L}from"../constants.js";import{constructInvalidTokenResponse as J,constructUnauthorizedResponse as P,handleMcpAuth as q,shouldHandleMcpAuth as B}from"../auth/auth-handlers.js";import{extractTokenFromAuthHeader as G}from"../utils/jwt.js";const u="X-Redocly-AI-Metadata";function $(r){if(r)try{const e=JSON.parse(r);if(k(e))return e;m.warn(`Ignoring ${u} header: not a JSON object.`)}catch{m.warn(`Ignoring ${u} header: invalid JSON.`)}}const z=async(r,e,h)=>{const n=!!e?.config?.access?.requiresLogin,i=e?.config?.access?.rbac||{};let a;const f=r.headers.get("Authorization");if(B(n,i)){const{isAuthenticated:o,isTokenValid:c,currentUser:t,accessToken:p}=await q(r,e);if(!o)return P(new URL(r.url).origin);if(!c)return J();t&&(e.user=t),a=p}else f&&(a=G(f||"")??void 0);let s;const g=async()=>{s&&(await s.cleanup(),s=void 0)};return await I(async()=>{if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using that URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return H();const o=h,c=o?.props?.config?.apiDescriptionsMap||{},t=o?.props?.config?.graphqlDescriptions||[],p=o?.props?.config?.mcpDocsServerName||"Docs MCP server",{config:{mcp:D={}}}=e,M=U(c,e.user,i,n),R=E(t,e.user,i,n),y=e.config.products?Object.values(e.config.products).map(l=>l?.name):[],A=D.docs?.name||p,w=$(r.headers.get(u)),T=o?.props?.tools||[];s=await O({name:A,tools:T,context:{...e,accessToken:a,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(r.url).origin,apiDescriptionsMap:M,graphqlDescriptions:R,products:y,metadata:w}});const v=await r.json(),{req:C,res:d}=N(r),S=j(d);try{await s.transport.handleRequest(C,d,v)}catch(l){throw S.stop(),l}return b(d)},L.Docs,g)};var ee=z;export{ee as default};
1
+ import{toFetchResponse as E,toReqRes as k}from"fetch-to-node";import{logger as m}from"../../../tools/notifiers/logger.js";import{isObject as v}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as N}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as O}from"../../../utils/skills/get-skill-url.js";import{createDocsMcpServer as L}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as H,filterGraphqlDescriptionsByRbac as I}from"../utils.js";import{createMethodNotAllowedError as j,withErrorHandling as B}from"./errors.js";import{attachSseKeepalive as _}from"./sse-keepalive.js";import{constructInvalidTokenResponse as J,constructUnauthorizedResponse as P,handleMcpAuth as F,shouldHandleMcpAuth as G}from"../auth/auth-handlers.js";import{extractTokenFromAuthHeader as V}from"../utils/jwt.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as $}from"../constants.js";const u="X-Redocly-AI-Metadata";function q(r){if(r)try{const e=JSON.parse(r);if(v(e))return e;m.warn(`Ignoring ${u} header: not a JSON object.`)}catch{m.warn(`Ignoring ${u} header: invalid JSON.`)}}const z=async(r,e,g)=>{const t=!!e?.config?.access?.requiresLogin,i=e?.config?.access?.rbac||{};let c;const f=r.headers.get("Authorization");if(G(t,i)){const{isAuthenticated:s,isTokenValid:p,currentUser:a,accessToken:d}=await F(r,e);if(!s)return P(new URL(r.url).origin);if(!p)return J();a&&(e.user=a),c=d}else f&&(c=V(f||"")??void 0);let n;return await B(async()=>{if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using that URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return j();const s=g,p=s?.props?.config?.apiDescriptionsMap||{},a=s?.props?.config?.graphqlDescriptions||[],d=s?.props?.config?.mcpDocsServerName||$,{config:{mcp:h={}}}=e,R=H(p,e.user,i,t),A=I(a,e.user,i,t),D=s?.props?.skillsBaseUrl||new URL(r.url).origin,M=N(s?.props?.skills||[],e.user,i,t).map(o=>({slug:o.slug,name:o.name,description:o.description,content:o.content,uri:O(D,o.slug)})),w=e.config.products?Object.values(e.config.products).map(o=>o?.name):[],y=h.docs?.name||d,S=q(r.headers.get(u)),T=s?.props?.tools||[];n=await L({name:y,tools:T,skills:M,context:{...e,accessToken:c,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(r.url).origin,apiDescriptionsMap:R,graphqlDescriptions:A,products:w,metadata:S}});const U=await r.json(),{req:C,res:l}=k(r),b=_(l);try{await n.transport.handleRequest(C,l,U)}catch(o){throw b.stop(),o}return E(l)},async()=>{n&&(await n.cleanup(),n=void 0)})};var ie=z;export{ie as default};
@@ -1,4 +1,4 @@
1
- import type { McpErrorCodeTypes, McpServerType } from '../types.js';
1
+ import type { McpErrorCodeTypes } from '../types.js';
2
2
  export type McpErrorData = {
3
3
  readonly code: McpErrorCodeTypes;
4
4
  readonly message: string;
@@ -10,29 +10,11 @@ export declare class McpError extends Error {
10
10
  readonly data?: unknown;
11
11
  readonly requestId?: string | number | null;
12
12
  constructor(code: McpErrorCodeTypes, message: string, data?: unknown, requestId?: string | number | null);
13
- /**
14
- * Creates a JSON-RPC 2.0 compliant error response
15
- */
16
13
  createErrorResponse(): Response;
17
14
  }
18
- /**
19
- * Creates a method not allowed error response
20
- */
21
15
  export declare function createMethodNotAllowedError(requestId?: string | number | null): Response;
22
- /**
23
- * Creates an internal server error response with telemetry
24
- */
25
- export declare function createInternalServerError(error: Error | string, serverType?: McpServerType, requestId?: string | number | null): Response;
26
- /**
27
- * Creates an invalid request error response
28
- */
16
+ export declare function createInternalServerError(error: Error | string, requestId?: string | number | null): Response;
29
17
  export declare function createInvalidRequestError(message?: string, requestId?: string | number | null): Response;
30
- /**
31
- * Creates an invalid parameters error response
32
- */
33
18
  export declare function createInvalidParamsError(message?: string, requestId?: string | number | null): Response;
34
- /**
35
- * Safely handles errors in async functions with proper cleanup
36
- */
37
- export declare function withErrorHandling<T>(operation: () => Promise<T>, serverType: McpServerType, cleanup?: () => Promise<void>): Promise<T | Response>;
19
+ export declare function withErrorHandling<T>(operation: () => Promise<T>, cleanup?: () => Promise<void>): Promise<T | Response>;
38
20
  //# sourceMappingURL=errors.d.ts.map