@redocly/realm 0.138.0-next.6 → 0.138.0-next.9

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 (61) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/client/App.js +1 -1
  3. package/dist/client/app/ReviewComments/ReviewComments.js +2 -2
  4. package/dist/client/app/l10n/hooks/useTranslationKeys.js +1 -1
  5. package/dist/client/app/markdoc/custom-components/openapi/openapi-example.js +1 -1
  6. package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
  7. package/dist/client/app/markdoc/hooks/use-store.d.ts +2 -3
  8. package/dist/client/app/pages/DevLogin/DevLoginForm.js +1 -1
  9. package/dist/client/app/pages/Invite/Invite.js +1 -1
  10. package/dist/client/app/search/useSearch.js +1 -1
  11. package/dist/client/runtime/loader.js +1 -1
  12. package/dist/constants/l10n/langs/ar.js +1 -1
  13. package/dist/constants/l10n/langs/de.js +1 -1
  14. package/dist/constants/l10n/langs/en.js +1 -1
  15. package/dist/constants/l10n/langs/es.js +1 -1
  16. package/dist/constants/l10n/langs/fr.js +1 -1
  17. package/dist/constants/l10n/langs/hi.js +1 -1
  18. package/dist/constants/l10n/langs/it.js +1 -1
  19. package/dist/constants/l10n/langs/ja.js +1 -1
  20. package/dist/constants/l10n/langs/ko.js +1 -1
  21. package/dist/constants/l10n/langs/pl.js +1 -1
  22. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  23. package/dist/constants/l10n/langs/pt.js +1 -1
  24. package/dist/constants/l10n/langs/ru.js +1 -1
  25. package/dist/constants/l10n/langs/uk.js +1 -1
  26. package/dist/constants/l10n/langs/zh.js +1 -1
  27. package/dist/server/config/env-config.d.ts +0 -2
  28. package/dist/server/config/env-schema.d.ts +0 -5
  29. package/dist/server/config/env-schemas/feature-flags.d.ts +0 -4
  30. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  31. package/dist/server/plugins/dev-onboarding/template/App.js +5 -5
  32. package/dist/server/plugins/dev-onboarding/template/components/ApiKeyOverview.js +3 -3
  33. package/dist/server/plugins/markdown/search/get-ai-search-documents.js +1 -1
  34. package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +3 -3
  35. package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -2
  36. package/dist/server/plugins/mcp/custom-tools/scan-custom-tools.js +1 -1
  37. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  38. package/dist/server/plugins/mcp/docs-mcp/tools/core/whoami.js +1 -1
  39. package/dist/server/plugins/mcp/gateway-mcp/credential-validation.js +1 -1
  40. package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +1 -7
  41. package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +5 -6
  42. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
  43. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
  44. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.js +1 -1
  45. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +0 -6
  46. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +2 -2
  47. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +1 -1
  48. package/dist/server/plugins/mcp/servers/mcp-server.js +2 -4
  49. package/dist/server/plugins/scorecard-classic/template/Grid/GridHeader.js +21 -8
  50. package/dist/server/plugins/scorecard-classic/template/ScorecardDashboard.js +3 -3
  51. package/dist/server/plugins/scorecard-classic/template/index.styles.d.ts +1 -0
  52. package/dist/server/plugins/scorecard-classic/template/index.styles.js +15 -5
  53. package/dist/server/plugins/scorecard-classic/template/views.js +1 -1
  54. package/dist/server/plugins/sidebars/tabs.js +1 -1
  55. package/dist/server/web-server/routes/cors-proxy.js +2 -2
  56. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  57. package/package.json +5 -5
  58. /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-blocklist.d.ts +0 -0
  59. /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-blocklist.js +0 -0
  60. /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-safe-lookup.d.ts +0 -0
  61. /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-safe-lookup.js +0 -0
@@ -57,7 +57,6 @@ export declare const envSchema: z.ZodEffects<z.ZodObject<{
57
57
  REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL: z.ZodOptional<z.ZodString>;
58
58
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT: z.ZodOptional<z.ZodString>;
59
59
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX: z.ZodEffects<z.ZodOptional<z.ZodEnum<["true", "false"]>>, boolean | undefined, "false" | "true" | undefined>;
60
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED: z.ZodEffects<z.ZodOptional<z.ZodEnum<["true", "false"]>>, boolean | undefined, "false" | "true" | undefined>;
61
60
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED: z.ZodEffects<z.ZodOptional<z.ZodEnum<["true", "false"]>>, boolean | undefined, "false" | "true" | undefined>;
62
61
  } & {
63
62
  SEARCH_DEV_REINIT: z.ZodOptional<z.ZodString>;
@@ -137,7 +136,6 @@ export declare const envSchema: z.ZodEffects<z.ZodObject<{
137
136
  REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL?: string | undefined;
138
137
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT?: string | undefined;
139
138
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX?: boolean | undefined;
140
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED?: boolean | undefined;
141
139
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED?: boolean | undefined;
142
140
  SEARCH_DEV_REINIT?: string | undefined;
143
141
  SEARCH_DEV_DEBUG: boolean;
@@ -210,7 +208,6 @@ export declare const envSchema: z.ZodEffects<z.ZodObject<{
210
208
  REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL?: string | undefined;
211
209
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT?: string | undefined;
212
210
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX?: "false" | "true" | undefined;
213
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED?: "false" | "true" | undefined;
214
211
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED?: "false" | "true" | undefined;
215
212
  SEARCH_DEV_REINIT?: string | undefined;
216
213
  SEARCH_DEV_DEBUG?: "false" | "true" | undefined;
@@ -283,7 +280,6 @@ export declare const envSchema: z.ZodEffects<z.ZodObject<{
283
280
  REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL?: string | undefined;
284
281
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT?: string | undefined;
285
282
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX?: boolean | undefined;
286
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED?: boolean | undefined;
287
283
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED?: boolean | undefined;
288
284
  SEARCH_DEV_REINIT?: string | undefined;
289
285
  SEARCH_DEV_DEBUG: boolean;
@@ -356,7 +352,6 @@ export declare const envSchema: z.ZodEffects<z.ZodObject<{
356
352
  REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL?: string | undefined;
357
353
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT?: string | undefined;
358
354
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX?: "false" | "true" | undefined;
359
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED?: "false" | "true" | undefined;
360
355
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED?: "false" | "true" | undefined;
361
356
  SEARCH_DEV_REINIT?: string | undefined;
362
357
  SEARCH_DEV_DEBUG?: "false" | "true" | undefined;
@@ -17,8 +17,6 @@ export declare const featureFlagsSchema: z.ZodObject<{
17
17
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT: z.ZodOptional<z.ZodString>;
18
18
  /** Escape hatch: disables the Node Permission Model sandbox on API function and MCP tool worker processes (hosted Reunite environments only). */
19
19
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX: z.ZodEffects<z.ZodOptional<z.ZodEnum<["true", "false"]>>, boolean | undefined, "false" | "true" | undefined>;
20
- /** Experimental: register custom MCP tools from `@mcp` folders. */
21
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED: z.ZodEffects<z.ZodOptional<z.ZodEnum<["true", "false"]>>, boolean | undefined, "false" | "true" | undefined>;
22
20
  /** Experimental: enables the GraphQL request body in Try It and embedded Replay. */
23
21
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED: z.ZodEffects<z.ZodOptional<z.ZodEnum<["true", "false"]>>, boolean | undefined, "false" | "true" | undefined>;
24
22
  }, "strip", z.ZodTypeAny, {
@@ -32,7 +30,6 @@ export declare const featureFlagsSchema: z.ZodObject<{
32
30
  REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL?: string | undefined;
33
31
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT?: string | undefined;
34
32
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX?: boolean | undefined;
35
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED?: boolean | undefined;
36
33
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED?: boolean | undefined;
37
34
  }, {
38
35
  NEW_CATALOG_ENABLED?: "false" | "true" | undefined;
@@ -45,7 +42,6 @@ export declare const featureFlagsSchema: z.ZodObject<{
45
42
  REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL?: string | undefined;
46
43
  REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT?: string | undefined;
47
44
  REDOCLY_DISABLE_API_FUNCTION_SANDBOX?: "false" | "true" | undefined;
48
- REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED?: "false" | "true" | undefined;
49
45
  REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED?: "false" | "true" | undefined;
50
46
  }>;
51
47
  //# sourceMappingURL=feature-flags.d.ts.map
@@ -1 +1 @@
1
- import{z as _}from"zod";import{envBooleanStringOptional as E}from"../../utils/envs/env-boolean-string.js";const D=_.object({NEW_CATALOG_ENABLED:E(),NEW_SCORECARDS_ENABLED:E(),ENABLE_COMMENTS:_.string().optional(),REDOCLY_EXP_DISABLE_MD_VALIDATION:E(),ENABLE_SOURCE_MAPS:E(),PLAN_GATES:_.string().optional(),REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_ENABLED:E(),REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL:_.string().optional(),REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT:_.string().optional(),REDOCLY_DISABLE_API_FUNCTION_SANDBOX:E(),REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED:E(),REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED:E()});export{D as featureFlagsSchema};
1
+ import{z as _}from"zod";import{envBooleanStringOptional as E}from"../../utils/envs/env-boolean-string.js";const D=_.object({NEW_CATALOG_ENABLED:E(),NEW_SCORECARDS_ENABLED:E(),ENABLE_COMMENTS:_.string().optional(),REDOCLY_EXP_DISABLE_MD_VALIDATION:E(),ENABLE_SOURCE_MAPS:E(),PLAN_GATES:_.string().optional(),REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_ENABLED:E(),REDOCLY_EXP_LLMSTXT_AGENT_FEEDBACK_URL:_.string().optional(),REDOCLY_EXP_LLMSTXT_AGENT_ENDPOINT:_.string().optional(),REDOCLY_DISABLE_API_FUNCTION_SANDBOX:E(),REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED:E()});export{D as featureFlagsSchema};
@@ -1,15 +1,15 @@
1
- import*as e from"react";import a from"styled-components";import{useQuery as f}from"@tanstack/react-query";import{useParams as b}from"react-router";import{Box as h,Flex as v}from"@redocly/portal-legacy-ui";import{Admonition as y}from"@redocly/theme/markdoc/components/Admonition/Admonition";import{useTranslate as E}from"../../../../client/app/hooks";import x from"../../../../client/app/CircularProgress";import{Container as A}from"./components/Container";import w from"./components/AppOverview";import T from"./components/ApiKeys";import C from"./components/ApiLogs";import k from"./components/CreateApiKey";import{Description as I}from"./components/Description";import{CallbackUrl as _}from"./components/CallbackUrl";const B="app-tab-actions-portal",m="api_keys",P="logs";function L(D){const{id:s}=b(),{isLoading:p,error:l,data:t}=f({queryKey:["APP:"+s],queryFn:()=>fetch(`/api/api-keys/apps/${s}`).then(n=>n.json())}),{translate:c}=E(),d=n=>o.findIndex(r=>r.id===n),o=[{id:m,name:c("dev.main.tab.appKeys","API keys"),content:e.createElement(e.Fragment,null,e.createElement(T,{credentials:t?.credentials,attributes:t?.attributes}),e.createElement(I,{text:t?.description}),t?.callbackUrl!==void 0&&e.createElement(_,{text:t.callbackUrl})),show:!0},{id:P,name:c("dev.main.tab.logs","Logs"),content:e.createElement(C,null),show:!!t?.supportsLogs}].filter(n=>n.show),[i,g]=e.useState(0),u=t?.canCreateKey&&i===d(m);return e.createElement(h,{my:"2rem"},e.createElement(A,null,p?e.createElement(v,{justifyContent:"center",mt:"2em"},e.createElement(x,null)):l?e.createElement(y,{type:"danger"},l?.message??"Something went wrong"):t?e.createElement(e.Fragment,null,e.createElement(w,{app:t}),e.createElement(K,null,e.createElement(S,null,o.map(({name:n},r)=>e.createElement("span",{key:n,className:i===r?"active":"",onClick:()=>g(r)},n))),e.createElement("div",{id:B}),u&&e.createElement(k,{initialEnabledApis:(t.credentials||[]).flatMap(n=>n.apiProductIds||[])})),e.createElement(z,null,o[i].content)):null))}const W=a.i`
1
+ import*as e from"react";import i from"styled-components";import{useQuery as v}from"@tanstack/react-query";import{useParams as x}from"react-router";import{Box as y,Flex as E}from"@redocly/portal-legacy-ui";import{Admonition as A}from"@redocly/theme/markdoc/components/Admonition/Admonition";import{useTabList as w}from"@redocly/theme/core/hooks";import{useTranslate as T}from"../../../../client/app/hooks";import C from"../../../../client/app/CircularProgress";import{Container as P}from"./components/Container";import k from"./components/AppOverview";import I from"./components/ApiKeys";import L from"./components/ApiLogs";import _ from"./components/CreateApiKey";import{Description as B}from"./components/Description";import{CallbackUrl as K}from"./components/CallbackUrl";const S="app-tab-actions-portal",p="api_keys",z="logs";function D(U){const{id:s}=x(),{isLoading:m,error:l,data:t}=v({queryKey:["APP:"+s],queryFn:()=>fetch(`/api/api-keys/apps/${s}`).then(a=>a.json())}),{translate:c}=T(),d=a=>r.findIndex(o=>o.id===a),r=[{id:p,name:c("dev.main.tab.appKeys","API keys"),content:e.createElement(e.Fragment,null,e.createElement(I,{credentials:t?.credentials,attributes:t?.attributes}),e.createElement(B,{text:t?.description}),t?.callbackUrl!==void 0&&e.createElement(K,{text:t.callbackUrl})),show:!0},{id:z,name:c("dev.main.tab.logs","Logs"),content:e.createElement(L,null),show:!!t?.supportsLogs}].filter(a=>a.show),[n,g]=e.useState(0),{tabListProps:u,getTabProps:b,getTabPanelProps:f}=w({count:r.length,activeIndex:n,onChange:g}),h=t?.canCreateKey&&n===d(p);return e.createElement(y,{my:"2rem"},e.createElement(P,null,m?e.createElement(E,{justifyContent:"center",mt:"2em"},e.createElement(C,null)):l?e.createElement(A,{type:"danger"},l?.message??"Something went wrong"):t?e.createElement(e.Fragment,null,e.createElement(k,{app:t}),e.createElement(F,null,e.createElement(O,{...u},r.map(({name:a},o)=>e.createElement("span",{key:a,className:n===o?"active":"",...b(o)},a))),e.createElement("div",{id:S}),h&&e.createElement(_,{initialEnabledApis:(t.credentials||[]).flatMap(a=>a.apiProductIds||[])})),e.createElement(j,{...f(n)},r[n].content)):null))}const ae=i.i`
2
2
  display: inline-block;
3
3
  width: 12px;
4
4
  height: 12px;
5
5
  background-repeat: no-repeat;
6
6
  background-size: 12px 12px;
7
7
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='black' viewBox='0 0 451.847 451.847' width='12px' height='12px' %3E%3Cpath d='M225.923 354.706c-8.098 0-16.195-3.092-22.369-9.263L9.27 151.157c-12.359-12.359-12.359-32.397 0-44.751 12.354-12.354 32.388-12.354 44.748 0l171.905 171.915 171.906-171.909c12.359-12.354 32.391-12.354 44.744 0 12.365 12.354 12.365 32.392 0 44.751L248.292 345.449c-6.177 6.172-14.274 9.257-22.369 9.257z' /%3E%3C/svg%3E");
8
- `,K=a.div`
8
+ `,F=i.div`
9
9
  display: flex;
10
10
  justify-content: space-between;
11
11
  align-items: end;
12
- `,S=a.div`
12
+ `,O=i.div`
13
13
  display: flex;
14
14
  align-items: center;
15
15
  height: 42px;
@@ -27,6 +27,6 @@ import*as e from"react";import a from"styled-components";import{useQuery as f}fr
27
27
  > span.active {
28
28
  border-bottom: 2px solid var(--border-color-primary);
29
29
  }
30
- `,z=a.div`
30
+ `,j=i.div`
31
31
  margin-top: var(--spacing-base);
32
- `;export{W as ArrowIcon,B as TAB_ACTIONS_PORTAL_ID,L as default};
32
+ `;export{ae as ArrowIcon,S as TAB_ACTIONS_PORTAL_ID,D as default};
@@ -1,4 +1,4 @@
1
- import*as t from"react";import i from"styled-components";import{Flex as a}from"@redocly/portal-legacy-ui";import{WarningAltIcon as l}from"@redocly/theme/icons/WarningAltIcon/WarningAltIcon";import n from"./ApiKeyRow";import s from"./CreatedAtRow";import c from"./ExpiresAtRow";import m from"./RevokeAPIKey";import p from"./RollAPIKey";import d from"./SecretRow";import x from"./StageRow";import f from"./StatusRow";function u(r){const{apiKey:e}=r,o=Number(e.expiresAt)>0&&Math.abs(Number(e.expiresAt)-Date.now())<1440*60*1e3;return t.createElement(a,{flexDirection:"column",flexGrow:1},o&&t.createElement(v,null,t.createElement("div",null,"Expires soon"),t.createElement(l,{size:"24px",color:"#C8102E"})),t.createElement(g,{borderColor:o?"var(--color-error-border)":e.stage==="production"?"var(--color-success-border)":""},e.stage&&t.createElement(x,{stage:e.stage})||null,e.clientId&&t.createElement(n,{apiKey:e.clientId})||null,e.clientSecret&&t.createElement(d,{secret:e.clientSecret,hasClientId:!!e.clientId})||null,e.status&&t.createElement(f,{status:e.status})||null,t.createElement(s,{createdAt:e.issuedAt}),t.createElement(c,{expiresAt:e.expiresAt,expiresSoon:o})),e.canBeRolled&&t.createElement(p,{apiKey:e}),e.canBeRevoked&&t.createElement(m,{apiKey:e}))}const g=i.div`
1
+ import*as t from"react";import a from"styled-components";import{Flex as l}from"@redocly/portal-legacy-ui";import{WarningAltIcon as n}from"@redocly/theme/icons/WarningAltIcon/WarningAltIcon";import s from"./ApiKeyRow";import c from"./CreatedAtRow";import m from"./ExpiresAtRow";import p from"./RevokeAPIKey";import d from"./RollAPIKey";import x from"./SecretRow";import f from"./StageRow";import u from"./StatusRow";function g(r){const{apiKey:e}=r,[i]=t.useState(()=>Date.now()),o=Number(e.expiresAt)>0&&Math.abs(Number(e.expiresAt)-i)<1440*60*1e3;return t.createElement(l,{flexDirection:"column",flexGrow:1},o&&t.createElement(E,null,t.createElement("div",null,"Expires soon"),t.createElement(n,{size:"24px",color:"#C8102E"})),t.createElement(v,{borderColor:o?"var(--color-error-border)":e.stage==="production"?"var(--color-success-border)":""},e.stage&&t.createElement(f,{stage:e.stage})||null,e.clientId&&t.createElement(s,{apiKey:e.clientId})||null,e.clientSecret&&t.createElement(x,{secret:e.clientSecret,hasClientId:!!e.clientId})||null,e.status&&t.createElement(u,{status:e.status})||null,t.createElement(c,{createdAt:e.issuedAt}),t.createElement(m,{expiresAt:e.expiresAt,expiresSoon:o})),e.canBeRolled&&t.createElement(d,{apiKey:e}),e.canBeRevoked&&t.createElement(p,{apiKey:e}))}const v=a.div`
2
2
  display: flex;
3
3
  flex-direction: column;
4
4
 
@@ -9,7 +9,7 @@ import*as t from"react";import i from"styled-components";import{Flex as a}from"@
9
9
  > :not(:last-child) {
10
10
  border-bottom: 1px solid var(--border-color-primary);
11
11
  }
12
- `,v=i.div`
12
+ `,E=a.div`
13
13
  display: flex;
14
14
  gap: var(--spacing-xs);
15
15
  font-weight: var(--font-weight-regular);
@@ -20,4 +20,4 @@ import*as t from"react";import i from"styled-components";import{Flex as a}from"@
20
20
  width: 18px;
21
21
  height: 18px;
22
22
  }
23
- `;export{u as default};
23
+ `;export{g as default};
@@ -6,4 +6,4 @@ ${g}
6
6
  `)});else{const a=t.parentNode?.id??j,m=c.get(a)??{title:r,content:"",url:i,level:1/0,toc:""};m.content+=m.content?`
7
7
  `:"",m.content+=t.content.trimEnd(),c.set(a,m)}const d=$(Array.from(c.values())),u=L(n.fsPath);return d.filter(t=>t.content).map(t=>({title:t.title,url:t.url,content:[A,t.toc||`# ${r}`,t.content].filter(Boolean).join(`
8
8
  `),fsPath:n.fsPath,locale:u,product:n.product?.name,facets:f}))}function _(n){return n.length/4}function $(n){if(n.length===0)return[];const o=[];let e=n[0];for(let r=1;r<n.length;r++){const i=n[r],c=_(e.content),l=_(i.content),f=r===n.length-1;l<R&&(c<v||f)&&i.level>e.level?e.content+=`
9
- `+i.content:(o.push(e),e=i)}return o.push(e),o}const k=String.raw`\((?:[^()]|\([^()]*\))*\)`,G=new RegExp(String.raw`!\[[^\]]*\]`+k,"g"),z=new RegExp(String.raw`\[([^\]]*)\]`+k,"g");function W(n,o){const e=h(o);return o.content===n||!e?n:`${n} \u2192 ${e}`}function h(n){return B(n.content.replace(/^#+/,""))}function B(n){return n.replace(G,"").replace(z,"$1").trim()}export{at as getAiDocumentsStore};
9
+ `+i.content:(o.push(e),e=i)}return o.push(e),o}const k=String.raw`\((?:[^()]|\([^()]*\))*\)`,G=new RegExp(String.raw`!\[[^\]]*\]`+k,"g"),z=new RegExp(String.raw`\[(?<!\[[^\]()]*?\[)([^\]]*)\]`+k,"g");function W(n,o){const e=h(o);return o.content===n||!e?n:`${n} \u2192 ${e}`}function h(n){return B(n.content.replace(/^#+/,""))}function B(n){return n.replace(G,"").replace(z,"$1").trim()}export{at as getAiDocumentsStore};
@@ -1,5 +1,5 @@
1
1
  import{getCallableApis as n,isFetchCapable as o}from"../../../gateway-mcp/callable-apis.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 | URL, 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;"," /** Security scheme name (from the operation's `security` or `getSecuritySchemes`) whose credential to send. Omit to let the server choose. */"," securityScheme?: string;","}): Promise<{"," status: number;"," statusText: string;"," ok: boolean;"," headers: { get(name: string): string | null };"," json(): Promise<unknown>;"," text(): Promise<string>;","}>;","```"].join(`
2
- `),c=["listApis","getEndpoints","getEndpointInfo"],h=["Example - list the paid invoices of a billing 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 ep = endpoints.find((e) => e.method === 'GET' && e.path.includes('invoices'));","const info = await tools.getEndpointInfo({ name: api.name, path: ep.path, method: ep.method });","// Replace every `{placeholder}` first.","const url = new URL((info.servers?.[0]?.url ?? '') + ep.path);","// Every name below comes from `info.endpoint.parameters` - read them first, never guess them.","url.searchParams.set('filter', 'status:paid');","url.searchParams.set('sort', '-createdTime');","url.searchParams.set('limit', '100');","try {"," const res = await fetch(url, { method: ep.method });"," 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
- `),p=["Example - call an endpoint you already read:","","```ts","// Call `getEndpointInfo` first for the server URL, the path, and the parameter names.","// Replace every `{placeholder}` first.","const url = new URL('https://api.example.com/invoices');","url.searchParams.set('filter', 'status:paid');","try {"," const res = await fetch(url, { method: 'GET' });"," return res.ok ? await res.json() : { status: res.status, error: await res.text() };","} catch (error) {"," return { error: error instanceof Error ? error.message : String(error) };","}","```"].join(`
4
- `);function m(r){return c.every(t=>r.includes(t))?h:p}function d(r){const t=new Map;for(const{name:e,version:a}of r){if(!e)continue;const s=t.get(e)??[];a&&s.push(a),t.set(e,s)}return[...t.entries()].map(([e,a])=>a.length>1?`${e} (${a.map(s=>`v${s}`).join(", ")})`:e).join(", ")}const g={id:i,purpose:"Call the documented APIs over HTTP",isActive:o,annotations:{readOnlyHint:!1,destructiveHint:!0,openWorldHint:!0},renderSection(r,t){const e=d(n(r));return["## `fetch` \u2014 call the documented APIs","",l,"","Always call `getEndpointInfo` before `fetch` for the exact URL, required parameters, and body shape. Put filtering, sorting, and paging in the query parameters, and keep sandbox JS for what the endpoint cannot express. Never guess.","","A `servers[].url` or an endpoint path can hold `{placeholders}`. Replace every one before you call `fetch`. Use the server variable `default`. Ask the user when the `default` only repeats the variable name, such as `{organizationId}`.","","When an operation accepts more than one security scheme, pass `securityScheme` with the scheme name the user holds a credential for; without it the server picks one, and a mismatched credential fails upstream.","",`Callable APIs (their documented hosts are reachable via \`fetch\`): ${e}`,"",m(t)].join(`
2
+ `),c=["listApis","getEndpoints","getEndpointInfo"],p=["Example - list the paid invoices of a billing 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 ep = endpoints.find((e) => e.method === 'GET' && e.path.includes('invoices'));","const info = await tools.getEndpointInfo({ name: api.name, path: ep.path, method: ep.method });","// Replace every `{placeholder}` first.","const url = new URL((info.servers?.[0]?.url ?? '') + ep.path);","// Every name below comes from `info.endpoint.parameters` - read them first, never guess them.","url.searchParams.set('filter', 'status:paid');","url.searchParams.set('sort', '-createdTime');","url.searchParams.set('limit', '100');","try {"," const res = await fetch(url, { method: ep.method });"," 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
+ `),d=["Example - call an endpoint you already read:","","```ts","// Call `getEndpointInfo` first for the server URL, the path, and the parameter names.","// Replace every `{placeholder}` first.","const url = new URL('https://api.example.com/invoices');","url.searchParams.set('filter', 'status:paid');","try {"," const res = await fetch(url, { method: 'GET' });"," return res.ok ? await res.json() : { status: res.status, error: await res.text() };","} catch (error) {"," return { error: error instanceof Error ? error.message : String(error) };","}","```"].join(`
4
+ `);function h(r){return c.every(t=>r.includes(t))?p:d}function m(r){const t=new Map;for(const{name:e,version:a}of r){if(!e)continue;const s=t.get(e)??[];a&&s.push(a),t.set(e,s)}return[...t.entries()].map(([e,a])=>a.length>1?`${e} (${a.map(s=>`v${s}`).join(", ")})`:e).join(", ")}const g={id:i,purpose:"Call the documented APIs over HTTP",isActive:o,annotations:{readOnlyHint:!1,destructiveHint:!0,openWorldHint:!0},renderSection(r,t){const e=m(n(r));return["## `fetch` \u2014 call the documented APIs","",l,"","Always call `getEndpointInfo` before `fetch` for the exact URL, required parameters, and body shape. Put filtering, sorting, and paging in the query parameters, and keep sandbox JS for what the endpoint cannot express. Never guess.","","A `servers[].url` or an endpoint path can hold `{placeholders}`. Replace every one before you call `fetch`. Use the server variable `default`. Ask the user when the `default` only repeats the variable name, such as `{organizationId}`.","",`Callable APIs (their documented hosts are reachable via \`fetch\`): ${e}`,"",h(t)].join(`
5
5
  `)}};export{l as FETCH_DECLARATION,g as fetchCapability};
@@ -1,2 +1,2 @@
1
- import{MANAGE_API_CREDENTIALS_TOOL_NAME as P}from"../../constants.js";import{acceptedCredentialsLink as k,buildCredentialsAcceptedHint as w,buildUpstreamCredentialFallback as S,buildUpstreamCredentialInputRequired as I,credentialElicitationAnswer as E,dedupeElicitation as C,isStatelessRequest as j,schemeLabelOf as q,supportsUrlElicitation as T}from"../../gateway-mcp/elicitation.js";import{getCallableApis as u,isFetchCapable as H}from"../../gateway-mcp/callable-apis.js";import{secretStore as R}from"../../gateway-mcp/secret-store.js";import{MISSING_SESSION_HANDLE_MESSAGE as U,resolveSecretSubject as $}from"../../gateway-mcp/subject.js";import{upstreamAuthKey as L}from"../../gateway-mcp/upstream-auth.js";import{resolveUpstreamApiAuth as N}from"../../gateway-mcp/upstream-auth-scheme.js";import{apiTitleKey as O,countApiTitles as _}from"../../docs-mcp/utils/api-titles.js";function Q(e){return!!e.elicitationEnabled&&H(e)}function V(e){const s=u(e),t=s.map(i=>i.relativePath),r=[...t,...M(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,destructiveHint:!1,idempotentHint:!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,...r.length>0?{enum:r}:{}},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 M(e){const s=_(e);return e.map(t=>t.name).filter(t=>s.get(O(t))===1)}function X(e,s){return async(t,r)=>{const i=$(e.user,typeof t.sessionHandle=="string"?t.sessionHandle:void 0);if(i.kind==="invalid")return m(i.message);if(i.kind==="anonymous")return m(U);const{subject:c}=i,p=typeof t.api=="string"?t.api:"",n=u(e).find(o=>o.relativePath===p||o.name===p);if(!n){const o=u(e).map(b=>b.relativePath).join(", ");return m(`Unknown api "${p}". Credentials can only be managed for the APIs this server can call: ${o||"none"}.`)}const d=E(r.mcpReq.inputResponses);if(d==="accepted"){const o=await k(r.mcpReq.requestState(),{kv:await s.getKv(),subject:c,baseUrl:e.baseUrl??"",apis:[n.relativePath]});return{content:[{type:"text",text:w(n.name,o?.url)}],isError:!1}}if(d==="declined")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 a=await N(e,n.relativePath),h=typeof t.scheme=="string"?t.scheme:void 0,y=Object.keys(a.schemes);if(h&&!a.schemes[h])return m(`Unknown scheme "${h}" for api "${n.relativePath}". The security schemes this server can store credentials for are: ${y.join(", ")}.`);const l=h??a.defaultScheme,f=q(a.schemes,l),A=await s.getKv(),v={subject:c,baseUrl:e.baseUrl??"",target:{api:n.relativePath,name:n.name,scheme:l,...f?{schemeLabel:f}:{}},auth:a.schemes[l],apiAuth:a,kv:A,hasExistingSecret:await R.hasSecret(A,c,n.relativePath,l),reason:{kind:"requested"}};if(j(r.mcpReq)&&T(s.getClientCapabilities()))return await I(v);const g=L({api:n.relativePath,scheme:l});return{content:[{type:"text",text:await C(`${c}:${g}`,()=>S(v))}],isError:!1}}}function m(e){return{content:[{type:"text",text:e}],isError:!0}}export{Q as isManageApiCredentialsToolAvailable,X as manageApiCredentials,V as manageApiCredentialsSchema};
1
+ import{MANAGE_API_CREDENTIALS_TOOL_NAME as P}from"../../constants.js";import{acceptedCredentialsLink as k,buildCredentialsAcceptedHint as w,buildUpstreamCredentialFallback as S,buildUpstreamCredentialInputRequired as I,credentialElicitationAnswer as E,dedupeElicitation as C,isStatelessRequest as j,schemeLabelOf as q,supportsUrlElicitation as T}from"../../gateway-mcp/elicitation.js";import{getCallableApis as u,isFetchCapable as H}from"../../gateway-mcp/callable-apis.js";import{secretStore as R}from"../../gateway-mcp/secret-store.js";import{MISSING_SESSION_HANDLE_MESSAGE as U,resolveSecretSubject as $}from"../../gateway-mcp/subject.js";import{upstreamAuthKey as L}from"../../gateway-mcp/upstream-auth.js";import{resolveUpstreamApiAuth as N}from"../../gateway-mcp/upstream-auth-scheme.js";import{apiTitleKey as O,countApiTitles as _}from"../../docs-mcp/utils/api-titles.js";function Q(e){return!!e.elicitationEnabled&&H(e)}function V(e){const s=u(e),t=s.map(r=>r.relativePath),i=[...t,...M(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,destructiveHint:!1,idempotentHint:!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,...i.length>0?{enum:i}:{}},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 M(e){const s=_(e);return e.map(t=>t.name).filter(t=>s.get(O(t))===1)}function X(e,s){return async(t,i)=>{const r=$(e.user,typeof t.sessionHandle=="string"?t.sessionHandle:void 0);if(r.kind==="invalid")return m(r.message);if(r.kind==="anonymous")return m(U);const{subject:c}=r,p=typeof t.api=="string"?t.api:"",n=u(e).find(l=>l.relativePath===p||l.name===p);if(!n){const l=u(e).map(b=>b.relativePath).join(", ");return m(`Unknown api "${p}". Credentials can only be managed for the APIs this server can call: ${l||"none"}.`)}const d=E(i.mcpReq.inputResponses);if(d==="accepted"){const l=await k(i.mcpReq.requestState(),{kv:await s.getKv(),subject:c,baseUrl:e.baseUrl??"",apis:[n.relativePath]});return{content:[{type:"text",text:w(n.name,l?.url)}],isError:!1}}if(d==="declined")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 a=await N(e,n.relativePath),o=typeof t.scheme=="string"?t.scheme:void 0,y=Object.keys(a.schemes);if(o&&!a.schemes[o])return m(`Unknown scheme "${o}" for api "${n.relativePath}". The security schemes this server can store credentials for are: ${y.join(", ")}.`);const h=o??a.defaultScheme,f=o?q(a.schemes,o):void 0,A=await s.getKv(),v={subject:c,baseUrl:e.baseUrl??"",target:{api:n.relativePath,name:n.name,scheme:h,...f?{schemeLabel:f}:{}},auth:a.schemes[h],apiAuth:a,kv:A,hasExistingSecret:await R.hasSecret(A,c,n.relativePath,h),reason:{kind:"requested"}};if(j(i.mcpReq)&&T(s.getClientCapabilities()))return await I(v);const g=L({api:n.relativePath,scheme:h});return{content:[{type:"text",text:await C(`${c}:${g}`,()=>S(v))}],isError:!1}}}function m(e){return{content:[{type:"text",text:e}],isError:!0}}export{Q as isManageApiCredentialsToolAvailable,X as manageApiCredentials,V as manageApiCredentialsSchema};
@@ -1 +1 @@
1
- import{basename as d,join as p}from"node:path";import{envConfig as f}from"../../../config/env-config.js";import{logger as h}from"../../../tools/notifiers/logger.js";import{reporter as s}from"../../../tools/notifiers/reporter.js";import{CODE_MODE_TOOL_NAMES as O}from"../codemode/constants.js";import{ALL_DEFAULT_TOOL_NAMES as E}from"../docs-mcp/tool-schemas.js";import{extractToolDefinition as T}from"./extract-tool-definition.js";const M=/(^|\/)@mcp\/.*\.(ts|js)$/,_=/^[a-zA-Z0-9_-]{1,64}$/,C=new Set([...O,...E]);async function w(o,a,n){if(!f.REDOCLY_EXP_MCP_CUSTOM_TOOLS_ENABLED)return 0;N(o,n);const u=new Set(o.getMcpTools().map(r=>r.name)),l=new Map;for(const r of a.fs.scan(M)){if(r.isVirtual||r.relativePath.endsWith(".d.ts"))continue;const{relativePath:t}=r,e=d(t).replace(/\.(ts|js)$/,"");if(!_.test(e)){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": the tool name "${e}" is derived from the file name and may only contain letters, numbers, hyphens, and underscores (max 64 characters). Rename the file.`);continue}const c=l.get(e);if(c){await s.panicOnBuildContentError(`Duplicate MCP tool name "${e}": defined by both "${c}" and "${t}". Tool names are file names, so each file name must be unique across @mcp folders.`);continue}if(C.has(e)||u.has(e)){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": the tool name "${e}" is already used by a built-in MCP tool. Rename the file.`);continue}l.set(e,t);const m=p(o.contentDir,t),i=await T({toolName:e,absoluteSourcePath:m,contentDir:o.contentDir,serverOutDir:o.serverOutDir});if(!i.ok){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": ${i.errors.join(" ")}`);continue}!i.schema.outputSchema&&!n.warnedNoOutputSchemaTools.has(e)&&(n.warnedNoOutputSchemaTools.add(e),h.warn(`MCP tool "${e}" in %rp declares no \`outputSchema\`. Add one that describes the returned value.`,t)),o.addMcpTools(m,[i.schema]),n.registeredToolNames.push(e)}return n.registeredToolNames.length}function N(o,a){o.removeMcpTools(a.registeredToolNames),a.registeredToolNames=[]}export{N as resetCustomMcpTools,w as scanCustomMcpTools};
1
+ import{basename as d,join as p}from"node:path";import{logger as f}from"../../../tools/notifiers/logger.js";import{reporter as s}from"../../../tools/notifiers/reporter.js";import{CODE_MODE_TOOL_NAMES as h}from"../codemode/constants.js";import{ALL_DEFAULT_TOOL_NAMES as O}from"../docs-mcp/tool-schemas.js";import{extractToolDefinition as T}from"./extract-tool-definition.js";const E=/(^|\/)@mcp\/.*\.(ts|js)$/,M=/^[a-zA-Z0-9_-]{1,64}$/,C=new Set([...h,...O]);async function g(o,a,n){_(o,n);const u=new Set(o.getMcpTools().map(r=>r.name)),l=new Map;for(const r of a.fs.scan(E)){if(r.isVirtual||r.relativePath.endsWith(".d.ts"))continue;const{relativePath:t}=r,e=d(t).replace(/\.(ts|js)$/,"");if(!M.test(e)){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": the tool name "${e}" is derived from the file name and may only contain letters, numbers, hyphens, and underscores (max 64 characters). Rename the file.`);continue}const c=l.get(e);if(c){await s.panicOnBuildContentError(`Duplicate MCP tool name "${e}": defined by both "${c}" and "${t}". Tool names are file names, so each file name must be unique across @mcp folders.`);continue}if(C.has(e)||u.has(e)){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": the tool name "${e}" is already used by a built-in MCP tool. Rename the file.`);continue}l.set(e,t);const m=p(o.contentDir,t),i=await T({toolName:e,absoluteSourcePath:m,contentDir:o.contentDir,serverOutDir:o.serverOutDir});if(!i.ok){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": ${i.errors.join(" ")}`);continue}!i.schema.outputSchema&&!n.warnedNoOutputSchemaTools.has(e)&&(n.warnedNoOutputSchemaTools.add(e),f.warn(`MCP tool "${e}" in %rp declares no \`outputSchema\`. Add one that describes the returned value.`,t)),o.addMcpTools(m,[i.schema]),n.registeredToolNames.push(e)}return n.registeredToolNames.length}function _(o,a){o.removeMcpTools(a.registeredToolNames),a.registeredToolNames=[]}export{_ as resetCustomMcpTools,g as scanCustomMcpTools};
@@ -1 +1 @@
1
- import{SEMANTIC_SEARCH_API_URL as y}from"../../../constants/common.js";import{shouldHandleMcpAuth as f}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as g,SUBMIT_FEEDBACK_TOOL_NAME as b}from"../constants.js";import{GRAPHQL_TYPE_KINDS as l,GRAPHQL_LIST_SCOPES as v}from"./tools/graphql/constants.js";import{OPERATION_METHODS as c}from"./tools/openapi/constants.js";const i={type:"string",nullable:!0},s={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},a={codemodeType:"OpenApiServer[]"},o={codemodeType:"OpenApiSecurityRequirement[]"},u={codemodeType:"Record<string, OpenApiSecurityScheme>"},P={codemodeType:"OpenApiDocument"},A={codemodeType:"OpenApiOperation & { path: string; method: string }"},S={codemodeType:"OpenApiComponents",description:"Components the endpoint references. A `$ref` in `endpoint` resolves against the root of the result."},n={filePath:{type:"string",description:"API definition file path"},otherMatches:{type:"array",description:"Other API definitions the lookup also matched. Present only when several matched; pass `filePath` to pick another one",items:{type:"object",required:["filePath"],properties:{version:{type:"string"},filePath:{type:"string"}}}}},r="When several definitions match the name, the highest version or the shortest file path is used and the rest are listed in `otherMatches`; tell the user which version or file the answer is based on.",H="A `$ref` in `endpoint` points into the `components` key at the root of the result: read `#/components/<section>/<name>` there.",L={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}}},p={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. When omitted and several versions exist, the highest one is used",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},q={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:[...c.map(e=>e.toUpperCase()),...c],minLength:1},version:{type:"string",description:"API version. When omitted and several versions exist, the highest one is used",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},O={type:"object",required:[],additionalProperties:!1,properties:{}},T={type:"object",required:[],additionalProperties:!1,properties:{}},G={type:"object",required:["path","summary"],additionalProperties:!1,properties:{path:{type:"string",description:"Path or URL of the documentation page the feedback is about (e.g. /guides/auth)",minLength:1,maxLength:1e3},summary:{type:"string",description:"One sentence that names what is wrong with the page",minLength:1,maxLength:500},details:{type:"string",description:"Expected versus actual behavior, missing steps, or the snippet that failed",maxLength:4e3,nullable:!0},targetFeature:{type:"string",description:"The API or feature the page documents",maxLength:500,nullable:!0}}};function I(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["items","limit","total","page","totalPages"],properties:{items:{type:"array",items:{type:"object",required:["name","description","version","servers","filePath"],properties:{name:{type:"string"},description:{type:"string"},version:{type:"string"},servers:a,filePath:{type:"string",description:"API definition file path"},ambiguousTitle:{type:"boolean",description:"true = another API shares this title; a lookup picks the highest version, or the shortest file path at the same version, and lists the rest in `otherMatches`. Pass `filePath` to pick another one"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...s}}},{name:"get-endpoints",title:"Get endpoints",description:`Get all endpoints for a specific API. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","servers","endpoints"],properties:{api:{type:"string"},version:{type:"string"},...n,servers:a,endpoints:{type:"array",items:{type:"object",required:["path","method"],properties:{path:{type:"string"},method:{type:"string"},summary:i,description:i,security:o}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:`Get comprehensive information about specific endpoint including parameters, security, and examples. ${H} ${r}`,schema:q,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","servers","endpoint","globalSecurity","securitySchemes"],properties:{api:{type:"string"},version:{type:"string"},...n,servers:a,endpoint:A,globalSecurity:o,securitySchemes:u,components:S}}},{name:"get-security-schemes",title:"Get security schemes",description:`Get the security schemes for a specific API. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","securitySchemes","security"],properties:{api:{type:"string"},version:{type:"string"},...n,securitySchemes:u,security:o}}},{name:"get-full-api-description",title:"Get full API description",description:`Get the complete OpenAPI description. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","definition"],properties:{api:{type:"string"},version:{type:"string"},...n,definition:P}}},...y?[d(e.products,e.locales)]:[]];return f(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:O,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.feedbackHidden||t.push({name:b,title:"Submit feedback",description:"Report a documentation page that is wrong or incomplete",schema:G,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["status","page","message"],properties:{status:{type:"string"},page:{type:"string"},message:{type:"string"}}}}),e.hasGraphqlApis&&t.push(...k()),e.elicitationEnabled&&e.hasCallableApis&&t.push({name:g,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:T,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const w={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}}},j={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:[...l,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:[...v,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}}},E={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}}},N={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function k(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:w,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["items","limit","total","page","totalPages"],properties:{items:{type:"array",items:{type:"object",required:["name"],properties:{name:{type:"string"},description:i}}},...s}}},{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:j,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["name","items","limit","total","page","totalPages"],properties:{name:{type:"string"},items:{type:"array",items:{type:"object",required:["kind","name"],properties:{kind:{type:"string",enum:l},name:{type:"string"},description:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...s}}},{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:E,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:N,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function d(e,t){const h=e&&e.length>0,m=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},...h?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:[...e,null],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:[...t,null],nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const Q=new Set([...I({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0,hasCallableApis:!0}).map(e=>e.name),d().name]);export{Q as ALL_DEFAULT_TOOL_NAMES,I as getDefaultToolSchemas};
1
+ import{SEMANTIC_SEARCH_API_URL as y}from"../../../constants/common.js";import{shouldHandleMcpAuth as f}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as g,SUBMIT_FEEDBACK_TOOL_NAME as b}from"../constants.js";import{GRAPHQL_TYPE_KINDS as l,GRAPHQL_LIST_SCOPES as v}from"./tools/graphql/constants.js";import{OPERATION_METHODS as c}from"./tools/openapi/constants.js";const i={type:"string",nullable:!0},s={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},a={codemodeType:"OpenApiServer[]"},o={codemodeType:"OpenApiSecurityRequirement[]"},u={codemodeType:"Record<string, OpenApiSecurityScheme>"},P={codemodeType:"OpenApiDocument"},A={codemodeType:"OpenApiOperation & { path: string; method: string }"},S={codemodeType:"OpenApiComponents",description:"Components the endpoint references. A `$ref` in `endpoint` resolves against the root of the result."},n={filePath:{type:"string",description:"API definition file path"},otherMatches:{type:"array",description:"Other API definitions the lookup also matched. Present only when several matched; pass `filePath` to pick another one",items:{type:"object",required:["filePath"],properties:{version:{type:"string"},filePath:{type:"string"}}}}},r="When several definitions match the name, the highest version or the shortest file path is used and the rest are listed in `otherMatches`; tell the user which version or file the answer is based on.",H="A `$ref` in `endpoint` points into the `components` key at the root of the result: read `#/components/<section>/<name>` there.",L={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}}},p={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. When omitted and several versions exist, the highest one is used",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},q={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:[...c.map(e=>e.toUpperCase()),...c],minLength:1},version:{type:"string",description:"API version. When omitted and several versions exist, the highest one is used",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},O={type:"object",required:[],additionalProperties:!1,properties:{}},T={type:"object",required:[],additionalProperties:!1,properties:{}},G={type:"object",required:["path","summary"],additionalProperties:!1,properties:{path:{type:"string",description:"Path or URL of the documentation page the feedback is about (e.g. /guides/auth)",minLength:1,maxLength:1e3},summary:{type:"string",description:"One sentence that names what is wrong with the page",minLength:1,maxLength:500},details:{type:"string",description:"Expected versus actual behavior, missing steps, or the snippet that failed",maxLength:4e3,nullable:!0},targetFeature:{type:"string",description:"The API or feature the page documents",maxLength:500,nullable:!0}}};function I(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["items","limit","total","page","totalPages"],properties:{items:{type:"array",items:{type:"object",required:["name","description","version","servers","filePath"],properties:{name:{type:"string"},description:{type:"string"},version:{type:"string"},servers:a,filePath:{type:"string",description:"API definition file path"},ambiguousTitle:{type:"boolean",description:"true = another API shares this title; a lookup picks the highest version, or the shortest file path at the same version, and lists the rest in `otherMatches`. Pass `filePath` to pick another one"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...s}}},{name:"get-endpoints",title:"Get endpoints",description:`Get all endpoints for a specific API. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","servers","endpoints"],properties:{api:{type:"string"},version:{type:"string"},...n,servers:a,endpoints:{type:"array",items:{type:"object",required:["path","method"],properties:{path:{type:"string"},method:{type:"string"},summary:i,description:i,security:o}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:`Get comprehensive information about specific endpoint including parameters, security, and examples. ${H} ${r}`,schema:q,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","servers","endpoint","globalSecurity","securitySchemes"],properties:{api:{type:"string"},version:{type:"string"},...n,servers:a,endpoint:A,globalSecurity:o,securitySchemes:u,components:S}}},{name:"get-security-schemes",title:"Get security schemes",description:`Get the security schemes for a specific API. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","securitySchemes","security"],properties:{api:{type:"string"},version:{type:"string"},...n,securitySchemes:u,security:o}}},{name:"get-full-api-description",title:"Get full API description",description:`Get the complete OpenAPI description. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["api","version","filePath","definition"],properties:{api:{type:"string"},version:{type:"string"},...n,definition:P}}},...y?[d(e.products,e.locales)]:[]];return f(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:O,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["authenticated"],properties:{authenticated:{type:"boolean"},email:{type:"string"},name:{type:"string"},subject:{type:"string"},clientId:{type:"string"},scope:{type:"string"},issuedAt:{type:"string"},expiresAt:{type:"string"}}}}),e.feedbackHidden||t.push({name:b,title:"Submit feedback",description:"Report a documentation page that is wrong or incomplete",schema:G,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["status","page","message"],properties:{status:{type:"string"},page:{type:"string"},message:{type:"string"}}}}),e.hasGraphqlApis&&t.push(...k()),e.elicitationEnabled&&e.hasCallableApis&&t.push({name:g,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:T,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const w={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}}},j={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:[...l,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:[...v,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}}},E={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}}},N={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function k(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:w,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["items","limit","total","page","totalPages"],properties:{items:{type:"array",items:{type:"object",required:["name"],properties:{name:{type:"string"},description:i}}},...s}}},{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:j,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["name","items","limit","total","page","totalPages"],properties:{name:{type:"string"},items:{type:"array",items:{type:"object",required:["kind","name"],properties:{kind:{type:"string",enum:l},name:{type:"string"},description:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...s}}},{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:E,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:N,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function d(e,t){const h=e&&e.length>0,m=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},...h?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:[...e,null],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:[...t,null],nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const Q=new Set([...I({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0,hasCallableApis:!0}).map(e=>e.name),d().name]);export{Q as ALL_DEFAULT_TOOL_NAMES,I as getDefaultToolSchemas};
@@ -1 +1 @@
1
- const s=async(i,e)=>e.user?.isAuthenticated?{content:[{type:"text",text:JSON.stringify({email:e.user.email,name:e.user.claims?.name,subject:e.user.claims?.sub,clientId:e.user.claims?.client_id,scope:e.user.claims?.scope,issuedAt:e.user.claims?.iat?new Date(Number(e.user.claims.iat)*1e3).toISOString():void 0,expiresAt:e.user.claims?.exp?new Date(Number(e.user.claims.exp)*1e3).toISOString():void 0})}],isError:!1}:{content:[{type:"text",text:JSON.stringify({error:"Not authenticated",message:"No valid authentication token found. Please authenticate first."})}],isError:!0};var r={whoami:s};export{r as default};
1
+ const s=async(i,e)=>e.user?.isAuthenticated?{content:[{type:"text",text:JSON.stringify({authenticated:!0,email:e.user.email,name:e.user.claims?.name,subject:e.user.claims?.sub,clientId:e.user.claims?.client_id,scope:e.user.claims?.scope,issuedAt:e.user.claims?.iat?new Date(Number(e.user.claims.iat)*1e3).toISOString():void 0,expiresAt:e.user.claims?.exp?new Date(Number(e.user.claims.exp)*1e3).toISOString():void 0})}]}:{content:[{type:"text",text:JSON.stringify({authenticated:!1})}]};var a={whoami:s};export{a as default};
@@ -1 +1 @@
1
- const r=/[\r\n]/,o=255;function a(n){for(let e=0;e<n.length;e+=1){const t=n.charCodeAt(e);if(t===0||t>255)return!0}return!1}function s(n,e){if(!e)return"Enter a value before saving.";if(r.test(e))return"The value contains a line break. Paste it as a single line and save again.";if(a(e))return"The value contains a character that cannot be sent in an HTTP header, such as a curly quote or an invisible character. Copy the value again as plain text and save.";if(n.kind==="cookie")return i(n.name,e)}function i(n,e){if(e.includes(";")||e.toLowerCase().includes(`${n.toLowerCase()}=`))return`This looks like a whole cookie header. Paste only the value of the ${n} cookie, without the "${n}=" prefix and without any other name=value pairs.`}function c(n,e){if(!(!r.test(e)&&!a(e)))throw new Error(`The credential cannot be sent as the ${n} header value.`)}export{c as assertHeaderSafe,s as rejectCredential};
1
+ const r=/[\r\n]/,s=255,i=/^bearer$/i;function a(t){for(let e=0;e<t.length;e+=1){const n=t.charCodeAt(e);if(n===0||n>255)return!0}return!1}function c(t,e){if(!e)return"Enter a value before saving.";if(r.test(e))return"The value contains a line break. Paste it as a single line and save again.";if(a(e))return"The value contains a character that cannot be sent in an HTTP header, such as a curly quote or an invisible character. Copy the value again as plain text and save.";if(t.kind==="cookie")return o(t.name,e);if((t.kind==="bearer"||t.kind==="oauth2ClientCredentials")&&i.test(e))return"Paste the token that follows the word Bearer, not only the word."}function o(t,e){if(e.includes(";")||e.toLowerCase().includes(`${t.toLowerCase()}=`))return`This looks like a whole cookie header. Paste only the value of the ${t} cookie, without the "${t}=" prefix and without any other name=value pairs.`}function h(t,e){if(!(!r.test(e)&&!a(e)))throw new Error(`The credential cannot be sent as the ${t} header value.`)}export{h as assertHeaderSafe,c as rejectCredential};
@@ -1,6 +1,6 @@
1
1
  import type { InputRequiredResult } from '@modelcontextprotocol/server';
2
2
  import type { UpstreamAuthRequiredEvent } from './upstream-auth.js';
3
- import type { SchemeChoice, UpstreamApiAuth, UpstreamAuthScheme } from './upstream-auth-scheme.js';
3
+ import type { UpstreamApiAuth, UpstreamAuthScheme } from './upstream-auth-scheme.js';
4
4
  import type { KvService } from '@redocly/config';
5
5
  export declare const CREDENTIALS_INPUT_REQUEST_KEY = "credentials";
6
6
  export type CredentialTarget = {
@@ -71,11 +71,5 @@ export declare function buildUpstreamCredentialFallback(request: CredentialElici
71
71
  * likely a permissions problem than a missing key.
72
72
  */
73
73
  export declare function buildCredentialsToolHint(event: UpstreamAuthRequiredEvent, schemeLabel?: string): string;
74
- /**
75
- * Text for an operation that accepts several security schemes and has no stored credential for
76
- * any of them. Picking one here is what sent an API key as a session cookie, so the model is told
77
- * to ask the user which credential they hold and pass it back as `scheme`.
78
- */
79
- export declare function buildSchemeChoiceHint(event: UpstreamAuthRequiredEvent, choices: readonly SchemeChoice[]): string;
80
74
  export {};
81
75
  //# sourceMappingURL=elicitation.d.ts.map
@@ -1,6 +1,5 @@
1
- import{inputRequired as u,inputResponse as A}from"@modelcontextprotocol/server";import{withPathPrefix as I}from"@redocly/theme/core/utils";import{MCP_CREDENTIALS_ROUTE as P}from"../../../constants/mcp.js";import{MANAGE_API_CREDENTIALS_TOOL_NAME as h}from"../constants.js";import{secretStore as d,ELICITATION_TTL_MS as g}from"./secret-store.js";import{operationsForScheme as k,orderedSchemesOf as E}from"./upstream-auth-scheme.js";import{ANONYMOUS_SUBJECT_PREFIX as p}from"./subject.js";const m="credentials",l=new Map;function F(e,t){const r=l.get(e);if(r)return r;const n=t().finally(()=>{l.delete(e)});return l.set(e,n),n}function H(e){return!!e?.elicitation?.url}function D(e){return e.envelope!==void 0}function q(e){const t=A(e,m);if(t.kind==="elicit")return t.action==="accept"?"accepted":"declined"}function B(e,t){return[`The user accepted the prompt to add credentials for the "${e}" API.`,...t?["The credentials page:",t]:[],"",`Wait until the user says they saved the credentials, then retry the call that needed them. Do not call \`${h}\` again unless the user asks for a new link.`].join(`
2
- `)}async function Y(e,{kv:t,subject:r,baseUrl:n,apis:a}){if(typeof e!="string")return;const i=await d.peekElicitation(t,e);if(!(i?.subject!==r||!a.includes(i.api)))return{apiName:i.name,url:w(n,e)}}function W(e,t){return Object.keys(e).length>1?t:void 0}async function z(e){const{token:t,url:r}=await $(e);return u({inputRequests:{[m]:u.elicitUrl({message:C(e),url:r})},requestState:t})}async function G(e){const{url:t}=await $(e);return O(e,t,S(e.subject))}function J(e,t){const r=f(e);if(e.status===401&&!e.sentScheme){const[i,o]=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}. ${i}`,"",o].join(`
3
- `)}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}.`,a=t?`api: "${e.api}" and scheme: "${t}"`:`api: "${e.api}"`;return[n,"",`Do not retry the same call. Call \`${h}\` with ${a} 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(`
4
- `)}function f({status:e,detail:t}){return t?`HTTP ${e}: ${t}`:`HTTP ${e}`}function K(e,t){const r=t.map(({name:n,label:a,description:i})=>`- ${n} \u2014 ${a}${i?`: ${i}`:""}`);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 \`${h}\` with api: "${e.api}" and scheme set to the name they picked to get a link where they enter it.`].join(`
5
- `)}async function $({kv:e,subject:t,baseUrl:r,target:n,auth:a,apiAuth:i,hasExistingSecret:o}){const s=i?await b(e,t,n.api,i):[],c=await d.createElicitation(e,{subject:t,api:n.api,name:n.name,scheme:n.scheme,...n.schemeLabel?{schemeLabel:n.schemeLabel}:{},auth:a,hasExistingSecret:o,...s.length>1?{schemes:s}:{}});return{token:c,url:w(r,c)}}async function b(e,t,r,n){const i=(await d.getSecretsForSubject(e,t))[r]??{};return E(n.schemes).map(o=>{const s=k(n,o),c=n.descriptions?.[o];return{name:o,...c?{label:c}:{},auth:n.schemes[o],hasExistingSecret:!!i[o],...s.length>0?{operations:s}:{}}})}function S(e){return e.startsWith(p)?e.slice(p.length):void 0}function C({target:e,hasExistingSecret:t,reason:r}){const n=`The link works for ${T()} minutes.`,a=x(e),i=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 ${a}. They go straight to the API and never enter the chat. ${n}`:`${v(a)} needs credentials.${i} Open this page in a browser to paste them - they go straight to the API and never enter the chat. ${n}`}function x({name:e,schemeLabel:t}){return t?`the "${t}" scheme of the "${e}" API`:`the "${e}" API`}function v(e){return e.charAt(0).toUpperCase()+e.slice(1)}function T(){return Math.round(g/6e4)}function w(e,t){const r=I(P);if(!e)return`${r}?token=${t}`;try{const n=new URL(r,e);return n.searchParams.set("token",t),n.toString()}catch{return`${e}${r}?token=${t}`}}function O({target:e,reason:t,hasExistingSecret:r},n,a){const o=[`**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.`]:[],a?`Once the user confirms they saved them, call this tool again with sessionHandle: "${a}" - 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."],s=t.kind==="authFailure"?t.otherApiNames??[]:[];if(s.length>0){const c=s.map(y=>`"${y}"`).join(", ");o.push("",`The remaining APIs (${c}) will prompt for credentials on subsequent calls.`)}return o.join(`
6
- `)}export{m as CREDENTIALS_INPUT_REQUEST_KEY,Y as acceptedCredentialsLink,B as buildCredentialsAcceptedHint,J as buildCredentialsToolHint,K as buildSchemeChoiceHint,G as buildUpstreamCredentialFallback,z as buildUpstreamCredentialInputRequired,q as credentialElicitationAnswer,F as dedupeElicitation,D as isStatelessRequest,W as schemeLabelOf,H as supportsUrlElicitation};
1
+ import{inputRequired as h,inputResponse as y}from"@modelcontextprotocol/server";import{withPathPrefix as I}from"@redocly/theme/core/utils";import{MCP_CREDENTIALS_ROUTE as A}from"../../../constants/mcp.js";import{MANAGE_API_CREDENTIALS_TOOL_NAME as u}from"../constants.js";import{secretStore as l,ELICITATION_TTL_MS as P}from"./secret-store.js";import{operationsForScheme as E,orderedSchemesOf as g}from"./upstream-auth-scheme.js";import{ANONYMOUS_SUBJECT_PREFIX as p}from"./subject.js";const m="credentials",d=new Map;function F(e,t){const r=d.get(e);if(r)return r;const n=t().finally(()=>{d.delete(e)});return d.set(e,n),n}function D(e){return!!e?.elicitation?.url}function H(e){return e.envelope!==void 0}function q(e){const t=y(e,m);if(t.kind==="elicit")return t.action==="accept"?"accepted":"declined"}function B(e,t){return[`The user accepted the prompt to add credentials for the "${e}" API.`,...t?["The credentials page:",t]:[],"",`Wait until the user says they saved the credentials, then retry the call that needed them. Do not call \`${u}\` again unless the user asks for a new link.`].join(`
2
+ `)}async function Y(e,{kv:t,subject:r,baseUrl:n,apis:o}){if(typeof e!="string")return;const i=await l.peekElicitation(t,e);if(!(i?.subject!==r||!o.includes(i.api)))return{apiName:i.name,url:T(n,e)}}function W(e,t){return Object.keys(e).length>1?t:void 0}async function z(e){const{token:t,url:r}=await f(e);return h({inputRequests:{[m]:h.elicitUrl({message:C(e),url:r})},requestState:t})}async function G(e){const{url:t}=await f(e);return _(e,t,S(e.subject))}function J(e,t){const r=b(e);if(e.status===401&&!e.sentScheme){const[i,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}. ${i}`,"",s].join(`
3
+ `)}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}.`,o=t?`api: "${e.api}" and scheme: "${t}"`:`api: "${e.api}"`;return[n,"",`Do not retry the same call. Call \`${u}\` with ${o} 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(`
4
+ `)}function b({status:e,detail:t}){return t?`HTTP ${e}: ${t}`:`HTTP ${e}`}async function f({kv:e,subject:t,baseUrl:r,target:n,auth:o,apiAuth:i,hasExistingSecret:s}){const a=i?await k(e,t,n.api,i):[],c=await l.createElicitation(e,{subject:t,api:n.api,name:n.name,scheme:n.scheme,...n.schemeLabel?{schemeLabel:n.schemeLabel}:{},auth:o,hasExistingSecret:s,...a.length>1?{schemes:a}:{}});return{token:c,url:T(r,c)}}async function k(e,t,r,n){const i=(await l.getSecretsForSubject(e,t))[r]??{};return g(n.schemes).map(s=>{const a=E(n,s),c=n.descriptions?.[s];return{name:s,...c?{label:c}:{},auth:n.schemes[s],hasExistingSecret:!!i[s],...a.length>0?{operations:a}:{}}})}function S(e){return e.startsWith(p)?e.slice(p.length):void 0}function C({target:e,hasExistingSecret:t,reason:r}){const n=`The link works for ${$()} minutes.`,o=x(e),i=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 ${o}. They go straight to the API and never enter the chat. ${n}`:`${O(o)} needs credentials.${i} Open this page in a browser to paste them - they go straight to the API and never enter the chat. ${n}`}function x({name:e,schemeLabel:t}){return t?`the "${t}" scheme of the "${e}" API`:`the "${e}" API`}function O(e){return e.charAt(0).toUpperCase()+e.slice(1)}function $(){return Math.round(P/6e4)}function T(e,t){const r=I(A);if(!e)return`${r}?token=${t}`;try{const n=new URL(r,e);return n.searchParams.set("token",t),n.toString()}catch{return`${e}${r}?token=${t}`}}function _({target:e,reason:t,hasExistingSecret:r},n,o){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 ${$()} 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.`]:[],o?`Once the user confirms they saved them, call this tool again with sessionHandle: "${o}" - 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,Y as acceptedCredentialsLink,B as buildCredentialsAcceptedHint,J as buildCredentialsToolHint,G as buildUpstreamCredentialFallback,z as buildUpstreamCredentialInputRequired,q as credentialElicitationAnswer,F as dedupeElicitation,H as isStatelessRequest,W as schemeLabelOf,D as supportsUrlElicitation};
@@ -1 +1 @@
1
- import{Agent as Q}from"undici";import{envConfig as Z}from"../../../../config/env-config.js";import{logger as N}from"../../../../tools/notifiers/logger.js";import{assertUrlAllowed as I}from"./ssrf-guard.js";import{createSsrfSafeLookup as q}from"./ssrf-safe-lookup.js";import{SsrfBlockedError as W}from"./ssrf-blocklist.js";import{GatewayFetchBlockedError as R,GatewayFetchSystemError as ee,GatewayFetchUserError as g}from"./fetch-errors.js";import{redactHeaders as J,redactSecretsFromString as te}from"./redact.js";import{extractUpstreamDetail as re}from"./upstream-detail.js";import{normalizeFetchPath as ne}from"./normalize-path.js";import{reportGatewayFetch as K}from"./fetch-telemetry.js";import{logGatewayFetchAudit as V}from"./fetch-audit.js";const X="x-forwarded-for",oe=3e4,se=1024*1024,ae=new Set([401,403,407]);let C;function ce(){if(!C){const e=Z.isDevelopMode;e&&N.warn("Gateway MCP SSRF guard: loopback upstreams are ALLOWED (develop mode only, never in runtime)."),C=new Q({connect:{lookup:q({allowLoopback:e})}})}return C}function _e({allowedHosts:e,apis:t=[],authorization:r,onAuthRequired:n,fetchImpl:c=fetch,dispatcher:a=ce(),timeoutMs:h=oe,maxResponseBytes:l=se,maxFetchesPerExec:w,clientIp:k}){const f=[...e,...t.flatMap(o=>o.matchers)],$=[...new Set(t.map(o=>o.name).filter(Boolean))].join(", "),m=t.flatMap(o=>Object.values(o.secrets??{})),D=[r,...m.map(o=>o.value)].filter(o=>!!o),x=m.map(o=>o.header);let O=0;return async o=>{const y=o.method??"GET",T=Date.now();let B,b,A,E={},H,_,j;try{if(w!==void 0){const u=Math.max(0,w);if(O+=1,O>u)throw new g(`Outbound fetch budget exceeded (max ${u} fetches per execute); split the work across calls`)}const d=le(o.url,f,$);B=d.hostname,b=ne(d.pathname);const v=t.filter(u=>u.matchers.some(z=>z.test(d.hostname))),s=v.length===1?v[0]:void 0;A=s?.slug;const S=pe(o.securityScheme,s),F=S?[S]:s?ye(s,d.pathname,y):void 0,L=s&&F?Se(s,F):void 0,P=L?s?.secrets?.[L]:void 0,M=be({callerHeaders:o.headers,secret:P,authorization:r,clientIp:k,credentialHeaders:s?.credentialHeaders});E=M.headers,H=P&&!M.callerHeader?L:void 0;const G=new AbortController;j=setTimeout(()=>G.abort(),h);const i=await c(d,{method:y,headers:E,body:o.body,redirect:"manual",signal:G.signal,dispatcher:a});_=i.status;let U="";try{U=await we(i,l)}finally{if(ae.has(i.status)&&s&&n){const u=re(U,i.headers.get("content-type"),D);n({api:s.slug,name:s.name,status:i.status,...L?{scheme:L}:{},...F?.length?{schemes:[...F]}:{},...H?{sentScheme:H}:{},...M.callerHeader?{callerHeader:M.callerHeader}:{},...u?{detail:u}:{}})}}let p=Ae(i.headers);if(fe(i.status)){p=J(p,x);const{location:u}=p;u&&!he(u,d,f)&&delete p.location}return K({host:d.hostname,method:y,outcome:"success",durationMs:Date.now()-T,path:b,api:A,status:i.status,bytes:Buffer.byteLength(U,"utf8")}),V({rawUrl:d.href,method:y,host:d.hostname,outcome:"success",durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:i.status,injectedScheme:H,requestHeaders:E,requestBody:o.body,responseHeaders:p,responseBody:U}),{status:i.status,statusText:i.statusText,ok:i.ok,headers:p,bodyText:U}}catch(d){const{outcome:v,userSafe:s}=ie(d),S=B??(s instanceof R?s.host:void 0)??ue(o.url)??"invalid-url";throw K({host:S,method:y,outcome:v,durationMs:Date.now()-T,path:b,api:A,status:_}),V({rawUrl:o.url,method:y,host:S,outcome:v,durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:_,injectedScheme:H,requestHeaders:E,requestBody:o.body}),s||(N.error(`Gateway MCP fetch failed [${y} ${S}]: ${te(me(d),D)} headers=${JSON.stringify(J(E,x))}`),new ee("Upstream fetch failed due to an internal error"))}finally{j!==void 0&&clearTimeout(j)}}}function de(e){let t=e;for(let r=0;r<5&&t instanceof Error;r++){if(t instanceof g||t instanceof W)return t;t=t.cause}}function ie(e){const t=de(e);return{outcome:t instanceof R||t instanceof W?"blocked":t?"user_error":"system_error",userSafe:t}}function le(e,t,r){try{return I(e,t)}catch(n){throw n instanceof R&&r?new R(`${n.message}. \`fetch\` reaches only the documented hosts of the callable APIs (${r}); other documented APIs can be read through the tools but not called.`,n.host):n}}function ue(e){try{return new URL(e).hostname||void 0}catch{return}}function fe(e){return e>=300&&e<400}function he(e,t,r){try{return!!I(new URL(e,t).href,r)}catch{return!1}}function me(e){if(!(e instanceof Error))return String(e);const t=e.cause;return t instanceof Error?`${e.message}: ${t.message}`:e.message}async function we(e,t){const r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>t)throw Y(t,r);if(!e.body)return"";const n=e.body.getReader(),c=new TextDecoder;let a=0,h="";try{for(;;){const{done:l,value:w}=await n.read();if(l)break;if(a+=w.byteLength,a>t)throw Y(t,a);h+=c.decode(w,{stream:!0})}return h+c.decode()}finally{await n.cancel().catch(()=>{})}}function Y(e,t){return new g(`Response is too large (over ${e} bytes, got ${t}); request less data`)}function ye(e,t,r){const n=e.routes?.find(c=>c.method===r&&c.pattern.test(t));return n?n.schemes:ge(e)}function Se(e,t){const r=t.filter(n=>e.secrets?.[n]);return r.length===0?t[0]:r.reduce((n,c)=>{const a=e.secrets?.[n]?.savedAt??0;return(e.secrets?.[c]?.savedAt??0)>a?c:n})}function pe(e,t){if(e==null)return;if(typeof e!="string")throw new g("securityScheme must be a security scheme name (a string)");if(!t)throw new g("securityScheme cannot be applied: the URL host does not identify exactly one callable API");const r=t.schemePriority??[];if(r.length>0&&!r.includes(e))throw new g(`Unknown securityScheme "${e}" for ${t.name}; valid values: ${r.join(", ")}`);return e}function ge(e){const t=Object.keys(e.secrets??{});if(t.length===0)return e.defaultScheme?[e.defaultScheme]:[];const r=(e.schemePriority??[]).filter(n=>t.includes(n));return[...r,...t.filter(n=>!r.includes(n))]}function be({callerHeaders:e,secret:t,authorization:r,clientIp:n,credentialHeaders:c}){const a={},h=new Set,l=t??(r?{header:"Authorization",value:r}:void 0),w=l?new Set((c??[]).map(f=>f.toLowerCase()).filter(f=>f!==l.header.toLowerCase())):new Set;for(const[f,$]of Object.entries(e??{})){const m=f.toLowerCase();m==="host"||m==="content-length"||m!==X&&(w.has(m)||(h.add(m),a[f]=$))}if(n&&(a[X]=n),!l)return{headers:a};const k=l.header.toLowerCase();return h.has(k)?{headers:a,callerHeader:k}:(a[l.header]=l.value,{headers:a})}function Ae(e){const t={};return e.forEach((r,n)=>{t[n.toLowerCase()]=r}),t}export{_e as buildFetchBridge,ce as getDefaultAgent,we as readCappedBody};
1
+ import{Agent as Q}from"undici";import{envConfig as Z}from"../../../../config/env-config.js";import{logger as N}from"../../../../tools/notifiers/logger.js";import{assertUrlAllowed as I}from"./ssrf-guard.js";import{createSsrfSafeLookup as q}from"../../../../web-server/utils/ssrf-safe-lookup.js";import{SsrfBlockedError as W}from"../../../../web-server/utils/ssrf-blocklist.js";import{GatewayFetchBlockedError as R,GatewayFetchSystemError as ee,GatewayFetchUserError as g}from"./fetch-errors.js";import{redactHeaders as J,redactSecretsFromString as te}from"./redact.js";import{extractUpstreamDetail as re}from"./upstream-detail.js";import{normalizeFetchPath as ne}from"./normalize-path.js";import{reportGatewayFetch as K}from"./fetch-telemetry.js";import{logGatewayFetchAudit as V}from"./fetch-audit.js";const X="x-forwarded-for",oe=3e4,se=1024*1024,ae=new Set([401,403,407]);let C;function ce(){if(!C){const e=Z.isDevelopMode;e&&N.warn("Gateway MCP SSRF guard: loopback upstreams are ALLOWED (develop mode only, never in runtime)."),C=new Q({connect:{lookup:q({allowLoopback:e})}})}return C}function _e({allowedHosts:e,apis:t=[],authorization:r,onAuthRequired:n,fetchImpl:c=fetch,dispatcher:a=ce(),timeoutMs:h=oe,maxResponseBytes:l=se,maxFetchesPerExec:w,clientIp:k}){const f=[...e,...t.flatMap(o=>o.matchers)],$=[...new Set(t.map(o=>o.name).filter(Boolean))].join(", "),m=t.flatMap(o=>Object.values(o.secrets??{})),D=[r,...m.map(o=>o.value)].filter(o=>!!o),x=m.map(o=>o.header);let O=0;return async o=>{const y=o.method??"GET",T=Date.now();let B,b,A,E={},H,_,j;try{if(w!==void 0){const u=Math.max(0,w);if(O+=1,O>u)throw new g(`Outbound fetch budget exceeded (max ${u} fetches per execute); split the work across calls`)}const d=le(o.url,f,$);B=d.hostname,b=ne(d.pathname);const v=t.filter(u=>u.matchers.some(z=>z.test(d.hostname))),s=v.length===1?v[0]:void 0;A=s?.slug;const S=pe(o.securityScheme,s),F=S?[S]:s?ye(s,d.pathname,y):void 0,L=s&&F?Se(s,F):void 0,P=L?s?.secrets?.[L]:void 0,M=be({callerHeaders:o.headers,secret:P,authorization:r,clientIp:k,credentialHeaders:s?.credentialHeaders});E=M.headers,H=P&&!M.callerHeader?L:void 0;const G=new AbortController;j=setTimeout(()=>G.abort(),h);const i=await c(d,{method:y,headers:E,body:o.body,redirect:"manual",signal:G.signal,dispatcher:a});_=i.status;let U="";try{U=await we(i,l)}finally{if(ae.has(i.status)&&s&&n){const u=re(U,i.headers.get("content-type"),D);n({api:s.slug,name:s.name,status:i.status,...L?{scheme:L}:{},...F?.length?{schemes:[...F]}:{},...H?{sentScheme:H}:{},...M.callerHeader?{callerHeader:M.callerHeader}:{},...u?{detail:u}:{}})}}let p=Ae(i.headers);if(fe(i.status)){p=J(p,x);const{location:u}=p;u&&!he(u,d,f)&&delete p.location}return K({host:d.hostname,method:y,outcome:"success",durationMs:Date.now()-T,path:b,api:A,status:i.status,bytes:Buffer.byteLength(U,"utf8")}),V({rawUrl:d.href,method:y,host:d.hostname,outcome:"success",durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:i.status,injectedScheme:H,requestHeaders:E,requestBody:o.body,responseHeaders:p,responseBody:U}),{status:i.status,statusText:i.statusText,ok:i.ok,headers:p,bodyText:U}}catch(d){const{outcome:v,userSafe:s}=ie(d),S=B??(s instanceof R?s.host:void 0)??ue(o.url)??"invalid-url";throw K({host:S,method:y,outcome:v,durationMs:Date.now()-T,path:b,api:A,status:_}),V({rawUrl:o.url,method:y,host:S,outcome:v,durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:_,injectedScheme:H,requestHeaders:E,requestBody:o.body}),s||(N.error(`Gateway MCP fetch failed [${y} ${S}]: ${te(me(d),D)} headers=${JSON.stringify(J(E,x))}`),new ee("Upstream fetch failed due to an internal error"))}finally{j!==void 0&&clearTimeout(j)}}}function de(e){let t=e;for(let r=0;r<5&&t instanceof Error;r++){if(t instanceof g||t instanceof W)return t;t=t.cause}}function ie(e){const t=de(e);return{outcome:t instanceof R||t instanceof W?"blocked":t?"user_error":"system_error",userSafe:t}}function le(e,t,r){try{return I(e,t)}catch(n){throw n instanceof R&&r?new R(`${n.message}. \`fetch\` reaches only the documented hosts of the callable APIs (${r}); other documented APIs can be read through the tools but not called.`,n.host):n}}function ue(e){try{return new URL(e).hostname||void 0}catch{return}}function fe(e){return e>=300&&e<400}function he(e,t,r){try{return!!I(new URL(e,t).href,r)}catch{return!1}}function me(e){if(!(e instanceof Error))return String(e);const t=e.cause;return t instanceof Error?`${e.message}: ${t.message}`:e.message}async function we(e,t){const r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>t)throw Y(t,r);if(!e.body)return"";const n=e.body.getReader(),c=new TextDecoder;let a=0,h="";try{for(;;){const{done:l,value:w}=await n.read();if(l)break;if(a+=w.byteLength,a>t)throw Y(t,a);h+=c.decode(w,{stream:!0})}return h+c.decode()}finally{await n.cancel().catch(()=>{})}}function Y(e,t){return new g(`Response is too large (over ${e} bytes, got ${t}); request less data`)}function ye(e,t,r){const n=e.routes?.find(c=>c.method===r&&c.pattern.test(t));return n?n.schemes:ge(e)}function Se(e,t){const r=t.filter(n=>e.secrets?.[n]);return r.length===0?t[0]:r.reduce((n,c)=>{const a=e.secrets?.[n]?.savedAt??0;return(e.secrets?.[c]?.savedAt??0)>a?c:n})}function pe(e,t){if(e==null)return;if(typeof e!="string")throw new g("securityScheme must be a security scheme name (a string)");if(!t)throw new g("securityScheme cannot be applied: the URL host does not identify exactly one callable API");const r=t.schemePriority??[];if(r.length>0&&!r.includes(e))throw new g(`Unknown securityScheme "${e}" for ${t.name}; valid values: ${r.join(", ")}`);return e}function ge(e){const t=Object.keys(e.secrets??{});if(t.length===0)return e.defaultScheme?[e.defaultScheme]:[];const r=(e.schemePriority??[]).filter(n=>t.includes(n));return[...r,...t.filter(n=>!r.includes(n))]}function be({callerHeaders:e,secret:t,authorization:r,clientIp:n,credentialHeaders:c}){const a={},h=new Set,l=t??(r?{header:"Authorization",value:r}:void 0),w=l?new Set((c??[]).map(f=>f.toLowerCase()).filter(f=>f!==l.header.toLowerCase())):new Set;for(const[f,$]of Object.entries(e??{})){const m=f.toLowerCase();m==="host"||m==="content-length"||m!==X&&(w.has(m)||(h.add(m),a[f]=$))}if(n&&(a[X]=n),!l)return{headers:a};const k=l.header.toLowerCase();return h.has(k)?{headers:a,callerHeader:k}:(a[l.header]=l.value,{headers:a})}function Ae(e){const t={};return e.forEach((r,n)=>{t[n.toLowerCase()]=r}),t}export{_e as buildFetchBridge,ce as getDefaultAgent,we as readCappedBody};
@@ -1 +1 @@
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};
1
+ import{isIP as d}from"node:net";import{isHostAllowed as h}from"./allowed-hosts.js";import{isBlockedIp as w}from"../../../../web-server/utils/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};
@@ -1 +1 @@
1
- import{isIP as l}from"node:net";import{getFeedbackClientIp as a}from"../../../../web-server/utils/feedback-ip.js";import{extractMappedIpv4 as c}from"../fetch/ssrf-blocklist.js";function I(t){const n=a(t);if(n)return f(n)}function f(t){if(l(t)===6){const n=c(t);return n||`${u(t)}::/64`}return t}function u(t){const n=t.split("%")[0],[e,i=""]=n.split("::"),r=e?e.split(":"):[],o=i?i.split(":"):[],s=8-r.length-o.length;return[...r,...Array(Math.max(0,s)).fill("0"),...o].slice(0,4).map(p=>parseInt(p||"0",16).toString(16)).join(":")}export{I as ipRateLimitKey};
1
+ import{isIP as l}from"node:net";import{getFeedbackClientIp as a}from"../../../../web-server/utils/feedback-ip.js";import{extractMappedIpv4 as c}from"../../../../web-server/utils/ssrf-blocklist.js";function I(t){const n=a(t);if(n)return f(n)}function f(t){if(l(t)===6){const n=c(t);return n||`${u(t)}::/64`}return t}function u(t){const n=t.split("%")[0],[e,i=""]=n.split("::"),r=e?e.split(":"):[],o=i?i.split(":"):[],s=8-r.length-o.length;return[...r,...Array(Math.max(0,s)).fill("0"),...o].slice(0,4).map(p=>parseInt(p||"0",16).toString(16)).join(":")}export{I as ipRateLimitKey};
@@ -27,15 +27,9 @@ export type UpstreamApiAuth = {
27
27
  routes: UpstreamAuthRoute[];
28
28
  descriptions?: Record<string, string>;
29
29
  };
30
- export type SchemeChoice = {
31
- name: string;
32
- label: string;
33
- description?: string;
34
- };
35
30
  type SecuritySchemeLoader = typeof getApiDescriptionFromFs;
36
31
  export declare const DEFAULT_SCHEME_NAME = "default";
37
32
  export declare function resolveUpstreamApiAuth(context: McpToolContext, apiRelativePath: string, loadDescription?: SecuritySchemeLoader): Promise<UpstreamApiAuth>;
38
- export declare function schemeChoicesOf(auth: UpstreamApiAuth, names: readonly string[]): SchemeChoice[];
39
33
  export declare function credentialHeadersOf(schemes: Record<string, UpstreamAuthScheme>): string[];
40
34
  export declare function orderedSchemesOf(schemes: Record<string, UpstreamAuthScheme>): string[];
41
35
  export declare function operationsForScheme(auth: UpstreamApiAuth, scheme: string): string[];
@@ -1,2 +1,2 @@
1
- import{getApiDescriptionFromFs as O}from"../docs-mcp/tools/openapi/utils.js";import{OPERATION_METHODS as S}from"../docs-mcp/tools/openapi/constants.js";const A=120,l="default",g={kind:"raw"},h=["oauth2ClientCredentials","bearer","apiKey","cookie","raw"],w=new Set(S),C=/\{(?<!\{[^}]*?\{)[^}]*\}/g;function c(){return{schemes:{[l]:g},defaultScheme:l,routes:[]}}async function L(e,t,n=O){const r=Object.values(e.apiDescriptionsMap??{}).find(i=>i.relativePath===t);if(!r)return c();try{const i=await n({relativePath:r.relativePath,outdir:e.outdir||"",user:e.user,rbac:e.config?.access?.rbac||{},requiresLogin:!!e.config?.access?.requiresLogin});return i?E(i,r.servers??[]):c()}catch{return c()}}function E(e,t){const n=$(e),r=Object.keys(n);if(r.length===0)return c();const i=m(e.security,n)[0]??a(r,n)[0],o=x(e,r);return{schemes:n,defaultScheme:i,routes:v(e,n,t),...Object.keys(o).length>0?{descriptions:o}:{}}}function N(e,t){return t.flatMap(n=>{const r=e.schemes[n];if(!r)return[];const i=e.descriptions?.[n];return[{name:n,label:j(r),...i?{description:i}:{}}]})}function U(e){return[...new Set(Object.values(e).map(P))]}function q(e){return a(Object.keys(e),e)}function z(e,t){const n=new Set;for(const r of e.routes)r.schemes.includes(t)&&n.add(`${r.method} ${r.path}`);return[...n]}function P(e){return e.kind==="apiKey"?e.header:e.kind==="cookie"?"Cookie":"Authorization"}function j(e){switch(e.kind){case"bearer":return"API key or bearer token";case"cookie":return`browser session cookie (${e.name})`;case"apiKey":return`API key in the ${e.header} header`;case"oauth2ClientCredentials":return"OAuth2 client credentials";default:return"Authorization header value"}}function x(e,t){const n={};for(const r of t){const i=e.components?.securitySchemes?.[r],o=k(i)?i.description:void 0;if(typeof o!="string")continue;const s=o.split(`
2
- `)[0].trim();s&&(n[r]=s.slice(0,A))}return n}function $(e){const t={};for(const[n,r]of Object.entries(e.components?.securitySchemes??{})){if(!k(r))continue;const i=T(r);i&&(t[n]=i)}return t}function T(e){if(e.type==="oauth2"){const t=e.flows?.clientCredentials;return t?{kind:"oauth2ClientCredentials",tokenUrl:t.tokenUrl,scopes:Object.keys(t.scopes??{})}:{kind:"bearer"}}if(e.type==="http"&&e.scheme==="bearer")return{kind:"bearer"};if(e.type==="apiKey"&&e.in==="header")return{kind:"apiKey",header:e.name||"X-Api-Key"};if(e.type==="apiKey"&&e.in==="cookie"&&e.name)return{kind:"cookie",name:e.name}}function a(e,t){return[...e].sort((n,r)=>h.indexOf(t[n].kind)-h.indexOf(t[r].kind)||e.indexOf(n)-e.indexOf(r))}function m(e,t){const n=[];for(const r of e??[])for(const i of Object.keys(r))t[i]&&!n.includes(i)&&n.push(i);return n}function v(e,t,n){const r=I(n),i=[];for(const[o,s]of Object.entries(e.paths??{})){if(!s||typeof s!="object")continue;const f=H(r,o);if(f)for(const[p,b]of Object.entries(s)){if(!w.has(p.toLowerCase()))continue;const u=b?.security??e.security;if(u===void 0)continue;const d=m(u,t);d.length===0&&u.length>0||i.push({pattern:f,path:o,method:p.toUpperCase(),schemes:a(d,t)})}}return i}function H(e,t){if(t.startsWith("/"))return new RegExp(`^${e}${y(t)}/?$`)}function y(e){return e.split(C).map(_).join("[^/]+").replace(/(?<!\/)\/+$/,"")}function I(e){const t=[...new Set(e.map(n=>R(n.url)).filter(Boolean).map(y))];return t.length>0?`(?:${t.join("|")})?`:""}function R(e){if(!e)return"";const t=e.replace(/^[a-z][a-z0-9+.-]*:\/\//i,""),n=t.indexOf("/");return n===-1?"":t.slice(n).split(/[?#]/)[0].replace(/(?<!\/)\/+$/,"")}function _(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function k(e){return typeof e=="object"&&e!==null&&"type"in e}export{l as DEFAULT_SCHEME_NAME,U as credentialHeadersOf,z as operationsForScheme,q as orderedSchemesOf,L as resolveUpstreamApiAuth,N as schemeChoicesOf};
1
+ import{getApiDescriptionFromFs as S}from"../docs-mcp/tools/openapi/utils.js";import{OPERATION_METHODS as b}from"../docs-mcp/tools/openapi/constants.js";const A=120,l="default",g={kind:"raw"},h=["oauth2ClientCredentials","bearer","apiKey","cookie","raw"],E=new Set(b),j=/\{(?<!\{[^}]*?\{)[^}]*\}/g;function c(){return{schemes:{[l]:g},defaultScheme:l,routes:[]}}async function L(e,t,n=S){const r=Object.values(e.apiDescriptionsMap??{}).find(i=>i.relativePath===t);if(!r)return c();try{const i=await n({relativePath:r.relativePath,outdir:e.outdir||"",user:e.user,rbac:e.config?.access?.rbac||{},requiresLogin:!!e.config?.access?.requiresLogin});return i?w(i,r.servers??[]):c()}catch{return c()}}function w(e,t){const n=x(e),r=Object.keys(n);if(r.length===0)return c();const i=m(e.security,n)[0]??a(r,n)[0],o=P(e,r);return{schemes:n,defaultScheme:i,routes:H(e,n,t),...Object.keys(o).length>0?{descriptions:o}:{}}}function M(e){return[...new Set(Object.values(e).map(C))]}function N(e){return a(Object.keys(e),e)}function U(e,t){const n=new Set;for(const r of e.routes)r.schemes.includes(t)&&n.add(`${r.method} ${r.path}`);return[...n]}function C(e){return e.kind==="apiKey"?e.header:e.kind==="cookie"?"Cookie":"Authorization"}function P(e,t){const n={};for(const r of t){const i=e.components?.securitySchemes?.[r],o=k(i)?i.description:void 0;if(typeof o!="string")continue;const s=o.split(`
2
+ `)[0].trim();s&&(n[r]=s.slice(0,A))}return n}function x(e){const t={};for(const[n,r]of Object.entries(e.components?.securitySchemes??{})){if(!k(r))continue;const i=T(r);i&&(t[n]=i)}return t}function T(e){if(e.type==="oauth2"){const t=e.flows?.clientCredentials;return t?{kind:"oauth2ClientCredentials",tokenUrl:t.tokenUrl,scopes:Object.keys(t.scopes??{})}:{kind:"bearer"}}if(e.type==="openIdConnect")return{kind:"bearer"};if(e.type==="http"&&e.scheme?.toLowerCase()==="bearer")return{kind:"bearer"};if(e.type==="apiKey"&&e.in==="header")return{kind:"apiKey",header:e.name||"X-Api-Key"};if(e.type==="apiKey"&&e.in==="cookie"&&e.name)return{kind:"cookie",name:e.name}}function a(e,t){return[...e].sort((n,r)=>h.indexOf(t[n].kind)-h.indexOf(t[r].kind)||e.indexOf(n)-e.indexOf(r))}function m(e,t){const n=[];for(const r of e??[])for(const i of Object.keys(r))t[i]&&!n.includes(i)&&n.push(i);return n}function H(e,t,n){const r=_(n),i=[];for(const[o,s]of Object.entries(e.paths??{})){if(!s||typeof s!="object")continue;const f=R(r,o);if(f)for(const[p,O]of Object.entries(s)){if(!E.has(p.toLowerCase()))continue;const u=O?.security??e.security;if(u===void 0)continue;const d=m(u,t);d.length===0&&u.length>0||i.push({pattern:f,path:o,method:p.toUpperCase(),schemes:a(d,t)})}}return i}function R(e,t){if(t.startsWith("/"))return new RegExp(`^${e}${y(t)}/?$`)}function y(e){return e.split(j).map(v).join("[^/]+").replace(/(?<!\/)\/+$/,"")}function _(e){const t=[...new Set(e.map(n=>$(n.url)).filter(Boolean).map(y))];return t.length>0?`(?:${t.join("|")})?`:""}function $(e){if(!e)return"";const t=e.replace(/^[a-z][a-z0-9+.-]*:\/\//i,""),n=t.indexOf("/");return n===-1?"":t.slice(n).split(/[?#]/)[0].replace(/(?<!\/)\/+$/,"")}function v(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function k(e){return typeof e=="object"&&e!==null&&"type"in e}export{l as DEFAULT_SCHEME_NAME,M as credentialHeadersOf,U as operationsForScheme,N as orderedSchemesOf,L as resolveUpstreamApiAuth};
@@ -1 +1 @@
1
- import{secretStore as u}from"../gateway-mcp/secret-store.js";import{rejectCredential as y}from"../gateway-mcp/credential-validation.js";import{buildAllowedHostMatchers as R}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as j}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as v,getDefaultAgent as O}from"../gateway-mcp/fetch/fetch-bridge.js";import{logger as N}from"../../../tools/notifiers/logger.js";import{clearedPage as F,formPage as x,multiOutcomePage as I,notFoundPage as D,successPage as $}from"./mcp-credentials-page.js";const w={"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","X-Frame-Options":"DENY","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; form-action 'self'"},M=3e4,U=64*1024;let P=fetch;function q(e){P=e}const B=async(e,i)=>{const t=await i.getKv();if(e.method==="GET"){const n=new URL(e.url).searchParams.get("token")??"",o=await u.peekElicitation(t,n);return o?new Response(x(o,n),{status:200,headers:w}):m()}if(e.method==="POST"){const n=await e.formData(),o=d(n,"token"),a=d(n,"mode")||"token";return a==="multi"?z(t,n,o):a==="client-credentials"?K(t,n,o):a==="clear"?H(t,o):G(t,n,o)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function G(e,i,t){const n=d(i,"secret").trim(),o=await u.peekElicitation(e,t);if(!o)return m();const a=y(o.auth,n);if(a)return h(o,t,a);const l=await u.consumeElicitation(e,t);return l?(await u.setSecret(e,l.subject,l.api,l.scheme,E(l.auth,n)),new Response($(l),{status:200,headers:w})):m()}async function H(e,i){const t=await u.consumeElicitation(e,i);return t?(await u.deleteSecret(e,t.subject,t.api,t.scheme),new Response(F(t),{status:200,headers:w})):m()}async function z(e,i,t){const n=await u.peekElicitation(e,t);if(!n?.schemes||n.schemes.length<=1)return m();const o=n.schemes,a=[];for(let r=0;r<o.length;r++){const s=o[r],p=d(i,`secret__${r}`).trim(),S=d(i,`client_id__${r}`).trim(),b=d(i,`client_secret__${r}`).trim();if(s.hasExistingSecret&&d(i,`remove__${r}`)){if(p||S||b)return h(n,t,`${s.name}: enter a new value or tick "Remove the stored credential", not both.`);a.push({kind:"remove",scheme:s.name});continue}if(s.auth.kind==="oauth2ClientCredentials"){if(p){const C=y(s.auth,p);if(C)return h(n,t,`${s.name}: ${C}`);a.push({kind:"set",scheme:s.name,secret:E(s.auth,p)})}else if(S&&b)a.push({kind:"exchange",scheme:s.name,auth:s.auth,clientId:S,clientSecret:b});else if(S||b)return h(n,t,`${s.name}: enter both the client ID and the client secret, or leave both blank.`);continue}if(!p)continue;const _=y(s.auth,p);if(_)return h(n,t,`${s.name}: ${_}`);a.push({kind:"set",scheme:s.name,secret:E(s.auth,p)})}if(a.length===0)return h(n,t,"Fill in at least one credential, or check a box to remove one, before saving.");const l=[];for(const r of a){if(r.kind!=="exchange"){l.push(r);continue}const s=await T(r.auth,r.clientId,r.clientSecret);if(!s.ok)return A(n,t,s.reason,r.scheme);l.push({kind:"set",scheme:r.scheme,secret:s.secret})}const c=await u.consumeElicitation(e,t);if(!c)return m();for(const r of l)r.kind==="remove"?await u.deleteSecret(e,c.subject,c.api,r.scheme):await u.setSecret(e,c.subject,c.api,r.scheme,r.secret);const k=await u.getSecretsForSubject(e,c.subject),f={saved:l.filter(r=>r.kind==="set").map(r=>r.scheme),removed:l.filter(r=>r.kind==="remove").map(r=>r.scheme),stored:Object.keys(k[c.api]??{})};return new Response(I(c,f),{status:200,headers:w})}async function K(e,i,t){const n=d(i,"client_id").trim(),o=d(i,"client_secret").trim(),a=await u.peekElicitation(e,t);if(!a||a.auth.kind!=="oauth2ClientCredentials")return m();if(!n||!o)return h(a,t,"Enter both the client ID and the client secret before saving.");const l=await T(a.auth,n,o);if(!l.ok)return A(a,t,l.reason);const c=await u.consumeElicitation(e,t);return c?(await u.setSecret(e,c.subject,c.api,c.scheme,l.secret),new Response($(c),{status:200,headers:w})):m()}async function T(e,i,t){try{const n=R([{url:e.tokenUrl}]),o=j(e.tokenUrl,n),a=new AbortController,l=setTimeout(()=>a.abort(),M);let c;try{c=await P(o,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:i,client_secret:t}),redirect:"manual",signal:a.signal,dispatcher:O()})}finally{clearTimeout(l)}if(!c.ok)return g(`token endpoint returned ${c.status}`);let k;try{k=await v(c,U)}catch{return g("token response exceeded the size cap")}let f;try{f=JSON.parse(k)}catch{return g("token response was not valid JSON")}const r=typeof f=="object"&&f!==null&&"access_token"in f?f.access_token:void 0,s=typeof r=="string"?r.trim():"";return s?{ok:!0,secret:{header:"Authorization",value:`Bearer ${s}`}}:g("token response had no access_token")}catch(n){return g(n instanceof Error?n.message:String(n))}}function g(e){return{ok:!1,reason:e}}function A(e,i,t,n){return N.warn(`gateway oauth2 client_credentials exchange failed for ${e.api}: ${t}`),h(e,i,`${n?`${n}: we`:"We"} could not exchange those client credentials for a token. Check the client ID and secret, then try again.`)}function d(e,i){const t=e.get(i);return typeof t=="string"?t:""}function h(e,i,t){return new Response(x(e,i,t),{status:400,headers:w})}function m(){return new Response(D(),{status:404,headers:w})}function E(e,i){return e.kind==="apiKey"?{header:e.header,value:i}:e.kind==="cookie"?{header:"Cookie",value:`${e.name}=${i}`}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:X(i)}:{header:"Authorization",value:i}}function X(e){const i=e.trim();return i.toLowerCase().startsWith("bearer")?i:`Bearer ${i}`}var ee=B;export{ee as default,q as setCredentialsFetchImpl};
1
+ import{secretStore as u}from"../gateway-mcp/secret-store.js";import{rejectCredential as b}from"../gateway-mcp/credential-validation.js";import{buildAllowedHostMatchers as A}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as j}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as v,getDefaultAgent as O}from"../gateway-mcp/fetch/fetch-bridge.js";import{logger as F}from"../../../tools/notifiers/logger.js";import{clearedPage as I,formPage as x,multiOutcomePage as N,notFoundPage as D,successPage as $}from"./mcp-credentials-page.js";const g={"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","X-Frame-Options":"DENY","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; form-action 'self'"},B=3e4,M=64*1024,U=/^bearer\s+/i;let P=fetch;function ee(e){P=e}const G=async(e,i)=>{const t=await i.getKv();if(e.method==="GET"){const n=new URL(e.url).searchParams.get("token")??"",o=await u.peekElicitation(t,n);return o?new Response(x(o,n),{status:200,headers:g}):m()}if(e.method==="POST"){const n=await e.formData(),o=d(n,"token"),s=d(n,"mode")||"token";return s==="multi"?z(t,n,o):s==="client-credentials"?K(t,n,o):s==="clear"?X(t,o):H(t,n,o)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function H(e,i,t){const n=d(i,"secret").trim(),o=await u.peekElicitation(e,t);if(!o)return m();const s=b(o.auth,n);if(s)return h(o,t,s);const l=await u.consumeElicitation(e,t);return l?(await u.setSecret(e,l.subject,l.api,l.scheme,S(l.auth,n)),new Response($(l),{status:200,headers:g})):m()}async function X(e,i){const t=await u.consumeElicitation(e,i);return t?(await u.deleteSecret(e,t.subject,t.api,t.scheme),new Response(I(t),{status:200,headers:g})):m()}async function z(e,i,t){const n=await u.peekElicitation(e,t);if(!n?.schemes||n.schemes.length<=1)return m();const o=n.schemes,s=[];for(let r=0;r<o.length;r++){const a=o[r],p=d(i,`secret__${r}`).trim(),E=d(i,`client_id__${r}`).trim(),_=d(i,`client_secret__${r}`).trim();if(a.hasExistingSecret&&d(i,`remove__${r}`)){if(p||E||_)return h(n,t,`${a.name}: enter a new value or tick "Remove the stored credential", not both.`);s.push({kind:"remove",scheme:a.name});continue}if(a.auth.kind==="oauth2ClientCredentials"){if(p){const C=b(a.auth,p);if(C)return h(n,t,`${a.name}: ${C}`);s.push({kind:"set",scheme:a.name,secret:S(a.auth,p)})}else if(E&&_)s.push({kind:"exchange",scheme:a.name,auth:a.auth,clientId:E,clientSecret:_});else if(E||_)return h(n,t,`${a.name}: enter both the client ID and the client secret, or leave both blank.`);continue}if(!p)continue;const y=b(a.auth,p);if(y)return h(n,t,`${a.name}: ${y}`);s.push({kind:"set",scheme:a.name,secret:S(a.auth,p)})}if(s.length===0)return h(n,t,"Fill in at least one credential, or check a box to remove one, before saving.");const l=[];for(const r of s){if(r.kind!=="exchange"){l.push(r);continue}const a=await R(r.auth,r.clientId,r.clientSecret);if(!a.ok)return T(n,t,a.reason,r.scheme);l.push({kind:"set",scheme:r.scheme,secret:a.secret})}const c=await u.consumeElicitation(e,t);if(!c)return m();for(const r of l)r.kind==="remove"?await u.deleteSecret(e,c.subject,c.api,r.scheme):await u.setSecret(e,c.subject,c.api,r.scheme,r.secret);const k=await u.getSecretsForSubject(e,c.subject),f={saved:l.filter(r=>r.kind==="set").map(r=>r.scheme),removed:l.filter(r=>r.kind==="remove").map(r=>r.scheme),stored:Object.keys(k[c.api]??{})};return new Response(N(c,f),{status:200,headers:g})}async function K(e,i,t){const n=d(i,"client_id").trim(),o=d(i,"client_secret").trim(),s=await u.peekElicitation(e,t);if(!s||s.auth.kind!=="oauth2ClientCredentials")return m();if(!n||!o)return h(s,t,"Enter both the client ID and the client secret before saving.");const l=await R(s.auth,n,o);if(!l.ok)return T(s,t,l.reason);const c=await u.consumeElicitation(e,t);return c?(await u.setSecret(e,c.subject,c.api,c.scheme,l.secret),new Response($(c),{status:200,headers:g})):m()}async function R(e,i,t){try{const n=A([{url:e.tokenUrl}]),o=j(e.tokenUrl,n),s=new AbortController,l=setTimeout(()=>s.abort(),B);let c;try{c=await P(o,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:i,client_secret:t}),redirect:"manual",signal:s.signal,dispatcher:O()})}finally{clearTimeout(l)}if(!c.ok)return w(`token endpoint returned ${c.status}`);let k;try{k=await v(c,M)}catch{return w("token response exceeded the size cap")}let f;try{f=JSON.parse(k)}catch{return w("token response was not valid JSON")}const r=typeof f=="object"&&f!==null&&"access_token"in f?f.access_token:void 0,a=typeof r=="string"?r.trim():"";return a?b(e,a)?w("token response had an access_token that cannot be sent in a header"):{ok:!0,secret:{header:"Authorization",value:`Bearer ${a}`}}:w("token response had no access_token")}catch(n){return w(n instanceof Error?n.message:String(n))}}function w(e){return{ok:!1,reason:e}}function T(e,i,t,n){return F.warn(`gateway oauth2 client_credentials exchange failed for ${e.api}: ${t}`),h(e,i,`${n?`${n}: we`:"We"} could not exchange those client credentials for a token. Check the client ID and secret, then try again.`)}function d(e,i){const t=e.get(i);return typeof t=="string"?t:""}function h(e,i,t){return new Response(x(e,i,t),{status:400,headers:g})}function m(){return new Response(D(),{status:404,headers:g})}function S(e,i){return e.kind==="apiKey"?{header:e.header,value:i}:e.kind==="cookie"?{header:"Cookie",value:`${e.name}=${i}`}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:J(i)}:{header:"Authorization",value:i}}function J(e){return`Bearer ${e.trim().replace(U,"")}`}var te=G;export{te as default,ee as setCredentialsFetchImpl};
@@ -1,5 +1,3 @@
1
- import{McpServer as L}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 H,stripAuthRequiredMeta as q,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{acceptedCredentialsLink as K,buildCredentialsAcceptedHint as N,buildCredentialsToolHint as P,buildSchemeChoiceHint as $,buildUpstreamCredentialFallback as y,buildUpstreamCredentialInputRequired as B,credentialElicitationAnswer as v,dedupeElicitation as x,isStatelessRequest as G,schemeLabelOf as V,supportsUrlElicitation as W}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as T,resolveUpstreamApiAuth as Y,schemeChoicesOf as J}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as Q,resolveSecretSubject as X}from"../gateway-mcp/subject.js";const Z=6e4;function fe(e,t){return new L({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function he(e,t){return r=>async(n,s)=>{S.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,u=G(s.mcpReq),o=i?X(e.user,n.sessionHandle):{kind:"anonymous"},l=o.kind==="resolved"?o.subject:void 0;if(o.kind==="invalid")return{content:[{type:"text",text:o.message}],isError:!0};const d=async()=>{if(!(!i||!l||!t?.getKv))try{const p=await t.getKv();return await F.getSecretsForSubject(p,l)}catch(p){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(p)}`);return}};let c;const f=async()=>{c=await d();const p={toolName:r,args:n,context:{...e,upstreamSecrets:c},extra:se(s)};return await j.exec(D,[p],{timeout:Z})};let a=await f();const m=H(a);if(m.length>0&&i&&!l)return q(I(a,[{type:"text",text:Q}]));if(m.length>0&&i&&l&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${u?"2026-07-28":"2025"} clientElicitation=${z(t)}`);const p=await t.getKv(),h=await ee(e,m),k=m.map(O=>te(O,h)),E=re(c),g=u?await ne(e,s,k,l,p,E,h,t):await ie(e,k,l,p,E,h);switch(g.kind){case"inputRequired":return g.result;case"retry":a=await f();break;case"prependText":a=I(a,[{type:"text",text:g.text},...a.content]);break;case"none":break}}return q(a)}}function I(e,t){const{structuredContent:r,...n}=e;return{...n,content:t,isError:!0}}function z(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}async function ee(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await Y(e,n));return r}function te(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??T};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function re(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 A(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?V(r.schemes,n):void 0}function M(e,t){const r=t.get(e.api);return!r||!e.schemes?.length?[]:J(r,e.schemes)}function C(e,t){return M(e,t).length>1}function w(e,t){return e.map(r=>P(r,A(r,t))).join(`
1
+ import{McpServer as C}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as O,MCP_TOOL_WORKER_KEY as _}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as L}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as D,stripAuthRequiredMeta as E,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{acceptedCredentialsLink as K,buildCredentialsAcceptedHint as j,buildCredentialsToolHint as F,buildUpstreamCredentialFallback as q,buildUpstreamCredentialInputRequired as v,credentialElicitationAnswer as H,dedupeElicitation as N,isStatelessRequest as P,schemeLabelOf as $,supportsUrlElicitation as B}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as y,resolveUpstreamApiAuth as G}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as V,resolveSecretSubject as W}from"../gateway-mcp/subject.js";const Y=6e4;function ue(e,t){return new C({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function le(e,t){return r=>async(n,s)=>{S.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,c=P(s.mcpReq),a=i?W(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 u=async()=>{if(!(!i||!o||!t?.getKv))try{const m=await t.getKv();return await L.getSecretsForSubject(m,o)}catch(m){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let l;const p=async()=>{l=await u();const m={toolName:r,args:n,context:{...e,upstreamSecrets:l},extra:ee(s)};return await O.exec(_,[m],{timeout:Y})};let d=await p();const f=D(d);if(f.length>0&&i&&!o)return E(I(d,[{type:"text",text:V}]));if(f.length>0&&i&&o&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${J(t)}`);const m=await t.getKv(),h=await Q(e,f),w=f.map(U=>X(U,h)),k=Z(l),g=c?await x(e,s,w,o,m,k,h,t):await z(e,w,o,m,k,h);switch(g.kind){case"inputRequired":return g.result;case"retry":d=await p();break;case"prependText":d=I(d,[{type:"text",text:g.text},...d.content]);break;case"none":break}}return E(d)}}function I(e,t){const{structuredContent:r,...n}=e;return{...n,content:t,isError:!0}}function J(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 Q(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 X(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??y};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 T(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?$(r.schemes,n):void 0}function M(e,t){return e.map(r=>F(r,T(r,t))).join(`
2
2
 
3
- `)}function U(e,t,r){const n=e.map(s=>$(s,M(s,r)));return t.length>0&&n.push(w(t,r)),n.join(`
4
-
5
- `)}function _(e,t,r,n,s){const[i,...u]=t,o=s.get(i.api),l=i.scheme??o?.defaultScheme??T,d=A(i,s);return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:l,...d?{schemeLabel:d}:{}},auth:o?.schemes[l]??{kind:"raw"},...o?{apiAuth:o}:{},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:u.map(c=>c.name)}}}async function ne(e,t,r,n,s,i,u,o){const l=v(t.mcpReq.inputResponses);if(l==="declined")return{kind:"none"};const d=r.filter(a=>R(a,i));if(d.length===0)return{kind:"prependText",text:w(r,u)};if(l==="accepted"){const a=await K(t.mcpReq.requestState(),{kv:s,subject:n,baseUrl:e.baseUrl??"",apis:d.map(p=>p.api)}),m=a?.apiName??d[0].name;return{kind:"prependText",text:N(m,a?.url)}}const c=d.filter(a=>C(a,u));if(c.length>0){const a=r.filter(m=>!c.includes(m));return{kind:"prependText",text:U(c,a,u)}}const f=_(e,d,n,s,u);return W(o?.getClientCapabilities())?{kind:"inputRequired",result:await B(f)}:{kind:"prependText",text:await y(f)}}async function ie(e,t,r,n,s,i){const u=t.filter(c=>R(c,s));if(u.length===0)return{kind:"prependText",text:w(t,i)};const o=u.filter(c=>C(c,i));if(o.length>0){const c=t.filter(f=>!o.includes(f));return{kind:"prependText",text:U(o,c,i)}}const l=_(e,u,r,n,i);return{kind:"prependText",text:await x(`${r}:${b(u[0])}`,()=>y(l))}}function se(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function ge(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,requestId:e.requestId,messageId:e.messageId,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,sandboxToolSchemas:e.sandboxToolSchemas,fs:void 0}}export{fe as createMcpServer,he as createToolDispatch,ge as extractSerializableContext};
3
+ `)}function A(e,t,r,n,s){const[i,...c]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??y,l=(i.schemes?.length??0)<=1?T(i,s):void 0;return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:o,...l?{schemeLabel:l}:{}},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(p=>p.name)}}}async function x(e,t,r,n,s,i,c,a){const o=H(t.mcpReq.inputResponses);if(o==="declined")return{kind:"none"};const u=r.filter(p=>R(p,i));if(u.length===0)return{kind:"prependText",text:M(r,c)};if(o==="accepted"){const p=await K(t.mcpReq.requestState(),{kv:s,subject:n,baseUrl:e.baseUrl??"",apis:u.map(f=>f.api)}),d=p?.apiName??u[0].name;return{kind:"prependText",text:j(d,p?.url)}}const l=A(e,u,n,s,c);return B(a?.getClientCapabilities())?{kind:"inputRequired",result:await v(l)}:{kind:"prependText",text:await q(l)}}async function z(e,t,r,n,s,i){const c=t.filter(u=>R(u,s));if(c.length===0)return{kind:"prependText",text:M(t,i)};const a=A(e,c,r,n,i);return{kind:"prependText",text:await N(`${r}:${b(c[0])}`,()=>q(a))}}function ee(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function pe(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,requestId:e.requestId,messageId:e.messageId,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,sandboxToolSchemas:e.sandboxToolSchemas,fs:void 0}}export{ue as createMcpServer,le as createToolDispatch,pe as extractSerializableContext};