@redocly/realm 0.137.0-next.8 → 0.137.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.
- package/CHANGELOG.md +241 -1
- package/dist/cli/build/index.js +1 -1
- package/dist/client/app/Sidebar/useActions.js +1 -1
- package/dist/client/app/Sidebar/useSidebarItems.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogClassic.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogFilter.js +1 -1
- package/dist/client/app/search/useFacets.js +1 -1
- package/dist/client/app/seo/SeoTags.js +1 -1
- package/dist/client/app/utils/loadAndNavigate.js +1 -1
- package/dist/client/templates/api-docs/template.js +8 -3
- 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 +5 -1
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/constants/common.d.ts +1 -0
- package/dist/server/constants/common.js +1 -1
- package/dist/server/constants/plugins/search.js +1 -1
- package/dist/server/esbuild/esbuild-logger.d.ts +2 -2
- package/dist/server/esbuild/esbuild-logger.js +3 -3
- package/dist/server/plugins/api-docs/options.js +1 -1
- package/dist/server/plugins/api-docs/search/create-indexer.d.ts +5 -0
- package/dist/server/plugins/api-docs/search/create-indexer.js +1 -0
- package/dist/server/plugins/api-docs/search/get-ai-search-documents.d.ts +1 -1
- package/dist/server/plugins/api-docs/search/get-ai-search-documents.js +41 -41
- package/dist/server/plugins/api-docs/search/search-resolver.js +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/common/revision-repository.js +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/common/version-repository.js +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/utils/normalize-revision-flags.js +1 -1
- package/dist/server/plugins/config-parser/loaders/content-slugs-loader.js +1 -1
- package/dist/server/plugins/config-parser/loaders/versions-config-loader.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDescriptionDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditCallbackUrlDialog.js +1 -1
- package/dist/server/plugins/markdown/is-partial.js +1 -1
- package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +5 -4
- package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +5 -2
- package/dist/server/plugins/mcp/codemode/capabilities/utils.js +4 -4
- package/dist/server/plugins/mcp/codemode/code-execution-audit.js +1 -1
- package/dist/server/plugins/mcp/codemode/prompts.d.ts +1 -1
- package/dist/server/plugins/mcp/codemode/prompts.js +7 -6
- package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.d.ts +2 -2
- package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.js +1 -11
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/console.d.ts +2 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/console.js +7 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.d.ts +1 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.js +2 -2
- package/dist/server/plugins/mcp/codemode/sandbox/tool-input-validator.d.ts +5 -0
- package/dist/server/plugins/mcp/codemode/sandbox/tool-input-validator.js +1 -0
- package/dist/server/plugins/mcp/codemode/sandbox/unknown-tool-hint.d.ts +8 -0
- package/dist/server/plugins/mcp/codemode/sandbox/unknown-tool-hint.js +2 -0
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +3 -1
- package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.d.ts +2 -2
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -2
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/create-anonymous-session.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +2 -2
- package/dist/server/plugins/mcp/docs-mcp/tools/core/types.d.ts +2 -2
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.js +5 -5
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +2 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.d.ts +4 -2
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +6 -2
- package/dist/server/plugins/mcp/docs-mcp/utils/api-titles.d.ts +6 -0
- package/dist/server/plugins/mcp/docs-mcp/utils/api-titles.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +11 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +5 -5
- package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/url-placeholders.d.ts +5 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/url-placeholders.js +1 -0
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/servers/mcp-server.js +3 -3
- package/dist/server/plugins/mcp/types.d.ts +1 -0
- package/dist/server/plugins/mcp/utils/available-sandbox-tools.js +1 -1
- package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
- package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.d.ts +4 -2
- package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.js +1 -3
- package/dist/server/plugins/search/engines/flexsearch/index.js +1 -1
- package/dist/server/plugins/search/engines/flexsearch/search-index.d.ts +8 -4
- package/dist/server/plugins/search/engines/flexsearch/search-index.js +1 -1
- package/dist/server/plugins/search/index.js +1 -1
- package/dist/server/plugins/search/llmstxt/build-page-llms-txt-md.d.ts +4 -0
- package/dist/server/plugins/search/llmstxt/build-page-llms-txt-md.js +3 -0
- package/dist/server/plugins/search/llmstxt/create-llms-txt-generator.d.ts +4 -0
- package/dist/server/plugins/search/llmstxt/create-llms-txt-generator.js +1 -0
- package/dist/server/plugins/search/llmstxt/get-llms-txt-exclude-matcher.d.ts +4 -0
- package/dist/server/plugins/search/llmstxt/get-llms-txt-exclude-matcher.js +1 -0
- package/dist/server/plugins/search/llmstxt/index.d.ts +5 -3
- package/dist/server/plugins/search/llmstxt/index.js +9 -9
- package/dist/server/plugins/search/llmstxt/is-included-in-llms-txt.d.ts +6 -0
- package/dist/server/plugins/search/llmstxt/is-included-in-llms-txt.js +1 -0
- package/dist/server/sandbox/sandbox.js +2 -2
- package/dist/server/sandbox/types.d.ts +9 -0
- package/dist/server/sandbox/utils/execution-budget.js +1 -1
- package/dist/server/sandbox/utils/return-last-expression.d.ts +6 -0
- package/dist/server/sandbox/utils/return-last-expression.js +1 -0
- package/dist/server/sandbox/utils/returns-from-top-level.d.ts +1 -2
- package/dist/server/sandbox/utils/returns-from-top-level.js +1 -1
- package/dist/server/sandbox/utils/setup-host-functions.d.ts +1 -0
- package/dist/server/sandbox/utils/setup-host-functions.js +2 -2
- package/dist/server/ssr/render.js +1 -1
- package/dist/server/store.js +1 -1
- package/dist/server/types/plugins/search.d.ts +7 -2
- package/dist/server/types/web-server.d.ts +8 -0
- package/dist/server/utils/envs/get-api-route-allowed-env-variables.js +1 -1
- package/dist/server/utils/get-route-ai-documents-store.d.ts +5 -0
- package/dist/server/utils/get-route-ai-documents-store.js +1 -0
- package/dist/server/utils/get-route-static-data.d.ts +4 -0
- package/dist/server/utils/get-route-static-data.js +1 -0
- package/dist/server/utils/globs.d.ts +4 -0
- package/dist/server/utils/globs.js +1 -1
- package/dist/server/utils/llmstxt/agent-feedback-llms-footer.js +1 -1
- package/dist/server/utils/llmstxt/resolve-llms-txt-md.d.ts +10 -0
- package/dist/server/utils/llmstxt/resolve-llms-txt-md.js +1 -0
- package/dist/server/utils/search/highlight-text-for-search.js +1 -1
- package/dist/server/web-server/auth.d.ts +13 -2
- package/dist/server/web-server/auth.js +3 -3
- package/dist/server/web-server/dev-server.js +1 -1
- package/dist/server/web-server/middleware/ensureSearchData.js +1 -1
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/dynamic-route.d.ts +2 -1
- package/dist/server/web-server/routes/dynamic-route.js +1 -1
- package/dist/server/web-server/routes/index.d.ts +2 -1
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/llms-txt.d.ts +4 -0
- package/dist/server/web-server/routes/llms-txt.js +1 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
- package/dist/{server/plugins/catalog-entities/utils/version-compare.d.ts → utils/version/compare-versions.d.ts} +1 -16
- package/dist/utils/version/compare-versions.js +1 -0
- package/package.json +13 -12
- package/dist/server/plugins/api-docs/search/search-indexer.d.ts +0 -9
- package/dist/server/plugins/api-docs/search/search-indexer.js +0 -1
- package/dist/server/plugins/catalog-entities/utils/version-compare.js +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import{buildToolList as i}from"./build-tool-list.js";const
|
|
1
|
+
import{buildToolList as i}from"./build-tool-list.js";const r=2048,d="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).",n="Available tools (exact signatures come from `describe-tools`):";function a(e,t){if(t.length===0)return e;const o=r-e.length-n.length-3,s=i(t,o);return s?[e,"",n,s].join(`
|
|
2
2
|
`):e}function h(e,t=[]){const o=["Run JavaScript in a sandbox against the documentation tools on the global `tools` object.",e?"The extra globals are `tools`, `fetch`, `URL`, `URLSearchParams`, and `FormData` - 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.","2. Call `describe-tools` with those names to get their exact TypeScript signatures - inputs, result shapes, and a worked example. NEVER call `execute` with guessed method names, parameter names, enum values, or result field names: read fields off the declared return types, not from assumptions.","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."].join(`
|
|
3
|
-
`);return a(o,t)}const
|
|
4
|
-
`);function
|
|
5
|
-
`);return a(o,t)}const
|
|
6
|
-
`)
|
|
7
|
-
`)
|
|
3
|
+
`);return a(o,t)}const p=["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(`
|
|
4
|
+
`);function m(e,t=[]){const o=["This server exposes documentation tools (API discovery, endpoint details, security schemes, full-text search) through `describe-tools` and `execute`:","- `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(`
|
|
5
|
+
`);return a(o,t)}const l=["listApis","getEndpoints"],c=["Example - list the write endpoints of an API:","","```ts","const { items } = await tools.listApis({ filter: 'billing' });","const [api] = items;",`if (!api) return { error: 'no API matches "billing"' };`,"const { endpoints } = await tools.getEndpoints({ name: api.name });","const writes = endpoints.filter((e) => e.method !== 'GET');","return { api: api.name, writes: writes.map((e) => `${e.method} ${e.path}`) };","```"].join(`
|
|
6
|
+
`);function g(e){if(l.every(o=>e.includes(o)))return c;const[t]=e;return t?[`Example - call \`${t}\` and return what the request needs:`,"","```ts",`const result = await tools.${t}({ /* the input its signature above declares */ });`,"return result;","```"].join(`
|
|
7
|
+
`):""}const b=["Types named `OpenApi\u2026` are the standard OpenAPI Specification objects.","Payload samples live on a media type object (`requestBody.content[mediaType]`, `responses[code].content[mediaType]`): `.example` holds a single value, `.examples[name].value` a named map, and some descriptions only set `.schema.example`. Read each before concluding a sample is absent."].join(`
|
|
8
|
+
`);export{p as DESCRIBE_TOOLS_DESCRIPTION,r as DESCRIPTION_CHAR_LIMIT,d as EXECUTE_ARGS_NOTE,b as USAGE_NOTES,m as buildCodeModeInstructions,h as buildExecuteDescription,g as buildExecuteExample};
|
|
@@ -3,8 +3,8 @@ import type { SandboxFetch, SandboxTool } from '../types.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Builds the `setupContext` that shapes the shared sandbox (`~/server/sandbox`) for code
|
|
5
5
|
* mode: the given tools — and, when provided, host fetch — become host-function rails, each
|
|
6
|
-
* capped and bound by the run's budget, and the prelude installs the
|
|
7
|
-
* over
|
|
6
|
+
* capped and bound by the run's budget, and the fetch prelude installs the guest `fetch`
|
|
7
|
+
* surface over its rail.
|
|
8
8
|
*/
|
|
9
9
|
export declare function createSandboxSetup(tools: Record<string, SandboxTool>, hostFetch?: SandboxFetch): SetupSandboxContext;
|
|
10
10
|
//# sourceMappingURL=create-sandbox-setup.d.ts.map
|
|
@@ -1,11 +1 @@
|
|
|
1
|
-
import{setupHostFunctions as
|
|
2
|
-
const tools = ${e};
|
|
3
|
-
${e} = new Proxy(tools, {
|
|
4
|
-
get(target, prop) {
|
|
5
|
-
if (typeof prop !== 'string' || prop in target || prop === 'then' || prop === 'toJSON') {
|
|
6
|
-
return target[prop];
|
|
7
|
-
}
|
|
8
|
-
throw new TypeError('Unknown tool "' + prop + '". Available tools: ' + Object.keys(target).join(', '));
|
|
9
|
-
},
|
|
10
|
-
});
|
|
11
|
-
})();`}export{T as createSandboxSetup};
|
|
1
|
+
import{setupHostFunctions as l}from"../../../../sandbox/utils/setup-host-functions.js";import{evalGuestCode as r}from"../../../../sandbox/utils/eval-guest-code.js";import{CONSOLE_STUB as u,SANDBOX_FETCH_SETUP as _}from"./polyfills/index.js";import{FETCH_BRIDGE_FUNCTION_NAME as i,FETCH_BRIDGE_GLOBAL_NAME as E,TOOLS_BRIDGE_GLOBAL_NAME as L}from"../constants.js";const T=1e3,c=50,p=8*1024*1024;function A(m,t){return(o,s)=>{r(o,`(() => {${u}})();`);const a=[l(o,m,{globalName:L,budget:s,maxCalls:T,maxOutputBytes:p,messages:{outputTooLarge:e=>`Tool output is too large (${e} bytes); request narrower data instead`,callLimitExceeded:e=>`Exceeded the limit of ${e} tool calls`}})];return t&&(a.push(l(o,{[i]:e=>t(e)},{globalName:E,budget:s,maxCalls:c,messages:{outputTooLarge:e=>`Response is too large (${e} bytes); request less data`,callLimitExceeded:e=>`Exceeded the limit of ${e} fetch calls`}})),r(o,`(() => {${_}})();`)),()=>{for(const e of a)e()}}}export{A as createSandboxSetup};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const CONSOLE_STUB = "\nglobalThis.console = Object.freeze({\n assert() {}, clear() {}, count() {}, countReset() {}, debug() {}, dir() {}, dirxml() {},\n error() {}, group() {}, groupCollapsed() {}, groupEnd() {}, info() {}, log() {}, table() {},\n time() {}, timeEnd() {}, timeLog() {}, trace() {}, warn() {},\n});\n";
|
|
2
|
+
//# sourceMappingURL=console.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const e=`
|
|
2
|
+
globalThis.console = Object.freeze({
|
|
3
|
+
assert() {}, clear() {}, count() {}, countReset() {}, debug() {}, dir() {}, dirxml() {},
|
|
4
|
+
error() {}, group() {}, groupCollapsed() {}, groupEnd() {}, info() {}, log() {}, table() {},
|
|
5
|
+
time() {}, timeEnd() {}, timeLog() {}, trace() {}, warn() {},
|
|
6
|
+
});
|
|
7
|
+
`;export{e as CONSOLE_STUB};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{FETCH_SHIM as o}from"./fetch-shim.js";import{FORM_DATA_POLYFILL as L}from"./form-data.js";import{URL_POLYFILL as r}from"./url.js";import{URL_SEARCH_PARAMS_POLYFILL as _}from"./url-search-params.js";const
|
|
2
|
-
`);export{
|
|
1
|
+
import{FETCH_SHIM as o}from"./fetch-shim.js";import{FORM_DATA_POLYFILL as L}from"./form-data.js";import{URL_POLYFILL as r}from"./url.js";import{URL_SEARCH_PARAMS_POLYFILL as _}from"./url-search-params.js";const p=[_,r,L,o].join(`
|
|
2
|
+
`);import{CONSOLE_STUB as f}from"./console.js";export{f as CONSOLE_STUB,p as SANDBOX_FETCH_SETUP};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type ToolInputValidator = (input: unknown) => string | undefined;
|
|
2
|
+
/** Validates a sandbox tool call against the tool's MCP input schema before the handler runs. */
|
|
3
|
+
export declare function createToolInputValidator(sandboxName: string, schema: Record<string, unknown>): ToolInputValidator;
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=tool-input-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import s from"@redocly/ajv";const c=new s({allErrors:!0}),n=new Map;function f(t,r){const e=d(r);if(!e)return()=>{};const o=Object.keys(r.properties??{});return i=>{if(e(i??{}))return;const a=p(e.errors??[]);return`Invalid input for tools.${t}: ${a.join("; ")}. Accepted properties: ${o.join(", ")}. Call describe-tools for the exact signature.`}}function d(t){const r=JSON.stringify(t);if(n.has(r))return n.get(r);let e;try{e=c.compile(t)}catch{e=void 0}return n.set(r,e),e}function p(t){const r=new Set;for(const e of t)switch(e.keyword){case"additionalProperties":r.add(`unknown property "${e.params.additionalProperty}"`);break;case"required":r.add(`missing required property "${e.params.missingProperty}"`);break;default:r.add(`${u(e.instancePath)} ${e.message}`)}return[...r]}function u(t){return t?`"${t.replace(/^\//,"").replace(/\//g,".")}"`:"input"}export{f as createToolInputValidator};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { GuestPosition } from '../../../../sandbox/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Turns a guest error into the message the model reads. A call on a tool the sandbox does not
|
|
4
|
+
* hold names that tool and lists the available ones; every other error keeps its message and
|
|
5
|
+
* gains the line it was thrown on.
|
|
6
|
+
*/
|
|
7
|
+
export declare function describeGuestError(code: string, message: string, position: GuestPosition | undefined, availableTools: string[]): string;
|
|
8
|
+
//# sourceMappingURL=unknown-tool-hint.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{TOOLS_BRIDGE_GLOBAL_NAME as c}from"../constants.js";const i="not a function",d=new RegExp(`(?:^|[^\\w$.])${c}\\s*(?:(?:\\?\\.|\\.)\\s*([A-Za-z_$][\\w$]*)|(?:\\?\\.)?\\s*\\[\\s*(['"])([^'"]*)\\2\\s*\\])\\s*(?:\\?\\.)?\\s*$`);function $(o,t,n,e){const u=n&&E(o,n);if(!n||u===void 0)return t;const f=t===i?l(o.slice(0,u),e):void 0;return f===void 0?`${t} (line ${n.line})`:`Unknown tool "${f}". Available tools: ${e.join(", ")}`}function l(o,t){const n=d.exec(o),e=n?.[1]??n?.[3];return e!==void 0&&!t.includes(e)?e:void 0}function E(o,{line:t,column:n}){const e=o.split(`
|
|
2
|
+
`);if(t>e.length)return;const f=e.slice(0,t-1).reduce((r,s)=>r+s.length+1,0)+n-1;return f<=o.length?f:void 0}export{$ as describeGuestError};
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
import{renderDescribeToolsOutput as
|
|
1
|
+
import{renderDescribeToolsOutput as O}from"../capabilities/index.js";import{McpServerType as M}from"../../constants.js";import{reportMcpToolCalled as _,reportMcpToolError as k}from"../../workers/mcp-tool-telemetry.js";import{DESCRIBE_TOOLS_TOOL_NAME as d}from"../constants.js";import{DESCRIBE_TOOLS_DESCRIPTION as D}from"../prompts.js";import{sanitizeToolName as n}from"../build-tool-type-declarations.js";import{UnknownToolError as v}from"./tool-errors.js";function x(i,c){const t=[...new Set([...i.map(s=>n(s.name)),...c.map(s=>n(s.id))])];return{name:d,title:"Describe tools",description:D,schema:{type:"object",required:[],additionalProperties:!1,properties:{tools:{type:"array",description:`Tool names to describe: ${t.join(", ")}. Omit to describe everything.`,items:t.length>0?{type:"string",enum:t}:{type:"string"},nullable:!0}}}}}function P(i,c,t,s){const l=new Map(i.map(r=>[n(r.name),r])),f=new Map(t.map(r=>[n(r.id),r]));return async r=>{const u=performance.now(),h=s.mcpMode??"code";try{const o=[...new Set((r.tools??[]).map(n))],a=o.length===0,T=o.filter(e=>!l.has(e)&&!f.has(e));if(T.length>0){const e=[...l.keys(),...f.keys()];throw new v(`Unknown tool(s): ${T.join(", ")}. Valid tools: ${e.join(", ")}.`)}const E=a?t:t.filter(e=>o.includes(n(e.id))),p=a?i:o.filter(e=>l.has(e)).map(e=>l.get(e)),y=await Promise.all(p.map(e=>c(e.name))),S=p.filter((e,m)=>y[m]),w=p.filter((e,m)=>!y[m]),g=[O(S,E,s)];w.length>0&&g.push(`Not available for this request: ${w.map(e=>n(e.name)).join(", ")}`);const b=g.join(`
|
|
2
|
+
|
|
3
|
+
`);return _({tool:d,mode:h,serverType:M.Docs,durationMs:Math.round(performance.now()-u),outputLength:b.length}),{content:[{type:"text",text:b}]}}catch(o){const a=o instanceof v;throw k({tool:d,mode:h,serverType:M.Docs,durationMs:Math.round(performance.now()-u),message:o instanceof Error?o.message:String(o),stack:!a&&o instanceof Error&&o.stack||"",errorClass:a?"tool_error":"server_error"}),o}}}export{P as describeTools,x as describeToolsSchema};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{runInSandbox as
|
|
1
|
+
import{runInSandbox as b}from"../../../../sandbox/sandbox.js";import{returnLastExpression as w}from"../../../../sandbox/utils/return-last-expression.js";import{isMcpToolAvailable as C}from"../../workers/execute-mcp-tool.js";import{importMcpToolHandlers as O}from"../../workers/import-mcp-tool-handlers.js";import{isFetchCapable as T}from"../../gateway-mcp/callable-apis.js";import{buildExecuteHostFetch as y}from"../../gateway-mcp/fetch-capability.js";import{withAuthRequiredMeta as x}from"../../gateway-mcp/upstream-auth.js";import{CODE_MODE_TOOL_NAMES as M,EXECUTE_TOOL_NAME as S}from"../constants.js";import{sanitizeToolName as v}from"../build-tool-type-declarations.js";import{invokeTool as A}from"../invoke-tool.js";import{createSandboxSetup as _}from"../sandbox/create-sandbox-setup.js";import{createToolInputValidator as k}from"../sandbox/tool-input-validator.js";import{describeGuestError as F}from"../sandbox/unknown-tool-hint.js";import{auditCode as N}from"../code-audit.js";import{reportCodeExecuted as j}from"../code-execution-telemetry.js";import{logCodeExecutionAudit as D}from"../code-execution-audit.js";const H=async(o,r,u)=>{const i=new Set,n=await P(r,u,i),s=[],e=T(r)?await y(r,p=>s.push(p)):void 0;let m=0;const f=e?p=>(m+=1,e(p)):void 0,a=N(o.code);D({audit:a,code:o.code,description:o.description,sessionHandle:o.sessionHandle,toolNames:Object.keys(n),fetchBudget:r.gatewayFetchBudgetPerExec,fetchCapable:e!==void 0});const l=Date.now(),d=w(o.code),{result:c,error:t,errorPosition:h}=await b(d,{setupContext:_(n,f),authoredCode:o.code});j({audit:a,fetchCount:m,outcome:t===void 0?"ok":"error",durationMs:Date.now()-l,client:r.client,clientVersion:r.clientVersion});const E=t===void 0?void 0:F(d,t,h,Object.keys(n));return x({content:[{type:"text",text:JSON.stringify({result:c,error:E})}],isError:t!==void 0,...t!==void 0&&i.has(t)?{errorClass:"tool_error"}:{}},s)};async function P(o,r,u){const i=Object.keys(await O()).filter(e=>!M.has(e)),n=await Promise.all(i.map(e=>C({toolName:e,context:o}).catch(()=>!1))),s={};return i.forEach((e,m)=>{if(!n[m])return;const f=v(e),a=o.sandboxToolSchemas?.[e],l=a?k(f,a):void 0;s[f]=d=>{const c=l?.(d);return c?(u.add(c),Promise.reject(new Error(c))):A(e,d,o,r).catch(t=>{throw t instanceof Error&&u.add(t.message),t})}}),s}var Z={[S]:H};export{Z as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CallToolResult, InputRequiredResult } from '@modelcontextprotocol/server';
|
|
1
|
+
import type { CallToolResult, InputRequiredResult, ServerContext } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { McpToolSchema } from '../../../../types';
|
|
3
3
|
import type { McpToolContext } from '../../types.js';
|
|
4
4
|
import type { KvService } from '@redocly/config';
|
|
@@ -16,5 +16,5 @@ export declare function manageApiCredentials(context: McpToolContext, deps: Mana
|
|
|
16
16
|
api?: unknown;
|
|
17
17
|
scheme?: unknown;
|
|
18
18
|
sessionHandle?: unknown;
|
|
19
|
-
}) => Promise<CallToolResult | InputRequiredResult>;
|
|
19
|
+
}, ctx: ServerContext) => Promise<CallToolResult | InputRequiredResult>;
|
|
20
20
|
//# sourceMappingURL=manage-credentials.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{MANAGE_API_CREDENTIALS_TOOL_NAME as
|
|
2
|
-
`),annotations:{readOnlyHint:!1,openWorldHint:!1},schema:{type:"object",required:["api"],additionalProperties:!1,properties:{api:{type:"string",description:`The API to manage credentials for
|
|
1
|
+
import{MANAGE_API_CREDENTIALS_TOOL_NAME as P}from"../../constants.js";import{buildUpstreamCredentialFallback as b,buildUpstreamCredentialInputRequired as I,dedupeElicitation as S,isCredentialElicitationDeclined as k,isStatelessRequest as E,schemeLabelOf as w,supportsUrlElicitation as C}from"../../gateway-mcp/elicitation.js";import{getCallableApis as u,isFetchCapable as j}from"../../gateway-mcp/callable-apis.js";import{secretStore as T}from"../../gateway-mcp/secret-store.js";import{MISSING_SESSION_HANDLE_MESSAGE as q,resolveSecretSubject as $}from"../../gateway-mcp/subject.js";import{upstreamAuthKey as R}from"../../gateway-mcp/upstream-auth.js";import{resolveUpstreamApiAuth as L}from"../../gateway-mcp/upstream-auth-scheme.js";import{apiTitleKey as N,countApiTitles as O}from"../../docs-mcp/utils/api-titles.js";function W(e){return!!e.elicitationEnabled&&j(e)}function z(e){const s=u(e),t=s.map(r=>r.relativePath),a=[...t,...U(s)];return{name:P,title:"Manage API credentials",description:["Get a secure link where the user sets, replaces, or removes the credentials this server sends to a documented API.","Call it when the user wants to change or clear an API key, or when a tool result tells you the stored credentials were rejected.","The link covers every credential the API accepts, so scheme is optional - pass it only when a tool result names the scheme that was rejected.","It returns a link for the user to open - never ask for the secret in the conversation and never pass it as an argument."].join(`
|
|
2
|
+
`),annotations:{readOnlyHint:!1,openWorldHint:!1},schema:{type:"object",required:["api"],additionalProperties:!1,properties:{api:{type:"string",description:`The API to manage credentials for: its \`filePath\` or the \`name\` from \`listApis\`.${t.length>0?` The file paths are: ${t.join(", ")}.`:""}`,minLength:1,...a.length>0?{enum:a}:{}},scheme:{type:"string",description:"Name of the security scheme to manage the credential for, as named in the API description (a tool result that reports a rejected credential names it). Omit it to let the link cover every scheme the API accepts.",minLength:1},sessionHandle:{type:"string",description:"Handle returned by createAnonymousSession. Required while the caller is anonymous, so the credentials are stored against the same subject the API calls use.",minLength:1}}}}}function U(e){const s=O(e);return e.map(t=>t.name).filter(t=>s.get(N(t))===1)}function J(e,s){return async(t,a)=>{const r=$(e.user,typeof t.sessionHandle=="string"?t.sessionHandle:void 0);if(r.kind==="invalid")return h(r.message);if(r.kind==="anonymous")return h(q);const{subject:m}=r,p=typeof t.api=="string"?t.api:"",n=u(e).find(c=>c.relativePath===p||c.name===p);if(!n){const c=u(e).map(v=>v.relativePath).join(", ");return h(`Unknown api "${p}". Credentials can only be managed for the APIs this server can call: ${c||"none"}.`)}if(k(a.mcpReq.inputResponses))return{content:[{type:"text",text:`The user declined the credentials prompt for the "${n.name}" API, so this call minted no link.`}],isError:!1};const i=await L(e,n.relativePath),l=typeof t.scheme=="string"?t.scheme:void 0,y=Object.keys(i.schemes);if(l&&!i.schemes[l])return h(`Unknown scheme "${l}" for api "${n.relativePath}". The security schemes this server can store credentials for are: ${y.join(", ")}.`);const o=l??i.defaultScheme,d=w(i.schemes,o),f=await s.getKv(),A={subject:m,baseUrl:e.baseUrl??"",target:{api:n.relativePath,name:n.name,scheme:o,...d?{schemeLabel:d}:{}},auth:i.schemes[o],apiAuth:i,kv:f,hasExistingSecret:await T.hasSecret(f,m,n.relativePath,o),reason:{kind:"requested"}};if(E(a.mcpReq)&&C(s.getClientCapabilities()))return await I(A);const g=R({api:n.relativePath,scheme:o});return{content:[{type:"text",text:await S(`${m}:${g}`,()=>b(A))}],isError:!1}}}function h(e){return{content:[{type:"text",text:e}],isError:!0}}export{W as isManageApiCredentialsToolAvailable,J as manageApiCredentials,z as manageApiCredentialsSchema};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{shouldHandleMcpAuth as d}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as m}from"../constants.js";import{GRAPHQL_TYPE_KINDS as o,GRAPHQL_LIST_SCOPES as h}from"./tools/graphql/constants.js";import{OPERATION_METHODS as p}from"./tools/openapi/constants.js";const i={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"},f={codemodeType:"OpenApiOperation & { path: string; method: string }"},g={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"Matches part of an API name, or of a description when no name matches",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, or a unique part of it",minLength:1},version:{type:"string",description:"API version",nullable:!0},filePath:{type:"string",description:"API definition file path",nullable:!0}}},b={type:"object",required:["name","path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it",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.map(e=>e.toUpperCase()),...p],minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0},filePath:{type:"string",description:"API definition file path",nullable:!0}}},S={type:"object",required:[],additionalProperties:!1,properties:{}},v={type:"object",required:[],additionalProperties:!1,properties:{}};function H(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:g,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i,version:i,servers:r,filePath:{type:"string",description:"API definition file path"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...n}}},{name:"get-endpoints",title:"Get endpoints",description:"Get all endpoints for a specific API",schema:a,annotations:{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:i,description:i,security:s}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:b,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoint:f,globalSecurity:s,securitySchemes:l}}},{name:"get-security-schemes",title:"Get security schemes",description:"Get the security schemes for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:i,version:i,securitySchemes:l,security:s}}},{name:"get-full-api-description",title:"Get full API description",description:"Get the complete OpenAPI description",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},definition:y}}},T(e.products,e.locales)];return d(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:S,annotations:{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&&t.push(...O()),e.elicitationEnabled&&t.push({name:m,title:"Create anonymous session",description:"Create an anonymous session handle for storing upstream API credentials. Pass the returned sessionHandle to execute when an API needs credentials and the caller is not signed in. Treat it as a secret and reuse it across calls.",schema:v,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const A={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}}},P={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. With scope "fields", restricts to the fields of that parent category ("objects", "interfaces", or "inputs" only).',enum:[...o],nullable:!0},scope:{type:"string",description:'Optional: what each list item is. "members" (default) lists top-level types and operations. "fields" flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions \u2014 combine with `filter` to search nested fields anywhere in the schema.',enum:[...h],nullable:!0},filter:{type:"string",description:'Optional: only members whose name or description contains this substring, case-insensitive (e.g. "custom tags")',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}}},L={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}}},q={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function O(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:A,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i}}},...n}}},{name:"get-graphql-type-list",title:"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` (case-insensitive substring of the member name or description, 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. To search nested fields \u2014 not just type names \u2014 set scope "fields": it flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions, so `filter` finds things like an input field whose docstring mentions your keyword.',schema:P,annotations:{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:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...n}}},{name:"get-graphql-type",title:"Get GraphQL type",description:'Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Without includeReferencedTypes, the SDL is followed by a one-level manifest of every directly referenced type\'s field names (e.g. "input ActionOperationInput { addTags, removeTags }"), so you can see what nested types contain before fetching them. Set includeReferencedTypes to instead pull in the full SDL of every type it references transitively \u2014 the whole 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:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",title:"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:q,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function T(e,t){const c=e&&e.length>0,u=t&&t.length>0;return{name:"search",title:"Search documentation",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:t,nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const E=new Set(H({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0}).map(e=>e.name));export{E as ALL_DEFAULT_TOOL_NAMES,H as getDefaultToolSchemas};
|
|
1
|
+
import{SEMANTIC_SEARCH_API_URL as m}from"../../../constants/common.js";import{shouldHandleMcpAuth as h}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as y}from"../constants.js";import{GRAPHQL_TYPE_KINDS as o,GRAPHQL_LIST_SCOPES as f}from"./tools/graphql/constants.js";import{OPERATION_METHODS as p}from"./tools/openapi/constants.js";const i={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>"},g={codemodeType:"OpenApiDocument"},b={codemodeType:"OpenApiOperation & { path: string; method: string }"},v={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"Matches part of an API name, or of a description when no name matches",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:[],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},version:{type:"string",description:"API version",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},S={type:"object",required:["path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},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.map(e=>e.toUpperCase()),...p],minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},A={type:"object",required:[],additionalProperties:!1,properties:{}},H={type:"object",required:[],additionalProperties:!1,properties:{}};function P(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:v,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i,version:i,servers:r,filePath:{type:"string",description:"API definition file path"},ambiguousTitle:{type:"boolean",description:"true = another API shares this title; pass `filePath`, or `version` when the copies differ by version"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...n}}},{name:"get-endpoints",title:"Get endpoints",description:"Get all endpoints for a specific API",schema:a,annotations:{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:i,description:i,security:s}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:S,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoint:b,globalSecurity:s,securitySchemes:l}}},{name:"get-security-schemes",title:"Get security schemes",description:"Get the security schemes for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:i,version:i,securitySchemes:l,security:s}}},{name:"get-full-api-description",title:"Get full API description",description:"Get the complete OpenAPI description",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},definition:g}}},...m?[c(e.products,e.locales)]:[]];return h(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:A,annotations:{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&&t.push(...G()),e.elicitationEnabled&&e.hasCallableApis&&t.push({name:y,title:"Create anonymous session",description:"Create an anonymous session handle for storing upstream API credentials. Pass the returned sessionHandle to execute when an API needs credentials and the caller is not signed in. Treat it as a secret and reuse it across calls.",schema:H,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const L={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}}},O={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. With scope "fields", restricts to the fields of that parent category ("objects", "interfaces", or "inputs" only).',enum:[...o,null],nullable:!0},scope:{type:"string",description:'Optional: what each list item is. "members" (default) lists top-level types and operations. "fields" flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions \u2014 combine with `filter` to search nested fields anywhere in the schema.',enum:[...f,null],nullable:!0},filter:{type:"string",description:'Optional: only members whose name or description contains this substring, case-insensitive (e.g. "custom tags")',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"],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,nullable:!0},typeName:{type:"string",description:"Alias of `type`",nullable:!0},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}}},q={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function G(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i}}},...n}}},{name:"get-graphql-type-list",title:"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` (case-insensitive substring of the member name or description, 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. To search nested fields \u2014 not just type names \u2014 set scope "fields": it flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions, so `filter` finds things like an input field whose docstring mentions your keyword.',schema:O,annotations:{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:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...n}}},{name:"get-graphql-type",title:"Get GraphQL type",description:'Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Without includeReferencedTypes, the SDL is followed by a one-level manifest of every directly referenced type\'s field names (e.g. "input ActionOperationInput { addTags, removeTags }"), so you can see what nested types contain before fetching them. Set includeReferencedTypes to instead pull in the full SDL of every type it references transitively \u2014 the whole 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:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",title:"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:q,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function c(e,t){const u=e&&e.length>0,d=t&&t.length>0;return{name:"search",title:"Search documentation",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,null],nullable:!0}}:{},...d?{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:[...t,null],nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const D=new Set([...P({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0,hasCallableApis:!0}).map(e=>e.name),c().name]);export{D as ALL_DEFAULT_TOOL_NAMES,P as getDefaultToolSchemas};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as
|
|
1
|
+
import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as o}from"../../../constants.js";import{isFetchCapable as i}from"../../../gateway-mcp/callable-apis.js";import{createSessionHandle as t}from"../../../gateway-mcp/subject.js";const r=async()=>({content:[{type:"text",text:JSON.stringify({sessionHandle:t()})}],isError:!1});function s(e){return!!e.elicitationEnabled&&e.mcpMode==="code"&&i(e)&&!e.user?.isAuthenticated}var c={[o]:{execute:r,isAvailable:s}};export{c as default,s as isAnonymousSessionToolAvailable};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{removeTrailingSlash as g,withPathPrefix as y,withoutPathPrefix as E}from"@redocly/theme/core/utils";import{ServerRoutes as L}from"../../../../../../constants/api.js";import{DEFAULT_LOCALE_PLACEHOLDER as S}from"../../../../../../constants/common.js";const w=async(n,t)=>{const{query:e,product:
|
|
1
|
+
import{removeTrailingSlash as g,withPathPrefix as y,withoutPathPrefix as E}from"@redocly/theme/core/utils";import{ServerRoutes as L}from"../../../../../../constants/api.js";import{DEFAULT_LOCALE_PLACEHOLDER as S}from"../../../../../../constants/common.js";const w=async(n,t)=>{const{query:e,product:o,locale:l}=n,u=t.config.l10n?.defaultLocale||S,h=JSON.stringify({query:e,...o?{product:o}:{},locale:l||u}),f=`${t.internalBaseUrl||t.baseUrl}${y(L.SEMANTIC_SEARCH)}`,s=t.accessToken?`authorization=${String(t.accessToken).replace(/^Bearer /,"")}`:"";try{const a=await fetch(f,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...s?{Cookie:s}:{}},body:h});if(!a.ok)return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0};const p=await a.json(),d=new Set(t.searchIgnoredRoutes??[]),i=(p||[]).filter(r=>!R(r.url,d));if(i.length===0)return{content:[{type:"text",text:"No results found."}]};const m=r=>{try{return new URL(r,t.baseUrl).toString()}catch{return r}},c=i.map(r=>`### [${r.title}](${m(r.url)})
|
|
2
2
|
|
|
3
3
|
${r.content}
|
|
4
4
|
`).join(`
|
|
5
5
|
|
|
6
|
-
`).trim();return{content:[{type:"text",text:
|
|
6
|
+
`).trim();return{content:[{type:"text",text:c.length?c:"No results found."}]}}catch{return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0}}};function R(n,t){if(t.size===0)return!1;let e;try{e=new URL(n,"https://relative.invalid").pathname}catch{return!1}e=g(E(e));try{e=decodeURI(e)}catch{}return t.has(e)}var v={search:w};export{v as default};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{respondWithGraphqlSchema as
|
|
2
|
-
# Type: ${e} (+ ${
|
|
1
|
+
import{respondWithGraphqlSchema as s}from"./tool-helpers.js";import{printTypeOrField as d,printTypeOrFieldWithReferences as a,referencedTypeManifest as m}from"./utils.js";const h=(n,i)=>s(n.name,i,({name:p,schema:t})=>{const{includeReferencedTypes:c}=n,e=n.type??n.typeName;if(!e)throw new Error("Pass `type`: the name of the type, operation, or directive.");if(c){const{sdl:r,referencedCount:l}=a(t,e);return`# Schema: ${p}
|
|
2
|
+
# Type: ${e} (+ ${l} referenced types)
|
|
3
3
|
|
|
4
|
-
${
|
|
4
|
+
${r}`}const o=`# Schema: ${p}
|
|
5
5
|
# Type: ${e}
|
|
6
6
|
|
|
7
|
-
${
|
|
7
|
+
${d(t,e)}`,f=m(t,e);if(f.length===0)return o;const y=["# Referenced types (one level, names only; fetch a type or set includeReferencedTypes for full SDL):",...f.map(r=>`# ${r}`)].join(`
|
|
8
8
|
`);return`${o}
|
|
9
9
|
|
|
10
|
-
${
|
|
10
|
+
${y}`});var T={"get-graphql-type":h};export{T as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isFetchCapable as d}from"../../../gateway-mcp/callable-apis.js";import{filterApiDescriptionsByName as
|
|
1
|
+
import{isFetchCapable as d}from"../../../gateway-mcp/callable-apis.js";import{filterApiDescriptionsByName as h}from"../../utils/api-name-matching.js";import{apiTitleKey as y,countApiTitles as x}from"../../utils/api-titles.js";const A=async(c,i)=>{const{filter:s,page:l=1,limit:e=300}=c,p=d(i),n=Object.values(i.apiDescriptionsMap),r=x(n);let t=n;s&&(t=h(t,s));const a=(l-1)*e,m=a+e,u=Math.ceil(t.length/e),f=t.length;return t=t.slice(a,m),{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:g,fetchEligible:b,...o})=>({filePath:g,...o,...(r.get(y(o.name))??0)>1?{ambiguousTitle:!0}:{},...p?{callable:b===!0}:{}})),limit:e,total:f,page:l,totalPages:u})}]}};var I={"list-apis":A};export{I as default};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { OpenAPIDefinition } from '@redocly/api-docs';
|
|
2
2
|
import type { McpToolContext } from '../../../types.js';
|
|
3
|
-
export declare function loadApiDescription(
|
|
4
|
-
name
|
|
3
|
+
export declare function loadApiDescription(args: {
|
|
4
|
+
name?: string;
|
|
5
|
+
apiName?: string;
|
|
6
|
+
api?: string;
|
|
5
7
|
version?: string;
|
|
6
8
|
filePath?: string;
|
|
7
9
|
}, context: McpToolContext): Promise<OpenAPIDefinition>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{describeAvailableApis as
|
|
1
|
+
import{describeAvailableApis as l,findApiDescriptionByNameAndVersion as h}from"../../utils/api-name-matching.js";import{getApiDescriptionFromFs as u}from"./utils.js";async function P(o,i){const{version:p,filePath:e}=o,r=o.name??o.apiName??o.api;if(!e&&!r)throw new Error("Pass `name` (the API title, or a unique part of it) or `filePath` from list-apis.");const t=Object.values(i.apiDescriptionsMap),n=e?t.find(a=>a.relativePath===e):t.find(a=>a.relativePath===r)??h(i.apiDescriptionsMap,r??"",p);if(!n){if(e)throw new Error(`No API found with filePath "${e}". File paths are returned by the list-apis tool.`);const a=l(i.apiDescriptionsMap,r??"");throw new Error(a?`No API found matching "${r}". Available APIs: ${a}.`:`No API found matching "${r}".`)}const c=!!i?.config?.access?.requiresLogin,f=i?.config?.access?.rbac||{},s=await u({relativePath:n.relativePath||"",outdir:i.outdir||"",user:i.user,rbac:f,requiresLogin:c});if(!s)throw new Error(`No API found matching "${e||r}".`);return s}export{P as loadApiDescription};
|
|
@@ -4,12 +4,16 @@ export type ListApisArgs = {
|
|
|
4
4
|
limit?: number;
|
|
5
5
|
};
|
|
6
6
|
export type ApiNameVersionArgs = {
|
|
7
|
-
name
|
|
7
|
+
name?: string;
|
|
8
|
+
apiName?: string;
|
|
9
|
+
api?: string;
|
|
8
10
|
version?: string;
|
|
9
11
|
filePath?: string;
|
|
10
12
|
};
|
|
11
13
|
export type GetEndpointInfoArgs = {
|
|
12
|
-
name
|
|
14
|
+
name?: string;
|
|
15
|
+
apiName?: string;
|
|
16
|
+
api?: string;
|
|
13
17
|
path: string;
|
|
14
18
|
method: string;
|
|
15
19
|
version?: string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ApiDescriptionInfo } from '../../types.js';
|
|
2
|
+
/** The form the API lookup compares titles in, so a collision here is a collision there. */
|
|
3
|
+
export declare function apiTitleKey(name: string): string;
|
|
4
|
+
/** How many APIs carry each title, keyed by `apiTitleKey`, so a shared title is detectable. */
|
|
5
|
+
export declare function countApiTitles(apis: ApiDescriptionInfo[]): Map<string, number>;
|
|
6
|
+
//# sourceMappingURL=api-titles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function r(t){return t.trim().toLowerCase()}function c(t){const e=new Map;for(const{name:o}of t){const n=r(o);e.set(n,(e.get(n)??0)+1)}return e}export{r as apiTitleKey,c as countApiTitles};
|
|
@@ -31,6 +31,17 @@ type CredentialElicitationRequest = {
|
|
|
31
31
|
hasExistingSecret: boolean;
|
|
32
32
|
reason: CredentialElicitationReason;
|
|
33
33
|
};
|
|
34
|
+
/** Concurrent prompts for one subject and scheme share the link the first one mints. */
|
|
35
|
+
export declare function dedupeElicitation(key: string, run: () => Promise<string>): Promise<string>;
|
|
36
|
+
export declare function supportsUrlElicitation(capabilities: {
|
|
37
|
+
elicitation?: {
|
|
38
|
+
url?: unknown;
|
|
39
|
+
};
|
|
40
|
+
} | undefined): boolean;
|
|
41
|
+
/** Only a 2026-07-28-era request carries `_meta` envelope keys, and it needs no session. */
|
|
42
|
+
export declare function isStatelessRequest(mcpReq: {
|
|
43
|
+
envelope?: unknown;
|
|
44
|
+
}): boolean;
|
|
34
45
|
export declare function isCredentialElicitationDeclined(inputResponses: Record<string, unknown> | undefined): boolean;
|
|
35
46
|
export declare function schemeLabelOf(schemes: Record<string, unknown>, scheme: string): string | undefined;
|
|
36
47
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{inputRequired as
|
|
2
|
-
`)}const n=e.status===401?`The "${e.name}" API rejected the stored ${t?`"${t}" `:""}credential (${r}).`:`The "${e.name}" API rejected the request with ${r}.`,i=t?`api: "${e.api}" and scheme: "${t}"`:`api: "${e.api}"`;return[n,"",`Do not retry the same call. Call \`${
|
|
3
|
-
`)}function
|
|
4
|
-
`)}async function
|
|
5
|
-
`)}export{m as CREDENTIALS_INPUT_REQUEST_KEY,
|
|
1
|
+
import{inputRequired as l,inputResponse as I}from"@modelcontextprotocol/server";import{MANAGE_API_CREDENTIALS_TOOL_NAME as d}from"../constants.js";import{secretStore as u,ELICITATION_TTL_MS as y}from"./secret-store.js";import{operationsForScheme as A,orderedSchemesOf as P}from"./upstream-auth-scheme.js";import{ANONYMOUS_SUBJECT_PREFIX as p}from"./subject.js";const m="credentials",h=new Map;function j(e,t){const r=h.get(e);if(r)return r;const n=t().finally(()=>{h.delete(e)});return h.set(e,n),n}function U(e){return!!e?.elicitation?.url}function F(e){return e.envelope!==void 0}function L(e){const t=I(e,m);return t.kind==="elicit"&&(t.action==="decline"||t.action==="cancel")}function M(e,t){return Object.keys(e).length>1?t:void 0}async function H(e){const{url:t}=await $(e);return l({inputRequests:{[m]:l.elicitUrl({message:k(e),url:t})}})}async function q(e){const{url:t}=await $(e);return v(e,t,g(e.subject))}function D(e,t){const r=f(e);if(e.status===401&&!e.sentScheme){const[o,s]=e.callerHeader?[`Your code set the "${e.callerHeader}" header itself, so the stored credential was not sent.`,"Remove that header from the request and retry. Do not replace the stored credentials."]:["No stored credential was sent with this request, so this result says nothing about the stored credentials.","Do not replace them. Check whether this operation needs a different kind of credential or a different route."];return[`The "${e.name}" API returned ${r}. ${o}`,"",s].join(`
|
|
2
|
+
`)}const n=e.status===401?`The "${e.name}" API rejected the stored ${t?`"${t}" `:""}credential (${r}).`:`The "${e.name}" API rejected the request with ${r}.`,i=t?`api: "${e.api}" and scheme: "${t}"`:`api: "${e.api}"`;return[n,"",`Do not retry the same call. Call \`${d}\` with ${i} to get a link the user has to open in a browser to replace or remove the stored credentials, then retry once they confirm they saved them.`].join(`
|
|
3
|
+
`)}function f({status:e,detail:t}){return t?`HTTP ${e}: ${t}`:`HTTP ${e}`}function B(e,t){const r=t.map(({name:n,label:i,description:o})=>`- ${n} \u2014 ${i}${o?`: ${o}`:""}`);return[`The "${e.name}" API rejected the request with ${f(e)} and this operation accepts more than one kind of credential:`,"",...r,"","Ask the user which one of these they have, and wait for the answer. Never guess and never reuse a value meant for another kind.",`Then call \`${d}\` with api: "${e.api}" and scheme set to the name they picked to get a link where they enter it.`].join(`
|
|
4
|
+
`)}async function $({kv:e,subject:t,baseUrl:r,target:n,auth:i,apiAuth:o,hasExistingSecret:s}){const a=o?await b(e,t,n.api,o):[],c=await u.createElicitation(e,{subject:t,api:n.api,name:n.name,scheme:n.scheme,...n.schemeLabel?{schemeLabel:n.schemeLabel}:{},auth:i,hasExistingSecret:s,...a.length>1?{schemes:a}:{}});return{token:c,url:C(r,c)}}async function b(e,t,r,n){const o=(await u.getSecretsForSubject(e,t))[r]??{};return P(n.schemes).map(s=>{const a=A(n,s),c=n.descriptions?.[s];return{name:s,...c?{label:c}:{},auth:n.schemes[s],hasExistingSecret:!!o[s],...a.length>0?{operations:a}:{}}})}function g(e){return e.startsWith(p)?e.slice(p.length):void 0}function k({target:e,hasExistingSecret:t,reason:r}){const n=`The link works for ${T()} minutes.`,i=E(e),o=r.kind==="authFailure"&&r.detail?` The API answered: ${r.detail}.`:"";return t?`Open this page in a browser to replace or remove the stored credentials for ${i}. They go straight to the API and never enter the chat. ${n}`:`${S(i)} needs credentials.${o} Open this page in a browser to paste them - they go straight to the API and never enter the chat. ${n}`}function E({name:e,schemeLabel:t}){return t?`the "${t}" scheme of the "${e}" API`:`the "${e}" API`}function S(e){return e.charAt(0).toUpperCase()+e.slice(1)}function T(){return Math.round(y/6e4)}function C(e,t){if(!e)return`/mcp/credentials?token=${t}`;try{const r=new URL("/mcp/credentials",e);return r.searchParams.set("token",t),r.toString()}catch{return`${e}/mcp/credentials?token=${t}`}}function v({target:e,reason:t,hasExistingSecret:r},n,i){const s=[`**Stop and show the user this link. They have to open it in a browser to ${r?`replace or remove the stored credentials for the "${e.name}" API`:`add credentials for the "${e.name}" API`} - nothing continues until they do.**`,"",n,"",`The link is valid ${T()} minutes and opens a form on this site. Credentials go straight to the API from there: never ask for them in the conversation and never pass them as a tool argument.`,"",t.kind==="authFailure"?`The upstream API "${e.name}" returned ${t.status}${t.detail?` (${t.detail})`:""} and needs credentials.`:r?`Credentials are already stored for the "${e.name}" API; the link lets the user replace or remove them.`:`The "${e.name}" API needs credentials.`,...e.schemeLabel?[`The operation authenticates with its "${e.schemeLabel}" security scheme.`]:[],i?`Once the user confirms they saved them, call this tool again with sessionHandle: "${i}" - the credentials are stored against that handle, applied server-side, and never appear in the conversation.`:"Once the user confirms they saved them, call this tool again - the credentials are applied server-side and never appear in the conversation."],a=t.kind==="authFailure"?t.otherApiNames??[]:[];if(a.length>0){const c=a.map(w=>`"${w}"`).join(", ");s.push("",`The remaining APIs (${c}) will prompt for credentials on subsequent calls.`)}return s.join(`
|
|
5
|
+
`)}export{m as CREDENTIALS_INPUT_REQUEST_KEY,D as buildCredentialsToolHint,B as buildSchemeChoiceHint,q as buildUpstreamCredentialFallback,H as buildUpstreamCredentialInputRequired,j as dedupeElicitation,L as isCredentialElicitationDeclined,F as isStatelessRequest,M as schemeLabelOf,U as supportsUrlElicitation};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isIP as
|
|
1
|
+
import{isIP as d}from"node:net";import{isHostAllowed as h}from"./allowed-hosts.js";import{isBlockedIp as w}from"./ssrf-blocklist.js";import{GatewayFetchBlockedError as p,GatewayFetchUserError as r}from"./fetch-errors.js";import{findUnresolvedPlaceholders as a,unresolvedPlaceholderMessage as i}from"./url-placeholders.js";function v(o,t){let e;try{e=new URL(o)}catch{throw new r(`Invalid URL: ${o}`)}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new r(`Only http(s) URLs are allowed, got ${e.protocol}`);if(e.username||e.password)throw new r("URLs must not contain embedded credentials");const n=a(e.hostname);if(n.length>0)throw new r(i(n));const s=c(e.hostname);if(f(s)||!h(s,t))throw new p(`Host "${s}" is not allowed`,s);const l=a(e.pathname);if(l.length>0)throw new r(i(l));return e}function f(o){const t=c(o.toLowerCase()).split("%")[0];return t==="localhost"||t.endsWith(".localhost")?!0:d(t)!==0?w(t):!1}function c(o){return o.replace(/^\[|\]$/g,"")}export{v as assertUrlAllowed,f as isBlockedAddress};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Collect the placeholder names one part of a URL still carries. */
|
|
2
|
+
export declare function findUnresolvedPlaceholders(urlPart: string): string[];
|
|
3
|
+
/** The refusal a caller reads when it left a placeholder in the URL. */
|
|
4
|
+
export declare function unresolvedPlaceholderMessage(names: readonly string[]): string;
|
|
5
|
+
//# sourceMappingURL=url-placeholders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=/\{([^}/]+)\}/g,t=/^[A-Za-z_][A-Za-z0-9_]*$/;function n(e){const a=e.replace(/%7B/gi,"{").replace(/%7D/gi,"}"),l=new Set;for(const[,r]of a.matchAll(o))t.test(r)&&l.add(r);return[...l]}function s(e){const a=e.length>1?"placeholders":"placeholder",l=e.map(r=>`"${r}"`).join(", ");return`Unresolved ${a} ${l} in the URL. This is not a credentials problem. Replace every placeholder with a real value. Use the server variable default, or ask the user.`}export{n as findUnresolvedPlaceholders,s as unresolvedPlaceholderMessage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as
|
|
1
|
+
import{logger as g}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 x}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as h}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as D,CODE_MODE_TOOL_NAMES as w,FETCH_TOOL_NAME as N}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 A}from"../utils/tool-registration.js";import{createMcpServer as X,createToolDispatch as Y,extractSerializableContext as $}from"./mcp-server.js";function S(s,t){const o=t.schema;if(C(s))return o;const{sessionHandle:f,...p}=o.properties;return{...o,properties:p}}function j(s){return Object.fromEntries(s.map(t=>[t.name,t.schema]))}async function se({name:s,tools:t,context:o,skills:f=[],getKv:p}){const n=$(o),r=o.mcpMode==="code",c=r?P(o):[],T=c.some(e=>e.id===N),m=r?await W(t.filter(e=>!w.has(e.name)),n):[],b=U(m,c),O=r&&L(o),l=X(s,r?H(T,b):void 0),E={getClientCapabilities:()=>l.server.getClientCapabilities(),getKv:p},d=Y(r?{...n,sandboxToolSchemas:j(m)}:n,E),u=async e=>{try{return await M.exec(v,[{toolName:e,context:n}],{timeout:1e4})}catch(i){return g.error(`Failed to check MCP tool availability for "${e}": ${i instanceof Error?i.message:String(i)}`),!1}};if(r){const e=[{tool:{...h,description:I(T,b),schema:S(o,h),annotations:F(c)},callback:d(D)},{tool:R(m,c),callback:z(m,u,c,o)}],i=t.find(a=>a.name===k);if(i&&C(o)&&e.push({tool:i,callback:d(i.name)}),O){const a=x(o);e.push({tool:{...a,schema:S(o,a)},callback:y(n,E)})}for(const{tool:a,callback:_}of e)l.registerTool(a.name,A(a),_)}else await Promise.all(t.map(async e=>{const i=l.registerTool(e.name,A(e),d(e.name));await u(e.name)||i.disable()}));for(const e of f)l.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 l}export{se as createDocsMcpServer};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{McpServer as
|
|
1
|
+
import{McpServer as _}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as j,MCP_TOOL_WORKER_KEY as D}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as F}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as K,stripAuthRequiredMeta as y,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as L,buildSchemeChoiceHint as H,buildUpstreamCredentialFallback as T,buildUpstreamCredentialInputRequired as P,dedupeElicitation as $,isCredentialElicitationDeclined as B,isStatelessRequest as x,schemeLabelOf as N,supportsUrlElicitation as v}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as q,resolveUpstreamApiAuth as G,schemeChoicesOf as V}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as W,resolveSecretSubject as Y}from"../gateway-mcp/subject.js";const J=6e4;function pe(e,t){return new _({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function de(e,t){return r=>async(n,s)=>{S.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,c=x(s.mcpReq),a=i?Y(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 F.getSecretsForSubject(m,o)}catch(m){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let u;const l=async()=>{u=await p();const m={toolName:r,args:n,context:{...e,upstreamSecrets:u},extra:re(s)};return await j.exec(D,[m],{timeout:J})};let d=await l();const f=K(d);if(f.length>0&&i&&!o)return y({...d,content:[{type:"text",text:W}],isError:!0});if(f.length>0&&i&&o&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${Q(t)}`);const m=await t.getKv(),h=await X(e,f),w=f.map(O=>Z(O,h)),E=z(u),g=c?await ee(e,s,w,o,m,E,h,t):await te(e,w,o,m,E,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 y(d)}}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 G(e,n));return r}function Z(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??q};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function z(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(b({api:r,scheme:s}));return t}function R(e,t){return e.status===401&&!t.has(b(e))}function M(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?N(r.schemes,n):void 0}function A(e,t){const r=t.get(e.api);return!r||!e.schemes?.length?[]:V(r,e.schemes)}function I(e,t){return A(e,t).length>1}function k(e,t){return e.map(r=>L(r,M(r,t))).join(`
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
3
|
+
`)}function C(e,t,r){const n=e.map(s=>H(s,A(s,r)));return t.length>0&&n.push(k(t,r)),n.join(`
|
|
4
4
|
|
|
5
|
-
`)}function
|
|
5
|
+
`)}function U(e,t,r,n,s){const[i,...c]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??q,p=M(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(B(t.mcpReq.inputResponses))return{kind:"none"};const o=r.filter(l=>R(l,i));if(o.length===0)return{kind:"prependText",text:k(r,c)};const p=o.filter(l=>I(l,c));if(p.length>0){const l=r.filter(d=>!p.includes(d));return{kind:"prependText",text:C(p,l,c)}}const u=U(e,o,n,s,c);return v(a?.getClientCapabilities())?{kind:"inputRequired",result:await P(u)}:{kind:"prependText",text:await T(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:k(t,i)};const a=c.filter(u=>I(u,i));if(a.length>0){const u=t.filter(l=>!a.includes(l));return{kind:"prependText",text:C(a,u,i)}}const o=U(e,c,r,n,i);return{kind:"prependText",text:await $(`${r}:${b(c[0])}`,()=>T(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,sandboxToolSchemas:e.sandboxToolSchemas,fs:void 0}}export{pe as createMcpServer,de as createToolDispatch,me as extractSerializableContext};
|
|
@@ -107,6 +107,7 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
|
|
|
107
107
|
upstreamSecrets?: UpstreamSecrets;
|
|
108
108
|
searchIgnoredRoutes?: string[];
|
|
109
109
|
internalBaseUrl?: string;
|
|
110
|
+
sandboxToolSchemas?: Record<string, Record<string, unknown>>;
|
|
110
111
|
fs?: McpToolFileSystem;
|
|
111
112
|
};
|
|
112
113
|
export type McpToolHandler<TArgs extends ToolArgs = ToolArgs> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse | McpToolJsonValue>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as
|
|
1
|
+
import{logger as a}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as n,MCP_TOOL_AVAILABILITY_KEY as m}from"../../../workers/mcp-tool-worker-pool.js";async function p(t,l){if(t.length===0)return t;const e=t.map(o=>o.name);let r;try{r=await n.exec(m,[{toolNames:e,context:l}],{timeout:1e4})}catch(o){return i(t,o instanceof Error?o.message:String(o))}return!r||typeof r!="object"?i(t,"the worker returned no availability map"):t.filter(o=>r[o.name]!==!1)}function i(t,l){const e=t.filter(r=>r.hasAvailabilityGate);return e.length===0?t:(a.warn(`MCP tool availability is unknown (${l}); the sandbox tool list drops the gated tools: ${e.map(r=>r.name).join(", ")}.`),t.filter(r=>!r.hasAvailabilityGate))}export{p as availableSandboxTools};
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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 p}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 b}from"./import-mcp-tool-handlers.js";function A(t){return t.content.map(e=>e.type==="text"?e.text:"")}async function D(t){h.initialize();const{toolName:e,args:o,extra:s}=t,r=E(t.context),n=r?.mcpMode??"tools",a={client:r?.client,clientVersion:r?.clientVersion},d=performance.now();try{const i=await M(e);if(!i)throw new Error(`MCP tool "${e}" is not registered or its module does not export a handler for "${e}". Expected \`export default { '${e}': handler }\` or a single tool definition with \`description\` and \`execute\` as the default export.`);const C=typeof i=="function"?i:i.execute,l=P(e,await C(o,r,s),n),m=Math.round(performance.now()-d),{errorClass:y}=l;delete l.errorClass;const f=l.isError?y??(e===w?"sandbox_error":"tool_error"):void 0,v=e===w&&y==="tool_error",x=A(l),T=x.join("");return g({tool:e,mode:n,serverType:c.Docs,args:o,result:T,errorClass:f,...a}),f?v||u({tool:e,message:x.join(" "),mode:n,serverType:c.Docs,durationMs:m,errorClass:f,...a}):_({tool:e,mode:n,serverType:c.Docs,durationMs:m,outputLength:T.length,...a}),l}catch(i){throw g({tool:e,mode:n,serverType:c.Docs,args:o,errorClass:"server_error",...a}),u({tool:e,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 S(t){return"execute"in t&&typeof t.execute=="function"&&"description"in t&&typeof t.description=="string"}async function M(t){const e=(await b())[t];if(!e)return;const{default:o}=await e();return O(o,t)}function O(t,e){return S(t)?t:t[e]}function P(t,e,o){if(L(e))return e;if(typeof e=="string")return{content:[{type:"text",text:e}]};let s;try{s=JSON.stringify(e)}catch(n){throw new Error(`MCP tool "${t}" 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 "${t}" returned an invalid result.`);const r=o==="code"?JSON.parse(s):void 0;return p(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(t){if(!p(t))return!1;const{content:e}=t;return Array.isArray(e)&&e.every(o=>p(o)&&k.has(o.type))}async function j(t){h.initialize();const{toolName:e}=t;if(N(e,t.context.metadata))return!1;const o=E(t.context),s=performance.now();try{const r=await M(e);return r?typeof r=="object"&&typeof r.isAvailable=="function"?await r.isAvailable(o):!0:!1}catch(r){throw u({tool:e,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}}function N(t,e){const o=e?.disabledTools;return Array.isArray(o)&&o.includes(t)}async function F(t){const{toolNames:e,context:o}=t,s=await Promise.all(e.map(r=>j({toolName:r,context:o}).catch(()=>!1)));return Object.fromEntries(e.map((r,n)=>[r,s[n]]))}export{D as executeMcpTool,j as isMcpToolAvailable,F as mcpToolAvailability,O as resolveToolHandler};
|