mcp-trellis 1.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -93
- package/dist/adapters/node-request.d.ts +53 -0
- package/dist/adapters/node-request.d.ts.map +1 -0
- package/dist/adapters/node-request.js +165 -0
- package/dist/adapters/node-request.js.map +1 -0
- package/dist/adapters/node.d.ts +13 -30
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +55 -101
- package/dist/adapters/node.js.map +1 -1
- package/dist/advanced.d.ts +18 -0
- package/dist/advanced.d.ts.map +1 -0
- package/dist/advanced.js +18 -0
- package/dist/advanced.js.map +1 -0
- package/dist/app-options.d.ts +132 -0
- package/dist/app-options.d.ts.map +1 -0
- package/dist/app-options.js +2 -0
- package/dist/app-options.js.map +1 -0
- package/dist/app.d.ts +2 -89
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +143 -63
- package/dist/app.js.map +1 -1
- package/dist/audit.d.ts +5 -5
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +19 -8
- package/dist/audit.js.map +1 -1
- package/dist/auth/bearer.d.ts +4 -1
- package/dist/auth/bearer.d.ts.map +1 -1
- package/dist/auth/bearer.js +19 -4
- package/dist/auth/bearer.js.map +1 -1
- package/dist/auth/signed-token.d.ts +26 -0
- package/dist/auth/signed-token.d.ts.map +1 -0
- package/dist/auth/signed-token.js +96 -0
- package/dist/auth/signed-token.js.map +1 -0
- package/dist/clients.js +1 -1
- package/dist/clients.js.map +1 -1
- package/dist/deprecated.d.ts +42 -0
- package/dist/deprecated.d.ts.map +1 -0
- package/dist/deprecated.js +35 -0
- package/dist/deprecated.js.map +1 -0
- package/dist/{body.d.ts → http/body.d.ts} +27 -6
- package/dist/http/body.d.ts.map +1 -0
- package/dist/{body.js → http/body.js} +33 -13
- package/dist/http/body.js.map +1 -0
- package/dist/http/http.d.ts +42 -0
- package/dist/http/http.d.ts.map +1 -0
- package/dist/http/http.js +100 -0
- package/dist/http/http.js.map +1 -0
- package/dist/http/origins.d.ts +37 -0
- package/dist/http/origins.d.ts.map +1 -0
- package/dist/http/origins.js +87 -0
- package/dist/http/origins.js.map +1 -0
- package/dist/{dispatch.d.ts → mcp/dispatch.d.ts} +1 -1
- package/dist/mcp/dispatch.d.ts.map +1 -0
- package/dist/mcp/dispatch.js +99 -0
- package/dist/mcp/dispatch.js.map +1 -0
- package/dist/{jsonrpc.d.ts → mcp/jsonrpc.d.ts} +9 -0
- package/dist/mcp/jsonrpc.d.ts.map +1 -0
- package/dist/mcp/jsonrpc.js +88 -0
- package/dist/mcp/jsonrpc.js.map +1 -0
- package/dist/{methods.d.ts → mcp/methods.d.ts} +60 -11
- package/dist/mcp/methods.d.ts.map +1 -0
- package/dist/mcp/methods.js +84 -0
- package/dist/mcp/methods.js.map +1 -0
- package/dist/{protocol.d.ts → mcp/protocol.d.ts} +1 -3
- package/dist/mcp/protocol.d.ts.map +1 -0
- package/dist/{protocol.js → mcp/protocol.js} +1 -3
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/registry.d.ts +58 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +81 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/rpc-handlers.d.ts +11 -0
- package/dist/mcp/rpc-handlers.d.ts.map +1 -0
- package/dist/mcp/rpc-handlers.js +133 -0
- package/dist/mcp/rpc-handlers.js.map +1 -0
- package/dist/{tools.d.ts → mcp/tools.d.ts} +20 -1
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +166 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/{validate.d.ts → mcp/validate.d.ts} +18 -21
- package/dist/mcp/validate.d.ts.map +1 -0
- package/dist/{validate.js → mcp/validate.js} +59 -41
- package/dist/mcp/validate.js.map +1 -0
- package/dist/oauth/audit.d.ts +20 -0
- package/dist/oauth/audit.d.ts.map +1 -0
- package/dist/oauth/audit.js +29 -0
- package/dist/oauth/audit.js.map +1 -0
- package/dist/oauth/cimd/cimd-parse.d.ts +4 -0
- package/dist/oauth/cimd/cimd-parse.d.ts.map +1 -0
- package/dist/oauth/cimd/cimd-parse.js +70 -0
- package/dist/oauth/cimd/cimd-parse.js.map +1 -0
- package/dist/oauth/cimd/cimd-ssrf.d.ts +8 -0
- package/dist/oauth/cimd/cimd-ssrf.d.ts.map +1 -0
- package/dist/oauth/cimd/cimd-ssrf.js +193 -0
- package/dist/oauth/cimd/cimd-ssrf.js.map +1 -0
- package/dist/oauth/cimd/cimd.d.ts +36 -0
- package/dist/oauth/cimd/cimd.d.ts.map +1 -0
- package/dist/oauth/cimd/cimd.js +132 -0
- package/dist/oauth/cimd/cimd.js.map +1 -0
- package/dist/oauth/cimd/types.d.ts +12 -0
- package/dist/oauth/cimd/types.d.ts.map +1 -0
- package/dist/oauth/cimd/types.js +3 -0
- package/dist/oauth/cimd/types.js.map +1 -0
- package/dist/oauth/config.d.ts +51 -0
- package/dist/oauth/config.d.ts.map +1 -0
- package/dist/oauth/config.js +108 -0
- package/dist/oauth/config.js.map +1 -0
- package/dist/oauth/constants.d.ts +11 -0
- package/dist/oauth/constants.d.ts.map +1 -1
- package/dist/oauth/constants.js +11 -0
- package/dist/oauth/constants.js.map +1 -1
- package/dist/oauth/{base64url.d.ts → crypto/base64url.d.ts} +0 -1
- package/dist/oauth/crypto/base64url.d.ts.map +1 -0
- package/dist/oauth/{base64url.js → crypto/base64url.js} +0 -1
- package/dist/oauth/crypto/base64url.js.map +1 -0
- package/dist/oauth/crypto/clientauth.d.ts +13 -0
- package/dist/oauth/crypto/clientauth.d.ts.map +1 -0
- package/dist/oauth/crypto/clientauth.js +195 -0
- package/dist/oauth/crypto/clientauth.js.map +1 -0
- package/dist/oauth/crypto/codes.d.ts +65 -0
- package/dist/oauth/crypto/codes.d.ts.map +1 -0
- package/dist/oauth/crypto/codes.js +121 -0
- package/dist/oauth/crypto/codes.js.map +1 -0
- package/dist/oauth/crypto/hkdf.d.ts +13 -0
- package/dist/oauth/crypto/hkdf.d.ts.map +1 -0
- package/dist/oauth/crypto/hkdf.js +30 -0
- package/dist/oauth/crypto/hkdf.js.map +1 -0
- package/dist/oauth/crypto/keycache.d.ts +19 -0
- package/dist/oauth/crypto/keycache.d.ts.map +1 -0
- package/dist/oauth/crypto/keycache.js +44 -0
- package/dist/oauth/crypto/keycache.js.map +1 -0
- package/dist/oauth/crypto/pkce.d.ts.map +1 -0
- package/dist/oauth/{pkce.js → crypto/pkce.js} +1 -1
- package/dist/oauth/crypto/pkce.js.map +1 -0
- package/dist/oauth/{sealed.d.ts → crypto/sealed.d.ts} +12 -3
- package/dist/oauth/crypto/sealed.d.ts.map +1 -0
- package/dist/oauth/{sealed.js → crypto/sealed.js} +22 -14
- package/dist/oauth/crypto/sealed.js.map +1 -0
- package/dist/oauth/{secrethash.d.ts → crypto/secrethash.d.ts} +14 -0
- package/dist/oauth/crypto/secrethash.d.ts.map +1 -0
- package/dist/oauth/{secrethash.js → crypto/secrethash.js} +27 -11
- package/dist/oauth/crypto/secrethash.js.map +1 -0
- package/dist/oauth/deprecated.d.ts +52 -0
- package/dist/oauth/deprecated.d.ts.map +1 -0
- package/dist/oauth/deprecated.js +49 -0
- package/dist/oauth/deprecated.js.map +1 -0
- package/dist/oauth/endpoints/authorize.d.ts +3 -0
- package/dist/oauth/endpoints/authorize.d.ts.map +1 -0
- package/dist/oauth/endpoints/authorize.js +209 -0
- package/dist/oauth/endpoints/authorize.js.map +1 -0
- package/dist/oauth/endpoints/callback.d.ts +20 -0
- package/dist/oauth/endpoints/callback.d.ts.map +1 -0
- package/dist/oauth/endpoints/callback.js +31 -0
- package/dist/oauth/endpoints/callback.js.map +1 -0
- package/dist/oauth/endpoints/consent-page.d.ts +5 -0
- package/dist/oauth/endpoints/consent-page.d.ts.map +1 -0
- package/dist/oauth/endpoints/consent-page.js +63 -0
- package/dist/oauth/endpoints/consent-page.js.map +1 -0
- package/dist/oauth/endpoints/consent.d.ts +29 -0
- package/dist/oauth/endpoints/consent.d.ts.map +1 -0
- package/dist/oauth/endpoints/consent.js +98 -0
- package/dist/oauth/endpoints/consent.js.map +1 -0
- package/dist/oauth/{metadata.d.ts → endpoints/metadata.d.ts} +8 -2
- package/dist/oauth/endpoints/metadata.d.ts.map +1 -0
- package/dist/oauth/{metadata.js → endpoints/metadata.js} +10 -4
- package/dist/oauth/endpoints/metadata.js.map +1 -0
- package/dist/oauth/endpoints/register.d.ts +10 -0
- package/dist/oauth/endpoints/register.d.ts.map +1 -0
- package/dist/oauth/endpoints/register.js +96 -0
- package/dist/oauth/endpoints/register.js.map +1 -0
- package/dist/oauth/{revoke.d.ts → endpoints/revoke.d.ts} +1 -1
- package/dist/oauth/endpoints/revoke.d.ts.map +1 -0
- package/dist/oauth/{revoke.js → endpoints/revoke.js} +8 -18
- package/dist/oauth/endpoints/revoke.js.map +1 -0
- package/dist/oauth/endpoints/token.d.ts +3 -0
- package/dist/oauth/endpoints/token.d.ts.map +1 -0
- package/dist/oauth/{token.js → endpoints/token.js} +32 -25
- package/dist/oauth/endpoints/token.js.map +1 -0
- package/dist/oauth/{wellknown.d.ts → endpoints/wellknown.d.ts} +1 -1
- package/dist/oauth/endpoints/wellknown.d.ts.map +1 -0
- package/dist/oauth/{wellknown.js → endpoints/wellknown.js} +7 -9
- package/dist/oauth/endpoints/wellknown.js.map +1 -0
- package/dist/oauth/policy/redirect.d.ts.map +1 -0
- package/dist/oauth/policy/redirect.js.map +1 -0
- package/dist/oauth/policy/reqbody.d.ts +18 -0
- package/dist/oauth/policy/reqbody.d.ts.map +1 -0
- package/dist/oauth/policy/reqbody.js +68 -0
- package/dist/oauth/policy/reqbody.js.map +1 -0
- package/dist/oauth/{resource.d.ts → policy/resource.d.ts} +1 -1
- package/dist/oauth/policy/resource.d.ts.map +1 -0
- package/dist/oauth/{resource.js → policy/resource.js} +2 -2
- package/dist/oauth/policy/resource.js.map +1 -0
- package/dist/oauth/{scope.d.ts → policy/scope.d.ts} +2 -2
- package/dist/oauth/policy/scope.d.ts.map +1 -0
- package/dist/oauth/{scope.js → policy/scope.js} +3 -3
- package/dist/oauth/policy/scope.js.map +1 -0
- package/dist/oauth/router.d.ts +10 -13
- package/dist/oauth/router.d.ts.map +1 -1
- package/dist/oauth/router.js +93 -115
- package/dist/oauth/router.js.map +1 -1
- package/dist/oauth/types.d.ts +99 -45
- package/dist/oauth/types.d.ts.map +1 -1
- package/dist/oauth/types.js +1 -90
- package/dist/oauth/types.js.map +1 -1
- package/dist/server.d.ts +13 -12
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -8
- package/dist/server.js.map +1 -1
- package/dist/util/defined.d.ts +11 -0
- package/dist/util/defined.d.ts.map +1 -0
- package/dist/util/defined.js +15 -0
- package/dist/util/defined.js.map +1 -0
- package/dist/util/json.d.ts +3 -0
- package/dist/util/json.d.ts.map +1 -0
- package/dist/util/json.js +3 -0
- package/dist/util/json.js.map +1 -0
- package/docs/ROADMAP.md +37 -47
- package/docs/compatibility.md +86 -0
- package/docs/diagrams/demo-tool-result.png +0 -0
- package/docs/diagrams/mcp-trellis-architecture.html +305 -0
- package/docs/guide.md +46 -16
- package/docs/reference.md +55 -22
- package/docs/security.md +58 -9
- package/docs/troubleshooting.md +19 -0
- package/package.json +27 -10
- package/dist/adapters/origins.d.ts +0 -19
- package/dist/adapters/origins.d.ts.map +0 -1
- package/dist/adapters/origins.js +0 -52
- package/dist/adapters/origins.js.map +0 -1
- package/dist/body.d.ts.map +0 -1
- package/dist/body.js.map +0 -1
- package/dist/dispatch.d.ts.map +0 -1
- package/dist/dispatch.js +0 -119
- package/dist/dispatch.js.map +0 -1
- package/dist/http.d.ts +0 -17
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js +0 -38
- package/dist/http.js.map +0 -1
- package/dist/jsonrpc.d.ts.map +0 -1
- package/dist/jsonrpc.js +0 -18
- package/dist/jsonrpc.js.map +0 -1
- package/dist/methods.d.ts.map +0 -1
- package/dist/methods.js +0 -130
- package/dist/methods.js.map +0 -1
- package/dist/oauth/authorize.d.ts +0 -3
- package/dist/oauth/authorize.d.ts.map +0 -1
- package/dist/oauth/authorize.js +0 -141
- package/dist/oauth/authorize.js.map +0 -1
- package/dist/oauth/base64url.d.ts.map +0 -1
- package/dist/oauth/base64url.js.map +0 -1
- package/dist/oauth/clientauth.d.ts +0 -24
- package/dist/oauth/clientauth.d.ts.map +0 -1
- package/dist/oauth/clientauth.js +0 -119
- package/dist/oauth/clientauth.js.map +0 -1
- package/dist/oauth/codes.d.ts +0 -30
- package/dist/oauth/codes.d.ts.map +0 -1
- package/dist/oauth/codes.js +0 -85
- package/dist/oauth/codes.js.map +0 -1
- package/dist/oauth/consent.d.ts +0 -65
- package/dist/oauth/consent.d.ts.map +0 -1
- package/dist/oauth/consent.js +0 -173
- package/dist/oauth/consent.js.map +0 -1
- package/dist/oauth/metadata.d.ts.map +0 -1
- package/dist/oauth/metadata.js.map +0 -1
- package/dist/oauth/pkce.d.ts.map +0 -1
- package/dist/oauth/pkce.js.map +0 -1
- package/dist/oauth/redirect.d.ts.map +0 -1
- package/dist/oauth/redirect.js.map +0 -1
- package/dist/oauth/reqbody.d.ts +0 -10
- package/dist/oauth/reqbody.d.ts.map +0 -1
- package/dist/oauth/reqbody.js +0 -29
- package/dist/oauth/reqbody.js.map +0 -1
- package/dist/oauth/resource.d.ts.map +0 -1
- package/dist/oauth/resource.js.map +0 -1
- package/dist/oauth/revoke.d.ts.map +0 -1
- package/dist/oauth/revoke.js.map +0 -1
- package/dist/oauth/scope.d.ts.map +0 -1
- package/dist/oauth/scope.js.map +0 -1
- package/dist/oauth/sealed.d.ts.map +0 -1
- package/dist/oauth/sealed.js.map +0 -1
- package/dist/oauth/secrethash.d.ts.map +0 -1
- package/dist/oauth/secrethash.js.map +0 -1
- package/dist/oauth/token.d.ts +0 -3
- package/dist/oauth/token.d.ts.map +0 -1
- package/dist/oauth/token.js.map +0 -1
- package/dist/oauth/wellknown.d.ts.map +0 -1
- package/dist/oauth/wellknown.js.map +0 -1
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js.map +0 -1
- package/dist/registry.d.ts +0 -37
- package/dist/registry.d.ts.map +0 -1
- package/dist/registry.js +0 -77
- package/dist/registry.js.map +0 -1
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -98
- package/dist/tools.js.map +0 -1
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js.map +0 -1
- /package/dist/oauth/{pkce.d.ts → crypto/pkce.d.ts} +0 -0
- /package/dist/oauth/{redirect.d.ts → policy/redirect.d.ts} +0 -0
- /package/dist/oauth/{redirect.js → policy/redirect.js} +0 -0
package/dist/adapters/node.js
CHANGED
|
@@ -1,121 +1,65 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Node HTTP `(req, res)` adapter — Express, Cloud Functions, `http.createServer`, etc.
|
|
3
3
|
* Bridges duck-typed Node request/response objects to Web `Request`/`Response`.
|
|
4
|
+
* Request-side plumbing (origin resolution, `toWebRequest`, body reading)
|
|
5
|
+
* lives in `node-request.ts` and is re-exported below unchanged.
|
|
4
6
|
*/
|
|
5
|
-
import { BodyTooLargeError
|
|
6
|
-
import { INTERNAL_ERROR } from "../http.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** Derive origin from Host, or from forwarded headers when trustProxy. */
|
|
13
|
-
export const resolveOrigin = (req, options = {}) => {
|
|
14
|
-
const trustProxy = options.trustProxy === true;
|
|
15
|
-
const proto = trustProxy
|
|
16
|
-
? lastForwarded(headerValue(req.headers["x-forwarded-proto"])) || "https"
|
|
17
|
-
: "https";
|
|
18
|
-
const host = trustProxy
|
|
19
|
-
? lastForwarded(headerValue(req.headers["x-forwarded-host"])) || headerValue(req.headers.host)
|
|
20
|
-
: headerValue(req.headers.host);
|
|
21
|
-
if (!host) {
|
|
22
|
-
throw new Error("Cannot resolve origin: pass options.origin or set Host" +
|
|
23
|
-
(trustProxy ? " / X-Forwarded-Host" : ""));
|
|
24
|
-
}
|
|
25
|
-
return `${proto}://${host}`;
|
|
26
|
-
};
|
|
27
|
-
const toBodyInit = (body) => {
|
|
28
|
-
if (body === undefined || body === null)
|
|
29
|
-
return undefined;
|
|
30
|
-
if (typeof body === "string")
|
|
31
|
-
return body;
|
|
32
|
-
if (body instanceof Uint8Array) {
|
|
33
|
-
return body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength);
|
|
34
|
-
}
|
|
35
|
-
return JSON.stringify(body);
|
|
36
|
-
};
|
|
37
|
-
export const toWebRequest = (req, options) => {
|
|
38
|
-
// Never trust an absolute-form request target — rebase onto the validated origin.
|
|
39
|
-
const target = new URL(req.url ?? "/", options.origin);
|
|
40
|
-
const url = `${options.origin}${target.pathname}${target.search}`;
|
|
41
|
-
const headers = new Headers(Object.entries(req.headers)
|
|
42
|
-
.map(([key, value]) => {
|
|
43
|
-
const resolved = headerValue(value);
|
|
44
|
-
return resolved === undefined ? null : [key, resolved];
|
|
45
|
-
})
|
|
46
|
-
.filter((entry) => entry !== null));
|
|
47
|
-
const method = (req.method ?? "GET").toUpperCase();
|
|
48
|
-
if (method === "GET" || method === "HEAD") {
|
|
49
|
-
return new Request(url, { method, headers });
|
|
50
|
-
}
|
|
51
|
-
const body = options.body !== undefined ? options.body : req.body;
|
|
52
|
-
const bodyInit = toBodyInit(body);
|
|
53
|
-
return new Request(url, {
|
|
54
|
-
method,
|
|
55
|
-
headers,
|
|
56
|
-
...(bodyInit !== undefined ? { body: bodyInit } : {}),
|
|
57
|
-
});
|
|
58
|
-
};
|
|
59
|
-
const isAsyncIterable = (value) => typeof value?.[Symbol.asyncIterator] ===
|
|
60
|
-
"function";
|
|
61
|
-
const requestPath = (req) => (req.url ?? "/").split("?")[0] ?? "/";
|
|
62
|
-
/** OAuth routes under `…/oauth/…` get the 64 KiB cap; everything else gets 1 MiB. */
|
|
63
|
-
export const bodyLimitForPath = (path) => /\/oauth(?:\/|$)/.test(path) ? DEFAULT_OAUTH_BODY_LIMIT : DEFAULT_MCP_BODY_LIMIT;
|
|
64
|
-
const enforcePresetBodySize = (body, maxBytes) => {
|
|
65
|
-
if (typeof body === "string" && new TextEncoder().encode(body).byteLength > maxBytes) {
|
|
66
|
-
throw new BodyTooLargeError(maxBytes);
|
|
67
|
-
}
|
|
68
|
-
if (body instanceof Uint8Array && body.byteLength > maxBytes) {
|
|
69
|
-
throw new BodyTooLargeError(maxBytes);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
7
|
+
import { BodyTooLargeError } from "../http/body.js";
|
|
8
|
+
import { INTERNAL_ERROR } from "../http/http.js";
|
|
9
|
+
import { isAllowedOrigin } from "../http/origins.js";
|
|
10
|
+
import { JSONRPC_PAYLOAD_TOO_LARGE, rpcError } from "../mcp/jsonrpc.js";
|
|
11
|
+
import { bodyLimitForPath, InvalidOriginError, isOAuthPath, readNodeBody, requestPath, resolveOrigin, toWebRequest, } from "./node-request.js";
|
|
12
|
+
export { isAllowedOrigin, isAllowedRequestOrigin, } from "../http/origins.js";
|
|
13
|
+
export { bodyLimitForPath, InvalidOriginError, readNodeBody, resolveOrigin, toWebRequest, } from "./node-request.js";
|
|
72
14
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
15
|
+
* Unlike every other header, `Set-Cookie` cannot be folded into one
|
|
16
|
+
* comma-joined value — a cookie's own `Expires` attribute contains a comma.
|
|
17
|
+
* The Fetch `Headers` object accordingly keeps duplicates apart internally
|
|
18
|
+
* and exposes them via `getSetCookie()`, but `forEach`/`entries()` still
|
|
19
|
+
* yields one `"set-cookie"` pair per cookie — calling `res.setHeader` once
|
|
20
|
+
* per pair (as for any other header) makes each call overwrite the last,
|
|
21
|
+
* silently dropping every cookie but the final one.
|
|
76
22
|
*/
|
|
77
|
-
export const readNodeBody = async (req, maxBytes = DEFAULT_MCP_BODY_LIMIT) => {
|
|
78
|
-
if (req.body !== undefined && req.body !== null) {
|
|
79
|
-
enforcePresetBodySize(req.body, maxBytes);
|
|
80
|
-
return req.body;
|
|
81
|
-
}
|
|
82
|
-
const opts = { contentLength: headerValue(req.headers["content-length"]) };
|
|
83
|
-
if (isNodeReadable(req)) {
|
|
84
|
-
const bytes = await readBoundedNodeBody(req, maxBytes, opts);
|
|
85
|
-
return bytes.byteLength > 0 ? bytes : undefined;
|
|
86
|
-
}
|
|
87
|
-
if (!isAsyncIterable(req))
|
|
88
|
-
return undefined;
|
|
89
|
-
const bytes = await readBoundedNodeBody(req, maxBytes, opts);
|
|
90
|
-
return bytes.byteLength > 0 ? bytes : undefined;
|
|
91
|
-
};
|
|
92
23
|
export const sendWebResponse = async (res, response) => {
|
|
93
24
|
res.statusCode = response.status;
|
|
94
25
|
response.headers.forEach((value, key) => {
|
|
26
|
+
if (key.toLowerCase() === "set-cookie")
|
|
27
|
+
return;
|
|
95
28
|
res.setHeader(key, value);
|
|
96
29
|
});
|
|
30
|
+
const cookies = response.headers.getSetCookie();
|
|
31
|
+
if (cookies.length > 0)
|
|
32
|
+
res.setHeader("set-cookie", cookies);
|
|
97
33
|
res.end(new Uint8Array(await response.arrayBuffer()));
|
|
98
34
|
};
|
|
99
|
-
/**
|
|
100
|
-
|
|
101
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Always answer — an unhandled rejection on `http.createServer` hangs the
|
|
37
|
+
* client. `onFlushed` also closes the connection once the body is written.
|
|
38
|
+
*/
|
|
39
|
+
const sendJsonError = (res, error, onFlushed) => {
|
|
40
|
+
res.statusCode = error.status;
|
|
102
41
|
res.setHeader("Content-Type", "application/json");
|
|
103
|
-
if (
|
|
42
|
+
if (onFlushed)
|
|
104
43
|
res.setHeader("Connection", "close");
|
|
105
|
-
res.end(body,
|
|
44
|
+
res.end(error.body, onFlushed);
|
|
106
45
|
};
|
|
107
|
-
const
|
|
46
|
+
const ORIGIN_NOT_ALLOWED = { status: 400, body: JSON.stringify({ error: "origin not allowed" }) };
|
|
47
|
+
const payloadTooLargeBody = (path) => isOAuthPath(path)
|
|
108
48
|
? JSON.stringify({ error: "request body too large" })
|
|
109
49
|
: JSON.stringify(rpcError(null, JSONRPC_PAYLOAD_TOO_LARGE, "Payload too large"));
|
|
110
|
-
/**
|
|
111
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Validates that `options` resolves to an origin `asNodeHandler` can trust —
|
|
52
|
+
* either an explicit `options.origin` already covered by `allowedOrigins`,
|
|
53
|
+
* or (Host-derived) an `allowedOrigins` that isn't empty. A forgettable Host
|
|
54
|
+
* spoof would otherwise leak straight into the AS issuer / PRM /
|
|
55
|
+
* WWW-Authenticate values every request produces.
|
|
56
|
+
*/
|
|
57
|
+
const assertNodeHandlerOptions = (options) => {
|
|
112
58
|
const hostDerived = !options?.origin;
|
|
113
59
|
if (hostDerived && options?.trustProxy !== true) {
|
|
114
60
|
throw new Error("asNodeHandler requires options.origin or options.trustProxy: true");
|
|
115
61
|
}
|
|
116
|
-
|
|
117
|
-
// explicit allowlist whenever origin comes from the request.
|
|
118
|
-
if (hostDerived && !options.allowedOrigins?.length) {
|
|
62
|
+
if (hostDerived && !options?.allowedOrigins?.length) {
|
|
119
63
|
throw new Error('asNodeHandler with Host-derived origin requires options.allowedOrigins (use ["*"] to admit any Host)');
|
|
120
64
|
}
|
|
121
65
|
if (options?.origin &&
|
|
@@ -123,26 +67,36 @@ export const asNodeHandler = (mcp, options) => {
|
|
|
123
67
|
!isAllowedOrigin(options.origin, options)) {
|
|
124
68
|
throw new Error("asNodeHandler: options.origin is not in options.allowedOrigins");
|
|
125
69
|
}
|
|
70
|
+
};
|
|
71
|
+
/** One-liner: Node `(req, res)` → MCP / OAuth Web handler. */
|
|
72
|
+
export const asNodeHandler = (mcp, options) => {
|
|
73
|
+
assertNodeHandlerOptions(options);
|
|
126
74
|
return async (req, res) => {
|
|
127
75
|
const path = requestPath(req);
|
|
128
76
|
try {
|
|
129
77
|
const origin = options?.origin ?? resolveOrigin(req, { trustProxy: true });
|
|
130
78
|
if (!isAllowedOrigin(origin, options)) {
|
|
131
|
-
sendJsonError(res,
|
|
79
|
+
sendJsonError(res, ORIGIN_NOT_ALLOWED);
|
|
132
80
|
return;
|
|
133
81
|
}
|
|
134
82
|
const body = await readNodeBody(req, bodyLimitForPath(path));
|
|
135
83
|
const request = toWebRequest(req, { origin, body });
|
|
136
84
|
await sendWebResponse(res, await mcp.fetch(request));
|
|
137
85
|
}
|
|
138
|
-
catch (
|
|
139
|
-
if (
|
|
140
|
-
sendJsonError(res, 413, payloadTooLargeBody(path), () => {
|
|
86
|
+
catch (caught) {
|
|
87
|
+
if (caught instanceof BodyTooLargeError) {
|
|
88
|
+
sendJsonError(res, { status: 413, body: payloadTooLargeBody(path) }, () => {
|
|
141
89
|
req.destroy?.();
|
|
142
90
|
});
|
|
143
91
|
return;
|
|
144
92
|
}
|
|
145
|
-
|
|
93
|
+
if (caught instanceof InvalidOriginError) {
|
|
94
|
+
// Bad client input (a malformed or missing Host / X-Forwarded-*),
|
|
95
|
+
// not a server fault — 400, not the generic 500 below.
|
|
96
|
+
sendJsonError(res, ORIGIN_NOT_ALLOWED);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
sendJsonError(res, { status: 500, body: JSON.stringify({ error: INTERNAL_ERROR }) });
|
|
146
100
|
}
|
|
147
101
|
};
|
|
148
102
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/adapters/node.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/adapters/node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mcp-trellis/advanced` — low-level building blocks for hosts assembling
|
|
3
|
+
* their own MCP transport or OAuth flow. Less stable than the root and
|
|
4
|
+
* `mcp-trellis/oauth` entry points: these follow the internals more closely
|
|
5
|
+
* and may change in a minor release when the protocol work requires it.
|
|
6
|
+
*/
|
|
7
|
+
export { matchesAny, timingSafeEqual } from "./auth/bearer.js";
|
|
8
|
+
export { corsHeaders, emptyResponse, methodNotAllowed, optionsResponse } from "./http/http.js";
|
|
9
|
+
export { ASSUMED_HEADER_PROTOCOL_VERSION, pickProtocolVersion } from "./mcp/protocol.js";
|
|
10
|
+
export { IGNORED_SCHEMA_KEYWORDS, JSON_SCHEMA_TYPES, missingObjectType, SUPPORTED_SCHEMA_KEYWORDS, unsupportedKeywords, validateAgainstSchema, } from "./mcp/validate.js";
|
|
11
|
+
export { advertisedScopes, defaultScopes, registeredClientsRequired, unregisteredClientsAllowed, } from "./oauth/config.js";
|
|
12
|
+
export { type ClientAuth, firstClientAuthError, readClientAuth, } from "./oauth/crypto/clientauth.js";
|
|
13
|
+
export { type AuthCodeRecord, type CodeStore, consumeAuthCode, issueAuthCode, newClientId, } from "./oauth/crypto/codes.js";
|
|
14
|
+
export { randomBase64Url, sha256Base64Url, verifyPkceS256 } from "./oauth/crypto/pkce.js";
|
|
15
|
+
export { buildErrorRedirectUrl } from "./oauth/endpoints/callback.js";
|
|
16
|
+
export { firstResourceError, normalizeConfiguredPath, resourceErrorInfo, } from "./oauth/policy/resource.js";
|
|
17
|
+
export { firstScopeError, formatScope, parseScope, requestedScopes, scopeErrorInfo, } from "./oauth/policy/scope.js";
|
|
18
|
+
//# sourceMappingURL=advanced.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,+BAA+B,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACzF,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,UAAU,EACf,oBAAoB,EACpB,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,GACf,MAAM,yBAAyB,CAAC"}
|
package/dist/advanced.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mcp-trellis/advanced` — low-level building blocks for hosts assembling
|
|
3
|
+
* their own MCP transport or OAuth flow. Less stable than the root and
|
|
4
|
+
* `mcp-trellis/oauth` entry points: these follow the internals more closely
|
|
5
|
+
* and may change in a minor release when the protocol work requires it.
|
|
6
|
+
*/
|
|
7
|
+
export { matchesAny, timingSafeEqual } from "./auth/bearer.js";
|
|
8
|
+
export { corsHeaders, emptyResponse, methodNotAllowed, optionsResponse } from "./http/http.js";
|
|
9
|
+
export { ASSUMED_HEADER_PROTOCOL_VERSION, pickProtocolVersion } from "./mcp/protocol.js";
|
|
10
|
+
export { IGNORED_SCHEMA_KEYWORDS, JSON_SCHEMA_TYPES, missingObjectType, SUPPORTED_SCHEMA_KEYWORDS, unsupportedKeywords, validateAgainstSchema, } from "./mcp/validate.js";
|
|
11
|
+
export { advertisedScopes, defaultScopes, registeredClientsRequired, unregisteredClientsAllowed, } from "./oauth/config.js";
|
|
12
|
+
export { firstClientAuthError, readClientAuth, } from "./oauth/crypto/clientauth.js";
|
|
13
|
+
export { consumeAuthCode, issueAuthCode, newClientId, } from "./oauth/crypto/codes.js";
|
|
14
|
+
export { randomBase64Url, sha256Base64Url, verifyPkceS256 } from "./oauth/crypto/pkce.js";
|
|
15
|
+
export { buildErrorRedirectUrl } from "./oauth/endpoints/callback.js";
|
|
16
|
+
export { firstResourceError, normalizeConfiguredPath, resourceErrorInfo, } from "./oauth/policy/resource.js";
|
|
17
|
+
export { firstScopeError, formatScope, parseScope, requestedScopes, scopeErrorInfo, } from "./oauth/policy/scope.js";
|
|
18
|
+
//# sourceMappingURL=advanced.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advanced.js","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,+BAA+B,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACzF,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,oBAAoB,EACpB,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAGL,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,GACf,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ClientName } from "./clients.js";
|
|
2
|
+
import type { AuditEntry, Principal, ServerInfo } from "./mcp/methods.js";
|
|
3
|
+
import type { ToolDef } from "./mcp/registry.js";
|
|
4
|
+
import type { CimdCache } from "./oauth/cimd/types.js";
|
|
5
|
+
import type { CodeStore } from "./oauth/crypto/codes.js";
|
|
6
|
+
import type { ClientStore, ConsentOptions, MintAccessTokenInput, MintedToken, OAuthAuditEntry, OAuthUser, RefreshAccessTokenInput, RevokeTokenInput } from "./oauth/types.js";
|
|
7
|
+
/** One sink for both MCP tool-call and OAuth AS audit events. */
|
|
8
|
+
export type UnifiedAuditEntry = ({
|
|
9
|
+
source: "mcp";
|
|
10
|
+
} & AuditEntry) | ({
|
|
11
|
+
source: "oauth";
|
|
12
|
+
} & OAuthAuditEntry);
|
|
13
|
+
/** What your token verification returns. The library checks the audience. */
|
|
14
|
+
export type VerifiedToken = {
|
|
15
|
+
userId: string;
|
|
16
|
+
scopes: string[];
|
|
17
|
+
/** RFC 8707 audience the token was minted for. */
|
|
18
|
+
audience: string;
|
|
19
|
+
/** Optional host claims passed through to `context` via `Principal`. */
|
|
20
|
+
claims?: Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
export type McpAppAuth = {
|
|
23
|
+
/**
|
|
24
|
+
* Secret(s) that seal auth codes, consent tickets, and self-issued DCR
|
|
25
|
+
* client assertions, and key `ClientStore.secretHash`. Pass a string, or
|
|
26
|
+
* an array for key rotation — the first
|
|
27
|
+
* entry seals new material, every entry is tried when unsealing/verifying.
|
|
28
|
+
* See `OAuthPorts.codeSecret` for the full rotation contract.
|
|
29
|
+
*/
|
|
30
|
+
codeSecret: string | string[] | ((req: Request) => string | string[] | Promise<string | string[]>);
|
|
31
|
+
/** Resolve the logged-in user, or null → redirect to `loginUrl`. */
|
|
32
|
+
resolveUser: (req: Request) => Promise<OAuthUser | null>;
|
|
33
|
+
/** Where to send unauthenticated authorize requests. */
|
|
34
|
+
loginUrl: (req: Request, nextPath: string) => string;
|
|
35
|
+
/** Mint an access token; embed `resource` as the audience. */
|
|
36
|
+
mintAccessToken: (input: MintAccessTokenInput) => Promise<MintedToken>;
|
|
37
|
+
/**
|
|
38
|
+
* Decode and validate a bearer token. Return its `audience` —
|
|
39
|
+
* `createMcpApp` rejects tokens minted for a different resource itself,
|
|
40
|
+
* so this check cannot be forgotten.
|
|
41
|
+
*/
|
|
42
|
+
verifyToken: (token: string, req: Request) => Promise<VerifiedToken | null>;
|
|
43
|
+
refreshAccessToken?: (input: RefreshAccessTokenInput) => Promise<MintedToken | null>;
|
|
44
|
+
/** RFC 7009 — presence mounts `/revoke` and advertises it. */
|
|
45
|
+
revokeToken?: (input: RevokeTokenInput) => Promise<void>;
|
|
46
|
+
codeStore?: CodeStore;
|
|
47
|
+
/** Required when any configured client is pre-registered (e.g. Gemini). */
|
|
48
|
+
clientStore?: ClientStore;
|
|
49
|
+
/**
|
|
50
|
+
* Opt-in OAuth-side metrics hook — see the tool-call `audit` below for
|
|
51
|
+
* the general shape. This one sees the real reason behind a collapsed
|
|
52
|
+
* `invalid_client` or a rejected `codeSecret`, which the caller never
|
|
53
|
+
* does. Omit for silence.
|
|
54
|
+
*/
|
|
55
|
+
audit?: (entry: OAuthAuditEntry) => void | Promise<void>;
|
|
56
|
+
};
|
|
57
|
+
export type McpAppOptions<TCtx> = {
|
|
58
|
+
serverInfo: ServerInfo;
|
|
59
|
+
tools: ToolDef<TCtx>[];
|
|
60
|
+
auth: McpAppAuth;
|
|
61
|
+
/** Connector clients to serve. Default: `["claude"]`. */
|
|
62
|
+
clients?: ClientName[];
|
|
63
|
+
instructions?: string;
|
|
64
|
+
/** MCP endpoint path. Default `"/mcp"`. */
|
|
65
|
+
resourcePath?: string;
|
|
66
|
+
/** OAuth prefix. Default `` `${resourcePath}/oauth` ``. */
|
|
67
|
+
oauthPath?: string;
|
|
68
|
+
/** Scopes this server grants. Default `["mcp"]`. */
|
|
69
|
+
scopes?: string[];
|
|
70
|
+
/** Required when `scopes` has more than one entry — see `OAuthRouterOptions.defaultScopes`. */
|
|
71
|
+
defaultScopes?: string[];
|
|
72
|
+
realm?: string;
|
|
73
|
+
/** Extra exact-match redirect URIs beyond the client profiles. */
|
|
74
|
+
extraRedirectUris?: string[];
|
|
75
|
+
/** Allow loopback redirects (native clients). Default true. */
|
|
76
|
+
allowLoopback?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Consent policy — policy, not a credential, so it sits alongside
|
|
79
|
+
* `allowLoopback` rather than under `auth`. Omit for the built-in
|
|
80
|
+
* hardened interstitial.
|
|
81
|
+
*/
|
|
82
|
+
consent?: ConsentOptions;
|
|
83
|
+
/**
|
|
84
|
+
* Require every `client_id` to come from `clientStore` or this server's
|
|
85
|
+
* own `/register` (sealed assertion). Default **true** since 1.0.
|
|
86
|
+
* Set false only to accept invented public ids (pre-CIMD).
|
|
87
|
+
*/
|
|
88
|
+
requireRegisteredClients?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Validate tools/call args against each tool's `inputSchema`. Default
|
|
91
|
+
* **true** since 2.0. Set false only to skip schema checks intentionally.
|
|
92
|
+
*/
|
|
93
|
+
validateArgs?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* See `OAuthRouterOptions.allowInMemoryCodeStore`. Default false.
|
|
96
|
+
*/
|
|
97
|
+
allowInMemoryCodeStore?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Opt into CIMD (HTTPS URL `client_id`s). Default **false** — see
|
|
100
|
+
* `OAuthRouterOptions.cimd`.
|
|
101
|
+
*/
|
|
102
|
+
cimd?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* CIMD document cache. Strongly recommended with `cimd: true` — see
|
|
105
|
+
* `OAuthRouterOptions.cimdCache`.
|
|
106
|
+
*/
|
|
107
|
+
cimdCache?: CimdCache;
|
|
108
|
+
/** Optional DNS lookup for CIMD SSRF checks. */
|
|
109
|
+
cimdLookup?: (hostname: string) => Promise<string[]>;
|
|
110
|
+
onToolError?: (error: unknown) => string;
|
|
111
|
+
/**
|
|
112
|
+
* Per-call context for tools, built only when a `tools/call` is about to
|
|
113
|
+
* run (see `McpPorts.context`). Defaults to an empty object.
|
|
114
|
+
*/
|
|
115
|
+
context?: (req: Request, principal: Principal | null) => TCtx | Promise<TCtx>;
|
|
116
|
+
/**
|
|
117
|
+
* Unified metrics hook for MCP and OAuth events (`source: "mcp" | "oauth"`).
|
|
118
|
+
* Omit for silence. `auth.audit` overrides OAuth delivery when both are set.
|
|
119
|
+
* See `consoleAudit` or `examples/audit-store.ts`.
|
|
120
|
+
*/
|
|
121
|
+
audit?: (entry: UnifiedAuditEntry) => void | Promise<void>;
|
|
122
|
+
/** Max time to wait for `audit` above before responding anyway. Default 1000ms. Also applied to `auth.audit`. */
|
|
123
|
+
auditTimeoutMs?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Browser `Origin` allowlist for `/mcp` — see `McpHandlerOptions.allowedRequestOrigins`.
|
|
126
|
+
* Omitted → reject any request that sends `Origin`. Native clients omit the header.
|
|
127
|
+
*/
|
|
128
|
+
allowedRequestOrigins?: string[];
|
|
129
|
+
/** Filter `tools/list` by scope. See `McpHandlerOptions.hideToolsOutsideScope`. Default false. */
|
|
130
|
+
hideToolsOutsideScope?: boolean;
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=app-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-options.d.ts","sourceRoot":"","sources":["../src/app-options.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-options.js","sourceRoot":"","sources":["../src/app-options.ts"],"names":[],"mappings":""}
|
package/dist/app.d.ts
CHANGED
|
@@ -4,95 +4,8 @@
|
|
|
4
4
|
* This layers over `createMcpHandler` and `createOAuthRouter`, which stay
|
|
5
5
|
* exported for anyone who wants to compose the pieces themselves.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import type { CodeStore } from "./oauth/codes.js";
|
|
10
|
-
import type { ConsentOptions } from "./oauth/consent.js";
|
|
11
|
-
import type { ClientStore, MintAccessTokenInput, MintedToken, OAuthAuditEntry, OAuthUser, RefreshAccessTokenInput, RevokeTokenInput } from "./oauth/types.js";
|
|
12
|
-
import { type ToolDef } from "./registry.js";
|
|
13
|
-
/** What your token verification returns. The library checks the audience. */
|
|
14
|
-
export type VerifiedToken = {
|
|
15
|
-
userId: string;
|
|
16
|
-
scopes: string[];
|
|
17
|
-
/** RFC 8707 audience the token was minted for. */
|
|
18
|
-
audience: string;
|
|
19
|
-
/** Optional host claims passed through to `context` via `Principal`. */
|
|
20
|
-
claims?: Record<string, unknown>;
|
|
21
|
-
};
|
|
22
|
-
export type McpAppAuth = {
|
|
23
|
-
/** HMAC secret for signing auth codes. */
|
|
24
|
-
codeSecret: string | ((req: Request) => string | Promise<string>);
|
|
25
|
-
/** Resolve the logged-in user, or null → redirect to `loginUrl`. */
|
|
26
|
-
resolveUser: (req: Request) => Promise<OAuthUser | null>;
|
|
27
|
-
/** Where to send unauthenticated authorize requests. */
|
|
28
|
-
loginUrl: (req: Request, nextPath: string) => string;
|
|
29
|
-
/** Mint an access token; embed `resource` as the audience. */
|
|
30
|
-
mintAccessToken: (input: MintAccessTokenInput) => Promise<MintedToken>;
|
|
31
|
-
/**
|
|
32
|
-
* Decode and validate a bearer token. Return its `audience` —
|
|
33
|
-
* `createMcpApp` rejects tokens minted for a different resource itself,
|
|
34
|
-
* so this check cannot be forgotten.
|
|
35
|
-
*/
|
|
36
|
-
verifyToken: (token: string, req: Request) => Promise<VerifiedToken | null>;
|
|
37
|
-
refreshAccessToken?: (input: RefreshAccessTokenInput) => Promise<MintedToken | null>;
|
|
38
|
-
/** RFC 7009 — presence mounts `/revoke` and advertises it. */
|
|
39
|
-
revokeToken?: (input: RevokeTokenInput) => Promise<void>;
|
|
40
|
-
codeStore?: CodeStore;
|
|
41
|
-
/** Required when any configured client is pre-registered (e.g. Gemini). */
|
|
42
|
-
clientStore?: ClientStore;
|
|
43
|
-
/**
|
|
44
|
-
* Opt-in OAuth-side metrics hook — see the tool-call `audit` below for
|
|
45
|
-
* the general shape. This one sees the real reason behind a collapsed
|
|
46
|
-
* `invalid_client` or a rejected `codeSecret`, which the caller never
|
|
47
|
-
* does. Omit for silence.
|
|
48
|
-
*/
|
|
49
|
-
audit?: (entry: OAuthAuditEntry) => void | Promise<void>;
|
|
50
|
-
};
|
|
51
|
-
export type McpAppOptions<TCtx> = {
|
|
52
|
-
serverInfo: ServerInfo;
|
|
53
|
-
tools: ToolDef<TCtx>[];
|
|
54
|
-
auth: McpAppAuth;
|
|
55
|
-
/** Connector clients to serve. Default: `["claude"]`. */
|
|
56
|
-
clients?: ClientName[];
|
|
57
|
-
instructions?: string;
|
|
58
|
-
/** MCP endpoint path. Default `"/mcp"`. */
|
|
59
|
-
resourcePath?: string;
|
|
60
|
-
/** OAuth prefix. Default `` `${resourcePath}/oauth` ``. */
|
|
61
|
-
oauthPath?: string;
|
|
62
|
-
/** Scopes this server grants. Default `["mcp"]`. */
|
|
63
|
-
scopes?: string[];
|
|
64
|
-
/** Required when `scopes` has more than one entry — see `OAuthRouterOptions.defaultScopes`. */
|
|
65
|
-
defaultScopes?: string[];
|
|
66
|
-
realm?: string;
|
|
67
|
-
/** Extra exact-match redirect URIs beyond the client profiles. */
|
|
68
|
-
extraRedirectUris?: string[];
|
|
69
|
-
/** Allow loopback redirects (native clients). Default true. */
|
|
70
|
-
allowLoopback?: boolean;
|
|
71
|
-
/**
|
|
72
|
-
* Consent policy — policy, not a credential, so it sits alongside
|
|
73
|
-
* `allowLoopback` rather than under `auth`. Omit for the built-in
|
|
74
|
-
* hardened interstitial.
|
|
75
|
-
*/
|
|
76
|
-
consent?: ConsentOptions;
|
|
77
|
-
/**
|
|
78
|
-
* Require every `client_id` to come from `clientStore` or this server's
|
|
79
|
-
* own `/register` (sealed assertion). Default **true** since 1.0.
|
|
80
|
-
* Set false only to accept invented public ids (pre-CIMD).
|
|
81
|
-
*/
|
|
82
|
-
requireRegisteredClients?: boolean;
|
|
83
|
-
validateArgs?: boolean;
|
|
84
|
-
onToolError?: (exc: unknown) => string;
|
|
85
|
-
/** Per-request context for tools. Defaults to an empty object. */
|
|
86
|
-
context?: (req: Request, principal: Principal | null) => TCtx | Promise<TCtx>;
|
|
87
|
-
/**
|
|
88
|
-
* Opt-in metrics hook — same as `McpPorts.audit`. Omit for silence. The
|
|
89
|
-
* library never stores or prints these itself. See `consoleAudit` or
|
|
90
|
-
* `examples/audit-store.ts`.
|
|
91
|
-
*/
|
|
92
|
-
audit?: (entry: AuditEntry) => void | Promise<void>;
|
|
93
|
-
/** Max time to wait for `audit` above before responding anyway. Default 1000ms. */
|
|
94
|
-
auditTimeoutMs?: number;
|
|
95
|
-
};
|
|
7
|
+
import type { McpAppOptions } from "./app-options.js";
|
|
8
|
+
export type { McpAppAuth, McpAppOptions, UnifiedAuditEntry, VerifiedToken, } from "./app-options.js";
|
|
96
9
|
export type McpApp = {
|
|
97
10
|
fetch: (request: Request) => Promise<Response>;
|
|
98
11
|
};
|
package/dist/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA0BtD,YAAY,EACV,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD,CAAC;AAwLF,eAAO,MAAM,YAAY,GAAI,IAAI,EAAE,SAAS,aAAa,CAAC,IAAI,CAAC,KAAG,MA8CjE,CAAC"}
|