@cyanmycelium/mcp-broker 0.3.0 → 1.0.1
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/.mcp-broker.example/CONFIGURATION-EN.md +861 -0
- package/.mcp-broker.example/CONFIGURATION-FR.md +871 -0
- package/.mcp-broker.example/README.md +5 -0
- package/.mcp-broker.example/config.json +86 -0
- package/README.md +116 -1
- package/dist/auth/auth.config.d.ts +40 -0
- package/dist/auth/auth.config.js +62 -0
- package/dist/auth/auth.config.js.map +1 -0
- package/dist/auth/auth.types.d.ts +119 -0
- package/dist/auth/auth.types.js +38 -0
- package/dist/auth/auth.types.js.map +1 -0
- package/dist/auth/http.auth.d.ts +51 -0
- package/dist/auth/http.auth.js +121 -0
- package/dist/auth/http.auth.js.map +1 -0
- package/dist/auth/index.d.ts +16 -0
- package/dist/auth/index.js +12 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/jwt.validator.d.ts +35 -0
- package/dist/auth/jwt.validator.js +46 -0
- package/dist/auth/jwt.validator.js.map +1 -0
- package/dist/auth/provider.auth.d.ts +51 -0
- package/dist/auth/provider.auth.js +80 -0
- package/dist/auth/provider.auth.js.map +1 -0
- package/dist/auth/resource.metadata.d.ts +32 -0
- package/dist/auth/resource.metadata.js +26 -0
- package/dist/auth/resource.metadata.js.map +1 -0
- package/dist/authorization/audit.d.ts +14 -0
- package/dist/authorization/audit.js +20 -0
- package/dist/authorization/audit.js.map +1 -0
- package/dist/authorization/capability.classifier.d.ts +30 -0
- package/dist/authorization/capability.classifier.js +85 -0
- package/dist/authorization/capability.classifier.js.map +1 -0
- package/dist/authorization/index.d.ts +13 -0
- package/dist/authorization/index.js +8 -0
- package/dist/authorization/index.js.map +1 -0
- package/dist/authorization/policy.engine.d.ts +11 -0
- package/dist/authorization/policy.engine.js +192 -0
- package/dist/authorization/policy.engine.js.map +1 -0
- package/dist/authorization/policy.types.d.ts +92 -0
- package/dist/authorization/policy.types.js +2 -0
- package/dist/authorization/policy.types.js.map +1 -0
- package/dist/authorization/resource.path.d.ts +27 -0
- package/dist/authorization/resource.path.js +122 -0
- package/dist/authorization/resource.path.js.map +1 -0
- package/dist/authorization/runtime.d.ts +22 -0
- package/dist/authorization/runtime.js +34 -0
- package/dist/authorization/runtime.js.map +1 -0
- package/dist/authorization/slot.resource.d.ts +12 -0
- package/dist/authorization/slot.resource.js +41 -0
- package/dist/authorization/slot.resource.js.map +1 -0
- package/dist/authorization/subject.mapper.d.ts +15 -0
- package/dist/authorization/subject.mapper.js +67 -0
- package/dist/authorization/subject.mapper.js.map +1 -0
- package/dist/bin.js +49 -0
- package/dist/bin.js.map +1 -1
- package/dist/broker/adapters/broker.adapter.info.d.ts +3 -3
- package/dist/broker/adapters/broker.adapter.info.js +1 -1
- package/dist/broker/adapters/broker.adapter.info.js.map +1 -1
- package/dist/broker/adapters/broker.adapter.providers.d.ts +2 -2
- package/dist/broker/adapters/broker.adapter.providers.js.map +1 -1
- package/dist/broker/aggregate/aggregate.catalog.d.ts +23 -11
- package/dist/broker/aggregate/aggregate.catalog.js +14 -0
- package/dist/broker/aggregate/aggregate.catalog.js.map +1 -1
- package/dist/broker/aggregate/aggregate.server.d.ts +22 -3
- package/dist/broker/aggregate/aggregate.server.js +115 -9
- package/dist/broker/aggregate/aggregate.server.js.map +1 -1
- package/dist/broker/aggregate/provider.client.session.d.ts +9 -9
- package/dist/broker/aggregate/provider.client.session.js +1 -1
- package/dist/broker/aggregate/provider.client.session.js.map +1 -1
- package/dist/broker/behaviors/broker.behavior.info.d.ts +2 -2
- package/dist/broker/behaviors/broker.behavior.info.js.map +1 -1
- package/dist/broker/behaviors/broker.behavior.providers.d.ts +2 -2
- package/dist/broker/behaviors/broker.behavior.providers.js.map +1 -1
- package/dist/broker/broker.context.d.ts +8 -4
- package/dist/broker/broker.grammars.d.ts +52 -86
- package/dist/broker/broker.grammars.js +55 -84
- package/dist/broker/broker.grammars.js.map +1 -1
- package/dist/broker/broker.server.d.ts +28 -24
- package/dist/broker/broker.server.js +21 -70
- package/dist/broker/broker.server.js.map +1 -1
- package/dist/broker/index.d.ts +4 -4
- package/dist/broker/index.js +1 -1
- package/dist/broker/index.js.map +1 -1
- package/dist/config.d.ts +51 -5
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +13 -9
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/mcpb.loader.d.ts +6 -4
- package/dist/mcpb.loader.js +3 -3
- package/dist/mcpb.loader.js.map +1 -1
- package/dist/remote.transports.d.ts +4 -2
- package/dist/remote.transports.js.map +1 -1
- package/dist/remote.upstream.d.ts +6 -4
- package/dist/remote.upstream.js.map +1 -1
- package/dist/stdio.upstream.d.ts +6 -4
- package/dist/stdio.upstream.js.map +1 -1
- package/dist/upstream.d.ts +3 -1
- package/dist/ws.tunnel.builder.d.ts +41 -4
- package/dist/ws.tunnel.builder.js +66 -0
- package/dist/ws.tunnel.builder.js.map +1 -1
- package/dist/ws.tunnel.d.ts +116 -36
- package/dist/ws.tunnel.js +384 -51
- package/dist/ws.tunnel.js.map +1 -1
- package/package.json +7 -3
- package/src/auth/auth.config.ts +98 -0
- package/src/auth/auth.types.ts +145 -0
- package/src/auth/http.auth.ts +132 -0
- package/src/auth/index.ts +34 -0
- package/src/auth/jwt.validator.ts +63 -0
- package/src/auth/provider.auth.ts +114 -0
- package/src/auth/resource.metadata.ts +41 -0
- package/src/authorization/audit.ts +35 -0
- package/src/authorization/capability.classifier.ts +114 -0
- package/src/authorization/index.ts +37 -0
- package/src/authorization/policy.engine.ts +212 -0
- package/src/authorization/policy.types.ts +105 -0
- package/src/authorization/resource.path.ts +126 -0
- package/src/authorization/runtime.ts +56 -0
- package/src/authorization/slot.resource.ts +50 -0
- package/src/authorization/subject.mapper.ts +81 -0
- package/src/bin.ts +53 -0
- package/src/broker/adapters/broker.adapter.info.ts +3 -3
- package/src/broker/adapters/broker.adapter.providers.ts +3 -3
- package/src/broker/aggregate/aggregate.catalog.ts +48 -20
- package/src/broker/aggregate/aggregate.server.ts +146 -16
- package/src/broker/aggregate/provider.client.session.ts +22 -22
- package/src/broker/behaviors/broker.behavior.info.ts +2 -2
- package/src/broker/behaviors/broker.behavior.providers.ts +2 -2
- package/src/broker/broker.context.ts +10 -4
- package/src/broker/broker.grammars.ts +77 -122
- package/src/broker/broker.server.ts +51 -101
- package/src/broker/index.ts +5 -7
- package/src/config.ts +57 -6
- package/src/index.ts +109 -16
- package/src/mcpb.loader.ts +14 -11
- package/src/remote.transports.ts +8 -5
- package/src/remote.upstream.ts +10 -7
- package/src/stdio.upstream.ts +8 -5
- package/src/upstream.ts +4 -1
- package/src/ws.tunnel.builder.ts +89 -9
- package/src/ws.tunnel.ts +521 -102
- package/web/README.md +94 -0
- package/web/assets/logo.png +0 -0
- package/web/broker-self-mcp.html +338 -0
- package/web/css/styles.css +580 -0
- package/web/demos/DemoPlaceholder.html +258 -0
- package/web/demos/broker-explorer/css/app.css +393 -0
- package/web/demos/broker-explorer/index.html +94 -0
- package/web/demos/broker-explorer/js/app.js +271 -0
- package/web/demos/broker-explorer/js/mcp-ws-client.js +132 -0
- package/web/demos/oauth-lab/README.md +68 -0
- package/web/demos/oauth-lab/config.json +116 -0
- package/web/demos/oauth-lab/css/app.css +1097 -0
- package/web/demos/oauth-lab/index.html +323 -0
- package/web/demos/oauth-lab/js/app.js +630 -0
- package/web/demos/oauth-lab/server/auth-server.mjs +426 -0
- package/web/demos/oauth-lab/server/factory-provider.mjs +269 -0
- package/web/demos/oauth-lab/server/smoke-test.mjs +261 -0
- package/web/demos/oauth-lab/server/start.mjs +106 -0
- package/web/demos/provider-tunnel/css/app.css +384 -0
- package/web/demos/provider-tunnel/index.html +99 -0
- package/web/demos/provider-tunnel/js/app.js +226 -0
- package/web/demos/provider-tunnel/js/toolbox-server.js +186 -0
- package/web/index.html +558 -0
- package/web/js/lib/broker-tunnel.js +173 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { AuthError, scopesOf } from "./auth.types.js";
|
|
2
|
+
import { buildResourceMetadata } from "./resource.metadata.js";
|
|
3
|
+
import { SubjectMappingError } from "../authorization/index.js";
|
|
4
|
+
/** Well-known prefix under which per-slot Protected Resource Metadata is served. */
|
|
5
|
+
const PRM_PREFIX = "/.well-known/oauth-protected-resource/";
|
|
6
|
+
/** Extracts the bearer token from an `Authorization` header, or `null`. */
|
|
7
|
+
function extractBearer(header) {
|
|
8
|
+
if (typeof header !== "string")
|
|
9
|
+
return null;
|
|
10
|
+
const match = /^Bearer\s+(.+)$/i.exec(header.trim());
|
|
11
|
+
return match ? match[1].trim() : null;
|
|
12
|
+
}
|
|
13
|
+
/** Strips characters that would break (or inject into) an HTTP header value. */
|
|
14
|
+
function headerSafe(value) {
|
|
15
|
+
return value.replace(/[\r\n"]/g, " ").trim();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The HTTP enforcement point for the resource-server layer. Wraps a
|
|
19
|
+
* {@link IResolvedAuth} plus the configured `/mcp` path suffix and turns it into
|
|
20
|
+
* the three operations the transport needs: serve Protected Resource Metadata,
|
|
21
|
+
* authorize a request, and write an RFC 9728 `401`/`403` challenge.
|
|
22
|
+
*
|
|
23
|
+
* A slot's **canonical resource URI** is `<publicBaseUrl>/<slot>/<mcp>` and is
|
|
24
|
+
* used uniformly across all of that slot's HTTP endpoints (`/mcp`, `/sse`,
|
|
25
|
+
* `/messages`) so a single token audience covers the whole slot.
|
|
26
|
+
*/
|
|
27
|
+
export class HttpAuthGuard {
|
|
28
|
+
_auth;
|
|
29
|
+
/** The `/mcp` suffix without a leading slash, e.g. `"mcp"`. */
|
|
30
|
+
_mcpSuffix;
|
|
31
|
+
constructor(auth, mcpSuffix) {
|
|
32
|
+
this._auth = auth;
|
|
33
|
+
this._mcpSuffix = mcpSuffix.replace(/^\//, "");
|
|
34
|
+
}
|
|
35
|
+
/** Canonical resource identifier for a slot (RFC 8707 §2). */
|
|
36
|
+
resourceFor(slot) {
|
|
37
|
+
return `${this._auth.publicBaseUrl}/${encodeURIComponent(slot)}/${this._mcpSuffix}`;
|
|
38
|
+
}
|
|
39
|
+
/** RFC 9728 metadata URL for a slot, advertised in the `401` challenge. */
|
|
40
|
+
metadataUrlFor(slot) {
|
|
41
|
+
return `${this._auth.publicBaseUrl}${PRM_PREFIX}${encodeURIComponent(slot)}/${this._mcpSuffix}`;
|
|
42
|
+
}
|
|
43
|
+
/** Required scope(s) for a slot: per-slot override, else the baseline. */
|
|
44
|
+
requiredScopesFor(slot) {
|
|
45
|
+
return this._auth.perSlotScopes?.[slot] ?? this._auth.requiredScopes ?? [];
|
|
46
|
+
}
|
|
47
|
+
/** The RFC 9728 metadata document for a slot. */
|
|
48
|
+
metadataFor(slot) {
|
|
49
|
+
return buildResourceMetadata({
|
|
50
|
+
resource: this.resourceFor(slot),
|
|
51
|
+
authorizationServers: this._auth.authorizationServers,
|
|
52
|
+
scopesSupported: this._auth.scopesSupported,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* If `rawUrl` is a Protected Resource Metadata request
|
|
57
|
+
* (`/.well-known/oauth-protected-resource/<slot>/<mcp>`), returns the slot;
|
|
58
|
+
* otherwise `null`.
|
|
59
|
+
*/
|
|
60
|
+
matchMetadataRequest(rawUrl) {
|
|
61
|
+
if (!rawUrl.startsWith(PRM_PREFIX))
|
|
62
|
+
return null;
|
|
63
|
+
const parts = rawUrl.slice(PRM_PREFIX.length).split("/").filter(Boolean);
|
|
64
|
+
if (parts.length !== 2 || parts[1] !== this._mcpSuffix)
|
|
65
|
+
return null;
|
|
66
|
+
return decodeURIComponent(parts[0]);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Validates the request's bearer token against the slot's canonical resource
|
|
70
|
+
* and enforces the slot's required scopes. Resolves to the {@link IPrincipal}
|
|
71
|
+
* on success; rejects with an {@link AuthError} (`401` missing/invalid token,
|
|
72
|
+
* `403` insufficient scope) otherwise.
|
|
73
|
+
*/
|
|
74
|
+
async authorize(req, slot) {
|
|
75
|
+
const token = extractBearer(req.headers["authorization"]);
|
|
76
|
+
if (!token) {
|
|
77
|
+
throw new AuthError(401, "invalid_token", "Missing bearer token");
|
|
78
|
+
}
|
|
79
|
+
const claims = await this._auth.validator.validate(token, this.resourceFor(slot));
|
|
80
|
+
const scopes = scopesOf(claims);
|
|
81
|
+
const required = this.requiredScopesFor(slot);
|
|
82
|
+
const missing = required.filter((s) => !scopes.has(s));
|
|
83
|
+
if (missing.length > 0) {
|
|
84
|
+
throw new AuthError(403, "insufficient_scope", `Missing required scope(s): ${missing.join(" ")}`, required.join(" "));
|
|
85
|
+
}
|
|
86
|
+
let subject;
|
|
87
|
+
try {
|
|
88
|
+
subject = this._auth.authorization?.subjectMapper.map(claims);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error instanceof SubjectMappingError) {
|
|
92
|
+
throw new AuthError(403, "insufficient_scope", "Malformed configured JWT subject claim");
|
|
93
|
+
}
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
return subject ? { claims, scopes, subject } : { claims, scopes };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Builds the RFC 9728 §5.1 `WWW-Authenticate` header value for a challenge.
|
|
100
|
+
* Always points the client at the slot's metadata URL so it can discover the
|
|
101
|
+
* authorization server and retry. Shared by the HTTP and WebSocket paths.
|
|
102
|
+
*/
|
|
103
|
+
challengeHeader(slot, err) {
|
|
104
|
+
const params = [`resource_metadata="${this.metadataUrlFor(slot)}"`, `error="${err.code}"`];
|
|
105
|
+
if (err.description)
|
|
106
|
+
params.push(`error_description="${headerSafe(err.description)}"`);
|
|
107
|
+
if (err.scope)
|
|
108
|
+
params.push(`scope="${headerSafe(err.scope)}"`);
|
|
109
|
+
return `Bearer ${params.join(", ")}`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Writes an RFC 9728 §5.1 `WWW-Authenticate` challenge and the matching
|
|
113
|
+
* status to an HTTP response.
|
|
114
|
+
*/
|
|
115
|
+
writeChallenge(res, slot, err) {
|
|
116
|
+
res.setHeader("WWW-Authenticate", this.challengeHeader(slot, err));
|
|
117
|
+
res.writeHead(err.status, { "Content-Type": "application/json; charset=utf-8" });
|
|
118
|
+
res.end(JSON.stringify({ error: err.code, error_description: err.description }));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=http.auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.auth.js","sourceRoot":"","sources":["../../src/auth/http.auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for the broker's OAuth 2.1 resource-server layer. See the individual
|
|
3
|
+
* modules for details; the transport wires these up in `ws.tunnel.ts`.
|
|
4
|
+
*/
|
|
5
|
+
export { AuthError, scopesOf } from "./auth.types.js";
|
|
6
|
+
export type { IAccessTokenClaims, ITokenValidator, AuthErrorCode, IPrincipal, IResolvedAuth, AggregateScopeFilter, AccessTokenClaims, TokenValidator, Principal, ResolvedAuth, } from "./auth.types.js";
|
|
7
|
+
export { JwtTokenValidator } from "./jwt.validator.js";
|
|
8
|
+
export type { IJwtValidatorOptions, JwtValidatorOptions } from "./jwt.validator.js";
|
|
9
|
+
export { buildResourceMetadata } from "./resource.metadata.js";
|
|
10
|
+
export type { IProtectedResourceMetadata, ProtectedResourceMetadata } from "./resource.metadata.js";
|
|
11
|
+
export { HttpAuthGuard } from "./http.auth.js";
|
|
12
|
+
export { buildJwtAuth } from "./auth.config.js";
|
|
13
|
+
export type { IJwtAuthOptions, JwtAuthOptions } from "./auth.config.js";
|
|
14
|
+
export { SharedSecretProviderAuthenticator } from "./provider.auth.js";
|
|
15
|
+
export { normalizeProviderAuthentication, providerMayPublish } from "./provider.auth.js";
|
|
16
|
+
export type { IProviderAuthenticator, IProviderPrincipal, ProviderAuthenticationResult, ProviderAuthenticator, ProviderAuthenticatorReturn, ProviderPrincipal, } from "./provider.auth.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for the broker's OAuth 2.1 resource-server layer. See the individual
|
|
3
|
+
* modules for details; the transport wires these up in `ws.tunnel.ts`.
|
|
4
|
+
*/
|
|
5
|
+
export { AuthError, scopesOf } from "./auth.types.js";
|
|
6
|
+
export { JwtTokenValidator } from "./jwt.validator.js";
|
|
7
|
+
export { buildResourceMetadata } from "./resource.metadata.js";
|
|
8
|
+
export { HttpAuthGuard } from "./http.auth.js";
|
|
9
|
+
export { buildJwtAuth } from "./auth.config.js";
|
|
10
|
+
export { SharedSecretProviderAuthenticator } from "./provider.auth.js";
|
|
11
|
+
export { normalizeProviderAuthentication, providerMayPublish } from "./provider.auth.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAatD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,iCAAiC,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,+BAA+B,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type IAccessTokenClaims, type ITokenValidator } from "./auth.types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Options for {@link JwtTokenValidator}. `jwksUri` points at the authorization
|
|
4
|
+
* server's JWKS endpoint; `issuer` (when set) is checked against the token `iss`.
|
|
5
|
+
*/
|
|
6
|
+
export interface IJwtValidatorOptions {
|
|
7
|
+
/** URL of the authorization server's JWKS document. */
|
|
8
|
+
jwksUri: string;
|
|
9
|
+
/** Expected token issuer(s). When omitted, the `iss` claim is not checked. */
|
|
10
|
+
issuer?: string | string[];
|
|
11
|
+
/** Leeway in seconds for `exp`/`nbf` checks. Defaults to jose's `0`. */
|
|
12
|
+
clockToleranceSec?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* An {@link ITokenValidator} that verifies JWT access tokens **statelessly** by
|
|
16
|
+
* checking the signature against the authorization server's JWKS and validating
|
|
17
|
+
* the standard claims. This is the default validator for a public deployment:
|
|
18
|
+
* no per-request round-trip to the AS, no shared introspection secret.
|
|
19
|
+
*
|
|
20
|
+
* Audience binding (RFC 8707) is enforced by passing the per-request canonical
|
|
21
|
+
* resource URI as the required `audience`, so a token minted for another slot —
|
|
22
|
+
* or another service — is rejected.
|
|
23
|
+
*
|
|
24
|
+
* The JWKS is fetched lazily and cached (with rotation/cooldown) by
|
|
25
|
+
* `jose.createRemoteJWKSet`.
|
|
26
|
+
*/
|
|
27
|
+
export declare class JwtTokenValidator implements ITokenValidator {
|
|
28
|
+
private readonly _jwks;
|
|
29
|
+
private readonly _issuer?;
|
|
30
|
+
private readonly _clockTolerance;
|
|
31
|
+
constructor(options: IJwtValidatorOptions);
|
|
32
|
+
validate(token: string, resource: string): Promise<IAccessTokenClaims>;
|
|
33
|
+
}
|
|
34
|
+
/** @deprecated Use {@link IJwtValidatorOptions}. */
|
|
35
|
+
export type JwtValidatorOptions = IJwtValidatorOptions;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createRemoteJWKSet, jwtVerify, errors } from "jose";
|
|
2
|
+
import { AuthError } from "./auth.types.js";
|
|
3
|
+
/**
|
|
4
|
+
* An {@link ITokenValidator} that verifies JWT access tokens **statelessly** by
|
|
5
|
+
* checking the signature against the authorization server's JWKS and validating
|
|
6
|
+
* the standard claims. This is the default validator for a public deployment:
|
|
7
|
+
* no per-request round-trip to the AS, no shared introspection secret.
|
|
8
|
+
*
|
|
9
|
+
* Audience binding (RFC 8707) is enforced by passing the per-request canonical
|
|
10
|
+
* resource URI as the required `audience`, so a token minted for another slot —
|
|
11
|
+
* or another service — is rejected.
|
|
12
|
+
*
|
|
13
|
+
* The JWKS is fetched lazily and cached (with rotation/cooldown) by
|
|
14
|
+
* `jose.createRemoteJWKSet`.
|
|
15
|
+
*/
|
|
16
|
+
export class JwtTokenValidator {
|
|
17
|
+
_jwks;
|
|
18
|
+
_issuer;
|
|
19
|
+
_clockTolerance;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this._jwks = createRemoteJWKSet(new URL(options.jwksUri));
|
|
22
|
+
this._issuer = options.issuer;
|
|
23
|
+
this._clockTolerance = options.clockToleranceSec ?? 0;
|
|
24
|
+
}
|
|
25
|
+
async validate(token, resource) {
|
|
26
|
+
try {
|
|
27
|
+
const { payload } = await jwtVerify(token, this._jwks, {
|
|
28
|
+
audience: resource,
|
|
29
|
+
issuer: this._issuer,
|
|
30
|
+
clockTolerance: this._clockTolerance,
|
|
31
|
+
});
|
|
32
|
+
return payload;
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
// Token-level failures (bad signature, wrong audience/issuer, expired,
|
|
36
|
+
// no matching key) are JOSEError subclasses ⇒ a genuine 401. Anything
|
|
37
|
+
// else (JWKS endpoint unreachable, malformed config) is infrastructure:
|
|
38
|
+
// rethrow so the caller surfaces a 500 instead of a misleading 401.
|
|
39
|
+
if (err instanceof errors.JOSEError) {
|
|
40
|
+
throw new AuthError(401, "invalid_token", err.message);
|
|
41
|
+
}
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=jwt.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.validator.js","sourceRoot":"","sources":["../../src/auth/jwt.validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAwB,MAAM,MAAM,CAAC;AACnF,OAAO,EAAE,SAAS,EAAiD,MAAM,iBAAiB,CAAC;AAe3F;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,iBAAiB;IACT,KAAK,CAAkB;IACvB,OAAO,CAAqB;IAC5B,eAAe,CAAS;IAEzC,YAAY,OAA6B;QACrC,IAAI,CAAC,KAAK,GAAG,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,iBAAiB,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,QAAgB;QAC1C,IAAI,CAAC;YACD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;gBACnD,QAAQ,EAAE,QAAQ;gBAClB,MAAM,EAAE,IAAI,CAAC,OAAO;gBACpB,cAAc,EAAE,IAAI,CAAC,eAAe;aACvC,CAAC,CAAC;YACH,OAAO,OAA6B,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,oEAAoE;YACpE,IAAI,GAAG,YAAY,MAAM,CAAC,SAAS,EAAE,CAAC;gBAClC,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YAC3D,CAAC;YACD,MAAM,GAAG,CAAC;QACd,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { IncomingMessage } from "http";
|
|
2
|
+
import { ResourcePath } from "../authorization/index.js";
|
|
3
|
+
export interface IProviderPrincipal {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly subjects?: readonly string[];
|
|
6
|
+
readonly allowedResources?: readonly string[];
|
|
7
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
8
|
+
}
|
|
9
|
+
export type ProviderAuthenticationResult = {
|
|
10
|
+
readonly authenticated: true;
|
|
11
|
+
readonly principal: IProviderPrincipal;
|
|
12
|
+
} | {
|
|
13
|
+
readonly authenticated: false;
|
|
14
|
+
readonly reason?: string;
|
|
15
|
+
};
|
|
16
|
+
export type ProviderAuthenticatorReturn = boolean | ProviderAuthenticationResult;
|
|
17
|
+
/**
|
|
18
|
+
* Authenticates a **provider** (the engine that connects _into_ the broker to
|
|
19
|
+
* serve a slot) at the WebSocket upgrade handshake. This is a distinct concern
|
|
20
|
+
* from the OAuth 2.1 resource-server layer that guards *clients*: a provider is
|
|
21
|
+
* not an OAuth client acting for a resource owner, it is the backend claiming a
|
|
22
|
+
* slot. Authenticating it is what stops a stranger from occupying a free slot
|
|
23
|
+
* (`ws://host/provider/<slot>`) and impersonating the real engine.
|
|
24
|
+
*/
|
|
25
|
+
export interface IProviderAuthenticator {
|
|
26
|
+
/**
|
|
27
|
+
* Returns a structured result, or a legacy boolean for backward
|
|
28
|
+
* compatibility. `slot` is the dedicated slot name for
|
|
29
|
+
* `/provider/<slot>`, or `undefined` for the multiplexed `/providers`
|
|
30
|
+
* socket, which is authenticated before any provider name is known.
|
|
31
|
+
*/
|
|
32
|
+
authenticate(req: IncomingMessage, slot: string | undefined): ProviderAuthenticatorReturn | Promise<ProviderAuthenticatorReturn>;
|
|
33
|
+
}
|
|
34
|
+
export declare function normalizeProviderAuthentication(result: ProviderAuthenticatorReturn, fallbackId?: string): ProviderAuthenticationResult;
|
|
35
|
+
export declare function providerMayPublish(principal: IProviderPrincipal, resource: ResourcePath): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The default {@link IProviderAuthenticator}: every provider connection must
|
|
38
|
+
* present a single shared secret (via `X-Provider-Token` or `Authorization:
|
|
39
|
+
* Bearer`). Compared in constant time. Suitable when the broker and its
|
|
40
|
+
* providers are operated by the same party; swap in a custom authenticator for
|
|
41
|
+
* per-slot secrets, mTLS, or a signed handshake.
|
|
42
|
+
*/
|
|
43
|
+
export declare class SharedSecretProviderAuthenticator implements IProviderAuthenticator {
|
|
44
|
+
private readonly _secret;
|
|
45
|
+
constructor(secret: string);
|
|
46
|
+
authenticate(req: IncomingMessage): ProviderAuthenticationResult;
|
|
47
|
+
}
|
|
48
|
+
/** @deprecated Use {@link IProviderPrincipal}. */
|
|
49
|
+
export type ProviderPrincipal = IProviderPrincipal;
|
|
50
|
+
/** @deprecated Use {@link IProviderAuthenticator}. */
|
|
51
|
+
export type ProviderAuthenticator = IProviderAuthenticator;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { timingSafeEqual } from "crypto";
|
|
2
|
+
import { ResourcePathPattern } from "../authorization/index.js";
|
|
3
|
+
export function normalizeProviderAuthentication(result, fallbackId = "legacy-provider") {
|
|
4
|
+
if (typeof result === "boolean") {
|
|
5
|
+
return result ? { authenticated: true, principal: { id: fallbackId, allowedResources: ["**"] } } : { authenticated: false };
|
|
6
|
+
}
|
|
7
|
+
if (!result.authenticated)
|
|
8
|
+
return result;
|
|
9
|
+
if (!result.principal.id)
|
|
10
|
+
return { authenticated: false, reason: "provider principal id is empty" };
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
export function providerMayPublish(principal, resource) {
|
|
14
|
+
const allowed = principal.allowedResources;
|
|
15
|
+
if (allowed === undefined)
|
|
16
|
+
return true;
|
|
17
|
+
if (allowed.length === 0)
|
|
18
|
+
return false;
|
|
19
|
+
try {
|
|
20
|
+
const patterns = allowed.map((pattern) => ResourcePathPattern.parse(pattern));
|
|
21
|
+
return patterns.some((pattern) => pattern.matches(resource));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Constant-time string comparison; `false` on any length mismatch. */
|
|
28
|
+
function safeEqual(a, b) {
|
|
29
|
+
const ab = Buffer.from(a);
|
|
30
|
+
const bb = Buffer.from(b);
|
|
31
|
+
if (ab.length !== bb.length)
|
|
32
|
+
return false;
|
|
33
|
+
return timingSafeEqual(ab, bb);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Reads the secret a provider presents, from either the `X-Provider-Token`
|
|
37
|
+
* header or an `Authorization: Bearer <secret>` header.
|
|
38
|
+
*/
|
|
39
|
+
function presentedSecret(req) {
|
|
40
|
+
const xheader = req.headers["x-provider-token"];
|
|
41
|
+
if (typeof xheader === "string" && xheader.trim())
|
|
42
|
+
return xheader.trim();
|
|
43
|
+
const auth = req.headers["authorization"];
|
|
44
|
+
if (typeof auth === "string") {
|
|
45
|
+
const match = /^Bearer\s+(.+)$/i.exec(auth.trim());
|
|
46
|
+
if (match)
|
|
47
|
+
return match[1].trim();
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The default {@link IProviderAuthenticator}: every provider connection must
|
|
53
|
+
* present a single shared secret (via `X-Provider-Token` or `Authorization:
|
|
54
|
+
* Bearer`). Compared in constant time. Suitable when the broker and its
|
|
55
|
+
* providers are operated by the same party; swap in a custom authenticator for
|
|
56
|
+
* per-slot secrets, mTLS, or a signed handshake.
|
|
57
|
+
*/
|
|
58
|
+
export class SharedSecretProviderAuthenticator {
|
|
59
|
+
_secret;
|
|
60
|
+
constructor(secret) {
|
|
61
|
+
if (!secret) {
|
|
62
|
+
throw new Error("provider auth: a non-empty shared secret is required.");
|
|
63
|
+
}
|
|
64
|
+
this._secret = secret;
|
|
65
|
+
}
|
|
66
|
+
authenticate(req) {
|
|
67
|
+
const presented = presentedSecret(req);
|
|
68
|
+
if (!presented || !safeEqual(presented, this._secret)) {
|
|
69
|
+
return { authenticated: false };
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
authenticated: true,
|
|
73
|
+
principal: {
|
|
74
|
+
id: "shared-secret",
|
|
75
|
+
allowedResources: ["**"],
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=provider.auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.auth.js","sourceRoot":"","sources":["../../src/auth/provider.auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.0 Protected Resource Metadata (RFC 9728).
|
|
3
|
+
*
|
|
4
|
+
* Each slot exposed over HTTP is an independent resource server; its metadata
|
|
5
|
+
* document tells an MCP client which authorization server(s) issue tokens for
|
|
6
|
+
* that slot and which bearer methods it accepts. Served (unauthenticated, it is
|
|
7
|
+
* public discovery data) at
|
|
8
|
+
* `<publicBaseUrl>/.well-known/oauth-protected-resource/<slot>/<mcp>`.
|
|
9
|
+
*/
|
|
10
|
+
/** The RFC 9728 metadata document for a single protected resource. */
|
|
11
|
+
export interface IProtectedResourceMetadata {
|
|
12
|
+
/** Canonical resource identifier (RFC 8707) — the slot's `/mcp` endpoint. */
|
|
13
|
+
resource: string;
|
|
14
|
+
/** Authorization server issuer URLs; MUST contain at least one. */
|
|
15
|
+
authorization_servers: string[];
|
|
16
|
+
/** Scopes the resource understands, when advertised. */
|
|
17
|
+
scopes_supported?: string[];
|
|
18
|
+
/** How bearer tokens may be presented. The broker only reads the header. */
|
|
19
|
+
bearer_methods_supported: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Builds the RFC 9728 metadata document for one slot. `bearer_methods_supported`
|
|
23
|
+
* is fixed to `["header"]` because the broker rejects tokens passed any other
|
|
24
|
+
* way (never the query string, per OAuth 2.1 §5).
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildResourceMetadata(params: {
|
|
27
|
+
resource: string;
|
|
28
|
+
authorizationServers: string[];
|
|
29
|
+
scopesSupported?: string[];
|
|
30
|
+
}): IProtectedResourceMetadata;
|
|
31
|
+
/** @deprecated Use {@link IProtectedResourceMetadata}. */
|
|
32
|
+
export type ProtectedResourceMetadata = IProtectedResourceMetadata;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.0 Protected Resource Metadata (RFC 9728).
|
|
3
|
+
*
|
|
4
|
+
* Each slot exposed over HTTP is an independent resource server; its metadata
|
|
5
|
+
* document tells an MCP client which authorization server(s) issue tokens for
|
|
6
|
+
* that slot and which bearer methods it accepts. Served (unauthenticated, it is
|
|
7
|
+
* public discovery data) at
|
|
8
|
+
* `<publicBaseUrl>/.well-known/oauth-protected-resource/<slot>/<mcp>`.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Builds the RFC 9728 metadata document for one slot. `bearer_methods_supported`
|
|
12
|
+
* is fixed to `["header"]` because the broker rejects tokens passed any other
|
|
13
|
+
* way (never the query string, per OAuth 2.1 §5).
|
|
14
|
+
*/
|
|
15
|
+
export function buildResourceMetadata(params) {
|
|
16
|
+
const doc = {
|
|
17
|
+
resource: params.resource,
|
|
18
|
+
authorization_servers: params.authorizationServers,
|
|
19
|
+
bearer_methods_supported: ["header"],
|
|
20
|
+
};
|
|
21
|
+
if (params.scopesSupported && params.scopesSupported.length > 0) {
|
|
22
|
+
doc.scopes_supported = params.scopesSupported;
|
|
23
|
+
}
|
|
24
|
+
return doc;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=resource.metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.metadata.js","sourceRoot":"","sources":["../../src/auth/resource.metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAcH;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAwF;IAC1H,MAAM,GAAG,GAA+B;QACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,qBAAqB,EAAE,MAAM,CAAC,oBAAoB;QAClD,wBAAwB,EAAE,CAAC,QAAQ,CAAC;KACvC,CAAC;IACF,IAAI,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9D,GAAG,CAAC,gBAAgB,GAAG,MAAM,CAAC,eAAe,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IAuthorizationAuditEvent, IAuthorizationDecision, IAuthorizationSubject } from "./policy.types.js";
|
|
2
|
+
import type { ResourcePath } from "./resource.path.js";
|
|
3
|
+
export interface IAuditContext {
|
|
4
|
+
readonly subject: IAuthorizationSubject;
|
|
5
|
+
readonly slot: string;
|
|
6
|
+
readonly resource?: ResourcePath;
|
|
7
|
+
readonly capability?: string;
|
|
8
|
+
readonly provider?: string;
|
|
9
|
+
readonly tool?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function makeAuthorizationAuditEvent(context: IAuditContext, decision: IAuthorizationDecision): IAuthorizationAuditEvent;
|
|
12
|
+
export declare function writeAuthorizationAuditEvent(event: IAuthorizationAuditEvent): void;
|
|
13
|
+
/** @deprecated Use {@link IAuditContext}. */
|
|
14
|
+
export type AuditContext = IAuditContext;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function makeAuthorizationAuditEvent(context, decision) {
|
|
2
|
+
const clientId = context.subject.ids.find((id) => id.startsWith("client:"))?.slice("client:".length);
|
|
3
|
+
return {
|
|
4
|
+
timestamp: new Date().toISOString(),
|
|
5
|
+
allowed: decision.allowed,
|
|
6
|
+
subjectIds: context.subject.ids,
|
|
7
|
+
clientId,
|
|
8
|
+
slot: context.slot,
|
|
9
|
+
resource: context.resource?.value,
|
|
10
|
+
capability: context.capability,
|
|
11
|
+
provider: context.provider,
|
|
12
|
+
tool: context.tool,
|
|
13
|
+
reason: decision.reason,
|
|
14
|
+
matchedPolicies: decision.matchedPolicies,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function writeAuthorizationAuditEvent(event) {
|
|
18
|
+
console.error(`[broker] authorization ${JSON.stringify(event)}`);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/authorization/audit.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,2BAA2B,CAAC,OAAsB,EAAE,QAAgC;IAChG,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACrG,OAAO;QACH,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG;QAC/B,QAAQ;QACR,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK;QACjC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,eAAe,EAAE,QAAQ,CAAC,eAAe;KAC5C,CAAC;AACN,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,KAA+B;IACxE,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ResourcePath } from "./resource.path.js";
|
|
2
|
+
export interface IMcpOperation {
|
|
3
|
+
readonly method?: string;
|
|
4
|
+
readonly params?: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface IClassifiedCapability {
|
|
7
|
+
readonly capability: string;
|
|
8
|
+
readonly tool?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ICapabilityClassifier {
|
|
11
|
+
classify(operation: IMcpOperation, resource: ResourcePath, provider?: string): IClassifiedCapability | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare function validateCapability(capability: string, label?: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Classifies MCP methods without deriving privilege from arbitrary tool names.
|
|
16
|
+
* Provider-qualified mappings win over global mappings, then tools/call falls
|
|
17
|
+
* back to `mcp.tools.call`.
|
|
18
|
+
*/
|
|
19
|
+
export declare class ConfiguredCapabilityClassifier implements ICapabilityClassifier {
|
|
20
|
+
private readonly _globalTools;
|
|
21
|
+
private readonly _providerMappings;
|
|
22
|
+
constructor(toolCapabilities?: Readonly<Record<string, string>>, providerToolCapabilities?: Readonly<Record<string, Readonly<Record<string, string>>>>);
|
|
23
|
+
classify(operation: IMcpOperation, resource: ResourcePath, provider?: string): IClassifiedCapability | undefined;
|
|
24
|
+
}
|
|
25
|
+
/** @deprecated Use {@link IMcpOperation}. */
|
|
26
|
+
export type McpOperation = IMcpOperation;
|
|
27
|
+
/** @deprecated Use {@link IClassifiedCapability}. */
|
|
28
|
+
export type ClassifiedCapability = IClassifiedCapability;
|
|
29
|
+
/** @deprecated Use {@link ICapabilityClassifier}. */
|
|
30
|
+
export type CapabilityClassifier = ICapabilityClassifier;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ResourcePathPattern } from "./resource.path.js";
|
|
2
|
+
const STATIC_CAPABILITIES = {
|
|
3
|
+
"resources/list": "mcp.resources.read",
|
|
4
|
+
"resources/read": "mcp.resources.read",
|
|
5
|
+
"tools/list": "mcp.tools.list",
|
|
6
|
+
"prompts/list": "mcp.prompts.read",
|
|
7
|
+
"prompts/get": "mcp.prompts.read",
|
|
8
|
+
"completion/complete": "mcp.completion.use",
|
|
9
|
+
"notifications/resources/list_changed": "mcp.resources.read",
|
|
10
|
+
"notifications/resources/updated": "mcp.resources.read",
|
|
11
|
+
"notifications/tools/list_changed": "mcp.tools.list",
|
|
12
|
+
"notifications/prompts/list_changed": "mcp.prompts.read",
|
|
13
|
+
};
|
|
14
|
+
const BROKER_READ_TOOLS = new Set(["broker_info", "providers_list", "provider_status"]);
|
|
15
|
+
function toolNameFrom(params) {
|
|
16
|
+
if (typeof params !== "object" || params === null || Array.isArray(params))
|
|
17
|
+
return undefined;
|
|
18
|
+
const name = params["name"];
|
|
19
|
+
return typeof name === "string" && name ? name : undefined;
|
|
20
|
+
}
|
|
21
|
+
export function validateCapability(capability, label = "capability") {
|
|
22
|
+
if (typeof capability !== "string" || (capability !== "*" && !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(capability))) {
|
|
23
|
+
throw new Error(`authorization ${label}: "${capability}" is malformed.`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Classifies MCP methods without deriving privilege from arbitrary tool names.
|
|
28
|
+
* Provider-qualified mappings win over global mappings, then tools/call falls
|
|
29
|
+
* back to `mcp.tools.call`.
|
|
30
|
+
*/
|
|
31
|
+
export class ConfiguredCapabilityClassifier {
|
|
32
|
+
_globalTools;
|
|
33
|
+
_providerMappings;
|
|
34
|
+
constructor(toolCapabilities = {}, providerToolCapabilities = {}) {
|
|
35
|
+
for (const [tool, capability] of Object.entries(toolCapabilities)) {
|
|
36
|
+
if (!tool)
|
|
37
|
+
throw new Error("authorization toolCapabilities: tool names must not be empty.");
|
|
38
|
+
validateCapability(capability, `toolCapabilities["${tool}"]`);
|
|
39
|
+
}
|
|
40
|
+
this._globalTools = Object.freeze({ ...toolCapabilities });
|
|
41
|
+
const mappings = [];
|
|
42
|
+
for (const [patternValue, tools] of Object.entries(providerToolCapabilities)) {
|
|
43
|
+
const pattern = ResourcePathPattern.parse(patternValue);
|
|
44
|
+
for (const [tool, capability] of Object.entries(tools)) {
|
|
45
|
+
if (!tool)
|
|
46
|
+
throw new Error(`authorization providerToolCapabilities["${patternValue}"]: tool names must not be empty.`);
|
|
47
|
+
validateCapability(capability, `providerToolCapabilities["${patternValue}"]["${tool}"]`);
|
|
48
|
+
}
|
|
49
|
+
mappings.push({ pattern, tools: Object.freeze({ ...tools }) });
|
|
50
|
+
}
|
|
51
|
+
mappings.sort((left, right) => right.pattern.specificity - left.pattern.specificity || left.pattern.value.localeCompare(right.pattern.value));
|
|
52
|
+
this._providerMappings = Object.freeze(mappings);
|
|
53
|
+
}
|
|
54
|
+
classify(operation, resource, provider) {
|
|
55
|
+
const method = operation.method;
|
|
56
|
+
if (!method)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (provider === "_broker") {
|
|
59
|
+
if (method === "tools/list" || method === "resources/list" || method === "resources/read") {
|
|
60
|
+
return { capability: "broker.providers.read" };
|
|
61
|
+
}
|
|
62
|
+
if (method === "tools/call") {
|
|
63
|
+
const tool = toolNameFrom(operation.params);
|
|
64
|
+
if (tool && BROKER_READ_TOOLS.has(tool))
|
|
65
|
+
return { capability: "broker.providers.read", tool };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (method !== "tools/call") {
|
|
69
|
+
const capability = STATIC_CAPABILITIES[method];
|
|
70
|
+
return capability ? { capability } : undefined;
|
|
71
|
+
}
|
|
72
|
+
const tool = toolNameFrom(operation.params);
|
|
73
|
+
if (!tool)
|
|
74
|
+
return { capability: "mcp.tools.call" };
|
|
75
|
+
for (const mapping of this._providerMappings) {
|
|
76
|
+
if (mapping.pattern.matches(resource)) {
|
|
77
|
+
const capability = mapping.tools[tool];
|
|
78
|
+
if (capability)
|
|
79
|
+
return { capability, tool };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { capability: this._globalTools[tool] ?? "mcp.tools.call", tool };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=capability.classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.classifier.js","sourceRoot":"","sources":["../../src/authorization/capability.classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { ResourcePath, ResourcePathPattern } from "./resource.path.js";
|
|
2
|
+
export { ConfiguredCapabilityClassifier, validateCapability } from "./capability.classifier.js";
|
|
3
|
+
export type { CapabilityClassifier, ClassifiedCapability, ICapabilityClassifier, IClassifiedCapability, IMcpOperation, McpOperation } from "./capability.classifier.js";
|
|
4
|
+
export { ConfigPolicyEngine } from "./policy.engine.js";
|
|
5
|
+
export { JwtSubjectMapper, SubjectMappingError } from "./subject.mapper.js";
|
|
6
|
+
export type { ISubjectMapper, SubjectMapper } from "./subject.mapper.js";
|
|
7
|
+
export { DefaultSlotResourceResolver } from "./slot.resource.js";
|
|
8
|
+
export type { ISlotResourceResolver, SlotResourceResolver } from "./slot.resource.js";
|
|
9
|
+
export { authorizationWithEngine, compileAuthorizationPolicy, hasAuthorizationPolicies } from "./runtime.js";
|
|
10
|
+
export type { IPolicyAuthorization, PolicyAuthorization } from "./runtime.js";
|
|
11
|
+
export { makeAuthorizationAuditEvent, writeAuthorizationAuditEvent } from "./audit.js";
|
|
12
|
+
export type { AuditContext, IAuditContext } from "./audit.js";
|
|
13
|
+
export type { AuthorizationAuditConfig, AuthorizationAuditEvent, AuthorizationDecision, AuthorizationDecisionReason, AuthorizationPolicyConfig, AuthorizationRequest, AuthorizationSubject, DenyPolicy, IAuthorizationAuditConfig, IAuthorizationAuditEvent, IAuthorizationDecision, IAuthorizationPolicyConfig, IAuthorizationRequest, IAuthorizationSubject, IDenyPolicy, IPolicyAssignment, IPolicyEngine, IRoleDefinition, ISubjectMappingConfig, PolicyAssignment, PolicyEngine, RoleDefinition, SubjectMappingConfig, } from "./policy.types.js";
|