@redocly/realm 0.137.0-next.0 → 0.137.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -0
- package/dist/cli/stats/collectors/page-slugs/index.d.ts +9 -0
- package/dist/cli/stats/collectors/page-slugs/index.js +1 -0
- package/dist/cli/stats/index.js +1 -1
- package/dist/constants/l10n/langs/ar.js +1 -1
- package/dist/constants/l10n/langs/de.js +1 -1
- package/dist/constants/l10n/langs/en.js +1 -1
- package/dist/constants/l10n/langs/es.js +1 -1
- package/dist/constants/l10n/langs/fr.js +1 -1
- package/dist/constants/l10n/langs/hi.js +1 -1
- package/dist/constants/l10n/langs/it.js +1 -1
- package/dist/constants/l10n/langs/ja.js +1 -1
- package/dist/constants/l10n/langs/ko.js +1 -1
- package/dist/constants/l10n/langs/pl.js +1 -1
- package/dist/constants/l10n/langs/pt-BR.js +1 -1
- package/dist/constants/l10n/langs/pt.js +1 -1
- package/dist/constants/l10n/langs/ru.js +1 -1
- package/dist/constants/l10n/langs/uk.js +1 -1
- package/dist/constants/l10n/langs/zh.js +1 -1
- package/dist/server/config/env-config.d.ts +2 -0
- package/dist/server/config/env-schema.d.ts +5 -0
- package/dist/server/config/env-schemas/feature-flags.d.ts +4 -0
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/plugins/config-parser/loaders/content-slugs-loader.d.ts +5 -0
- package/dist/server/plugins/config-parser/loaders/content-slugs-loader.js +1 -1
- package/dist/server/plugins/markdown/html/html-jsx-attribute-mapping.js +1 -1
- package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
- package/dist/server/plugins/mcp/auth/token-audience-telemetry.d.ts +7 -0
- package/dist/server/plugins/mcp/auth/token-audience-telemetry.js +1 -0
- package/dist/server/plugins/mcp/auth/token-audience.d.ts +6 -0
- package/dist/server/plugins/mcp/auth/token-audience.js +1 -0
- package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.d.ts +1 -0
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -2
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/credential-validation.d.ts +4 -0
- package/dist/server/plugins/mcp/gateway-mcp/credential-validation.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +11 -3
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +4 -3
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +10 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +8 -4
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +24 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +2 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +6 -0
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -1
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +53 -33
- package/dist/server/plugins/mcp/servers/mcp-server.js +4 -2
- package/dist/server/plugins/mcp/types.d.ts +2 -2
- package/dist/server/web-server/utils/prepare-list-response.d.ts +2 -0
- package/dist/server/web-server/utils/prepare-list-response.js +1 -1
- package/package.json +8 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{secretStore as
|
|
1
|
+
import{secretStore as c,ELICITATION_TTL_MS as C}from"../gateway-mcp/secret-store.js";import{rejectCredential as z}from"../gateway-mcp/credential-validation.js";import{buildAllowedHostMatchers as F}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as O}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as j,getDefaultAgent as B}from"../gateway-mcp/fetch/fetch-bridge.js";const p={"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,q=64*1024;let I=fetch;function re(e){I=e}const H=async(e,t)=>{const n=await t.getKv();if(e.method==="GET"){const o=new URL(e.url).searchParams.get("token")??"",r=await c.peekElicitation(n,o);return r?new Response(S(r,o),{status:200,headers:p}):m()}if(e.method==="POST"){const o=await e.formData(),r=f(o,"token"),s=f(o,"mode")||"token";return s==="client-credentials"?G(n,o,r):s==="clear"?D(n,r):U(n,o,r)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function U(e,t,n){const o=f(t,"secret").trim(),r=await c.peekElicitation(e,n);if(!r)return m();const s=z(r.auth,o);if(s)return P(r,n,s);const a=await c.consumeElicitation(e,n);return a?(await c.setSecret(e,a.subject,a.api,a.scheme,K(a.auth,o)),new Response(E(a),{status:200,headers:p})):m()}async function D(e,t){const n=await c.consumeElicitation(e,t);return n?(await c.deleteSecret(e,n.subject,n.api,n.scheme),new Response(V(n),{status:200,headers:p})):m()}async function G(e,t,n){const o=f(t,"client_id").trim(),r=f(t,"client_secret").trim(),s=await c.peekElicitation(e,n);if(!s||s.auth.kind!=="oauth2ClientCredentials")return m();if(!o||!r)return P(s,n,"Enter both the client ID and the client secret before saving.");const a=await c.consumeElicitation(e,n);if(!a||a.auth.kind!=="oauth2ClientCredentials")return m();const g=a.auth;try{const T=F([{url:g.tokenUrl}]),_=O(g.tokenUrl,T),w=new AbortController,R=setTimeout(()=>w.abort(),M);let v;try{v=await I(_,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:o,client_secret:r,...g.scopes.length>0?{scope:g.scopes.join(" ")}:{}}),redirect:"manual",signal:w.signal,dispatcher:B()})}finally{clearTimeout(R)}if(!v.ok)return y(a.name);let $;try{$=await j(v,q)}catch{return y(a.name)}let h;try{h=JSON.parse($)}catch{return y(a.name)}const x=typeof h=="object"&&h!==null&&"access_token"in h?h.access_token:void 0,A=typeof x=="string"?x.trim():"";return A?(await c.setSecret(e,a.subject,a.api,a.scheme,{header:"Authorization",value:`Bearer ${A}`}),new Response(E(a),{status:200,headers:p})):y(a.name)}catch{return y(a.name)}}function f(e,t){const n=e.get(t);return typeof n=="string"?n:""}function P(e,t,n){return new Response(S(e,t,n),{status:400,headers:p})}function K(e,t){return e.kind==="apiKey"?{header:e.header,value:t}:e.kind==="cookie"?{header:"Cookie",value:`${e.name}=${t}`}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:L(t)}:{header:"Authorization",value:t}}function L(e){const t=e.trim();return t.toLowerCase().startsWith("bearer")?t:`Bearer ${t}`}function i(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""")}function d(e){return`<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
@@ -14,6 +14,7 @@ h1{font-size:1.25rem;margin:0 0 .5rem}
|
|
|
14
14
|
.section{margin-top:1.5rem;padding-top:1.5rem;border-top:1px solid #e5e7eb}
|
|
15
15
|
.section h2{font-size:1rem;margin:0 0 .5rem}
|
|
16
16
|
p.hint{color:#6b7280;font-size:.875rem;line-height:1.4}
|
|
17
|
+
p.error{margin:1rem 0 0;padding:.75rem;border:1px solid #fecaca;border-radius:.5rem;background:#fef2f2;color:#991b1b;font-size:.875rem;line-height:1.4}
|
|
17
18
|
label{display:block;margin:1rem 0 .25rem;font-weight:600;font-size:.875rem}
|
|
18
19
|
input[type=password],input[type=text]{width:100%;padding:.625rem .75rem;font-size:1rem;border:1px solid #d1d5db;border-radius:.5rem;background:#fff;color:#111827}
|
|
19
20
|
input:focus{outline:none;border-color:#4f46e5;box-shadow:0 0 0 3px rgba(79,70,229,.2)}
|
|
@@ -30,6 +31,7 @@ body{background:#0b0f19;color:#e5e7eb}
|
|
|
30
31
|
.card{background:#111827;box-shadow:0 10px 25px -5px rgba(0,0,0,.4)}
|
|
31
32
|
.section{border-top-color:#1f2937}
|
|
32
33
|
p.hint{color:#9ca3af}
|
|
34
|
+
p.error{border-color:#7f1d1d;background:#2a1215;color:#fca5a5}
|
|
33
35
|
input[type=password],input[type=text]{background:#0b0f19;border-color:#374151;color:#e5e7eb}
|
|
34
36
|
code{background:#1f2937}
|
|
35
37
|
footer{border-top-color:#1f2937;color:#6b7280}
|
|
@@ -37,20 +39,21 @@ footer{border-top-color:#1f2937;color:#6b7280}
|
|
|
37
39
|
</style>
|
|
38
40
|
</head>
|
|
39
41
|
<body><div class="card">${e}</div></body>
|
|
40
|
-
</html>`}function
|
|
42
|
+
</html>`}function l(e){return`<h1>\u{1F512} ${i(e)}</h1>`}function u(){return"<footer>Secured by Redocly · credentials never enter the AI conversation</footer>"}function b(){return`<p class="hint">This link expires ${Math.round(C/6e4)} minutes after it was issued. If it stops working, ask your AI client for a new one.</p>`}function S(e,t,n){const o=e.hasExistingSecret?N(t):"",r=n?`<p class="error">${i(n)}</p>`:"",s=k(e);switch(e.auth.kind){case"bearer":return W(s,t,o,r);case"apiKey":return X(s,t,e.auth.header,o,r);case"cookie":return Y(s,t,e.auth.name,o,r);case"oauth2ClientCredentials":return J(s,t,e.auth.scopes,o,r);default:return Q(s,t,o,r)}}function k({name:e,schemeLabel:t}){return t?`${e} (${t})`:e}function N(e){return`
|
|
41
43
|
<div class="section">
|
|
42
44
|
<h2>Remove stored credentials</h2>
|
|
43
45
|
<p class="hint">This API already has credentials stored. Save above to replace them, or remove them to make calls anonymous again.</p>
|
|
44
46
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
45
|
-
<input type="hidden" name="token" value="${
|
|
47
|
+
<input type="hidden" name="token" value="${i(e)}">
|
|
46
48
|
<input type="hidden" name="mode" value="clear">
|
|
47
49
|
<button class="danger" type="submit">Remove credentials</button>
|
|
48
50
|
</form>
|
|
49
|
-
</div>`}function
|
|
50
|
-
${
|
|
51
|
+
</div>`}function W(e,t,n,o){return d(`
|
|
52
|
+
${l(`Credentials for ${e}`)}
|
|
53
|
+
${o}
|
|
51
54
|
<p class="hint">Stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
|
|
52
55
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
53
|
-
<input type="hidden" name="token" value="${
|
|
56
|
+
<input type="hidden" name="token" value="${i(t)}">
|
|
54
57
|
<input type="hidden" name="mode" value="token">
|
|
55
58
|
<label for="secret">API token</label>
|
|
56
59
|
<input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
|
|
@@ -58,26 +61,42 @@ ${d(`Credentials for ${e}`)}
|
|
|
58
61
|
<button type="submit">Save credentials</button>
|
|
59
62
|
</form>
|
|
60
63
|
${n}
|
|
61
|
-
${
|
|
62
|
-
${
|
|
63
|
-
${
|
|
64
|
-
|
|
64
|
+
${b()}
|
|
65
|
+
${u()}`)}function X(e,t,n,o,r){return d(`
|
|
66
|
+
${l(`Credentials for ${e}`)}
|
|
67
|
+
${r}
|
|
68
|
+
<p class="hint">Stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent to the API as the <code>${i(n)}</code> header. It never passes through the AI conversation.</p>
|
|
69
|
+
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
70
|
+
<input type="hidden" name="token" value="${i(t)}">
|
|
71
|
+
<input type="hidden" name="mode" value="token">
|
|
72
|
+
<label for="secret">${i(n)} value</label>
|
|
73
|
+
<input type="password" id="secret" name="secret" placeholder="value" required autofocus>
|
|
74
|
+
<button type="submit">Save credentials</button>
|
|
75
|
+
</form>
|
|
76
|
+
${o}
|
|
77
|
+
${b()}
|
|
78
|
+
${u()}`)}function Y(e,t,n,o,r){return d(`
|
|
79
|
+
${l(`Credentials for ${e}`)}
|
|
80
|
+
${r}
|
|
81
|
+
<p class="hint">Stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent to the API as the <code>${i(n)}</code> cookie. It never passes through the AI conversation.</p>
|
|
65
82
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
66
|
-
<input type="hidden" name="token" value="${
|
|
83
|
+
<input type="hidden" name="token" value="${i(t)}">
|
|
67
84
|
<input type="hidden" name="mode" value="token">
|
|
68
|
-
<label for="secret">${
|
|
85
|
+
<label for="secret">${i(n)} cookie value</label>
|
|
69
86
|
<input type="password" id="secret" name="secret" placeholder="value" required autofocus>
|
|
87
|
+
<p class="hint">Paste only the value — we send it as <code>${i(n)}=<value></code>.</p>
|
|
70
88
|
<button type="submit">Save credentials</button>
|
|
71
89
|
</form>
|
|
72
90
|
${o}
|
|
73
|
-
${
|
|
74
|
-
${
|
|
75
|
-
${
|
|
91
|
+
${b()}
|
|
92
|
+
${u()}`)}function J(e,t,n,o,r){const s=n.length>0?n.map(i).join(", "):"default scopes";return d(`
|
|
93
|
+
${l(`Credentials for ${e}`)}
|
|
94
|
+
${r}
|
|
76
95
|
<p class="hint">Paste a token you already have, or let us exchange client credentials for one via OAuth2 client_credentials.</p>
|
|
77
96
|
<div class="section">
|
|
78
97
|
<h2>I have a token</h2>
|
|
79
98
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
80
|
-
<input type="hidden" name="token" value="${
|
|
99
|
+
<input type="hidden" name="token" value="${i(t)}">
|
|
81
100
|
<input type="hidden" name="mode" value="token">
|
|
82
101
|
<label for="secret">API token</label>
|
|
83
102
|
<input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
|
|
@@ -87,9 +106,9 @@ ${d(`Credentials for ${e}`)}
|
|
|
87
106
|
</div>
|
|
88
107
|
<div class="section">
|
|
89
108
|
<h2>Exchange client credentials</h2>
|
|
90
|
-
<p class="hint">We request a token from the API on your behalf. Scopes: ${
|
|
109
|
+
<p class="hint">We request a token from the API on your behalf. Scopes: ${s}.</p>
|
|
91
110
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
92
|
-
<input type="hidden" name="token" value="${
|
|
111
|
+
<input type="hidden" name="token" value="${i(t)}">
|
|
93
112
|
<input type="hidden" name="mode" value="client-credentials">
|
|
94
113
|
<label for="client_id">Client ID</label>
|
|
95
114
|
<input type="text" id="client_id" name="client_id" required>
|
|
@@ -99,26 +118,27 @@ ${d(`Credentials for ${e}`)}
|
|
|
99
118
|
</form>
|
|
100
119
|
</div>
|
|
101
120
|
${o}
|
|
102
|
-
${
|
|
103
|
-
${
|
|
104
|
-
${
|
|
121
|
+
${b()}
|
|
122
|
+
${u()}`)}function Q(e,t,n,o){return d(`
|
|
123
|
+
${l(`Credentials for ${e}`)}
|
|
124
|
+
${o}
|
|
105
125
|
<p class="hint">The value is stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and is sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
|
|
106
126
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
107
|
-
<input type="hidden" name="token" value="${
|
|
127
|
+
<input type="hidden" name="token" value="${i(t)}">
|
|
108
128
|
<input type="hidden" name="mode" value="token">
|
|
109
129
|
<label for="secret">Authorization header value</label>
|
|
110
130
|
<input type="password" id="secret" name="secret" placeholder="Bearer <your token>" required autofocus>
|
|
111
131
|
<button type="submit">Save credentials</button>
|
|
112
132
|
</form>
|
|
113
133
|
${n}
|
|
114
|
-
${
|
|
115
|
-
${
|
|
116
|
-
${
|
|
117
|
-
<p>The stored credentials for ${
|
|
118
|
-
${
|
|
119
|
-
${
|
|
120
|
-
<p>Credentials for ${
|
|
121
|
-
${
|
|
122
|
-
${
|
|
123
|
-
<p>We could not exchange your client credentials for a token for ${
|
|
124
|
-
${
|
|
134
|
+
${b()}
|
|
135
|
+
${u()}`)}function V(e){return d(`
|
|
136
|
+
${l("Credentials removed")}
|
|
137
|
+
<p>The stored credentials for ${i(k(e))} are gone. Calls to that API are anonymous again until you add new ones.</p>
|
|
138
|
+
${u()}`)}function E(e){return d(`
|
|
139
|
+
${l("Credentials saved")}
|
|
140
|
+
<p>Credentials for ${i(k(e))} are saved. Go back to your AI client and ask it to retry - or confirm the prompt it left open, if there is one. You can close this tab.</p>
|
|
141
|
+
${u()}`)}function y(e){return new Response(d(`
|
|
142
|
+
${l("Exchange failed")}
|
|
143
|
+
<p>We could not exchange your client credentials for a token for ${i(e)}. This link has been used up - go back to your AI client and request a new link, then try again.</p>
|
|
144
|
+
${u()}`),{status:502,headers:p})}function m(){return new Response(d(`${l("Link expired")}<p>This credentials link is invalid, already used, or older than ${Math.round(C/6e4)} minutes. Retry the request in your AI client to get a fresh link.</p>${u()}`),{status:404,headers:p})}var ae=H;export{ae as default,re as setCredentialsFetchImpl};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import{McpServer as
|
|
1
|
+
import{McpServer as L,WebStandardStreamableHTTPServerTransport as j}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as D,MCP_TOOL_WORKER_KEY as K}from"../../../workers/mcp-tool-worker-pool.js";import{SSE_KEEPALIVE_INTERVAL_MS as x}from"../constants.js";import{secretStore as F}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as H,stripAuthRequiredMeta as M,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as P,buildSchemeChoiceHint as v,buildUpstreamCredentialFallback as T,buildUpstreamCredentialInputRequired as $,isCredentialElicitationDeclined as N,schemeLabelOf as B}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as q,resolveUpstreamApiAuth as G,schemeChoicesOf as W}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as V,resolveSecretSubject as Y}from"../gateway-mcp/subject.js";const J=6e4,E=new Map;function Q(e,t){const r=E.get(e);if(r)return r;const n=t().finally(()=>{E.delete(e)});return E.set(e,n),n}function fe(e,t){const r=new L({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}}),n=new j({keepAliveMs:x,sessionIdGenerator:void 0});return{server:r,transport:n}}async function he(e,t){return await e.connect(t),{server:e,transport:t,cleanup:async()=>{t.close()}}}function ge(e,t){return r=>async(n,s)=>{S.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,a=s.mcpReq.envelope!==void 0,u=i?Y(e.user,n.sessionHandle):{kind:"anonymous"},o=u.kind==="resolved"?u.subject:void 0;if(u.kind==="invalid")return{content:[{type:"text",text:u.message}],isError:!0};const p=async()=>{if(!(!i||!o||!t?.getKv))try{const m=await t.getKv();return await F.getSecretsForSubject(m,o)}catch(m){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let c;const l=async()=>{c=await p();const m={toolName:r,args:n,context:{...e,upstreamSecrets:c},extra:ie(s)};return await D.exec(K,[m],{timeout:J})};let d=await l();const f=H(d);if(f.length>0&&i&&!o)return M({...d,content:[{type:"text",text:V}],isError:!0});if(f.length>0&&i&&o&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${a?"2026-07-28":"2025"} clientElicitation=${Z(t)}`);const m=await t.getKv(),h=await z(e,f),k=f.map(U=>ee(U,h)),y=te(c),g=a?await re(e,s,k,o,m,y,h,t):await ne(e,k,o,m,y,h);switch(g.kind){case"inputRequired":return g.result;case"retry":d=await l();break;case"prependText":d={...d,content:[{type:"text",text:g.text},...d.content],isError:!0};break;case"none":break}}return M(d)}}function X(e){return!!e?.getClientCapabilities()?.elicitation?.url}function Z(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}async function z(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await G(e,n));return r}function ee(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??q};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function te(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(b({api:r,scheme:s}));return t}function I(e,t){return e.status===401&&!t.has(b(e))}function R(e,t){const r=t.get(e.api);return r&&e.scheme?B(r.schemes,e.scheme):void 0}function A(e,t){const r=t.get(e.api);return!r||!e.schemes?.length?[]:W(r,e.schemes)}function _(e,t){return A(e,t).length>1}function w(e,t){return e.map(r=>P(r,R(r,t))).join(`
|
|
2
2
|
|
|
3
|
-
`)}
|
|
3
|
+
`)}function C(e,t,r){const n=e.map(s=>v(s,A(s,r)));return t.length>0&&n.push(w(t,r)),n.join(`
|
|
4
|
+
|
|
5
|
+
`)}function O(e,t,r,n,s){const[i,...a]=t,u=s.get(i.api),o=i.scheme??u?.defaultScheme??q,p=R(i,s);return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:o,...p?{schemeLabel:p}:{}},auth:u?.schemes[o]??{kind:"raw"},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,otherApiNames:a.map(c=>c.name)}}}async function re(e,t,r,n,s,i,a,u){if(N(t.mcpReq.inputResponses))return{kind:"none"};const o=r.filter(l=>I(l,i));if(o.length===0)return{kind:"prependText",text:w(r,a)};const p=o.filter(l=>_(l,a));if(p.length>0){const l=r.filter(d=>!p.includes(d));return{kind:"prependText",text:C(p,l,a)}}const c=O(e,o,n,s,a);return X(u)?{kind:"inputRequired",result:await $(c)}:{kind:"prependText",text:await T(c)}}async function ne(e,t,r,n,s,i){const a=t.filter(c=>I(c,s));if(a.length===0)return{kind:"prependText",text:w(t,i)};const u=a.filter(c=>_(c,i));if(u.length>0){const c=t.filter(l=>!u.includes(l));return{kind:"prependText",text:C(u,c,i)}}const o=O(e,a,r,n,i);return{kind:"prependText",text:await Q(`${r}:${b(a[0])}`,()=>T(o))}}function ie(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function Se(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes}}export{he as connectMcpServer,fe as createMcpServer,ge as createToolDispatch,Se as extractSerializableContext};
|
|
@@ -4,7 +4,7 @@ import type { OpenAPIPath, OpenAPIServer, OpenAPIOperation } from '@redocly/api-
|
|
|
4
4
|
import type { McpErrorCodes, McpServerType } from './constants';
|
|
5
5
|
import type { McpToolSchema } from '../../types';
|
|
6
6
|
import type { Skill } from '../../types/plugins/skills.js';
|
|
7
|
-
import type {
|
|
7
|
+
import type { UpstreamSecrets } from './gateway-mcp/secret-store.js';
|
|
8
8
|
type ObjectValues<T> = T[keyof T];
|
|
9
9
|
export type McpServerType = ObjectValues<typeof McpServerType>;
|
|
10
10
|
export type McpErrorCodeTypes = ObjectValues<typeof McpErrorCodes>;
|
|
@@ -98,7 +98,7 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
|
|
|
98
98
|
elicitationEnabled?: boolean;
|
|
99
99
|
gatewayFetchBudgetPerExec?: number;
|
|
100
100
|
clientIp?: string;
|
|
101
|
-
upstreamSecrets?:
|
|
101
|
+
upstreamSecrets?: UpstreamSecrets;
|
|
102
102
|
searchIgnoredRoutes?: string[];
|
|
103
103
|
};
|
|
104
104
|
export type McpToolHandler<TArgs extends ToolArgs = ToolArgs> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createCursor as
|
|
1
|
+
import{createCursor as c}from"../../providers/database/pagination/utils/create-cursor.js";import{DEFAULT_LIMIT as o}from"../../providers/database/pagination/limit.js";function h(e){return!!(e.after||e.before)}function b(e,i,n){const r=h(i),t=i.limit??o;if(r){if(i.before)return!0;if(i.after)return e.length===t}return n!==void 0&&i.skip!==void 0?i.skip+t<n:n!==void 0?t<n:e.length===t}function d(e){return!!(e.after||e.before||e.skip!==void 0&&e.skip>0)}function x({data:e,params:i,totalCount:n,nameTransformationsFromDatabase:r={},hasMore:t}){if(!e.length)return{object:"list",items:[],page:{total:0,limit:i.limit??o,hasNextPage:!1,hasPrevPage:!1,startCursor:null,endCursor:null,nextPage:null,previousPage:null}};const l=i.sort?.length?i.sort:[{field:"id",order:"ASC"}],u=t??b(e,i,n),g=d(i),P=!!(i.after||i.before&&t||i.skip!==void 0&&i.skip>0),f=c(e[0],l,r),s=c(e[e.length-1],l,r);return{object:"list",items:e,page:{total:n??0,limit:i.limit??o,hasNextPage:u,hasPrevPage:g,startCursor:f,endCursor:s,nextPage:u?s:null,previousPage:P?f:null}}}export{x as prepareListResponse};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/realm",
|
|
3
|
-
"version": "0.137.0-next.
|
|
3
|
+
"version": "0.137.0-next.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -93,15 +93,15 @@
|
|
|
93
93
|
"xpath": "0.0.34",
|
|
94
94
|
"yaml-ast-parser": "0.0.43",
|
|
95
95
|
"zod": "^3.25.76",
|
|
96
|
-
"@redocly/api-docs": "0.2.0-next.
|
|
97
|
-
"@redocly/asyncapi-docs": "1.14.0-next.
|
|
96
|
+
"@redocly/api-docs": "0.2.0-next.2",
|
|
97
|
+
"@redocly/asyncapi-docs": "1.14.0-next.2",
|
|
98
98
|
"@redocly/config": "0.53.1",
|
|
99
|
-
"@redocly/graphql-docs": "1.14.0-next.
|
|
100
|
-
"@redocly/openapi-docs": "3.25.0-next.
|
|
99
|
+
"@redocly/graphql-docs": "1.14.0-next.2",
|
|
100
|
+
"@redocly/openapi-docs": "3.25.0-next.2",
|
|
101
101
|
"@redocly/portal-legacy-ui": "0.19.0",
|
|
102
|
-
"@redocly/portal-plugin-mock-server": "0.22.0-next.
|
|
103
|
-
"@redocly/realm-asyncapi-sdk": "0.
|
|
104
|
-
"@redocly/theme": "0.69.0-next.
|
|
102
|
+
"@redocly/portal-plugin-mock-server": "0.22.0-next.2",
|
|
103
|
+
"@redocly/realm-asyncapi-sdk": "0.15.0-next.1",
|
|
104
|
+
"@redocly/theme": "0.69.0-next.2"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
107
|
"react": "^19.2.7",
|