mcp-trellis 0.2.1 → 2.1.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 +70 -620
- 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 +16 -24
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +69 -88
- 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 -66
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +150 -57
- 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 +25 -5
- package/dist/auth/bearer.js.map +1 -1
- package/dist/clients.d.ts.map +1 -1
- package/dist/clients.js +3 -6
- 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/http/body.d.ts +69 -0
- package/dist/http/body.d.ts.map +1 -0
- package/dist/http/body.js +165 -0
- 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/mcp/dispatch.d.ts +7 -0
- 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} +10 -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/mcp/methods.d.ts +133 -0
- 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/mcp/protocol.d.ts +16 -0
- package/dist/mcp/protocol.d.ts.map +1 -0
- package/dist/mcp/protocol.js +22 -0
- 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} +30 -2
- 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} +24 -12
- package/dist/mcp/validate.d.ts.map +1 -0
- package/dist/mcp/validate.js +186 -0
- 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 +15 -0
- package/dist/oauth/constants.d.ts.map +1 -1
- package/dist/oauth/constants.js +15 -0
- package/dist/oauth/constants.js.map +1 -1
- package/dist/oauth/{base64url.d.ts → crypto/base64url.d.ts} +1 -2
- package/dist/oauth/crypto/base64url.d.ts.map +1 -0
- package/dist/oauth/{base64url.js → crypto/base64url.js} +1 -5
- 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/crypto/sealed.d.ts +26 -0
- package/dist/oauth/crypto/sealed.d.ts.map +1 -0
- package/dist/oauth/crypto/sealed.js +65 -0
- package/dist/oauth/crypto/sealed.js.map +1 -0
- package/dist/oauth/crypto/secrethash.d.ts +58 -0
- package/dist/oauth/crypto/secrethash.d.ts.map +1 -0
- package/dist/oauth/crypto/secrethash.js +82 -0
- 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} +14 -8
- 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} +11 -9
- 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} +33 -47
- 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 -7
- package/dist/oauth/endpoints/wellknown.js.map +1 -0
- package/dist/oauth/{redirect.d.ts → policy/redirect.d.ts} +6 -1
- package/dist/oauth/policy/redirect.d.ts.map +1 -0
- package/dist/oauth/policy/redirect.js +39 -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/policy/resource.d.ts +37 -0
- package/dist/oauth/policy/resource.d.ts.map +1 -0
- package/dist/oauth/policy/resource.js +74 -0
- package/dist/oauth/policy/resource.js.map +1 -0
- package/dist/oauth/policy/scope.d.ts +20 -0
- package/dist/oauth/policy/scope.d.ts.map +1 -0
- package/dist/oauth/policy/scope.js +35 -0
- package/dist/oauth/policy/scope.js.map +1 -0
- package/dist/oauth/router.d.ts +12 -12
- package/dist/oauth/router.d.ts.map +1 -1
- package/dist/oauth/router.js +105 -87
- package/dist/oauth/router.js.map +1 -1
- package/dist/oauth/types.d.ts +177 -26
- package/dist/oauth/types.d.ts.map +1 -1
- package/dist/oauth/types.js +1 -27
- package/dist/oauth/types.js.map +1 -1
- package/dist/server.d.ts +14 -13
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -9
- 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 +283 -0
- package/docs/compatibility.md +84 -0
- package/docs/diagrams/mcp-trellis-architecture.html +305 -0
- package/docs/guide.md +441 -0
- package/docs/reference.md +210 -0
- package/docs/security.md +112 -0
- package/docs/troubleshooting.md +19 -0
- package/package.json +24 -8
- package/dist/adapters/origins.d.ts +0 -19
- package/dist/adapters/origins.d.ts.map +0 -1
- package/dist/adapters/origins.js +0 -55
- package/dist/adapters/origins.js.map +0 -1
- package/dist/dispatch.d.ts +0 -7
- package/dist/dispatch.d.ts.map +0 -1
- package/dist/dispatch.js +0 -79
- 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 -17
- package/dist/jsonrpc.js.map +0 -1
- package/dist/methods.d.ts +0 -61
- package/dist/methods.d.ts.map +0 -1
- package/dist/methods.js +0 -114
- 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 -109
- 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 -19
- package/dist/oauth/clientauth.d.ts.map +0 -1
- package/dist/oauth/clientauth.js +0 -76
- 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 -93
- package/dist/oauth/codes.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 +0 -26
- package/dist/oauth/redirect.js.map +0 -1
- package/dist/oauth/resource.d.ts +0 -7
- package/dist/oauth/resource.d.ts.map +0 -1
- package/dist/oauth/resource.js +0 -44
- 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 +0 -11
- package/dist/oauth/scope.d.ts.map +0 -1
- package/dist/oauth/scope.js +0 -24
- package/dist/oauth/scope.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 +0 -4
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -14
- 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 -69
- package/dist/registry.js.map +0 -1
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -97
- package/dist/tools.js.map +0 -1
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -130
- package/dist/validate.js.map +0 -1
- /package/dist/oauth/{pkce.d.ts → crypto/pkce.d.ts} +0 -0
package/dist/auth/bearer.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/** Bearer auth helpers for MCP (RFC 9728 WWW-Authenticate). */
|
|
2
|
-
|
|
2
|
+
const BEARER_PREFIX = "Bearer ";
|
|
3
3
|
/** Above any real JWT / HMAC sig; prevents allocation DoS on attacker input. */
|
|
4
4
|
export const MAX_COMPARE_LENGTH = 4096;
|
|
5
|
+
/** RFC 7235 §2.1 — the auth-scheme token is case-insensitive ("bearer", "BEARER", "Bearer" all valid). */
|
|
6
|
+
const BEARER_SCHEME_RE = /^bearer\s+/i;
|
|
5
7
|
export const parseBearer = (authorization) => {
|
|
6
|
-
if (!authorization
|
|
8
|
+
if (!authorization)
|
|
7
9
|
return null;
|
|
8
|
-
const
|
|
10
|
+
const match = BEARER_SCHEME_RE.exec(authorization);
|
|
11
|
+
if (!match)
|
|
12
|
+
return null;
|
|
13
|
+
const token = authorization.slice(match[0].length).trim();
|
|
9
14
|
return token.length > 0 ? token : null;
|
|
10
15
|
};
|
|
11
16
|
/**
|
|
@@ -14,6 +19,11 @@ export const parseBearer = (authorization) => {
|
|
|
14
19
|
* so unequal lengths do not short-circuit. Rejects over-long inputs.
|
|
15
20
|
*/
|
|
16
21
|
export const timingSafeEqual = (a, b) => {
|
|
22
|
+
// Both empty: the reduce below never runs and the seed 0 ^ 0 is 0 — "equal"
|
|
23
|
+
// by the accumulator's math, but never the right semantics for a secret
|
|
24
|
+
// comparison. An empty presented value must never authenticate.
|
|
25
|
+
if (a.length === 0 || b.length === 0)
|
|
26
|
+
return false;
|
|
17
27
|
if (a.length > MAX_COMPARE_LENGTH || b.length > MAX_COMPARE_LENGTH) {
|
|
18
28
|
return false;
|
|
19
29
|
}
|
|
@@ -25,8 +35,18 @@ export const timingSafeEqual = (a, b) => {
|
|
|
25
35
|
}, a.length ^ b.length);
|
|
26
36
|
return diff === 0;
|
|
27
37
|
};
|
|
28
|
-
export const matchesAny = (presented, accepted) => accepted.some((token) =>
|
|
29
|
-
|
|
38
|
+
export const matchesAny = (presented, accepted) => accepted.some((token) => timingSafeEqual(presented, token));
|
|
39
|
+
/** RFC 6750 / RFC 7235 quoted-string — escape `\` and `"` so host-controlled values cannot break or inject header params. */
|
|
40
|
+
const escapeWwwAuthenticateValue = (value) => value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
41
|
+
export const wwwAuthenticateHeader = (options) => {
|
|
42
|
+
const parts = [
|
|
43
|
+
`realm="${escapeWwwAuthenticateValue(options.realm)}"`,
|
|
44
|
+
`resource_metadata="${escapeWwwAuthenticateValue(options.resourceMetadataUrl)}"`,
|
|
45
|
+
...(options.error ? [`error="${escapeWwwAuthenticateValue(options.error)}"`] : []),
|
|
46
|
+
...(options.scope ? [`scope="${escapeWwwAuthenticateValue(options.scope)}"`] : []),
|
|
47
|
+
];
|
|
48
|
+
return `${BEARER_PREFIX}${parts.join(", ")}`;
|
|
49
|
+
};
|
|
30
50
|
/** RFC 6750 §2.3 uses `access_token`; also reject legacy `token`. */
|
|
31
51
|
export const rejectQueryToken = (url) => url.searchParams.has("token") || url.searchParams.has("access_token");
|
|
32
52
|
//# sourceMappingURL=bearer.js.map
|
package/dist/auth/bearer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bearer.js","sourceRoot":"","sources":["../../src/auth/bearer.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAE/D,MAAM,
|
|
1
|
+
{"version":3,"file":"bearer.js","sourceRoot":"","sources":["../../src/auth/bearer.ts"],"names":[],"mappings":"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"}
|
package/dist/clients.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../src/clients.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../src/clients.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAA+B,KAAK,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEjG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvD,MAAM,MAAM,aAAa,GAAG;IAC1B,sDAAsD;IACtD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gDAAgD;IAChD,wBAAwB,EAAE,uBAAuB,EAAE,CAAC;IACpD;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE,aAAa,CAsB7D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,UAAU,EAAe,CAAC;AAExD,kEAAkE;AAClE,eAAO,MAAM,eAAe,GAAI,SAAS,UAAU,EAAE,KAAG,MAAM,EAE7D,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,cAAc,GAAI,SAAS,UAAU,EAAE,KAAG,uBAAuB,EAS7E,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,oBAAoB,GAAI,SAAS,UAAU,EAAE,KAAG,UAAU,EACR,CAAC;AAEhE,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB,GAAI,SAAS,UAAU,EAAE,KAAG,OACK,CAAC;AAE/D,eAAO,MAAM,uBAAuB,GAClC,SAAS,UAAU,EAAE,EACrB,aAAa,WAAW,GAAG,SAAS,KACnC,IASF,CAAC"}
|
package/dist/clients.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* callback URLs, different registration models. Encoding that here is the
|
|
6
6
|
* point: you name your clients, the library configures the AS to match.
|
|
7
7
|
*/
|
|
8
|
-
import { TOKEN_ENDPOINT_AUTH_METHODS
|
|
9
|
-
import { CLAUDE_CALLBACK } from "./oauth/redirect.js";
|
|
8
|
+
import { TOKEN_ENDPOINT_AUTH_METHODS } from "./oauth/constants.js";
|
|
9
|
+
import { CLAUDE_CALLBACK } from "./oauth/policy/redirect.js";
|
|
10
10
|
export const CLIENT_PROFILES = {
|
|
11
11
|
/** Claude Custom Connectors — dynamic registration, public client + PKCE. */
|
|
12
12
|
claude: {
|
|
@@ -20,10 +20,7 @@ export const CLIENT_PROFILES = {
|
|
|
20
20
|
*/
|
|
21
21
|
gemini: {
|
|
22
22
|
redirectUris: [],
|
|
23
|
-
tokenEndpointAuthMethods: [
|
|
24
|
-
TOKEN_ENDPOINT_AUTH_METHODS.basic,
|
|
25
|
-
TOKEN_ENDPOINT_AUTH_METHODS.post,
|
|
26
|
-
],
|
|
23
|
+
tokenEndpointAuthMethods: [TOKEN_ENDPOINT_AUTH_METHODS.basic, TOKEN_ENDPOINT_AUTH_METHODS.post],
|
|
27
24
|
preRegistered: true,
|
|
28
25
|
},
|
|
29
26
|
/** OpenAI Codex / ChatGPT connectors — OAuth 2.1 per the MCP auth spec. */
|
package/dist/clients.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clients.js","sourceRoot":"","sources":["../src/clients.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"clients.js","sourceRoot":"","sources":["../src/clients.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,2BAA2B,EAAgC,MAAM,sBAAsB,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAiB7D,MAAM,CAAC,MAAM,eAAe,GAAsC;IAChE,6EAA6E;IAC7E,MAAM,EAAE;QACN,YAAY,EAAE,CAAC,eAAe,CAAC;QAC/B,wBAAwB,EAAE,CAAC,2BAA2B,CAAC,IAAI,CAAC;QAC5D,aAAa,EAAE,KAAK;KACrB;IACD;;;OAGG;IACH,MAAM,EAAE;QACN,YAAY,EAAE,EAAE;QAChB,wBAAwB,EAAE,CAAC,2BAA2B,CAAC,KAAK,EAAE,2BAA2B,CAAC,IAAI,CAAC;QAC/F,aAAa,EAAE,IAAI;KACpB;IACD,2EAA2E;IAC3E,KAAK,EAAE;QACL,YAAY,EAAE,EAAE;QAChB,wBAAwB,EAAE,CAAC,2BAA2B,CAAC,IAAI,CAAC;QAC5D,aAAa,EAAE,KAAK;KACrB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAiB,CAAC,QAAQ,CAAC,CAAC;AAExD,kEAAkE;AAClE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAqB,EAAY,EAAE,CAAC;IAClE,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;CAC1E,CAAC;AAEF,oDAAoD;AACpD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAqB,EAA6B,EAAE;IACjF,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,wBAAwB,CAAC,CAC1E,CAAC;IACF,OAAO;QACL,2BAA2B,CAAC,IAAI;QAChC,2BAA2B,CAAC,KAAK;QACjC,2BAA2B,CAAC,IAAI;KACjC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,wDAAwD;AACxD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAqB,EAAgB,EAAE,CAC1E,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC;AAEhE,2FAA2F;AAC3F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAqB,EAAW,EAAE,CACjE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC;AAE/D,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,OAAqB,EACrB,WAAoC,EAC9B,EAAE;IACR,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACtF,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,YAAY,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB;YACxD,0EAA0E,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root-entry aliases for symbols that moved to `mcp-trellis/advanced`.
|
|
3
|
+
* Declared as consts (not `export { } from`) so `@deprecated` reaches
|
|
4
|
+
* editors. Removed in 3.0.
|
|
5
|
+
*/
|
|
6
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
7
|
+
export declare const timingSafeEqual: (a: string, b: string) => boolean;
|
|
8
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
9
|
+
export declare const matchesAny: (presented: string, accepted: string[]) => boolean;
|
|
10
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
11
|
+
export declare const corsHeaders: (extra?: Record<string, string>) => Record<string, string>;
|
|
12
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
13
|
+
export declare const emptyResponse: (status: number) => Response;
|
|
14
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
15
|
+
export declare const methodNotAllowed: (message?: string, options?: import("./server.js").JsonResponseOptions) => Response;
|
|
16
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
17
|
+
export declare const optionsResponse: (options?: import("./server.js").JsonResponseOptions) => Response;
|
|
18
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
19
|
+
export declare const pickProtocolVersion: (params?: Record<string, unknown>) => string;
|
|
20
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
21
|
+
export declare const ASSUMED_HEADER_PROTOCOL_VERSION = "2025-03-26";
|
|
22
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
23
|
+
export declare const validateAgainstSchema: (value: unknown, schema: import("./server.js").JsonSchema) => string[];
|
|
24
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
25
|
+
export declare const unsupportedKeywords: (schema: import("./server.js").JsonSchema, path?: string) => string[];
|
|
26
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
27
|
+
export declare const missingObjectType: (schema: import("./server.js").JsonSchema, path?: string) => string[];
|
|
28
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
29
|
+
export declare const JSON_SCHEMA_TYPES: {
|
|
30
|
+
readonly string: "string";
|
|
31
|
+
readonly number: "number";
|
|
32
|
+
readonly integer: "integer";
|
|
33
|
+
readonly boolean: "boolean";
|
|
34
|
+
readonly object: "object";
|
|
35
|
+
readonly array: "array";
|
|
36
|
+
readonly null: "null";
|
|
37
|
+
};
|
|
38
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
39
|
+
export declare const SUPPORTED_SCHEMA_KEYWORDS: ReadonlySet<string>;
|
|
40
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
41
|
+
export declare const IGNORED_SCHEMA_KEYWORDS: ReadonlySet<string>;
|
|
42
|
+
//# sourceMappingURL=deprecated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecated.d.ts","sourceRoot":"","sources":["../src/deprecated.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,sEAAsE;AACtE,eAAO,MAAM,eAAe,mCAA2B,CAAC;AACxD,sEAAsE;AACtE,eAAO,MAAM,UAAU,oDAAsB,CAAC;AAC9C,sEAAsE;AACtE,eAAO,MAAM,WAAW,4DAAuB,CAAC;AAChD,sEAAsE;AACtE,eAAO,MAAM,aAAa,8BAAyB,CAAC;AACpD,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,qFAA4B,CAAC;AAC1D,sEAAsE;AACtE,eAAO,MAAM,eAAe,mEAA2B,CAAC;AACxD,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,8CAA+B,CAAC;AAChE,sEAAsE;AACtE,eAAO,MAAM,+BAA+B,eAA2C,CAAC;AACxF,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,wEAAiC,CAAC;AACpE,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,uEAA+B,CAAC;AAChE,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,uEAA6B,CAAC;AAC5D,sEAAsE;AACtE,eAAO,MAAM,iBAAiB;;;;;;;;CAA6B,CAAC;AAC5D,sEAAsE;AACtE,eAAO,MAAM,yBAAyB,qBAAqC,CAAC;AAC5E,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,qBAAmC,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root-entry aliases for symbols that moved to `mcp-trellis/advanced`.
|
|
3
|
+
* Declared as consts (not `export { } from`) so `@deprecated` reaches
|
|
4
|
+
* editors. Removed in 3.0.
|
|
5
|
+
*/
|
|
6
|
+
import * as advanced from "./advanced.js";
|
|
7
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
8
|
+
export const timingSafeEqual = advanced.timingSafeEqual;
|
|
9
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
10
|
+
export const matchesAny = advanced.matchesAny;
|
|
11
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
12
|
+
export const corsHeaders = advanced.corsHeaders;
|
|
13
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
14
|
+
export const emptyResponse = advanced.emptyResponse;
|
|
15
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
16
|
+
export const methodNotAllowed = advanced.methodNotAllowed;
|
|
17
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
18
|
+
export const optionsResponse = advanced.optionsResponse;
|
|
19
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
20
|
+
export const pickProtocolVersion = advanced.pickProtocolVersion;
|
|
21
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
22
|
+
export const ASSUMED_HEADER_PROTOCOL_VERSION = advanced.ASSUMED_HEADER_PROTOCOL_VERSION;
|
|
23
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
24
|
+
export const validateAgainstSchema = advanced.validateAgainstSchema;
|
|
25
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
26
|
+
export const unsupportedKeywords = advanced.unsupportedKeywords;
|
|
27
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
28
|
+
export const missingObjectType = advanced.missingObjectType;
|
|
29
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
30
|
+
export const JSON_SCHEMA_TYPES = advanced.JSON_SCHEMA_TYPES;
|
|
31
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
32
|
+
export const SUPPORTED_SCHEMA_KEYWORDS = advanced.SUPPORTED_SCHEMA_KEYWORDS;
|
|
33
|
+
/** @deprecated Import from "mcp-trellis/advanced". Removed in 3.0. */
|
|
34
|
+
export const IGNORED_SCHEMA_KEYWORDS = advanced.IGNORED_SCHEMA_KEYWORDS;
|
|
35
|
+
//# sourceMappingURL=deprecated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecated.js","sourceRoot":"","sources":["../src/deprecated.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,sEAAsE;AACtE,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;AACxD,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;AAC9C,sEAAsE;AACtE,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;AAChD,sEAAsE;AACtE,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;AACpD,sEAAsE;AACtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,CAAC;AAC1D,sEAAsE;AACtE,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;AACxD,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,mBAAmB,CAAC;AAChE,sEAAsE;AACtE,MAAM,CAAC,MAAM,+BAA+B,GAAG,QAAQ,CAAC,+BAA+B,CAAC;AACxF,sEAAsE;AACtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC,qBAAqB,CAAC;AACpE,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,mBAAmB,CAAC;AAChE,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC;AAC5D,sEAAsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC;AAC5D,sEAAsE;AACtE,MAAM,CAAC,MAAM,yBAAyB,GAAG,QAAQ,CAAC,yBAAyB,CAAC;AAC5E,sEAAsE;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request-body size limits. Nothing upstream caps body size on its own —
|
|
3
|
+
* `request.json()` / `request.text()` and a raw `http.createServer` stream
|
|
4
|
+
* both buffer the whole body in memory first, so an uncapped read is a
|
|
5
|
+
* straightforward memory-exhaustion DoS.
|
|
6
|
+
*/
|
|
7
|
+
export declare class BodyTooLargeError extends Error {
|
|
8
|
+
readonly maxBytes: number;
|
|
9
|
+
constructor(maxBytes: number);
|
|
10
|
+
}
|
|
11
|
+
/** Default cap for `/mcp` — JSON-RPC payloads, generally small but tool args can be text-heavy. */
|
|
12
|
+
export declare const DEFAULT_MCP_BODY_LIMIT = 1048576;
|
|
13
|
+
/** Default cap for OAuth endpoints (`/token`, `/revoke`, `/register`, `/consent`) — tiny form/JSON. */
|
|
14
|
+
export declare const DEFAULT_OAUTH_BODY_LIMIT = 65536;
|
|
15
|
+
/**
|
|
16
|
+
* Structural subset of `Request`/`Response` that `readBoundedBytes` actually
|
|
17
|
+
* needs — both are real `Request`s (every caller inside this package) and,
|
|
18
|
+
* via `tools.ts`'s `apiTool`, a `Response` from an upstream `fetch` call
|
|
19
|
+
* capping how much of that body a tool ever buffers into memory.
|
|
20
|
+
*/
|
|
21
|
+
export type BoundedBodySource = {
|
|
22
|
+
headers: {
|
|
23
|
+
get: (name: string) => string | null;
|
|
24
|
+
};
|
|
25
|
+
body: ReadableStream<Uint8Array> | null;
|
|
26
|
+
text: () => Promise<string>;
|
|
27
|
+
/** Preferred over `text` for the no-stream fallback — keeps binary bodies intact. */
|
|
28
|
+
arrayBuffer?: () => Promise<ArrayBuffer>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Reads a bounded body as raw bytes, rejecting early on an honest oversized
|
|
32
|
+
* `Content-Length`, then aborting mid-stream — before the whole body is
|
|
33
|
+
* buffered — if a chunked body (no `Content-Length`) exceeds `maxBytes`.
|
|
34
|
+
* Falls back to `source.arrayBuffer()` (or `source.text()`) when
|
|
35
|
+
* `source.body` is null (some runtimes don't expose a streaming body),
|
|
36
|
+
* still enforcing the cap.
|
|
37
|
+
*
|
|
38
|
+
* Optional `signal` cancels the active reader on abort — needed when a hop
|
|
39
|
+
* timeout must stop a stalled stream (a locked `body.cancel()` is a no-op).
|
|
40
|
+
*/
|
|
41
|
+
export declare const readBoundedBytes: (source: BoundedBodySource, maxBytes: number, signal?: AbortSignal) => Promise<Uint8Array>;
|
|
42
|
+
/** `readBoundedBytes`, decoded as UTF-8 — for JSON / form / text bodies. */
|
|
43
|
+
export declare const readBoundedText: (source: BoundedBodySource, maxBytes: number, signal?: AbortSignal) => Promise<string>;
|
|
44
|
+
export type BoundedNodeBodyOptions = {
|
|
45
|
+
/** Declared `Content-Length` header value, checked before reading anything. */
|
|
46
|
+
contentLength?: string | undefined;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Node `IncomingMessage`-shaped readable: event listeners + pause.
|
|
50
|
+
* Prefer this over `for await` — throwing out of `for await` on an
|
|
51
|
+
* IncomingMessage runs the async iterator's `return()`, which **destroys**
|
|
52
|
+
* the request before the caller can write a 413.
|
|
53
|
+
*/
|
|
54
|
+
export type NodeReadableLike = {
|
|
55
|
+
on(event: "data", listener: (chunk: Uint8Array | string) => void): void;
|
|
56
|
+
on(event: "end", listener: () => void): void;
|
|
57
|
+
on(event: "error", listener: (err: Error) => void): void;
|
|
58
|
+
pause(): void;
|
|
59
|
+
removeListener(event: string, listener: (...args: unknown[]) => void): void;
|
|
60
|
+
};
|
|
61
|
+
export declare const isNodeReadable: (value: unknown) => value is NodeReadableLike;
|
|
62
|
+
/**
|
|
63
|
+
* Same contract as `readBoundedText` for a raw Node request stream.
|
|
64
|
+
* Does **not** destroy the socket — that races a 413 response into EPIPE.
|
|
65
|
+
* On overflow the event path pauses and drops listeners; the caller writes
|
|
66
|
+
* 413 then tears down after flush.
|
|
67
|
+
*/
|
|
68
|
+
export declare const readBoundedNodeBody: (source: NodeReadableLike | AsyncIterable<Uint8Array | string>, maxBytes: number, options?: BoundedNodeBodyOptions) => Promise<Uint8Array>;
|
|
69
|
+
//# sourceMappingURL=body.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../src/http/body.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM;CAItC;AAED,mGAAmG;AACnG,eAAO,MAAM,sBAAsB,UAAY,CAAC;AAEhD,uGAAuG;AACvG,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAuB/C;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE;QAAE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAClD,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACxC,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,iBAAiB,EACzB,UAAU,MAAM,EAChB,SAAS,WAAW,KACnB,OAAO,CAAC,UAAU,CA6CpB,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,eAAe,GAC1B,QAAQ,iBAAiB,EACzB,UAAU,MAAM,EAChB,SAAS,WAAW,KACnB,OAAO,CAAC,MAAM,CAA+E,CAAC;AAEjG,MAAM,MAAM,sBAAsB,GAAG;IACnC,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACxE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC7C,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IACzD,KAAK,IAAI,IAAI,CAAC;IACd,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;CAC7E,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,gBAG6B,CAAC;AA+DvF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,gBAAgB,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,EAC7D,UAAU,MAAM,EAChB,UAAS,sBAA2B,KACnC,OAAO,CAAC,UAAU,CAQpB,CAAC"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request-body size limits. Nothing upstream caps body size on its own —
|
|
3
|
+
* `request.json()` / `request.text()` and a raw `http.createServer` stream
|
|
4
|
+
* both buffer the whole body in memory first, so an uncapped read is a
|
|
5
|
+
* straightforward memory-exhaustion DoS.
|
|
6
|
+
*/
|
|
7
|
+
export class BodyTooLargeError extends Error {
|
|
8
|
+
maxBytes;
|
|
9
|
+
constructor(maxBytes) {
|
|
10
|
+
super(`request body exceeds ${maxBytes} bytes`);
|
|
11
|
+
this.maxBytes = maxBytes;
|
|
12
|
+
this.name = "BodyTooLargeError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Default cap for `/mcp` — JSON-RPC payloads, generally small but tool args can be text-heavy. */
|
|
16
|
+
export const DEFAULT_MCP_BODY_LIMIT = 1_048_576; // 1 MiB
|
|
17
|
+
/** Default cap for OAuth endpoints (`/token`, `/revoke`, `/register`, `/consent`) — tiny form/JSON. */
|
|
18
|
+
export const DEFAULT_OAUTH_BODY_LIMIT = 65_536; // 64 KiB
|
|
19
|
+
const declaredContentLength = (headers) => {
|
|
20
|
+
const header = headers.get("content-length");
|
|
21
|
+
if (!header)
|
|
22
|
+
return null;
|
|
23
|
+
const declared = Number(header);
|
|
24
|
+
return Number.isFinite(declared) ? declared : null;
|
|
25
|
+
};
|
|
26
|
+
const concatBytes = (chunks, total) => {
|
|
27
|
+
const combined = new Uint8Array(total);
|
|
28
|
+
chunks.reduce((offset, chunk) => {
|
|
29
|
+
combined.set(chunk, offset);
|
|
30
|
+
return offset + chunk.byteLength;
|
|
31
|
+
}, 0);
|
|
32
|
+
return combined;
|
|
33
|
+
};
|
|
34
|
+
const toBytes = (chunk) => typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk;
|
|
35
|
+
/**
|
|
36
|
+
* Reads a bounded body as raw bytes, rejecting early on an honest oversized
|
|
37
|
+
* `Content-Length`, then aborting mid-stream — before the whole body is
|
|
38
|
+
* buffered — if a chunked body (no `Content-Length`) exceeds `maxBytes`.
|
|
39
|
+
* Falls back to `source.arrayBuffer()` (or `source.text()`) when
|
|
40
|
+
* `source.body` is null (some runtimes don't expose a streaming body),
|
|
41
|
+
* still enforcing the cap.
|
|
42
|
+
*
|
|
43
|
+
* Optional `signal` cancels the active reader on abort — needed when a hop
|
|
44
|
+
* timeout must stop a stalled stream (a locked `body.cancel()` is a no-op).
|
|
45
|
+
*/
|
|
46
|
+
export const readBoundedBytes = async (source, maxBytes, signal) => {
|
|
47
|
+
if (signal?.aborted)
|
|
48
|
+
throw new Error("body read aborted");
|
|
49
|
+
const declared = declaredContentLength(source.headers);
|
|
50
|
+
if (declared !== null && declared > maxBytes) {
|
|
51
|
+
throw new BodyTooLargeError(maxBytes);
|
|
52
|
+
}
|
|
53
|
+
const reader = source.body?.getReader();
|
|
54
|
+
if (!reader) {
|
|
55
|
+
// ponytail: no stream → arrayBuffer/text ignore signal; fine for request
|
|
56
|
+
// bodies. CIMD always has a stream on Node/undici. Upgrade: race abort
|
|
57
|
+
// or refuse the fallback when signal is required.
|
|
58
|
+
const bytes = source.arrayBuffer
|
|
59
|
+
? new Uint8Array(await source.arrayBuffer())
|
|
60
|
+
: new TextEncoder().encode(await source.text());
|
|
61
|
+
if (bytes.byteLength > maxBytes)
|
|
62
|
+
throw new BodyTooLargeError(maxBytes);
|
|
63
|
+
return bytes;
|
|
64
|
+
}
|
|
65
|
+
const onAbort = () => {
|
|
66
|
+
void reader.cancel().catch(() => { });
|
|
67
|
+
};
|
|
68
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
69
|
+
const chunks = [];
|
|
70
|
+
let total = 0;
|
|
71
|
+
try {
|
|
72
|
+
for (;;) {
|
|
73
|
+
const { done, value } = await reader.read();
|
|
74
|
+
// Cancel may settle read() as done — still treat abort as failure.
|
|
75
|
+
if (signal?.aborted)
|
|
76
|
+
throw new Error("body read aborted");
|
|
77
|
+
if (done)
|
|
78
|
+
break;
|
|
79
|
+
// ponytail: one oversized chunk can briefly allocate maxBytes + highWaterMark
|
|
80
|
+
// (~64 KiB on Node) before reject — fine for 1 MiB / 64 KiB caps.
|
|
81
|
+
total += value.byteLength;
|
|
82
|
+
if (total > maxBytes)
|
|
83
|
+
throw new BodyTooLargeError(maxBytes);
|
|
84
|
+
chunks.push(value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
signal?.removeEventListener("abort", onAbort);
|
|
89
|
+
await reader.cancel().catch(() => { });
|
|
90
|
+
}
|
|
91
|
+
return concatBytes(chunks, total);
|
|
92
|
+
};
|
|
93
|
+
/** `readBoundedBytes`, decoded as UTF-8 — for JSON / form / text bodies. */
|
|
94
|
+
export const readBoundedText = async (source, maxBytes, signal) => new TextDecoder().decode(await readBoundedBytes(source, maxBytes, signal));
|
|
95
|
+
export const isNodeReadable = (value) => typeof value?.on === "function" &&
|
|
96
|
+
typeof value?.pause === "function" &&
|
|
97
|
+
typeof value?.removeListener === "function";
|
|
98
|
+
const readFromEvents = (stream, maxBytes) => new Promise((resolve, reject) => {
|
|
99
|
+
const collected = [];
|
|
100
|
+
let total = 0;
|
|
101
|
+
let settled = false;
|
|
102
|
+
const onData = (chunk) => {
|
|
103
|
+
const bytes = toBytes(chunk);
|
|
104
|
+
total += bytes.byteLength;
|
|
105
|
+
if (total > maxBytes) {
|
|
106
|
+
fail(new BodyTooLargeError(maxBytes));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
collected.push(bytes);
|
|
110
|
+
};
|
|
111
|
+
const onEnd = () => {
|
|
112
|
+
if (settled)
|
|
113
|
+
return;
|
|
114
|
+
settled = true;
|
|
115
|
+
cleanup();
|
|
116
|
+
resolve(concatBytes(collected, total));
|
|
117
|
+
};
|
|
118
|
+
const onError = (err) => {
|
|
119
|
+
fail(err);
|
|
120
|
+
};
|
|
121
|
+
const cleanup = () => {
|
|
122
|
+
stream.removeListener("data", onData);
|
|
123
|
+
stream.removeListener("end", onEnd);
|
|
124
|
+
stream.removeListener("error", onError);
|
|
125
|
+
};
|
|
126
|
+
const fail = (err) => {
|
|
127
|
+
if (settled)
|
|
128
|
+
return;
|
|
129
|
+
settled = true;
|
|
130
|
+
stream.pause();
|
|
131
|
+
cleanup();
|
|
132
|
+
reject(err);
|
|
133
|
+
};
|
|
134
|
+
stream.on("data", onData);
|
|
135
|
+
stream.on("end", onEnd);
|
|
136
|
+
stream.on("error", onError);
|
|
137
|
+
});
|
|
138
|
+
const readFromAsyncIterable = async (chunks, maxBytes) => {
|
|
139
|
+
const collected = [];
|
|
140
|
+
let total = 0;
|
|
141
|
+
for await (const chunk of chunks) {
|
|
142
|
+
const bytes = toBytes(chunk);
|
|
143
|
+
total += bytes.byteLength;
|
|
144
|
+
if (total > maxBytes)
|
|
145
|
+
throw new BodyTooLargeError(maxBytes);
|
|
146
|
+
collected.push(bytes);
|
|
147
|
+
}
|
|
148
|
+
return concatBytes(collected, total);
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Same contract as `readBoundedText` for a raw Node request stream.
|
|
152
|
+
* Does **not** destroy the socket — that races a 413 response into EPIPE.
|
|
153
|
+
* On overflow the event path pauses and drops listeners; the caller writes
|
|
154
|
+
* 413 then tears down after flush.
|
|
155
|
+
*/
|
|
156
|
+
export const readBoundedNodeBody = async (source, maxBytes, options = {}) => {
|
|
157
|
+
const declared = options.contentLength ? Number(options.contentLength) : NaN;
|
|
158
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
159
|
+
throw new BodyTooLargeError(maxBytes);
|
|
160
|
+
}
|
|
161
|
+
if (isNodeReadable(source))
|
|
162
|
+
return readFromEvents(source, maxBytes);
|
|
163
|
+
return readFromAsyncIterable(source, maxBytes);
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=body.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body.js","sourceRoot":"","sources":["../../src/http/body.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** JSON `error` body / audit reason when a host port throws. */
|
|
2
|
+
export declare const INTERNAL_ERROR = "internal_error";
|
|
3
|
+
/** A caught value's audit-safe message — an `Error`'s own message, else its `String()` form. */
|
|
4
|
+
export declare const errorReason: (caught: unknown) => string;
|
|
5
|
+
/** Default cap on how long a response waits for an audit sink. */
|
|
6
|
+
export declare const DEFAULT_AUDIT_TIMEOUT_MS = 1000;
|
|
7
|
+
/**
|
|
8
|
+
* Run an audit sink so it can neither fail nor stall the response: errors
|
|
9
|
+
* are swallowed, and the wait is capped at `timeoutMs`. The timer is cleared
|
|
10
|
+
* as soon as the sink settles — a fast sink must not leave a pending timer
|
|
11
|
+
* holding the process (or a serverless invocation) open. Shared by the MCP
|
|
12
|
+
* `safeAudit` and OAuth `safeOAuthAudit`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const runAuditBounded: (sink: () => void | Promise<void>, timeoutMs: number) => Promise<void>;
|
|
15
|
+
export declare const corsHeaders: (extra?: Record<string, string>) => Record<string, string>;
|
|
16
|
+
export type JsonResponseOptions = {
|
|
17
|
+
/** Include permissive CORS headers. Default true (MCP). OAuth token set false. */
|
|
18
|
+
cors?: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** Single-object JSON response — keeps the call site under the ≤3-params rule. */
|
|
21
|
+
export type JsonResponseInput = {
|
|
22
|
+
data: unknown;
|
|
23
|
+
status?: number;
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
cors?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare const jsonResponse: (input: JsonResponseInput) => Response;
|
|
28
|
+
export declare const emptyResponse: (status: number) => Response;
|
|
29
|
+
export declare const optionsResponse: (options?: JsonResponseOptions) => Response;
|
|
30
|
+
/** Reflect a validated browser Origin on MCP CORS instead of `*`. */
|
|
31
|
+
export declare const withReflectedCorsOrigin: (response: Response, origin: string) => Response;
|
|
32
|
+
export declare const methodNotAllowed: (message?: string, options?: JsonResponseOptions) => Response;
|
|
33
|
+
export declare const GET_ONLY: ReadonlySet<string>;
|
|
34
|
+
export declare const POST_ONLY: ReadonlySet<string>;
|
|
35
|
+
/** For endpoints that must not send permissive CORS headers (`/token`, `/revoke`, `/consent`). */
|
|
36
|
+
export declare const NO_CORS: JsonResponseOptions;
|
|
37
|
+
/**
|
|
38
|
+
* OPTIONS → 204; allowed verb → null (continue); otherwise → 405.
|
|
39
|
+
* Shared by OAuth handlers that all need the same method gate.
|
|
40
|
+
*/
|
|
41
|
+
export declare const requireHttpMethod: (request: Request, allowed: ReadonlySet<string>, options?: JsonResponseOptions) => Response | null;
|
|
42
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,gGAAgG;AAChG,eAAO,MAAM,WAAW,GAAI,QAAQ,OAAO,KAAG,MACa,CAAC;AAE5D,kEAAkE;AAClE,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAChC,WAAW,MAAM,KAChB,OAAO,CAAC,IAAI,CAiBd,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAUhF,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG;IAChC,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,kFAAkF;AAClF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO,iBAAiB,KAAG,QAWvD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,QAI3C,CAAC;AAEL,eAAO,MAAM,eAAe,GAAI,UAAU,mBAAmB,KAAG,QAO5D,CAAC;AAEL,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,GAAI,UAAU,QAAQ,EAAE,QAAQ,MAAM,KAAG,QAU5E,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,gBAA8B,EAC9B,UAAU,mBAAmB,KAC5B,QAKC,CAAC;AAEL,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAoB,CAAC;AAC9D,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,MAAM,CAAqB,CAAC;AAChE,kGAAkG;AAClG,eAAO,MAAM,OAAO,EAAE,mBAAqC,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,OAAO,EAChB,SAAS,WAAW,CAAC,MAAM,CAAC,EAC5B,UAAU,mBAAmB,KAC5B,QAAQ,GAAG,IAIb,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** JSON `error` body / audit reason when a host port throws. */
|
|
2
|
+
export const INTERNAL_ERROR = "internal_error";
|
|
3
|
+
/** A caught value's audit-safe message — an `Error`'s own message, else its `String()` form. */
|
|
4
|
+
export const errorReason = (caught) => caught instanceof Error ? caught.message : String(caught);
|
|
5
|
+
/** Default cap on how long a response waits for an audit sink. */
|
|
6
|
+
export const DEFAULT_AUDIT_TIMEOUT_MS = 1000;
|
|
7
|
+
/**
|
|
8
|
+
* Run an audit sink so it can neither fail nor stall the response: errors
|
|
9
|
+
* are swallowed, and the wait is capped at `timeoutMs`. The timer is cleared
|
|
10
|
+
* as soon as the sink settles — a fast sink must not leave a pending timer
|
|
11
|
+
* holding the process (or a serverless invocation) open. Shared by the MCP
|
|
12
|
+
* `safeAudit` and OAuth `safeOAuthAudit`.
|
|
13
|
+
*/
|
|
14
|
+
export const runAuditBounded = async (sink, timeoutMs) => {
|
|
15
|
+
const settled = (async () => {
|
|
16
|
+
try {
|
|
17
|
+
await sink();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Intentionally ignored.
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
let timer;
|
|
24
|
+
const timeout = new Promise((resolve) => {
|
|
25
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
await Promise.race([settled, timeout]);
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export const corsHeaders = (extra) => ({
|
|
35
|
+
"Access-Control-Allow-Origin": "*",
|
|
36
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
37
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, MCP-Protocol-Version",
|
|
38
|
+
// Response headers are opaque to browser JS by default unless explicitly
|
|
39
|
+
// exposed — without this, a browser-based MCP client reading a 401 can
|
|
40
|
+
// see the status but not WWW-Authenticate itself, i.e. not the
|
|
41
|
+
// resource_metadata URL RFC 9728 discovery depends on.
|
|
42
|
+
"Access-Control-Expose-Headers": "WWW-Authenticate",
|
|
43
|
+
...extra,
|
|
44
|
+
});
|
|
45
|
+
export const jsonResponse = (input) => {
|
|
46
|
+
const cors = input.cors !== false;
|
|
47
|
+
return new Response(JSON.stringify(input.data), {
|
|
48
|
+
status: input.status ?? 200,
|
|
49
|
+
headers: {
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
"Cache-Control": "no-store",
|
|
52
|
+
...(cors ? corsHeaders() : {}),
|
|
53
|
+
...input.headers,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
export const emptyResponse = (status) => new Response(null, {
|
|
58
|
+
status,
|
|
59
|
+
headers: { ...corsHeaders(), "Cache-Control": "no-store" },
|
|
60
|
+
});
|
|
61
|
+
export const optionsResponse = (options) => new Response(null, {
|
|
62
|
+
status: 204,
|
|
63
|
+
headers: options?.cors === false
|
|
64
|
+
? { "Cache-Control": "no-store" }
|
|
65
|
+
: { ...corsHeaders(), "Cache-Control": "no-store" },
|
|
66
|
+
});
|
|
67
|
+
/** Reflect a validated browser Origin on MCP CORS instead of `*`. */
|
|
68
|
+
export const withReflectedCorsOrigin = (response, origin) => {
|
|
69
|
+
const headers = new Headers(response.headers);
|
|
70
|
+
if (!headers.has("Access-Control-Allow-Origin"))
|
|
71
|
+
return response;
|
|
72
|
+
headers.set("Access-Control-Allow-Origin", origin);
|
|
73
|
+
headers.set("Vary", "Origin");
|
|
74
|
+
return new Response(response.body, {
|
|
75
|
+
status: response.status,
|
|
76
|
+
statusText: response.statusText,
|
|
77
|
+
headers,
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
export const methodNotAllowed = (message = "Method not allowed", options) => jsonResponse({
|
|
81
|
+
data: { error: message },
|
|
82
|
+
status: 405,
|
|
83
|
+
...(options?.cors !== undefined ? { cors: options.cors } : {}),
|
|
84
|
+
});
|
|
85
|
+
export const GET_ONLY = new Set(["GET"]);
|
|
86
|
+
export const POST_ONLY = new Set(["POST"]);
|
|
87
|
+
/** For endpoints that must not send permissive CORS headers (`/token`, `/revoke`, `/consent`). */
|
|
88
|
+
export const NO_CORS = { cors: false };
|
|
89
|
+
/**
|
|
90
|
+
* OPTIONS → 204; allowed verb → null (continue); otherwise → 405.
|
|
91
|
+
* Shared by OAuth handlers that all need the same method gate.
|
|
92
|
+
*/
|
|
93
|
+
export const requireHttpMethod = (request, allowed, options) => {
|
|
94
|
+
if (request.method === "OPTIONS")
|
|
95
|
+
return optionsResponse(options);
|
|
96
|
+
if (allowed.has(request.method))
|
|
97
|
+
return null;
|
|
98
|
+
return methodNotAllowed(undefined, options);
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"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"}
|