@cyanmycelium/mcp-broker 0.4.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp-broker.example/CONFIGURATION-EN.md +861 -0
- package/.mcp-broker.example/CONFIGURATION-FR.md +871 -0
- package/.mcp-broker.example/README.md +8 -3
- package/.mcp-broker.example/config.json +86 -0
- package/README.md +122 -3
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +180 -208
- package/dist/bin.js.map +1 -1
- package/dist/chunk-FTDKH2C4.js +3670 -0
- package/dist/chunk-FTDKH2C4.js.map +1 -0
- package/dist/{broker/grammars → grammars}/claude/en.json +1 -1
- package/dist/{broker/grammars → grammars}/claude/fr.json +1 -1
- package/dist/index.d.ts +1790 -18
- package/dist/index.js +2 -14
- package/dist/index.js.map +1 -1
- package/package.json +14 -8
- package/scripts/copy-assets.mjs +16 -10
- package/scripts/gen-cert.mjs +5 -5
- package/scripts/pack-mcpb.mjs +5 -5
- package/scripts/sign-bundle.mjs +6 -6
- package/src/auth/auth.config.ts +98 -0
- package/src/auth/auth.types.ts +120 -0
- package/src/auth/http.auth.ts +128 -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 +34 -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 +90 -7
- 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 +49 -21
- package/src/broker/aggregate/aggregate.server.ts +149 -19
- package/src/broker/aggregate/provider.client.session.ts +22 -22
- package/src/broker/behaviors/broker.behavior.info.ts +4 -4
- package/src/broker/behaviors/broker.behavior.providers.ts +6 -6
- package/src/broker/broker.context.ts +10 -4
- package/src/broker/broker.grammars.ts +16 -13
- package/src/broker/broker.server.ts +12 -9
- package/src/broker/grammars/claude/en.json +1 -1
- package/src/broker/grammars/claude/fr.json +1 -1
- package/src/broker/index.ts +9 -9
- package/src/config.ts +81 -8
- package/src/index.ts +121 -20
- package/src/{mcpb.loader.ts → mcpb/mcpb.loader.ts} +24 -21
- package/src/{mcpb.unzip.ts → mcpb/mcpb.unzip.ts} +2 -2
- package/src/remote.transports.ts +11 -8
- package/src/remote.upstream.ts +11 -8
- package/src/stdio.upstream.ts +9 -6
- package/src/upstream.ts +6 -3
- package/src/ws/ws.interfaces.ts +357 -0
- package/src/{ws.tunnel.builder.ts → ws/ws.tunnel.builder.ts} +112 -9
- package/src/{ws.tunnel.ts → ws/ws.tunnel.ts} +646 -457
- 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 +94 -0
- package/web/demos/oauth-lab/config.json +117 -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 +654 -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 +308 -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
- package/dist/broker/adapters/broker.adapter.info.d.ts +0 -16
- package/dist/broker/adapters/broker.adapter.info.js +0 -43
- package/dist/broker/adapters/broker.adapter.info.js.map +0 -1
- package/dist/broker/adapters/broker.adapter.providers.d.ts +0 -18
- package/dist/broker/adapters/broker.adapter.providers.js +0 -61
- package/dist/broker/adapters/broker.adapter.providers.js.map +0 -1
- package/dist/broker/aggregate/aggregate.catalog.d.ts +0 -54
- package/dist/broker/aggregate/aggregate.catalog.js +0 -105
- package/dist/broker/aggregate/aggregate.catalog.js.map +0 -1
- package/dist/broker/aggregate/aggregate.server.d.ts +0 -47
- package/dist/broker/aggregate/aggregate.server.js +0 -151
- package/dist/broker/aggregate/aggregate.server.js.map +0 -1
- package/dist/broker/aggregate/provider.client.session.d.ts +0 -52
- package/dist/broker/aggregate/provider.client.session.js +0 -140
- package/dist/broker/aggregate/provider.client.session.js.map +0 -1
- package/dist/broker/behaviors/broker.behavior.info.d.ts +0 -15
- package/dist/broker/behaviors/broker.behavior.info.js +0 -41
- package/dist/broker/behaviors/broker.behavior.info.js.map +0 -1
- package/dist/broker/behaviors/broker.behavior.providers.d.ts +0 -19
- package/dist/broker/behaviors/broker.behavior.providers.js +0 -69
- package/dist/broker/behaviors/broker.behavior.providers.js.map +0 -1
- package/dist/broker/broker.context.d.ts +0 -59
- package/dist/broker/broker.context.js +0 -2
- package/dist/broker/broker.context.js.map +0 -1
- package/dist/broker/broker.grammars.d.ts +0 -130
- package/dist/broker/broker.grammars.js +0 -229
- package/dist/broker/broker.grammars.js.map +0 -1
- package/dist/broker/broker.server.d.ts +0 -66
- package/dist/broker/broker.server.js +0 -73
- package/dist/broker/broker.server.js.map +0 -1
- package/dist/broker/index.d.ts +0 -9
- package/dist/broker/index.js +0 -7
- package/dist/broker/index.js.map +0 -1
- package/dist/config.d.ts +0 -136
- package/dist/config.js +0 -61
- package/dist/config.js.map +0 -1
- package/dist/mcpb.loader.d.ts +0 -24
- package/dist/mcpb.loader.js +0 -161
- package/dist/mcpb.loader.js.map +0 -1
- package/dist/mcpb.unzip.d.ts +0 -6
- package/dist/mcpb.unzip.js +0 -95
- package/dist/mcpb.unzip.js.map +0 -1
- package/dist/remote.transports.d.ts +0 -16
- package/dist/remote.transports.js +0 -297
- package/dist/remote.transports.js.map +0 -1
- package/dist/remote.upstream.d.ts +0 -36
- package/dist/remote.upstream.js +0 -52
- package/dist/remote.upstream.js.map +0 -1
- package/dist/stdio.upstream.d.ts +0 -45
- package/dist/stdio.upstream.js +0 -85
- package/dist/stdio.upstream.js.map +0 -1
- package/dist/upstream.d.ts +0 -33
- package/dist/upstream.js +0 -2
- package/dist/upstream.js.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.js +0 -9
- package/dist/version.js.map +0 -1
- package/dist/ws.tunnel.builder.d.ts +0 -139
- package/dist/ws.tunnel.builder.js +0 -205
- package/dist/ws.tunnel.builder.js.map +0 -1
- package/dist/ws.tunnel.d.ts +0 -373
- package/dist/ws.tunnel.js +0 -1090
- package/dist/ws.tunnel.js.map +0 -1
- /package/dist/{broker/grammars → grammars}/default/en.json +0 -0
- /package/dist/{broker/grammars → grammars}/default/fr.json +0 -0
- /package/dist/{broker/grammars → grammars}/default/zh.json +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,1790 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import * as _cyanmycelium_mcp_core from '@cyanmycelium/mcp-core';
|
|
2
|
+
import { McpBehavior, McpResource, McpTool, McpResourceTemplate, GrammarResolverOptions, IMcpServer, IMessageTransport, McpGrammar, IAccessTokenClaims, IMcpPrincipal, McpAuthError, ITokenValidator, IProtectedResourceMetadata } from '@cyanmycelium/mcp-core';
|
|
3
|
+
export { IAccessTokenClaims, IProtectedResourceMetadata, ITokenValidator } from '@cyanmycelium/mcp-core';
|
|
4
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Read-only view of the broker's runtime state, exposed to broker behaviors.
|
|
8
|
+
*
|
|
9
|
+
* Decouples the behaviors from the concrete `WsTunnel` class, making them
|
|
10
|
+
* unit-testable and reusable (e.g. a future .NET-backed context).
|
|
11
|
+
*/
|
|
12
|
+
interface IBrokerContext {
|
|
13
|
+
/** Package version (from package.json). */
|
|
14
|
+
readonly version: string;
|
|
15
|
+
/** Logical broker name reported to MCP clients. */
|
|
16
|
+
readonly name: string;
|
|
17
|
+
/** Timestamp of the most recent successful `start()`, or `null` if never started. */
|
|
18
|
+
readonly startedAt: Date | null;
|
|
19
|
+
/** Seconds since `startedAt`, or `0` if not running. */
|
|
20
|
+
readonly uptimeSeconds: number;
|
|
21
|
+
/** Bind host. `undefined` means default (`0.0.0.0`). */
|
|
22
|
+
readonly host: string | undefined;
|
|
23
|
+
/** TCP port the broker is listening on. */
|
|
24
|
+
readonly port: number;
|
|
25
|
+
/** Whether TLS is active for the HTTP/WS server. */
|
|
26
|
+
readonly tls: boolean;
|
|
27
|
+
/** All configured URL paths, with defaults already substituted. */
|
|
28
|
+
readonly paths: {
|
|
29
|
+
provider: string;
|
|
30
|
+
providers: string;
|
|
31
|
+
client: string;
|
|
32
|
+
mcp: string;
|
|
33
|
+
sse: string;
|
|
34
|
+
messages: string;
|
|
35
|
+
};
|
|
36
|
+
/** Snapshot of every known provider slot, including disconnected ones. */
|
|
37
|
+
getProvidersInfo(): IBrokerProviderInfo[];
|
|
38
|
+
/** Snapshot of a single provider slot, or `undefined` if the name is unknown. */
|
|
39
|
+
getProviderInfo(name: string): IBrokerProviderInfo | undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Transport kind currently feeding a provider slot.
|
|
43
|
+
*
|
|
44
|
+
* - `ws`: dedicated WebSocket provider (`/provider/<name>`).
|
|
45
|
+
* - `ws-multiplex`: multiplexed WebSocket envelope on `/providers`.
|
|
46
|
+
* - `stdio`: child process spawned at broker startup.
|
|
47
|
+
* - `loopback`: in-process transport (e.g. the broker exposing itself as `_broker`).
|
|
48
|
+
* - `none`: the slot was referenced by a client but no provider has attached yet.
|
|
49
|
+
*/
|
|
50
|
+
type BrokerProviderTransport = "ws" | "ws-multiplex" | "stdio" | "loopback" | "none";
|
|
51
|
+
interface IBrokerProviderInfo {
|
|
52
|
+
/** Slot name as advertised on `/<name>/...` endpoints. */
|
|
53
|
+
name: string;
|
|
54
|
+
/** Which transport is currently feeding the slot. */
|
|
55
|
+
transport: BrokerProviderTransport;
|
|
56
|
+
/** `true` iff the slot is reachable for routing right now. */
|
|
57
|
+
connected: boolean;
|
|
58
|
+
/** Number of raw-WebSocket MCP clients on this slot. */
|
|
59
|
+
clientCount: number;
|
|
60
|
+
/** Number of long-lived sessions (SSE + Streamable HTTP GET streams). */
|
|
61
|
+
sessionCount: number;
|
|
62
|
+
/** Number of in-flight JSON-RPC requests awaiting a response. */
|
|
63
|
+
pendingCount: number;
|
|
64
|
+
}
|
|
65
|
+
/** @deprecated Use {@link IBrokerContext}. */
|
|
66
|
+
type BrokerContext = IBrokerContext;
|
|
67
|
+
/** @deprecated Use {@link IBrokerProviderInfo}. */
|
|
68
|
+
type BrokerProviderInfo = IBrokerProviderInfo;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Exposes basic broker identity (name, version, uptime, listening config) as
|
|
72
|
+
* one tool (`broker_info`) and one resource (`broker://info`).
|
|
73
|
+
*
|
|
74
|
+
* An MCP agent typically calls `broker_info` first to learn who it is talking to.
|
|
75
|
+
*/
|
|
76
|
+
declare class BrokerInfoBehavior extends McpBehavior {
|
|
77
|
+
static readonly NAMESPACE = "broker";
|
|
78
|
+
constructor(context: IBrokerContext);
|
|
79
|
+
protected _buildResources(): McpResource[];
|
|
80
|
+
protected _buildTools(): McpTool[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Exposes the broker's provider slots so an MCP agent can discover what is
|
|
85
|
+
* currently routable behind the broker, with two tools:
|
|
86
|
+
*
|
|
87
|
+
* - `providers_list`: every slot (including disconnected ones).
|
|
88
|
+
* - `provider_status({ name })`, detail on one slot.
|
|
89
|
+
*
|
|
90
|
+
* Plus matching resources at `broker://providers` and `broker://providers/<name>`.
|
|
91
|
+
*/
|
|
92
|
+
declare class BrokerProvidersBehavior extends McpBehavior {
|
|
93
|
+
static readonly NAMESPACE = "broker_providers";
|
|
94
|
+
constructor(context: IBrokerContext);
|
|
95
|
+
protected _buildResources(): McpResource[];
|
|
96
|
+
protected _buildTemplate(): McpResourceTemplate[];
|
|
97
|
+
protected _buildTools(): McpTool[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Reserved provider slot name under which the broker exposes itself as an MCP
|
|
102
|
+
* server. Clients reach it via `<host>/_broker/mcp` (or any other client transport).
|
|
103
|
+
*
|
|
104
|
+
* Prefixed with `_` to make it unambiguously a system slot, and to reduce the
|
|
105
|
+
* chance of collision with user-supplied provider names.
|
|
106
|
+
*/
|
|
107
|
+
declare const BROKER_PROVIDER_NAME = "_broker";
|
|
108
|
+
/**
|
|
109
|
+
* Optional knobs passed to {@link startBrokerServer}. Lets the embedder
|
|
110
|
+
* replace either resolver with custom logic without touching mcp-broker
|
|
111
|
+
* internals.
|
|
112
|
+
*/
|
|
113
|
+
interface IStartBrokerServerOptions {
|
|
114
|
+
/**
|
|
115
|
+
* Overrides for the built-in grammar resolver from `@cyanmycelium/mcp-core`.
|
|
116
|
+
*
|
|
117
|
+
* The broker installs sensible defaults: `localeSource` reads
|
|
118
|
+
* `process.env.MCP_BROKER_LOCALE`, the `agents` map uses the mcp-core
|
|
119
|
+
* defaults (`claude`, `gpt`, `mistral`, `copilot`, `default`), the
|
|
120
|
+
* narrowing chain is BCP-47-style, and `fallbackKey` is `default:en`
|
|
121
|
+
* so the baseline grammar always matches as last resort.
|
|
122
|
+
*
|
|
123
|
+
* Pass partial overrides here to inject a custom `localeSource` (e.g.
|
|
124
|
+
* pull from an HTTP header proxied by your transport), enable the
|
|
125
|
+
* `versionFrom` dimension, or extend the `agents` map with additional
|
|
126
|
+
* LLM families. Anything you omit keeps the broker default.
|
|
127
|
+
*/
|
|
128
|
+
grammarResolverOptions?: Partial<GrammarResolverOptions>;
|
|
129
|
+
/**
|
|
130
|
+
* Path to a user-supplied grammars directory whose `<userAgent>/<locale>.json`
|
|
131
|
+
* files are registered **in addition to** the packaged grammars.
|
|
132
|
+
*
|
|
133
|
+
* Both packaged and local entries are registered raw against the server
|
|
134
|
+
* via `withGrammar(brokerGrammarKey(ua, locale), grammar)`. The
|
|
135
|
+
* candidate-chain resolution implemented by `McpServer.initialize` in
|
|
136
|
+
* mcp-core@0.3.0 then walks the chain and merges the four layers
|
|
137
|
+
* (behavior, adapter, static, store) for the first matching key ,
|
|
138
|
+
* the old hand-rolled pre-merge cascade is no longer needed.
|
|
139
|
+
*
|
|
140
|
+
* When `undefined` (default), only the packaged grammars are loaded.
|
|
141
|
+
*/
|
|
142
|
+
localGrammarsDir?: string;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Constructs the broker's own MCP server (the Tier-1 introspection behaviors)
|
|
146
|
+
* and returns the running server plus the loopback transport that must be
|
|
147
|
+
* registered against the {@link WsTunnel} as the `_broker` provider slot.
|
|
148
|
+
*
|
|
149
|
+
* Usage from {@link WsTunnel.start}:
|
|
150
|
+
* ```ts
|
|
151
|
+
* const { server, clientTransport } = await startBrokerServer(this, { ... });
|
|
152
|
+
* this._registerLoopbackProvider(BROKER_PROVIDER_NAME, clientTransport);
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* @param context Read-only view of the broker's state.
|
|
156
|
+
* @param options Optional resolver overrides.
|
|
157
|
+
* @returns The running {@link IMcpServer} (call `.stop()` on shutdown) and the
|
|
158
|
+
* loopback transport to attach to the tunnel.
|
|
159
|
+
*/
|
|
160
|
+
declare function startBrokerServer(context: IBrokerContext, options?: IStartBrokerServerOptions): Promise<{
|
|
161
|
+
server: IMcpServer;
|
|
162
|
+
clientTransport: IMessageTransport;
|
|
163
|
+
}>;
|
|
164
|
+
/** @deprecated Use {@link IStartBrokerServerOptions}. */
|
|
165
|
+
type StartBrokerServerOptions = IStartBrokerServerOptions;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Locale identifier used to look up a grammar JSON file under
|
|
169
|
+
* `<userAgent>/<locale>.json`. Open string: a host application can use any
|
|
170
|
+
* value its grammar resources support.
|
|
171
|
+
*
|
|
172
|
+
* The broker registers each `(userAgent, locale)` pair found on disk as a
|
|
173
|
+
* separate `McpGrammar` keyed by {@link brokerGrammarKey}. The actual
|
|
174
|
+
* resolution of "which key to use for this session" is delegated to
|
|
175
|
+
* `@cyanmycelium/mcp-core@0.3.0`'s `grammarResolverFromOptions`, which
|
|
176
|
+
* handles BCP-47 narrowing (`fr-CA` → `fr` → `en`), agent-family fallback,
|
|
177
|
+
* and the optional version dimension natively.
|
|
178
|
+
*/
|
|
179
|
+
type BrokerLocale = string;
|
|
180
|
+
/**
|
|
181
|
+
* User-agent family identifier used to look up a grammar JSON file under
|
|
182
|
+
* `<userAgent>/<locale>.json`. Open string. Conventional values follow
|
|
183
|
+
* the defaults emitted by `grammarResolverFromOptions`: `claude`, `gpt`,
|
|
184
|
+
* `mistral`, `copilot`, plus the universal `default`. Custom families
|
|
185
|
+
* are supported by passing a custom `agents` map in
|
|
186
|
+
* `IStartBrokerServerOptions.grammarResolverOptions`.
|
|
187
|
+
*/
|
|
188
|
+
type BrokerUserAgent = string;
|
|
189
|
+
/**
|
|
190
|
+
* Builds the canonical grammar key for the `(userAgent, locale, version?)`
|
|
191
|
+
* matrix the broker registers on disk.
|
|
192
|
+
*
|
|
193
|
+
* Pattern:
|
|
194
|
+
* - `"<userAgent>:<locale>"` (no version), e.g. `"claude:fr"`, `"default:en"`
|
|
195
|
+
* - `"<userAgent>:<locale>@<version>"` (versioned), e.g. `"claude:fr@v2"`
|
|
196
|
+
*
|
|
197
|
+
* The colon separator is reserved for the `<ua>:<locale>` composition; the
|
|
198
|
+
* `@` separator is reserved for the optional version suffix. Neither
|
|
199
|
+
* character is allowed inside the identifier segments. This matches the
|
|
200
|
+
* default `composeKey` of `grammarResolverFromOptions` exactly, so a
|
|
201
|
+
* broker-loaded grammar at `claude/fr@v2.json` is automatically picked up
|
|
202
|
+
* when a Claude session resolves to the `claude:fr@v2` candidate.
|
|
203
|
+
*/
|
|
204
|
+
declare function brokerGrammarKey(userAgent: BrokerUserAgent, locale: BrokerLocale, version?: string): string;
|
|
205
|
+
/**
|
|
206
|
+
* Loads and caches the grammar for a given `(userAgent, locale, version?)`
|
|
207
|
+
* combination. Returns `undefined` (instead of throwing) when the resource
|
|
208
|
+
* file is missing, so the caller can implement a fallback chain.
|
|
209
|
+
*
|
|
210
|
+
* Filename convention on disk:
|
|
211
|
+
* - `<userAgent>/<locale>.json` (no version)
|
|
212
|
+
* - `<userAgent>/<locale>@<version>.json` (versioned)
|
|
213
|
+
*/
|
|
214
|
+
declare function loadBrokerGrammar(userAgent: BrokerUserAgent, locale: BrokerLocale, version?: string): McpGrammar | undefined;
|
|
215
|
+
/**
|
|
216
|
+
* Walks a grammars directory and yields every `(userAgent, locale)` pair
|
|
217
|
+
* found on disk. The directory must follow the layout
|
|
218
|
+
* `<dir>/<userAgent>/<locale>.json`.
|
|
219
|
+
*
|
|
220
|
+
* Used by the broker server at startup to bulk-register both the packaged
|
|
221
|
+
* grammars and any local overrides. No hard-coded list of supported
|
|
222
|
+
* user-agents or locales, adding a new grammar is dropping a JSON file.
|
|
223
|
+
*/
|
|
224
|
+
interface IBrokerGrammarEntry {
|
|
225
|
+
userAgent: BrokerUserAgent;
|
|
226
|
+
locale: BrokerLocale;
|
|
227
|
+
/** Set only for filenames carrying an `@<version>` suffix. */
|
|
228
|
+
version?: string;
|
|
229
|
+
/** Composed via {@link brokerGrammarKey} from the three segments above. */
|
|
230
|
+
key: string;
|
|
231
|
+
grammar: McpGrammar;
|
|
232
|
+
}
|
|
233
|
+
declare function iterBrokerGrammarsFrom(grammarsDir: string): Generator<IBrokerGrammarEntry>;
|
|
234
|
+
/**
|
|
235
|
+
* Walks the **packaged** grammars directory (the one shipped with the
|
|
236
|
+
* mcp-broker package). Equivalent to `iterBrokerGrammarsFrom(<packaged-dir>)`.
|
|
237
|
+
*
|
|
238
|
+
* For local user overrides, see {@link iterBrokerGrammarsFrom} with a custom
|
|
239
|
+
* directory, typically `.mcp-broker/grammars/` next to the config file.
|
|
240
|
+
*/
|
|
241
|
+
declare function iterAvailableBrokerGrammars(): Generator<IBrokerGrammarEntry>;
|
|
242
|
+
/** @deprecated Use {@link IBrokerGrammarEntry}. */
|
|
243
|
+
type BrokerGrammarEntry = IBrokerGrammarEntry;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Common contract for an upstream MCP server bound to a provider slot.
|
|
247
|
+
*
|
|
248
|
+
* The broker treats every upstream the same way: it muxes the slot's clients
|
|
249
|
+
* onto the single upstream connection, regardless of the underlying transport.
|
|
250
|
+
*
|
|
251
|
+
* Implementations:
|
|
252
|
+
* - `StdioUpstream` : a local child process (newline-delimited JSON-RPC over stdio).
|
|
253
|
+
* - `RemoteUpstream`: a remote MCP server reached by URL (Streamable HTTP / SSE / WebSocket).
|
|
254
|
+
*
|
|
255
|
+
* `StdioUpstream` is reused as-is by the future `.mcpb` bundle loader: a bundle
|
|
256
|
+
* is a local server whose `mcp_config` maps directly onto a stdio upstream.
|
|
257
|
+
*/
|
|
258
|
+
interface IUpstream {
|
|
259
|
+
/** Provider slot name this upstream is bound to. */
|
|
260
|
+
readonly name: string;
|
|
261
|
+
/** Whether the upstream connection is currently usable. */
|
|
262
|
+
readonly isOpen: boolean;
|
|
263
|
+
/** Receives one complete JSON-RPC message from the upstream server. */
|
|
264
|
+
onMessage: ((data: string) => void) | null;
|
|
265
|
+
/** Fires once the upstream connection is established and ready to send. */
|
|
266
|
+
onOpen: (() => void) | null;
|
|
267
|
+
/** Fires when the upstream connection closes. */
|
|
268
|
+
onClose: (() => void) | null;
|
|
269
|
+
/** Fires on a connection or runtime error. */
|
|
270
|
+
onError: ((error: Error) => void) | null;
|
|
271
|
+
/** Opens the upstream connection. */
|
|
272
|
+
connect(): void;
|
|
273
|
+
/** Sends one JSON-RPC message to the upstream server. */
|
|
274
|
+
send(data: string): void;
|
|
275
|
+
/** Closes the upstream connection. */
|
|
276
|
+
close(): void;
|
|
277
|
+
}
|
|
278
|
+
/** @deprecated Use {@link IUpstream}. */
|
|
279
|
+
type Upstream = IUpstream;
|
|
280
|
+
|
|
281
|
+
interface IStdioUpstreamConfig {
|
|
282
|
+
/** Logical name of this provider (matched against incoming WebSocket provider names). */
|
|
283
|
+
name: string;
|
|
284
|
+
/** Executable to spawn (e.g. `"node"`, `"python"`, an absolute path). */
|
|
285
|
+
command: string;
|
|
286
|
+
/** Arguments passed to the command. */
|
|
287
|
+
args?: string[];
|
|
288
|
+
/** Extra environment variables merged with `process.env`. */
|
|
289
|
+
env?: NodeJS.ProcessEnv;
|
|
290
|
+
/** When `true`, this upstream joins the `_all` aggregate slot once connected. */
|
|
291
|
+
aggregate?: boolean;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Manages a stdio-based MCP server process.
|
|
295
|
+
* JSON-RPC messages are exchanged over the child process stdin/stdout using
|
|
296
|
+
* newline-delimited framing (matching the MCP SDK stdio transport).
|
|
297
|
+
*
|
|
298
|
+
* One instance per configured provider. The broker uses this to bridge
|
|
299
|
+
* WebSocket/SSE/HTTP clients to local MCP server processes.
|
|
300
|
+
*/
|
|
301
|
+
declare class StdioUpstream implements IUpstream {
|
|
302
|
+
readonly name: string;
|
|
303
|
+
private readonly _config;
|
|
304
|
+
private _proc;
|
|
305
|
+
private _buffer;
|
|
306
|
+
private _open;
|
|
307
|
+
private _stopped;
|
|
308
|
+
/** Called when a complete JSON-RPC line arrives from the process stdout. */
|
|
309
|
+
onMessage: ((data: string) => void) | null;
|
|
310
|
+
/** Called when the process has started and stdin is writable. */
|
|
311
|
+
onOpen: (() => void) | null;
|
|
312
|
+
/** Called when the process exits (cleanly or otherwise). */
|
|
313
|
+
onClose: (() => void) | null;
|
|
314
|
+
/** Called on spawn or runtime errors. */
|
|
315
|
+
onError: ((error: Error) => void) | null;
|
|
316
|
+
constructor(config: IStdioUpstreamConfig);
|
|
317
|
+
get isOpen(): boolean;
|
|
318
|
+
/** Spawns the child process and wires up stdio listeners. */
|
|
319
|
+
connect(): void;
|
|
320
|
+
/** Sends a JSON-RPC message to the process stdin (appends newline). */
|
|
321
|
+
send(data: string): void;
|
|
322
|
+
/** Kills the child process and prevents further reconnection attempts. */
|
|
323
|
+
close(): void;
|
|
324
|
+
}
|
|
325
|
+
/** @deprecated Use {@link IStdioUpstreamConfig}. */
|
|
326
|
+
type StdioUpstreamConfig = IStdioUpstreamConfig;
|
|
327
|
+
|
|
328
|
+
/** The three supported remote transports. */
|
|
329
|
+
type RemoteTransportKind = "streamable-http" | "sse" | "websocket";
|
|
330
|
+
|
|
331
|
+
interface IRemoteUpstreamConfig {
|
|
332
|
+
/** Provider slot name this upstream is bound to. */
|
|
333
|
+
name: string;
|
|
334
|
+
/** URL of the remote MCP server. */
|
|
335
|
+
url: string;
|
|
336
|
+
/** Transport to use. Auto-detected from the URL scheme/path when omitted. */
|
|
337
|
+
transport?: RemoteTransportKind;
|
|
338
|
+
/** Extra HTTP / WebSocket headers (e.g. an `Authorization` header). */
|
|
339
|
+
headers?: Record<string, string>;
|
|
340
|
+
/** When `true`, this upstream joins the `_all` aggregate slot once connected. */
|
|
341
|
+
aggregate?: boolean;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Bridges a remote MCP server (reachable by URL) into a broker provider slot.
|
|
345
|
+
*
|
|
346
|
+
* The broker-facing contract is identical to {@link StdioUpstream}: the broker
|
|
347
|
+
* muxes the slot's clients onto this single upstream. The only difference is
|
|
348
|
+
* the transport, Streamable HTTP / SSE / WebSocket instead of a child process.
|
|
349
|
+
*/
|
|
350
|
+
declare class RemoteUpstream implements IUpstream {
|
|
351
|
+
readonly name: string;
|
|
352
|
+
onMessage: ((data: string) => void) | null;
|
|
353
|
+
onOpen: (() => void) | null;
|
|
354
|
+
onClose: (() => void) | null;
|
|
355
|
+
onError: ((error: Error) => void) | null;
|
|
356
|
+
private readonly _config;
|
|
357
|
+
private _transport;
|
|
358
|
+
private _open;
|
|
359
|
+
constructor(config: IRemoteUpstreamConfig);
|
|
360
|
+
get isOpen(): boolean;
|
|
361
|
+
connect(): void;
|
|
362
|
+
send(data: string): void;
|
|
363
|
+
close(): void;
|
|
364
|
+
}
|
|
365
|
+
/** @deprecated Use {@link IRemoteUpstreamConfig}. */
|
|
366
|
+
type RemoteUpstreamConfig = IRemoteUpstreamConfig;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* A normalized, case-sensitive hierarchical resource path.
|
|
370
|
+
*
|
|
371
|
+
* Parsing is deliberately independent from URLs and transports. A path is a
|
|
372
|
+
* stable resource identity, not a network address.
|
|
373
|
+
*/
|
|
374
|
+
declare class ResourcePath {
|
|
375
|
+
readonly value: string;
|
|
376
|
+
readonly segments: readonly string[];
|
|
377
|
+
private constructor();
|
|
378
|
+
static parse(value: string): ResourcePath;
|
|
379
|
+
static tryParse(value: string): ResourcePath | undefined;
|
|
380
|
+
toString(): string;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* A compiled resource expression supporting exact segments, `*` for one
|
|
384
|
+
* segment, and a final `**` for zero or more trailing segments.
|
|
385
|
+
*/
|
|
386
|
+
declare class ResourcePathPattern {
|
|
387
|
+
readonly value: string;
|
|
388
|
+
readonly segments: readonly string[];
|
|
389
|
+
readonly specificity: number;
|
|
390
|
+
private constructor();
|
|
391
|
+
static parse(value: string): ResourcePathPattern;
|
|
392
|
+
matches(path: ResourcePath): boolean;
|
|
393
|
+
toString(): string;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
interface IMcpOperation {
|
|
397
|
+
readonly method?: string;
|
|
398
|
+
readonly params?: unknown;
|
|
399
|
+
}
|
|
400
|
+
interface IClassifiedCapability {
|
|
401
|
+
readonly capability: string;
|
|
402
|
+
readonly tool?: string;
|
|
403
|
+
}
|
|
404
|
+
interface ICapabilityClassifier {
|
|
405
|
+
classify(operation: IMcpOperation, resource: ResourcePath, provider?: string): IClassifiedCapability | undefined;
|
|
406
|
+
}
|
|
407
|
+
declare function validateCapability(capability: string, label?: string): void;
|
|
408
|
+
/**
|
|
409
|
+
* Classifies MCP methods without deriving privilege from arbitrary tool names.
|
|
410
|
+
* Provider-qualified mappings win over global mappings, then tools/call falls
|
|
411
|
+
* back to `mcp.tools.call`.
|
|
412
|
+
*/
|
|
413
|
+
declare class ConfiguredCapabilityClassifier implements ICapabilityClassifier {
|
|
414
|
+
private readonly _globalTools;
|
|
415
|
+
private readonly _providerMappings;
|
|
416
|
+
constructor(toolCapabilities?: Readonly<Record<string, string>>, providerToolCapabilities?: Readonly<Record<string, Readonly<Record<string, string>>>>);
|
|
417
|
+
classify(operation: IMcpOperation, resource: ResourcePath, provider?: string): IClassifiedCapability | undefined;
|
|
418
|
+
}
|
|
419
|
+
/** @deprecated Use {@link IMcpOperation}. */
|
|
420
|
+
type McpOperation = IMcpOperation;
|
|
421
|
+
/** @deprecated Use {@link IClassifiedCapability}. */
|
|
422
|
+
type ClassifiedCapability = IClassifiedCapability;
|
|
423
|
+
/** @deprecated Use {@link ICapabilityClassifier}. */
|
|
424
|
+
type CapabilityClassifier = ICapabilityClassifier;
|
|
425
|
+
|
|
426
|
+
interface IAuthorizationSubject {
|
|
427
|
+
readonly ids: readonly string[];
|
|
428
|
+
readonly claims?: Readonly<Record<string, unknown>>;
|
|
429
|
+
}
|
|
430
|
+
interface IAuthorizationRequest {
|
|
431
|
+
readonly subject: IAuthorizationSubject;
|
|
432
|
+
readonly capability: string;
|
|
433
|
+
readonly resource: ResourcePath;
|
|
434
|
+
readonly provider?: string;
|
|
435
|
+
readonly tool?: string;
|
|
436
|
+
}
|
|
437
|
+
type AuthorizationDecisionReason = "explicit-deny" | "role-grant" | "no-matching-grant" | "invalid-resource" | "unknown-resource";
|
|
438
|
+
interface IAuthorizationDecision {
|
|
439
|
+
readonly allowed: boolean;
|
|
440
|
+
readonly reason: AuthorizationDecisionReason;
|
|
441
|
+
readonly matchedPolicies?: readonly string[];
|
|
442
|
+
}
|
|
443
|
+
interface IPolicyEngine {
|
|
444
|
+
authorize(request: IAuthorizationRequest): IAuthorizationDecision;
|
|
445
|
+
}
|
|
446
|
+
interface IRoleDefinition {
|
|
447
|
+
readonly inherits?: readonly string[];
|
|
448
|
+
readonly capabilities: readonly string[];
|
|
449
|
+
}
|
|
450
|
+
interface IPolicyAssignment {
|
|
451
|
+
readonly id?: string;
|
|
452
|
+
readonly subject: string;
|
|
453
|
+
readonly role: string;
|
|
454
|
+
readonly resource: string;
|
|
455
|
+
}
|
|
456
|
+
interface IDenyPolicy {
|
|
457
|
+
readonly id?: string;
|
|
458
|
+
readonly subject: string;
|
|
459
|
+
readonly effect?: "deny";
|
|
460
|
+
readonly capabilities: readonly string[];
|
|
461
|
+
readonly resource: string;
|
|
462
|
+
}
|
|
463
|
+
interface ISubjectMappingConfig {
|
|
464
|
+
readonly userClaim?: string;
|
|
465
|
+
readonly groupClaims?: readonly string[];
|
|
466
|
+
readonly clientClaim?: string;
|
|
467
|
+
readonly serviceClaims?: readonly string[];
|
|
468
|
+
}
|
|
469
|
+
interface IAuthorizationAuditConfig {
|
|
470
|
+
readonly logAllowed?: boolean;
|
|
471
|
+
}
|
|
472
|
+
interface IAuthorizationPolicyConfig {
|
|
473
|
+
readonly roles?: Readonly<Record<string, IRoleDefinition>>;
|
|
474
|
+
readonly assignments?: readonly IPolicyAssignment[];
|
|
475
|
+
readonly denies?: readonly IDenyPolicy[];
|
|
476
|
+
readonly subjectMapping?: ISubjectMappingConfig;
|
|
477
|
+
readonly slotResources?: Readonly<Record<string, string>>;
|
|
478
|
+
readonly toolCapabilities?: Readonly<Record<string, string>>;
|
|
479
|
+
readonly providerToolCapabilities?: Readonly<Record<string, Readonly<Record<string, string>>>>;
|
|
480
|
+
readonly audit?: IAuthorizationAuditConfig;
|
|
481
|
+
}
|
|
482
|
+
interface IAuthorizationAuditEvent {
|
|
483
|
+
readonly timestamp: string;
|
|
484
|
+
readonly allowed: boolean;
|
|
485
|
+
readonly subjectIds: readonly string[];
|
|
486
|
+
readonly clientId?: string;
|
|
487
|
+
readonly slot: string;
|
|
488
|
+
readonly resource?: string;
|
|
489
|
+
readonly capability?: string;
|
|
490
|
+
readonly provider?: string;
|
|
491
|
+
readonly tool?: string;
|
|
492
|
+
readonly reason: AuthorizationDecisionReason;
|
|
493
|
+
readonly matchedPolicies?: readonly string[];
|
|
494
|
+
}
|
|
495
|
+
/** @deprecated Use {@link IAuthorizationSubject}. */
|
|
496
|
+
type AuthorizationSubject = IAuthorizationSubject;
|
|
497
|
+
/** @deprecated Use {@link IAuthorizationRequest}. */
|
|
498
|
+
type AuthorizationRequest = IAuthorizationRequest;
|
|
499
|
+
/** @deprecated Use {@link IAuthorizationDecision}. */
|
|
500
|
+
type AuthorizationDecision = IAuthorizationDecision;
|
|
501
|
+
/** @deprecated Use {@link IPolicyEngine}. */
|
|
502
|
+
type PolicyEngine = IPolicyEngine;
|
|
503
|
+
/** @deprecated Use {@link IRoleDefinition}. */
|
|
504
|
+
type RoleDefinition = IRoleDefinition;
|
|
505
|
+
/** @deprecated Use {@link IPolicyAssignment}. */
|
|
506
|
+
type PolicyAssignment = IPolicyAssignment;
|
|
507
|
+
/** @deprecated Use {@link IDenyPolicy}. */
|
|
508
|
+
type DenyPolicy = IDenyPolicy;
|
|
509
|
+
/** @deprecated Use {@link ISubjectMappingConfig}. */
|
|
510
|
+
type SubjectMappingConfig = ISubjectMappingConfig;
|
|
511
|
+
/** @deprecated Use {@link IAuthorizationAuditConfig}. */
|
|
512
|
+
type AuthorizationAuditConfig = IAuthorizationAuditConfig;
|
|
513
|
+
/** @deprecated Use {@link IAuthorizationPolicyConfig}. */
|
|
514
|
+
type AuthorizationPolicyConfig = IAuthorizationPolicyConfig;
|
|
515
|
+
/** @deprecated Use {@link IAuthorizationAuditEvent}. */
|
|
516
|
+
type AuthorizationAuditEvent = IAuthorizationAuditEvent;
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Immutable, indexed in-memory policy engine. Role inheritance and resource
|
|
520
|
+
* expressions are fully compiled in the constructor.
|
|
521
|
+
*/
|
|
522
|
+
declare class ConfigPolicyEngine implements IPolicyEngine {
|
|
523
|
+
private readonly _assignmentsBySubject;
|
|
524
|
+
private readonly _deniesBySubject;
|
|
525
|
+
constructor(roles: Readonly<Record<string, IRoleDefinition>>, assignments: readonly IPolicyAssignment[], denies: readonly IDenyPolicy[]);
|
|
526
|
+
authorize(request: IAuthorizationRequest): IAuthorizationDecision;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
interface ISubjectMapper {
|
|
530
|
+
map(claims: Readonly<Record<string, unknown>>): IAuthorizationSubject;
|
|
531
|
+
}
|
|
532
|
+
declare class SubjectMappingError extends Error {
|
|
533
|
+
constructor(message: string);
|
|
534
|
+
}
|
|
535
|
+
/** Maps validated JWT claims to canonical, deduplicated authorization subjects. */
|
|
536
|
+
declare class JwtSubjectMapper implements ISubjectMapper {
|
|
537
|
+
private readonly _rules;
|
|
538
|
+
constructor(config?: ISubjectMappingConfig);
|
|
539
|
+
map(claims: Readonly<Record<string, unknown>>): IAuthorizationSubject;
|
|
540
|
+
}
|
|
541
|
+
/** @deprecated Use {@link ISubjectMapper}. */
|
|
542
|
+
type SubjectMapper = ISubjectMapper;
|
|
543
|
+
|
|
544
|
+
interface ISlotResourceResolver {
|
|
545
|
+
resolve(slot: string): ResourcePath | undefined;
|
|
546
|
+
}
|
|
547
|
+
/** Default resolver with optional explicit technical-slot mappings. */
|
|
548
|
+
declare class DefaultSlotResourceResolver implements ISlotResourceResolver {
|
|
549
|
+
private readonly _explicit;
|
|
550
|
+
constructor(slotResources?: Readonly<Record<string, string>>);
|
|
551
|
+
resolve(slot: string): ResourcePath | undefined;
|
|
552
|
+
}
|
|
553
|
+
/** @deprecated Use {@link ISlotResourceResolver}. */
|
|
554
|
+
type SlotResourceResolver = ISlotResourceResolver;
|
|
555
|
+
|
|
556
|
+
interface IPolicyAuthorization {
|
|
557
|
+
readonly engine: IPolicyEngine;
|
|
558
|
+
readonly subjectMapper: ISubjectMapper;
|
|
559
|
+
readonly slotResourceResolver: ISlotResourceResolver;
|
|
560
|
+
readonly capabilityClassifier: ICapabilityClassifier;
|
|
561
|
+
readonly audit: Readonly<Required<IAuthorizationAuditConfig>>;
|
|
562
|
+
}
|
|
563
|
+
declare function hasAuthorizationPolicies(config: IAuthorizationPolicyConfig): boolean;
|
|
564
|
+
/** Compiles and validates the complete hierarchical authorization runtime. */
|
|
565
|
+
declare function compileAuthorizationPolicy(config: IAuthorizationPolicyConfig): IPolicyAuthorization;
|
|
566
|
+
declare function authorizationWithEngine(engine: IPolicyEngine, overrides?: {
|
|
567
|
+
readonly subjectMapper?: ISubjectMapper;
|
|
568
|
+
readonly slotResourceResolver?: ISlotResourceResolver;
|
|
569
|
+
readonly capabilityClassifier?: ICapabilityClassifier;
|
|
570
|
+
readonly audit?: IAuthorizationAuditConfig;
|
|
571
|
+
}): IPolicyAuthorization;
|
|
572
|
+
/** @deprecated Use {@link IPolicyAuthorization}. */
|
|
573
|
+
type PolicyAuthorization = IPolicyAuthorization;
|
|
574
|
+
|
|
575
|
+
interface IAuditContext {
|
|
576
|
+
readonly subject: IAuthorizationSubject;
|
|
577
|
+
readonly slot: string;
|
|
578
|
+
readonly resource?: ResourcePath;
|
|
579
|
+
readonly capability?: string;
|
|
580
|
+
readonly provider?: string;
|
|
581
|
+
readonly tool?: string;
|
|
582
|
+
}
|
|
583
|
+
/** @deprecated Use {@link IAuditContext}. */
|
|
584
|
+
type AuditContext = IAuditContext;
|
|
585
|
+
|
|
586
|
+
/** OAuth 2.1 error codes the broker emits in `WWW-Authenticate` challenges. */
|
|
587
|
+
type AuthErrorCode = _cyanmycelium_mcp_core.McpAuthErrorCode;
|
|
588
|
+
/**
|
|
589
|
+
* A thrown authorization failure carrying the HTTP status and OAuth error code
|
|
590
|
+
* the enforcement point should surface. `scope` is set for `insufficient_scope`
|
|
591
|
+
* challenges to advertise the scope(s) the resource requires.
|
|
592
|
+
*
|
|
593
|
+
* The broker's own name for `mcp-core`'s `McpAuthError`, kept so `instanceof`
|
|
594
|
+
* checks and the published API survive the consolidation. There is one class at
|
|
595
|
+
* runtime, so an error thrown by `mcp-core` is caught by the broker and the
|
|
596
|
+
* other way round.
|
|
597
|
+
*/
|
|
598
|
+
declare const AuthError: typeof McpAuthError;
|
|
599
|
+
type AuthError = McpAuthError;
|
|
600
|
+
/**
|
|
601
|
+
* The authenticated caller, produced once a token passes validation and the
|
|
602
|
+
* required scopes are satisfied. Threaded through the request so downstream
|
|
603
|
+
* components (e.g. the `_all` aggregate) can make scope-aware decisions.
|
|
604
|
+
*
|
|
605
|
+
* Extends `mcp-core`'s principal with the subject the policy engine reasons
|
|
606
|
+
* about, which the specification says nothing about and which therefore stays
|
|
607
|
+
* here.
|
|
608
|
+
*/
|
|
609
|
+
interface IPrincipal extends IMcpPrincipal {
|
|
610
|
+
readonly claims: IAccessTokenClaims;
|
|
611
|
+
readonly scopes: ReadonlySet<string>;
|
|
612
|
+
/** Subjects derived exclusively from validated token claims. */
|
|
613
|
+
readonly subject?: IAuthorizationSubject;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Decides, per authenticated caller, whether a given provider is visible in the
|
|
617
|
+
* `_all` aggregate. This is the content-confidentiality enforcement point: a
|
|
618
|
+
* client only sees (and can call) tools/prompts from providers it is authorized
|
|
619
|
+
* for. Return `true` to include the provider for this principal.
|
|
620
|
+
*/
|
|
621
|
+
type AggregateScopeFilter = (principal: IPrincipal, providerName: string) => boolean;
|
|
622
|
+
/**
|
|
623
|
+
* A fully resolved authorization configuration, ready for the enforcement
|
|
624
|
+
* layer. Built either from JSON config (via `buildJwtAuth`) or supplied
|
|
625
|
+
* directly by an embedder with a custom {@link ITokenValidator}.
|
|
626
|
+
*/
|
|
627
|
+
interface IResolvedAuth {
|
|
628
|
+
/**
|
|
629
|
+
* Public origin the broker is reached at, used to build canonical resource
|
|
630
|
+
* URIs and metadata URLs. No trailing slash (e.g. `https://mcp.example.com`).
|
|
631
|
+
*/
|
|
632
|
+
publicBaseUrl: string;
|
|
633
|
+
/** One or more authorization server issuer URLs, advertised in the PRM. */
|
|
634
|
+
authorizationServers: string[];
|
|
635
|
+
/** Optional list of scopes advertised in the PRM `scopes_supported`. */
|
|
636
|
+
scopesSupported?: string[];
|
|
637
|
+
/** The token validator (JWKS-backed by default). */
|
|
638
|
+
validator: ITokenValidator;
|
|
639
|
+
/** Baseline scope(s) required to reach any slot. Empty ⇒ any valid token. */
|
|
640
|
+
requiredScopes?: string[];
|
|
641
|
+
/** Per-slot required-scope overrides (e.g. an admin scope for `_broker`). */
|
|
642
|
+
perSlotScopes?: Record<string, string[]>;
|
|
643
|
+
/**
|
|
644
|
+
* Per-caller filter for the `_all` aggregate. When set, a client's view of
|
|
645
|
+
* `_all` is narrowed to the providers this returns `true` for. When absent,
|
|
646
|
+
* every authenticated caller sees the full aggregate.
|
|
647
|
+
*/
|
|
648
|
+
aggregateScopeFilter?: AggregateScopeFilter;
|
|
649
|
+
/** Compiled hierarchical policy runtime, absent for legacy OAuth behavior. */
|
|
650
|
+
authorization?: IPolicyAuthorization;
|
|
651
|
+
/** Optional resolver usable for provider namespace checks without policies. */
|
|
652
|
+
slotResourceResolver?: ISlotResourceResolver;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Extracts the effective set of granted scopes from token claims.
|
|
656
|
+
*
|
|
657
|
+
* A deliberate superset of `mcp-core`'s: OAuth 2.1 only defines the
|
|
658
|
+
* space-delimited `scope` string, which is what the spec-level helper reads,
|
|
659
|
+
* but several authorization servers emit an array-form `scopes` claim instead.
|
|
660
|
+
* Dropping that here would silently strip every scope for those deployments, so
|
|
661
|
+
* the two are unioned. The `scope` half is parsed by `mcp-core` rather than
|
|
662
|
+
* re-implemented.
|
|
663
|
+
*/
|
|
664
|
+
declare function scopesOf(claims: IAccessTokenClaims): Set<string>;
|
|
665
|
+
/** @deprecated Use {@link IAccessTokenClaims}. */
|
|
666
|
+
type AccessTokenClaims = IAccessTokenClaims;
|
|
667
|
+
/** @deprecated Use {@link ITokenValidator}. */
|
|
668
|
+
type TokenValidator = ITokenValidator;
|
|
669
|
+
/** @deprecated Use {@link IPrincipal}. */
|
|
670
|
+
type Principal = IPrincipal;
|
|
671
|
+
/** @deprecated Use {@link IResolvedAuth}. */
|
|
672
|
+
type ResolvedAuth = IResolvedAuth;
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Options for {@link JwtTokenValidator}. `jwksUri` points at the authorization
|
|
676
|
+
* server's JWKS endpoint; `issuer` (when set) is checked against the token `iss`.
|
|
677
|
+
*/
|
|
678
|
+
interface IJwtValidatorOptions {
|
|
679
|
+
/** URL of the authorization server's JWKS document. */
|
|
680
|
+
jwksUri: string;
|
|
681
|
+
/** Expected token issuer(s). When omitted, the `iss` claim is not checked. */
|
|
682
|
+
issuer?: string | string[];
|
|
683
|
+
/** Leeway in seconds for `exp`/`nbf` checks. Defaults to jose's `0`. */
|
|
684
|
+
clockToleranceSec?: number;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* An {@link ITokenValidator} that verifies JWT access tokens **statelessly** by
|
|
688
|
+
* checking the signature against the authorization server's JWKS and validating
|
|
689
|
+
* the standard claims. This is the default validator for a public deployment:
|
|
690
|
+
* no per-request round-trip to the AS, no shared introspection secret.
|
|
691
|
+
*
|
|
692
|
+
* Audience binding (RFC 8707) is enforced by passing the per-request canonical
|
|
693
|
+
* resource URI as the required `audience`, so a token minted for another slot ,
|
|
694
|
+
* or another service, is rejected.
|
|
695
|
+
*
|
|
696
|
+
* The JWKS is fetched lazily and cached (with rotation/cooldown) by
|
|
697
|
+
* `jose.createRemoteJWKSet`.
|
|
698
|
+
*/
|
|
699
|
+
declare class JwtTokenValidator implements ITokenValidator {
|
|
700
|
+
private readonly _jwks;
|
|
701
|
+
private readonly _issuer?;
|
|
702
|
+
private readonly _clockTolerance;
|
|
703
|
+
constructor(options: IJwtValidatorOptions);
|
|
704
|
+
validate(token: string, resource: string): Promise<IAccessTokenClaims>;
|
|
705
|
+
}
|
|
706
|
+
/** @deprecated Use {@link IJwtValidatorOptions}. */
|
|
707
|
+
type JwtValidatorOptions = IJwtValidatorOptions;
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* OAuth 2.0 Protected Resource Metadata (RFC 9728).
|
|
711
|
+
*
|
|
712
|
+
* Each slot exposed over HTTP is an independent resource server; its metadata
|
|
713
|
+
* document tells an MCP client which authorization server(s) issue tokens for
|
|
714
|
+
* that slot and which bearer methods it accepts. Served (unauthenticated, it is
|
|
715
|
+
* public discovery data) at
|
|
716
|
+
* `<publicBaseUrl>/.well-known/oauth-protected-resource/<slot>/<mcp>`.
|
|
717
|
+
*/
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Builds the RFC 9728 metadata document for one slot.
|
|
721
|
+
*
|
|
722
|
+
* The document itself is shaped by `mcp-core`: it is defined by the MCP
|
|
723
|
+
* specification, identically for every server. What is broker-specific is only
|
|
724
|
+
* which resource a slot maps to, and that is decided by the caller.
|
|
725
|
+
* `bearer_methods_supported` comes out fixed to `["header"]`, matching the
|
|
726
|
+
* broker's refusal to read a token from anywhere but the header (OAuth 2.1 §5).
|
|
727
|
+
*/
|
|
728
|
+
declare function buildResourceMetadata(params: {
|
|
729
|
+
resource: string;
|
|
730
|
+
authorizationServers: string[];
|
|
731
|
+
scopesSupported?: string[];
|
|
732
|
+
}): IProtectedResourceMetadata;
|
|
733
|
+
/** @deprecated Use {@link IProtectedResourceMetadata}. */
|
|
734
|
+
type ProtectedResourceMetadata = IProtectedResourceMetadata;
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* The HTTP enforcement point for the resource-server layer. Wraps a
|
|
738
|
+
* {@link IResolvedAuth} plus the configured `/mcp` path suffix and turns it into
|
|
739
|
+
* the three operations the transport needs: serve Protected Resource Metadata,
|
|
740
|
+
* authorize a request, and write an RFC 9728 `401`/`403` challenge.
|
|
741
|
+
*
|
|
742
|
+
* A slot's **canonical resource URI** is `<publicBaseUrl>/<slot>/<mcp>` and is
|
|
743
|
+
* used uniformly across all of that slot's HTTP endpoints (`/mcp`, `/sse`,
|
|
744
|
+
* `/messages`) so a single token audience covers the whole slot.
|
|
745
|
+
*/
|
|
746
|
+
declare class HttpAuthGuard {
|
|
747
|
+
private readonly _auth;
|
|
748
|
+
/** The `/mcp` suffix without a leading slash, e.g. `"mcp"`. */
|
|
749
|
+
private readonly _mcpSuffix;
|
|
750
|
+
constructor(auth: IResolvedAuth, mcpSuffix: string);
|
|
751
|
+
/** Canonical resource identifier for a slot (RFC 8707 §2). */
|
|
752
|
+
resourceFor(slot: string): string;
|
|
753
|
+
/** RFC 9728 metadata URL for a slot, advertised in the `401` challenge. */
|
|
754
|
+
metadataUrlFor(slot: string): string;
|
|
755
|
+
/** Required scope(s) for a slot: per-slot override, else the baseline. */
|
|
756
|
+
requiredScopesFor(slot: string): string[];
|
|
757
|
+
/** The RFC 9728 metadata document for a slot. */
|
|
758
|
+
metadataFor(slot: string): IProtectedResourceMetadata;
|
|
759
|
+
/**
|
|
760
|
+
* If `rawUrl` is a Protected Resource Metadata request
|
|
761
|
+
* (`/.well-known/oauth-protected-resource/<slot>/<mcp>`), returns the slot;
|
|
762
|
+
* otherwise `null`.
|
|
763
|
+
*/
|
|
764
|
+
matchMetadataRequest(rawUrl: string): string | null;
|
|
765
|
+
/**
|
|
766
|
+
* Validates the request's bearer token against the slot's canonical resource
|
|
767
|
+
* and enforces the slot's required scopes. Resolves to the {@link IPrincipal}
|
|
768
|
+
* on success; rejects with an {@link AuthError} (`401` missing/invalid token,
|
|
769
|
+
* `403` insufficient scope) otherwise.
|
|
770
|
+
*/
|
|
771
|
+
authorize(req: IncomingMessage, slot: string): Promise<IPrincipal>;
|
|
772
|
+
/**
|
|
773
|
+
* Builds the RFC 9728 §5.1 `WWW-Authenticate` header value for a challenge.
|
|
774
|
+
* Always points the client at the slot's metadata URL so it can discover the
|
|
775
|
+
* authorization server and retry. Shared by the HTTP and WebSocket paths.
|
|
776
|
+
*/
|
|
777
|
+
challengeHeader(slot: string, err: AuthError): string;
|
|
778
|
+
/**
|
|
779
|
+
* Writes an RFC 9728 §5.1 `WWW-Authenticate` challenge and the matching
|
|
780
|
+
* status to an HTTP response.
|
|
781
|
+
*/
|
|
782
|
+
writeChallenge(res: ServerResponse, slot: string, err: AuthError): void;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* High-level options for the default JWT/JWKS resource-server setup. Mirrors the
|
|
787
|
+
* `auth` block of the broker JSON config and is turned into a fully
|
|
788
|
+
* {@link IResolvedAuth} (with a {@link JwtTokenValidator}) by {@link buildJwtAuth}.
|
|
789
|
+
*/
|
|
790
|
+
interface IJwtAuthOptions extends IAuthorizationPolicyConfig {
|
|
791
|
+
/** Public origin the broker is reached at (e.g. `https://mcp.example.com`). */
|
|
792
|
+
publicBaseUrl: string;
|
|
793
|
+
/** Authorization server issuer URL(s) advertised in the PRM. At least one. */
|
|
794
|
+
authorizationServers: string[];
|
|
795
|
+
/** URL of the authorization server's JWKS document. */
|
|
796
|
+
jwksUri: string;
|
|
797
|
+
/** Expected token issuer(s). Defaults to the sole authorization server. */
|
|
798
|
+
issuer?: string | string[];
|
|
799
|
+
/** Scopes advertised in the PRM `scopes_supported`. */
|
|
800
|
+
scopesSupported?: string[];
|
|
801
|
+
/** Baseline scope(s) required to reach any slot. */
|
|
802
|
+
requiredScopes?: string[];
|
|
803
|
+
/** Per-slot required-scope overrides (e.g. an admin scope for `_broker`). */
|
|
804
|
+
perSlotScopes?: Record<string, string[]>;
|
|
805
|
+
/**
|
|
806
|
+
* Per-provider scope requirements for the `_all` aggregate. A caller sees a
|
|
807
|
+
* provider in `_all` only if it holds at least one of the listed scopes.
|
|
808
|
+
* Providers not listed here stay visible to every authenticated caller.
|
|
809
|
+
* Turned into an {@link AggregateScopeFilter} automatically.
|
|
810
|
+
*/
|
|
811
|
+
providerScopes?: Record<string, string[]>;
|
|
812
|
+
/** Leeway in seconds for token `exp`/`nbf` checks. */
|
|
813
|
+
clockToleranceSec?: number;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Builds an {@link IResolvedAuth} backed by a {@link JwtTokenValidator}. Validates
|
|
817
|
+
* the required inputs up front and throws a descriptive error on misconfig, so
|
|
818
|
+
* an operator sees the problem at boot rather than as opaque `401`s later.
|
|
819
|
+
*/
|
|
820
|
+
declare function buildJwtAuth(options: IJwtAuthOptions): IResolvedAuth;
|
|
821
|
+
/** @deprecated Use {@link IJwtAuthOptions}. */
|
|
822
|
+
type JwtAuthOptions = IJwtAuthOptions;
|
|
823
|
+
|
|
824
|
+
interface IProviderPrincipal {
|
|
825
|
+
readonly id: string;
|
|
826
|
+
readonly subjects?: readonly string[];
|
|
827
|
+
readonly allowedResources?: readonly string[];
|
|
828
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
829
|
+
}
|
|
830
|
+
type ProviderAuthenticationResult = {
|
|
831
|
+
readonly authenticated: true;
|
|
832
|
+
readonly principal: IProviderPrincipal;
|
|
833
|
+
} | {
|
|
834
|
+
readonly authenticated: false;
|
|
835
|
+
readonly reason?: string;
|
|
836
|
+
};
|
|
837
|
+
type ProviderAuthenticatorReturn = boolean | ProviderAuthenticationResult;
|
|
838
|
+
/**
|
|
839
|
+
* Authenticates a **provider** (the engine that connects _into_ the broker to
|
|
840
|
+
* serve a slot) at the WebSocket upgrade handshake. This is a distinct concern
|
|
841
|
+
* from the OAuth 2.1 resource-server layer that guards *clients*: a provider is
|
|
842
|
+
* not an OAuth client acting for a resource owner, it is the backend claiming a
|
|
843
|
+
* slot. Authenticating it is what stops a stranger from occupying a free slot
|
|
844
|
+
* (`ws://host/provider/<slot>`) and impersonating the real engine.
|
|
845
|
+
*/
|
|
846
|
+
interface IProviderAuthenticator {
|
|
847
|
+
/**
|
|
848
|
+
* Returns a structured result, or a legacy boolean for backward
|
|
849
|
+
* compatibility. `slot` is the dedicated slot name for
|
|
850
|
+
* `/provider/<slot>`, or `undefined` for the multiplexed `/providers`
|
|
851
|
+
* socket, which is authenticated before any provider name is known.
|
|
852
|
+
*/
|
|
853
|
+
authenticate(req: IncomingMessage, slot: string | undefined): ProviderAuthenticatorReturn | Promise<ProviderAuthenticatorReturn>;
|
|
854
|
+
}
|
|
855
|
+
declare function normalizeProviderAuthentication(result: ProviderAuthenticatorReturn, fallbackId?: string): ProviderAuthenticationResult;
|
|
856
|
+
declare function providerMayPublish(principal: IProviderPrincipal, resource: ResourcePath): boolean;
|
|
857
|
+
/**
|
|
858
|
+
* The default {@link IProviderAuthenticator}: every provider connection must
|
|
859
|
+
* present a single shared secret (via `X-Provider-Token` or `Authorization:
|
|
860
|
+
* Bearer`). Compared in constant time. Suitable when the broker and its
|
|
861
|
+
* providers are operated by the same party; swap in a custom authenticator for
|
|
862
|
+
* per-slot secrets, mTLS, or a signed handshake.
|
|
863
|
+
*/
|
|
864
|
+
declare class SharedSecretProviderAuthenticator implements IProviderAuthenticator {
|
|
865
|
+
private readonly _secret;
|
|
866
|
+
constructor(secret: string);
|
|
867
|
+
authenticate(req: IncomingMessage): ProviderAuthenticationResult;
|
|
868
|
+
}
|
|
869
|
+
/** @deprecated Use {@link IProviderPrincipal}. */
|
|
870
|
+
type ProviderPrincipal = IProviderPrincipal;
|
|
871
|
+
/** @deprecated Use {@link IProviderAuthenticator}. */
|
|
872
|
+
type ProviderAuthenticator = IProviderAuthenticator;
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* How `/<slot>/mcp` decides whether a browser origin may reach it.
|
|
876
|
+
*
|
|
877
|
+
* - a list of origins, matched exactly against the whole `Origin` header
|
|
878
|
+
* - a `RegExp`, tested against the whole header
|
|
879
|
+
* - a predicate, when the decision needs more than the string
|
|
880
|
+
*/
|
|
881
|
+
type AllowedOrigins = readonly string[] | RegExp | ((origin: string) => boolean);
|
|
882
|
+
/**
|
|
883
|
+
* A single static-file mount: serves the contents of `dir` under `urlPrefix`.
|
|
884
|
+
*
|
|
885
|
+
* @example
|
|
886
|
+
* { urlPrefix: "/", dir: "/absolute/path/to/www" }
|
|
887
|
+
* { urlPrefix: "/bundle", dir: "/absolute/path/to/bundle" }
|
|
888
|
+
*/
|
|
889
|
+
interface IStaticMount {
|
|
890
|
+
/** URL prefix that triggers this mount (e.g. `"/"` or `"/bundle"`). */
|
|
891
|
+
urlPrefix: string;
|
|
892
|
+
/** Absolute path to the directory to serve. */
|
|
893
|
+
dir: string;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* In-process client handle for a provider slot: the symmetric counterpart of
|
|
897
|
+
* {@link WsTunnel.registerLoopbackProvider}. Lets a component inside the broker
|
|
898
|
+
* process (e.g. the aggregate server) issue MCP requests to a provider slot and
|
|
899
|
+
* receive both the responses and the provider's broadcast notifications,
|
|
900
|
+
* without opening a real network connection.
|
|
901
|
+
*/
|
|
902
|
+
interface IInternalClient {
|
|
903
|
+
/**
|
|
904
|
+
* Sends a JSON-RPC message to the provider slot. When the message carries an
|
|
905
|
+
* `id`, the matching response is delivered to {@link onMessage}. When the
|
|
906
|
+
* provider is not connected, a JSON-RPC error is delivered synchronously.
|
|
907
|
+
*/
|
|
908
|
+
send(message: string): void;
|
|
909
|
+
/** Receives responses to this client's requests and the provider's notifications. */
|
|
910
|
+
onMessage: ((data: string) => void) | null;
|
|
911
|
+
/** Fires when the provider slot loses its connection. */
|
|
912
|
+
onClose: (() => void) | null;
|
|
913
|
+
/** Detaches this internal client; pending requests are dropped. */
|
|
914
|
+
close(): void;
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Configuration options for a {@link WsTunnel} instance.
|
|
918
|
+
*/
|
|
919
|
+
interface IWsTunnelOptions {
|
|
920
|
+
/** TCP port to listen on. */
|
|
921
|
+
port: number;
|
|
922
|
+
/**
|
|
923
|
+
* Host/interface to bind to.
|
|
924
|
+
* @default "0.0.0.0"
|
|
925
|
+
*/
|
|
926
|
+
host?: string;
|
|
927
|
+
/**
|
|
928
|
+
* URL path **prefix** the MCP provider connects to via WebSocket.
|
|
929
|
+
* Each provider appends its name: `<providerPath>/<encodedName>`.
|
|
930
|
+
* @default "/provider"
|
|
931
|
+
*/
|
|
932
|
+
providerPath?: string;
|
|
933
|
+
/**
|
|
934
|
+
* URL path for **multiplexed** provider connections.
|
|
935
|
+
* A single WebSocket carries traffic for multiple providers using the
|
|
936
|
+
* envelope protocol `{ provider: string, payload: object }`.
|
|
937
|
+
* @default "/providers"
|
|
938
|
+
*/
|
|
939
|
+
providersPath?: string;
|
|
940
|
+
/**
|
|
941
|
+
* URL path raw WebSocket MCP clients connect to.
|
|
942
|
+
* @default "/"
|
|
943
|
+
*/
|
|
944
|
+
clientPath?: string;
|
|
945
|
+
/**
|
|
946
|
+
* **Suffix** appended to a provider name for the SSE endpoint.
|
|
947
|
+
* Full URL: `/<providerName>/sse`
|
|
948
|
+
* @default "/sse"
|
|
949
|
+
*/
|
|
950
|
+
ssePath?: string;
|
|
951
|
+
/**
|
|
952
|
+
* **Suffix** appended to a provider name for the legacy SSE POST endpoint.
|
|
953
|
+
* Full URL: `/<providerName>/messages`
|
|
954
|
+
* @default "/messages"
|
|
955
|
+
*/
|
|
956
|
+
messagesPath?: string;
|
|
957
|
+
/**
|
|
958
|
+
* **Suffix** appended to a provider name for the Streamable HTTP endpoint (MCP 2025-03-26).
|
|
959
|
+
* Full URL: `/<providerName>/mcp`
|
|
960
|
+
* MCP Inspector connects here.
|
|
961
|
+
* @default "/mcp"
|
|
962
|
+
*/
|
|
963
|
+
mcpPath?: string;
|
|
964
|
+
/**
|
|
965
|
+
* URL path that returns a `{ files: string[] }` JSON listing of every file
|
|
966
|
+
* inside the `samples/` subdirectory of the root static mount.
|
|
967
|
+
* @default "/__samples_index__"
|
|
968
|
+
*/
|
|
969
|
+
samplesIndexPath?: string;
|
|
970
|
+
/**
|
|
971
|
+
* Browser origins allowed to reach `/<slot>/mcp`.
|
|
972
|
+
*
|
|
973
|
+
* The MCP specification requires the `Origin` header to be validated,
|
|
974
|
+
* because without it any web page the operator's browser happens to load
|
|
975
|
+
* can drive a broker that machine can reach. A request carrying **no**
|
|
976
|
+
* `Origin` is always allowed: that covers every non-browser client, which
|
|
977
|
+
* is what Claude Desktop, MCP Inspector and the server-side SDKs are.
|
|
978
|
+
*
|
|
979
|
+
* Omit this and every browser origin is refused with `403`. The default is
|
|
980
|
+
* deliberately closed; opening it is an operator decision.
|
|
981
|
+
*
|
|
982
|
+
* @default undefined, no browser origin is allowed
|
|
983
|
+
*/
|
|
984
|
+
allowedOrigins?: AllowedOrigins;
|
|
985
|
+
/**
|
|
986
|
+
* Optional static-file mounts served over plain HTTP.
|
|
987
|
+
* Matched by longest URL prefix; directory requests fall back to `index.html`.
|
|
988
|
+
*/
|
|
989
|
+
staticMounts?: IStaticMount[];
|
|
990
|
+
/**
|
|
991
|
+
* Stdio upstream providers. Each entry spawns a child process and wires its
|
|
992
|
+
* stdin/stdout as an MCP transport. Clients reach the process using its `name`
|
|
993
|
+
* directly.
|
|
994
|
+
*
|
|
995
|
+
* If a WebSocket provider connects with the same name as a stdio upstream, the
|
|
996
|
+
* connection is rejected and a warning is logged, stdio takes priority.
|
|
997
|
+
* @default undefined: no stdio providers
|
|
998
|
+
*/
|
|
999
|
+
stdioUpstreams?: IStdioUpstreamConfig[];
|
|
1000
|
+
/** Remote MCP servers reached by URL, exposed as provider slots. */
|
|
1001
|
+
remoteUpstreams?: IRemoteUpstreamConfig[];
|
|
1002
|
+
/**
|
|
1003
|
+
* Stdio client transport. When set, the broker reads JSON-RPC from
|
|
1004
|
+
* `process.stdin` and writes responses to `process.stdout`, bridging an
|
|
1005
|
+
* external MCP client (e.g. Claude Desktop) to the named provider.
|
|
1006
|
+
*
|
|
1007
|
+
* In this mode ALL logging is redirected to stderr so stdout stays clean
|
|
1008
|
+
* for the JSON-RPC stream.
|
|
1009
|
+
*
|
|
1010
|
+
* Claude Desktop config example:
|
|
1011
|
+
* ```json
|
|
1012
|
+
* {
|
|
1013
|
+
* "command": "npx",
|
|
1014
|
+
* "args": ["-y", "@cyanmycelium/mcp-broker"],
|
|
1015
|
+
* "env": { "MCP_BROKER_STDIO_PROVIDER": "my-provider" }
|
|
1016
|
+
* }
|
|
1017
|
+
* ```
|
|
1018
|
+
* @default undefined, stdio client transport disabled
|
|
1019
|
+
*/
|
|
1020
|
+
stdioClient?: {
|
|
1021
|
+
providerName: string;
|
|
1022
|
+
};
|
|
1023
|
+
/**
|
|
1024
|
+
* TLS configuration. When provided, the server uses HTTPS and WSS instead of HTTP and WS.
|
|
1025
|
+
* Both `cert` and `key` must be PEM-encoded strings (file contents, not file paths).
|
|
1026
|
+
* Use {@link WsTunnelBuilder.withTlsFiles} to load from disk paths.
|
|
1027
|
+
* @default undefined, plain HTTP/WS
|
|
1028
|
+
*/
|
|
1029
|
+
tls?: {
|
|
1030
|
+
/** PEM-encoded TLS certificate. */
|
|
1031
|
+
cert: string;
|
|
1032
|
+
/** PEM-encoded private key. */
|
|
1033
|
+
key: string;
|
|
1034
|
+
};
|
|
1035
|
+
/**
|
|
1036
|
+
* When `true` (default), the broker exposes itself as an MCP server under the
|
|
1037
|
+
* reserved slot `_broker`. Tier-1 behaviors (`broker_info`, `providers_list`,
|
|
1038
|
+
* `provider_status`) become callable at `<host>/_broker/mcp`.
|
|
1039
|
+
*
|
|
1040
|
+
* Set to `false` to keep the broker invisible to MCP clients.
|
|
1041
|
+
* @default true
|
|
1042
|
+
*/
|
|
1043
|
+
enableBrokerProvider?: boolean;
|
|
1044
|
+
/**
|
|
1045
|
+
* When `true` (default), the broker exposes the reserved slot `_all`: an
|
|
1046
|
+
* aggregate MCP server that unions the tools and prompts of every provider
|
|
1047
|
+
* that opted in via the registration handshake. Reachable like any other
|
|
1048
|
+
* slot (`<host>/_all/mcp`, etc.).
|
|
1049
|
+
*
|
|
1050
|
+
* Set to `false` to disable aggregation entirely.
|
|
1051
|
+
* @default true
|
|
1052
|
+
*/
|
|
1053
|
+
enableAggregateProvider?: boolean;
|
|
1054
|
+
/**
|
|
1055
|
+
* Logical name reported by `broker_info`. Useful when running multiple
|
|
1056
|
+
* broker instances and you want to tell them apart from the agent side
|
|
1057
|
+
* (e.g. `"broker-eu-west"`).
|
|
1058
|
+
* @default PACKAGE_NAME, `@cyanmycelium/mcp-broker`
|
|
1059
|
+
*/
|
|
1060
|
+
brokerName?: string;
|
|
1061
|
+
/**
|
|
1062
|
+
* Overrides for the embedded broker server's grammar resolver, passed
|
|
1063
|
+
* straight through to `mcp-core`'s `grammarResolverFromOptions`. The
|
|
1064
|
+
* broker installs its own default `localeSource` (reads
|
|
1065
|
+
* `process.env.MCP_BROKER_LOCALE`); anything you set here wins.
|
|
1066
|
+
*
|
|
1067
|
+
* Use this to inject a custom `localeSource` (e.g. read from an HTTP
|
|
1068
|
+
* header proxied by your transport), enable the optional `versionFrom`
|
|
1069
|
+
* dimension, or extend the `agents` map with additional LLM families.
|
|
1070
|
+
*/
|
|
1071
|
+
brokerGrammarResolverOptions?: Partial<GrammarResolverOptions>;
|
|
1072
|
+
/**
|
|
1073
|
+
* Path to a user-supplied grammars directory whose `<userAgent>/<locale>.json`
|
|
1074
|
+
* files are registered alongside the packaged grammars used by the
|
|
1075
|
+
* embedded broker server. Typically pointed at `.mcp-broker/grammars/`.
|
|
1076
|
+
*
|
|
1077
|
+
* The candidate-chain resolution in `McpServer.initialize`
|
|
1078
|
+
* (mcp-core@0.3.0) handles cascade across user-agent and locale
|
|
1079
|
+
* dimensions, so partial files no longer need to be pre-merged with a
|
|
1080
|
+
* baseline.
|
|
1081
|
+
*/
|
|
1082
|
+
brokerLocalGrammarsDir?: string;
|
|
1083
|
+
/**
|
|
1084
|
+
* OAuth 2.1 resource-server authorization. When set, every HTTP client
|
|
1085
|
+
* request to a slot (`/<slot>/mcp`, `/<slot>/sse`, `/<slot>/messages`) must
|
|
1086
|
+
* carry a valid `Authorization: Bearer` token issued for that slot, and the
|
|
1087
|
+
* broker publishes Protected Resource Metadata (RFC 9728) under
|
|
1088
|
+
* `/.well-known/oauth-protected-resource/<slot>/<mcp>`.
|
|
1089
|
+
*
|
|
1090
|
+
* When `undefined` (default), the broker performs **no** authentication ,
|
|
1091
|
+
* appropriate only behind a trusted network boundary.
|
|
1092
|
+
*/
|
|
1093
|
+
auth?: IResolvedAuth;
|
|
1094
|
+
/**
|
|
1095
|
+
* Authenticates **providers** (engines) connecting to `/provider/<slot>` and
|
|
1096
|
+
* the multiplexed `/providers` socket. Independent of {@link auth} (which
|
|
1097
|
+
* guards clients): set this to stop strangers from occupying a free slot and
|
|
1098
|
+
* impersonating the real engine.
|
|
1099
|
+
*
|
|
1100
|
+
* When `undefined` (default), provider connections are **not** authenticated.
|
|
1101
|
+
*/
|
|
1102
|
+
providerAuth?: IProviderAuthenticator;
|
|
1103
|
+
/** Hierarchical policy runtime. Absent preserves legacy OAuth behavior. */
|
|
1104
|
+
authorization?: IPolicyAuthorization;
|
|
1105
|
+
/** Slot-to-resource resolver also used for provider namespace restrictions. */
|
|
1106
|
+
slotResourceResolver?: ISlotResourceResolver;
|
|
1107
|
+
}
|
|
1108
|
+
/** @deprecated Use {@link IStaticMount}. */
|
|
1109
|
+
type StaticMount = IStaticMount;
|
|
1110
|
+
/** @deprecated Use {@link IInternalClient}. */
|
|
1111
|
+
type InternalClient = IInternalClient;
|
|
1112
|
+
/** @deprecated Use {@link IWsTunnelOptions}. */
|
|
1113
|
+
type WsTunnelOptions = IWsTunnelOptions;
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* A multi-provider relay that bridges any number of MCP server instances
|
|
1117
|
+
* (the **providers**) with their respective MCP clients.
|
|
1118
|
+
*
|
|
1119
|
+
* ## Transport overview
|
|
1120
|
+
* ```
|
|
1121
|
+
* Provider "<name>"
|
|
1122
|
+
* ws://host/provider/<name> ← WebSocket registration
|
|
1123
|
+
*
|
|
1124
|
+
* MCP Inspector (Streamable HTTP, 2025-03-26)
|
|
1125
|
+
* GET http://host/<name>/mcp ← persistent SSE notification stream
|
|
1126
|
+
* POST http://host/<name>/mcp → JSON-RPC requests
|
|
1127
|
+
*
|
|
1128
|
+
* Claude (legacy SSE transport)
|
|
1129
|
+
* GET http://host/<name>/sse ← SSE notification stream
|
|
1130
|
+
* POST http://host/<name>/messages → JSON-RPC requests
|
|
1131
|
+
* ```
|
|
1132
|
+
*
|
|
1133
|
+
* Each provider gets its own isolated set of sessions, pending requests, and
|
|
1134
|
+
* notification streams. Multiple providers can be connected simultaneously.
|
|
1135
|
+
*/
|
|
1136
|
+
declare class WsTunnel implements IBrokerContext {
|
|
1137
|
+
private readonly _options;
|
|
1138
|
+
private _httpServer;
|
|
1139
|
+
private _wss;
|
|
1140
|
+
/**
|
|
1141
|
+
* Per-provider state, keyed by provider name.
|
|
1142
|
+
* Created lazily: a slot is allocated the first time any client references
|
|
1143
|
+
* a provider name, even before the provider WebSocket connects.
|
|
1144
|
+
*/
|
|
1145
|
+
private readonly _providers;
|
|
1146
|
+
/** Maps a multiplexed WebSocket to the set of provider names it feeds. */
|
|
1147
|
+
private readonly _multiplexSockets;
|
|
1148
|
+
/** Upstream providers (stdio child processes and remote URL servers), keyed by name. */
|
|
1149
|
+
private readonly _upstreams;
|
|
1150
|
+
/**
|
|
1151
|
+
* In-process loopback transports registered as provider slots.
|
|
1152
|
+
* Used by the embedded broker server (`_broker`) and any other component
|
|
1153
|
+
* that wants to expose itself as a provider without going through a network.
|
|
1154
|
+
*/
|
|
1155
|
+
private readonly _loopbackProviders;
|
|
1156
|
+
/** The embedded broker MCP server, when {@link IWsTunnelOptions.enableBrokerProvider} is on. */
|
|
1157
|
+
private _brokerServer;
|
|
1158
|
+
/** The aggregate MCP server (`_all` slot), when {@link IWsTunnelOptions.enableAggregateProvider} is on. */
|
|
1159
|
+
private _aggregateServer;
|
|
1160
|
+
/** Provider name that the stdio client transport is bridged to, or null when disabled. */
|
|
1161
|
+
private _stdioClientProvider;
|
|
1162
|
+
/** mcp-core transport connected to the broker process stdin/stdout. */
|
|
1163
|
+
private _stdioClientTransport;
|
|
1164
|
+
/** Timestamp of the most recent successful `start()`. */
|
|
1165
|
+
private _startedAt;
|
|
1166
|
+
/** HTTP resource-server enforcement point, or `null` when auth is disabled. */
|
|
1167
|
+
private readonly _authGuard;
|
|
1168
|
+
/** Provider (engine) authenticator, or `null` when provider auth is disabled. */
|
|
1169
|
+
private readonly _providerAuth;
|
|
1170
|
+
/** Compiled hierarchical authorization, or `null` for legacy behavior. */
|
|
1171
|
+
private readonly _authorization;
|
|
1172
|
+
/** Stable technical-slot to hierarchical-resource mapping. */
|
|
1173
|
+
private readonly _slotResourceResolver;
|
|
1174
|
+
/** Origin check applied by every slot's Streamable HTTP endpoint. */
|
|
1175
|
+
private readonly _allowedOrigins;
|
|
1176
|
+
/** Principal captured at a client's WS upgrade, keyed by the upgrade request. */
|
|
1177
|
+
private readonly _pendingClientPrincipals;
|
|
1178
|
+
/** Authenticated principal per raw WS client socket, for `_all` scope filtering. */
|
|
1179
|
+
private readonly _clientPrincipals;
|
|
1180
|
+
/** Authenticated principal attached to long-lived HTTP/SSE streams. */
|
|
1181
|
+
private readonly _streamPrincipals;
|
|
1182
|
+
/** Provider principals captured during successful WebSocket upgrades. */
|
|
1183
|
+
private readonly _pendingProviderPrincipals;
|
|
1184
|
+
private readonly _providerPrincipals;
|
|
1185
|
+
constructor(options: IWsTunnelOptions);
|
|
1186
|
+
get version(): string;
|
|
1187
|
+
get name(): string;
|
|
1188
|
+
get startedAt(): Date | null;
|
|
1189
|
+
get uptimeSeconds(): number;
|
|
1190
|
+
get host(): string | undefined;
|
|
1191
|
+
get port(): number;
|
|
1192
|
+
get tls(): boolean;
|
|
1193
|
+
get paths(): IBrokerContext["paths"];
|
|
1194
|
+
getProvidersInfo(): IBrokerProviderInfo[];
|
|
1195
|
+
getProviderInfo(name: string): IBrokerProviderInfo | undefined;
|
|
1196
|
+
private _buildProviderInfo;
|
|
1197
|
+
/**
|
|
1198
|
+
* Registers an in-process transport as a provider slot. Used by the embedded
|
|
1199
|
+
* broker server and may be used by application code that wants to host an
|
|
1200
|
+
* MCP server inside the same process without opening a real WebSocket.
|
|
1201
|
+
*
|
|
1202
|
+
* @throws if the name is already used by a stdio upstream or another loopback.
|
|
1203
|
+
*/
|
|
1204
|
+
registerLoopbackProvider(name: string, transport: IMessageTransport): void;
|
|
1205
|
+
/**
|
|
1206
|
+
* Opens an in-process client to a provider slot. The returned handle can
|
|
1207
|
+
* issue MCP requests and receives both the responses and the provider's
|
|
1208
|
+
* broadcast notifications. Used by the aggregate server to fan a single
|
|
1209
|
+
* in-process client out to every aggregated provider.
|
|
1210
|
+
*
|
|
1211
|
+
* The slot does not need a provider attached yet, `send` returns a
|
|
1212
|
+
* JSON-RPC error while the provider is disconnected.
|
|
1213
|
+
*/
|
|
1214
|
+
openInternalClient(providerName: string): IInternalClient;
|
|
1215
|
+
get isListening(): boolean;
|
|
1216
|
+
/** Total number of connected MCP clients across all providers. */
|
|
1217
|
+
get clientCount(): number;
|
|
1218
|
+
/** Names of all providers that currently have an active connection. */
|
|
1219
|
+
get providerNames(): readonly string[];
|
|
1220
|
+
/** @deprecated Check `providerNames.length > 0` instead. */
|
|
1221
|
+
get hasProvider(): boolean;
|
|
1222
|
+
/**
|
|
1223
|
+
* Starts the broker. Resolves once the HTTP server is listening.
|
|
1224
|
+
*/
|
|
1225
|
+
start(): Promise<void>;
|
|
1226
|
+
/**
|
|
1227
|
+
* Starts the in-process MCP server that exposes the broker's own behaviors
|
|
1228
|
+
* (`broker_info`, `providers_list`, `provider_status`) under the reserved
|
|
1229
|
+
* provider slot `_broker`. No-op when {@link IWsTunnelOptions.enableBrokerProvider}
|
|
1230
|
+
* is `false`.
|
|
1231
|
+
*/
|
|
1232
|
+
private _maybeStartBrokerServer;
|
|
1233
|
+
/**
|
|
1234
|
+
* Starts the aggregate MCP server and registers it on the reserved `_all`
|
|
1235
|
+
* slot. No-op when {@link IWsTunnelOptions.enableAggregateProvider} is `false`.
|
|
1236
|
+
*/
|
|
1237
|
+
private _maybeStartAggregateServer;
|
|
1238
|
+
/**
|
|
1239
|
+
* Gracefully closes all connections and stops the HTTP server.
|
|
1240
|
+
*/
|
|
1241
|
+
stop(): Promise<void>;
|
|
1242
|
+
private _authorizationSubject;
|
|
1243
|
+
private _auditDecision;
|
|
1244
|
+
/**
|
|
1245
|
+
* Applies hierarchical policy to the MCP operations carried in one
|
|
1246
|
+
* JSON-RPC frame. `_all` performs provider-specific checks internally.
|
|
1247
|
+
*/
|
|
1248
|
+
private _authorizeMcpFrame;
|
|
1249
|
+
private _policyDeniedPayload;
|
|
1250
|
+
/** The JSON-RPC error returned when the slot has nobody behind it. */
|
|
1251
|
+
private _notConnectedPayload;
|
|
1252
|
+
private _handleHttp;
|
|
1253
|
+
/**
|
|
1254
|
+
* Parses `/<providerName>/<endpoint>` from a URL path.
|
|
1255
|
+
* Returns `null` if the URL does not match this two-segment pattern.
|
|
1256
|
+
*/
|
|
1257
|
+
private _parseProviderRoute;
|
|
1258
|
+
/**
|
|
1259
|
+
* Classifies a `(endpoint, method)` pair as one of the four MCP/SSE client
|
|
1260
|
+
* handlers, or `null` when it is not a client transport request (the caller
|
|
1261
|
+
* then falls through to static-file serving, preserving prior behavior).
|
|
1262
|
+
*/
|
|
1263
|
+
private _mcpEndpointKind;
|
|
1264
|
+
/** Routes an already-authorized (or auth-disabled) request to its handler. */
|
|
1265
|
+
private _dispatchMcpEndpoint;
|
|
1266
|
+
/** Turns a rejected {@link HttpAuthGuard.authorize} into an HTTP response. */
|
|
1267
|
+
private _handleAuthFailure;
|
|
1268
|
+
/**
|
|
1269
|
+
* Builds the `ws` verifyClient hook that authenticates every WebSocket
|
|
1270
|
+
* upgrade before the connection is accepted, returning a real `401`/`403`
|
|
1271
|
+
* during the handshake rather than a post-handshake close:
|
|
1272
|
+
*
|
|
1273
|
+
* - **Raw MCP clients** (`/<slot>`) are gated by the OAuth 2.1 resource
|
|
1274
|
+
* server ({@link _authGuard}) with the RFC 9728 `WWW-Authenticate` challenge.
|
|
1275
|
+
* - **Providers** (`/provider/<slot>`, `/providers`) are gated by the
|
|
1276
|
+
* {@link _providerAuth} shared-secret / custom authenticator.
|
|
1277
|
+
*
|
|
1278
|
+
* Each side is independent: a branch with no authenticator configured is let
|
|
1279
|
+
* through unchanged. Returns `undefined` (no hook) when neither is set.
|
|
1280
|
+
*/
|
|
1281
|
+
private _makeVerifyClient;
|
|
1282
|
+
/**
|
|
1283
|
+
* Handles `GET /<providerName>/sse`, opens a long-lived SSE stream for Claude.
|
|
1284
|
+
* Sends an `endpoint` event so Claude knows where to POST its requests.
|
|
1285
|
+
*/
|
|
1286
|
+
private _handleSseConnect;
|
|
1287
|
+
/**
|
|
1288
|
+
* Handles `POST /<providerName>/messages?sessionId=…`, receives a JSON-RPC
|
|
1289
|
+
* request from Claude and forwards it to the provider.
|
|
1290
|
+
* Always responds 202 Accepted; the real response arrives over SSE.
|
|
1291
|
+
*/
|
|
1292
|
+
private _handleSseMessage;
|
|
1293
|
+
/**
|
|
1294
|
+
* Serves `/<providerName>/mcp` by handing the request to the slot's
|
|
1295
|
+
* Streamable HTTP endpoint.
|
|
1296
|
+
*
|
|
1297
|
+
* Everything protocol-shaped, sessions, `Mcp-Session-Id`, `DELETE`, the
|
|
1298
|
+
* `404` on a terminated session, `Origin` and `MCP-Protocol-Version`
|
|
1299
|
+
* validation, `202` on a notification, belongs to `mcp-core` and is no
|
|
1300
|
+
* longer reimplemented here. What stays is the broker's own business:
|
|
1301
|
+
* deciding who may speak (already done upstream by the auth guard) and
|
|
1302
|
+
* relaying frames to a provider that lives somewhere else entirely.
|
|
1303
|
+
*/
|
|
1304
|
+
private _handleStreamableHttp;
|
|
1305
|
+
/**
|
|
1306
|
+
* The slot's Streamable HTTP endpoint, built on first use.
|
|
1307
|
+
*
|
|
1308
|
+
* Its factory does not create an MCP server: the server is the provider,
|
|
1309
|
+
* reachable only through the tunnel. It creates a bridge instead: frames the
|
|
1310
|
+
* client sends go out to the provider, and frames coming back are addressed
|
|
1311
|
+
* to this session by id.
|
|
1312
|
+
*/
|
|
1313
|
+
private _endpointFor;
|
|
1314
|
+
/** Relays one frame from an HTTP session to the provider behind the slot. */
|
|
1315
|
+
private _fromHttpSession;
|
|
1316
|
+
/** Writes one JSON-RPC message as an SSE `message` event. */
|
|
1317
|
+
private _sendSseEvent;
|
|
1318
|
+
private _logProviderRegistration;
|
|
1319
|
+
private _onProviderConnect;
|
|
1320
|
+
/**
|
|
1321
|
+
* Inspects a provider's first WebSocket message for an optional registration
|
|
1322
|
+
* control frame `{ "type": "register", "aggregate": boolean }`. Returns
|
|
1323
|
+
* `true` when the message was a registration frame: and thus consumed, not
|
|
1324
|
+
* routed as MCP traffic. A normal MCP frame always carries `jsonrpc`, so it
|
|
1325
|
+
* returns `false` and the provider stays non-aggregated.
|
|
1326
|
+
*/
|
|
1327
|
+
private _tryHandleRegistration;
|
|
1328
|
+
private _onClientConnect;
|
|
1329
|
+
/**
|
|
1330
|
+
* Handles a multiplexed provider WebSocket (`/providers`).
|
|
1331
|
+
* A single socket carries traffic for multiple providers using the
|
|
1332
|
+
* envelope format `{ provider: string, payload: object }`.
|
|
1333
|
+
* Provider names are registered lazily on first message.
|
|
1334
|
+
*/
|
|
1335
|
+
private _onMultiplexProviderConnect;
|
|
1336
|
+
/**
|
|
1337
|
+
* Sends a raw JSON-RPC message to a provider, wrapping it in a multiplex
|
|
1338
|
+
* envelope when the provider's WebSocket is a multiplexed connection.
|
|
1339
|
+
*/
|
|
1340
|
+
private _sendToProvider;
|
|
1341
|
+
private _routeFromStdioClient;
|
|
1342
|
+
private _routeFromClient;
|
|
1343
|
+
private _routeFromProvider;
|
|
1344
|
+
/** Sends a message to all clients connected to one provider. */
|
|
1345
|
+
private _broadcast;
|
|
1346
|
+
/**
|
|
1347
|
+
* Notifies every pending sink and internal client that the provider slot
|
|
1348
|
+
* has disconnected, then clears the pending map. Shared by all provider
|
|
1349
|
+
* close handlers (dedicated WS, multiplexed WS, loopback).
|
|
1350
|
+
*/
|
|
1351
|
+
private _failProviderDisconnected;
|
|
1352
|
+
/**
|
|
1353
|
+
* Returns `true` if the provider is reachable, via a WebSocket connection,
|
|
1354
|
+
* a stdio upstream, or an in-process loopback transport.
|
|
1355
|
+
*/
|
|
1356
|
+
private _isProviderConnected;
|
|
1357
|
+
/** Returns the state for `name`, creating it lazily if it doesn't exist yet. */
|
|
1358
|
+
private _getOrCreateProviderState;
|
|
1359
|
+
private _handleSamplesIndex;
|
|
1360
|
+
private _serveStatic;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* Fluent builder that constructs a configured {@link WsTunnel}.
|
|
1365
|
+
*
|
|
1366
|
+
* @example
|
|
1367
|
+
* ```typescript
|
|
1368
|
+
* const tunnel = new WsTunnelBuilder()
|
|
1369
|
+
* .withPort(3000)
|
|
1370
|
+
* .withHost("localhost")
|
|
1371
|
+
* .withStaticMount("/", "/abs/path/to/www")
|
|
1372
|
+
* .build();
|
|
1373
|
+
*
|
|
1374
|
+
* await tunnel.start();
|
|
1375
|
+
* console.log("Broker listening on ws://localhost:3000");
|
|
1376
|
+
* console.log(" Provider connects to: ws://localhost:3000/provider/<name>");
|
|
1377
|
+
* console.log(" Clients connect to: ws://localhost:3000/<name>");
|
|
1378
|
+
* ```
|
|
1379
|
+
*/
|
|
1380
|
+
declare class WsTunnelBuilder {
|
|
1381
|
+
private _port;
|
|
1382
|
+
private _host;
|
|
1383
|
+
private _providerPath;
|
|
1384
|
+
private _providersPath;
|
|
1385
|
+
private _clientPath;
|
|
1386
|
+
private _ssePath;
|
|
1387
|
+
private _messagesPath;
|
|
1388
|
+
private _mcpPath;
|
|
1389
|
+
private _samplesIndexPath;
|
|
1390
|
+
private _allowedOrigins;
|
|
1391
|
+
private _staticMounts;
|
|
1392
|
+
private _stdioUpstreams;
|
|
1393
|
+
private _remoteUpstreams;
|
|
1394
|
+
private _stdioClient;
|
|
1395
|
+
private _tls;
|
|
1396
|
+
private _brokerLocalGrammarsDir;
|
|
1397
|
+
private _auth;
|
|
1398
|
+
private _providerAuth;
|
|
1399
|
+
private _authorization;
|
|
1400
|
+
private _slotResourceResolver;
|
|
1401
|
+
/** Sets the TCP port the broker listens on. */
|
|
1402
|
+
withPort(port: number): this;
|
|
1403
|
+
/**
|
|
1404
|
+
* Sets the host/interface to bind to.
|
|
1405
|
+
* @default "0.0.0.0" (all interfaces)
|
|
1406
|
+
*/
|
|
1407
|
+
withHost(host: string): this;
|
|
1408
|
+
/**
|
|
1409
|
+
* Sets the URL path the MCP provider connects to.
|
|
1410
|
+
* @default "/provider"
|
|
1411
|
+
*/
|
|
1412
|
+
withProviderPath(path: string): this;
|
|
1413
|
+
/**
|
|
1414
|
+
* Sets the URL path for multiplexed provider connections.
|
|
1415
|
+
* Multiple providers share a single WebSocket using the envelope protocol.
|
|
1416
|
+
* @default "/providers"
|
|
1417
|
+
*/
|
|
1418
|
+
withProvidersPath(path: string): this;
|
|
1419
|
+
/**
|
|
1420
|
+
* Sets the URL path MCP clients connect to.
|
|
1421
|
+
* @default "/"
|
|
1422
|
+
*/
|
|
1423
|
+
withClientPath(path: string): this;
|
|
1424
|
+
/**
|
|
1425
|
+
* Sets the URL path for the SSE stream (legacy Claude transport, GET).
|
|
1426
|
+
* @default "/sse"
|
|
1427
|
+
*/
|
|
1428
|
+
withSsePath(path: string): this;
|
|
1429
|
+
/**
|
|
1430
|
+
* Sets the URL path for JSON-RPC POST requests (legacy Claude transport).
|
|
1431
|
+
* @default "/messages"
|
|
1432
|
+
*/
|
|
1433
|
+
withMessagesPath(path: string): this;
|
|
1434
|
+
/**
|
|
1435
|
+
* Sets the URL path for the Streamable HTTP transport (MCP 2025-03-26).
|
|
1436
|
+
* MCP Inspector and other 2025+ clients POST JSON-RPC here.
|
|
1437
|
+
* @default "/mcp"
|
|
1438
|
+
*/
|
|
1439
|
+
withMcpPath(path: string): this;
|
|
1440
|
+
/**
|
|
1441
|
+
* Sets the URL path that returns a `{ files: string[] }` listing of the
|
|
1442
|
+
* `samples/` subdirectory under the root static mount.
|
|
1443
|
+
* @default "/__samples_index__"
|
|
1444
|
+
*/
|
|
1445
|
+
withSamplesIndexPath(path: string): this;
|
|
1446
|
+
/**
|
|
1447
|
+
* Allows browser origins to reach `/<slot>/mcp`.
|
|
1448
|
+
*
|
|
1449
|
+
* Without this call no browser origin is accepted, which is the safe
|
|
1450
|
+
* default: a request carrying an `Origin` is refused with `403`, while one
|
|
1451
|
+
* carrying none (any non-browser client) always passes. Call it only when a
|
|
1452
|
+
* web page really has to talk to the broker over HTTP.
|
|
1453
|
+
*
|
|
1454
|
+
* @example
|
|
1455
|
+
* ```typescript
|
|
1456
|
+
* builder.withAllowedOrigins(["https://app.example.com"]);
|
|
1457
|
+
* builder.withAllowedOrigins(/^https:\/\/[a-z0-9-]+\.example\.com$/);
|
|
1458
|
+
* builder.withAllowedOrigins((origin) => origin.endsWith(".example.com"));
|
|
1459
|
+
* ```
|
|
1460
|
+
*/
|
|
1461
|
+
withAllowedOrigins(allowed: AllowedOrigins): this;
|
|
1462
|
+
/**
|
|
1463
|
+
* Adds a static-file mount served over plain HTTP.
|
|
1464
|
+
* Can be called multiple times; longest-prefix match wins at runtime.
|
|
1465
|
+
*
|
|
1466
|
+
* @param urlPrefix URL prefix that triggers this mount (e.g. `"/"` or `"/bundle"`).
|
|
1467
|
+
* @param dir Absolute path to the directory to serve.
|
|
1468
|
+
*/
|
|
1469
|
+
withStaticMount(urlPrefix: string, dir: string): this;
|
|
1470
|
+
/**
|
|
1471
|
+
* Registers a stdio upstream provider. The broker spawns the configured
|
|
1472
|
+
* command and bridges its stdin/stdout as an MCP transport. Clients reach
|
|
1473
|
+
* it using `config.name` directly (e.g. `/<name>/mcp`).
|
|
1474
|
+
*
|
|
1475
|
+
* Can be called multiple times to register multiple providers.
|
|
1476
|
+
*/
|
|
1477
|
+
withStdioUpstream(config: IStdioUpstreamConfig): this;
|
|
1478
|
+
/**
|
|
1479
|
+
* Registers a remote MCP server reached by URL. The broker connects out to
|
|
1480
|
+
* it and exposes it as a provider slot named `config.name`, bridging the
|
|
1481
|
+
* Streamable HTTP / SSE / WebSocket transport for the slot's clients.
|
|
1482
|
+
*
|
|
1483
|
+
* Can be called multiple times to register multiple servers.
|
|
1484
|
+
*/
|
|
1485
|
+
withRemoteUpstream(config: IRemoteUpstreamConfig): this;
|
|
1486
|
+
/**
|
|
1487
|
+
* Enables the stdio client transport. The broker will read JSON-RPC from
|
|
1488
|
+
* `process.stdin` and write responses to `process.stdout`, bridging Claude
|
|
1489
|
+
* Desktop (or any stdio MCP client) to the named provider.
|
|
1490
|
+
*
|
|
1491
|
+
* All console output is automatically redirected to stderr in this mode so
|
|
1492
|
+
* stdout stays clean for the JSON-RPC stream.
|
|
1493
|
+
*
|
|
1494
|
+
* @param providerName The provider the stdio client maps to.
|
|
1495
|
+
*/
|
|
1496
|
+
withStdioClient(providerName: string): this;
|
|
1497
|
+
/**
|
|
1498
|
+
* Enables HTTPS/WSS mode by supplying PEM-encoded certificate and key strings directly.
|
|
1499
|
+
* Call this when you already have the PEM content in memory.
|
|
1500
|
+
*/
|
|
1501
|
+
withTls(cert: string, key: string): this;
|
|
1502
|
+
/**
|
|
1503
|
+
* Enables HTTPS/WSS mode by reading the certificate and key from the given file paths.
|
|
1504
|
+
* Files are read synchronously at call time.
|
|
1505
|
+
*
|
|
1506
|
+
* @param certPath Path to the PEM certificate file (e.g. `fullchain.pem`).
|
|
1507
|
+
* @param keyPath Path to the PEM private-key file (e.g. `privkey.pem`).
|
|
1508
|
+
*/
|
|
1509
|
+
withTlsFiles(certPath: string, keyPath: string): this;
|
|
1510
|
+
/**
|
|
1511
|
+
* Sets the path to a user-supplied grammars directory whose
|
|
1512
|
+
* `<userAgent>/<locale>.json` files are merged on top of the packaged
|
|
1513
|
+
* grammars used by the embedded broker server (the reserved `_broker`
|
|
1514
|
+
* provider slot). Typically pointed at `.mcp-broker/grammars/`.
|
|
1515
|
+
*/
|
|
1516
|
+
withBrokerLocalGrammarsDir(dir: string): this;
|
|
1517
|
+
/**
|
|
1518
|
+
* Enables OAuth 2.1 resource-server authorization with a pre-resolved config
|
|
1519
|
+
* (e.g. a custom {@link IResolvedAuth} carrying your own `ITokenValidator`).
|
|
1520
|
+
* Prefer {@link withJwtAuth} for the standard JWKS-backed setup.
|
|
1521
|
+
*/
|
|
1522
|
+
withAuth(auth: IResolvedAuth): this;
|
|
1523
|
+
/**
|
|
1524
|
+
* Enables OAuth 2.1 authorization with the default stateless JWT validator:
|
|
1525
|
+
* the broker verifies each bearer token's signature against the authorization
|
|
1526
|
+
* server's JWKS and its audience against the slot's canonical resource URI.
|
|
1527
|
+
*
|
|
1528
|
+
* @throws if `publicBaseUrl`, `authorizationServers`, or `jwksUri` are missing.
|
|
1529
|
+
*/
|
|
1530
|
+
withJwtAuth(options: IJwtAuthOptions): this;
|
|
1531
|
+
/** Installs a custom policy engine behind the broker's transport-neutral API. */
|
|
1532
|
+
withPolicyEngine(engine: IPolicyEngine): this;
|
|
1533
|
+
/** Compiles and validates roles, assignments, denies, mappings, and paths. */
|
|
1534
|
+
withAuthorizationPolicy(config: IAuthorizationPolicyConfig): this;
|
|
1535
|
+
/** Overrides the technical slot to hierarchical resource resolution strategy. */
|
|
1536
|
+
withSlotResourceResolver(resolver: ISlotResourceResolver): this;
|
|
1537
|
+
/**
|
|
1538
|
+
* Authenticates providers (engines) with a custom {@link IProviderAuthenticator}.
|
|
1539
|
+
* Prefer {@link withProviderSecret} for the standard shared-secret setup.
|
|
1540
|
+
*/
|
|
1541
|
+
withProviderAuth(authenticator: IProviderAuthenticator): this;
|
|
1542
|
+
/**
|
|
1543
|
+
* Requires every provider connecting to `/provider/<slot>` or `/providers` to
|
|
1544
|
+
* present the given shared secret (via `X-Provider-Token` or `Authorization:
|
|
1545
|
+
* Bearer`). Closes off slot occupation by strangers.
|
|
1546
|
+
*/
|
|
1547
|
+
withProviderSecret(secret: string): this;
|
|
1548
|
+
/** Constructs and returns a configured {@link WsTunnel}. */
|
|
1549
|
+
build(): WsTunnel;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
/** A `.mcpb` bundle entry from the broker config file. */
|
|
1553
|
+
interface IMcpbBundleConfig {
|
|
1554
|
+
/** Provider slot name the bundle is bound to. */
|
|
1555
|
+
name: string;
|
|
1556
|
+
/** Path to the `.mcpb` file. */
|
|
1557
|
+
path: string;
|
|
1558
|
+
/** Path to the trusted public key (PEM) verifying the detached signature. */
|
|
1559
|
+
publicKey: string;
|
|
1560
|
+
/** Path to the detached signature file. Defaults to `<path>.sig`. */
|
|
1561
|
+
signature?: string;
|
|
1562
|
+
/** Values substituted into the manifest's `${user_config.*}` placeholders. */
|
|
1563
|
+
userConfig?: Record<string, string | number | boolean | Array<string | number>>;
|
|
1564
|
+
/** When `false`, the bundle stays out of the `_all` aggregate slot. Defaults to `true`. */
|
|
1565
|
+
aggregate?: boolean;
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Verifies, unpacks and resolves a `.mcpb` bundle into an `IStdioUpstreamConfig`.
|
|
1569
|
+
*
|
|
1570
|
+
* @param cfg The bundle entry from the broker config.
|
|
1571
|
+
* @param baseDir Directory the bundle paths are resolved against.
|
|
1572
|
+
* @returns A ready upstream config, or `null` when the bundle is refused.
|
|
1573
|
+
*/
|
|
1574
|
+
declare function loadMcpbBundle(cfg: IMcpbBundleConfig, baseDir: string): Promise<IStdioUpstreamConfig | null>;
|
|
1575
|
+
/** @deprecated Use {@link IMcpbBundleConfig}. */
|
|
1576
|
+
type McpbBundleConfig = IMcpbBundleConfig;
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* Extracts every entry of the `.mcpb` archive at `mcpbPath` into `destDir`.
|
|
1580
|
+
* `destDir` is created if missing. Entries whose resolved path would escape
|
|
1581
|
+
* `destDir` (zip-slip) are rejected.
|
|
1582
|
+
*/
|
|
1583
|
+
declare function unzipMcpb(mcpbPath: string, destDir: string): void;
|
|
1584
|
+
|
|
1585
|
+
declare const VERSION: string;
|
|
1586
|
+
declare const PACKAGE_NAME: string;
|
|
1587
|
+
|
|
1588
|
+
interface IBrokerAuthConfig extends IAuthorizationPolicyConfig {
|
|
1589
|
+
/** Master switch. Absent/`false` keeps the broker unauthenticated. */
|
|
1590
|
+
enabled?: boolean;
|
|
1591
|
+
/** Public origin the broker is reached at (e.g. `https://mcp.example.com`). */
|
|
1592
|
+
publicBaseUrl?: string;
|
|
1593
|
+
/** Authorization server issuer URL(s) advertised in the metadata. */
|
|
1594
|
+
authorizationServers?: string[];
|
|
1595
|
+
/** URL of the authorization server's JWKS document. */
|
|
1596
|
+
jwks?: string;
|
|
1597
|
+
/** Expected token issuer. Defaults to the sole `authorizationServers` entry. */
|
|
1598
|
+
issuer?: string;
|
|
1599
|
+
/** Scopes advertised in the metadata `scopes_supported`. */
|
|
1600
|
+
scopesSupported?: string[];
|
|
1601
|
+
/** Baseline scope(s) required to reach any slot. */
|
|
1602
|
+
requiredScopes?: string[];
|
|
1603
|
+
/** Per-slot required-scope overrides (e.g. an admin scope for `_broker`). */
|
|
1604
|
+
perSlotScopes?: Record<string, string[]>;
|
|
1605
|
+
/**
|
|
1606
|
+
* Per-provider scope requirements for the `_all` aggregate. Deprecated in
|
|
1607
|
+
* favor of hierarchical policy assignments.
|
|
1608
|
+
*/
|
|
1609
|
+
providerScopes?: Record<string, string[]>;
|
|
1610
|
+
/**
|
|
1611
|
+
* Shared secret every provider must present to occupy a slot. Independent
|
|
1612
|
+
* of client authorization.
|
|
1613
|
+
*/
|
|
1614
|
+
providerSecret?: string;
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* Shape of the optional JSON config file consumed by `bin.ts` at startup.
|
|
1618
|
+
* Every field is optional. Environment variables (`MCP_BROKER_*`) always win
|
|
1619
|
+
* over file values, and file values win over the built-in defaults.
|
|
1620
|
+
*
|
|
1621
|
+
* @example
|
|
1622
|
+
* ```json
|
|
1623
|
+
* {
|
|
1624
|
+
* "port": 3001,
|
|
1625
|
+
* "locale": "fr",
|
|
1626
|
+
* "tls": { "cert": "certs/cert.pem", "key": "certs/key.pem" },
|
|
1627
|
+
* "stdioUpstreams": [
|
|
1628
|
+
* { "name": "fs", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"] }
|
|
1629
|
+
* ]
|
|
1630
|
+
* }
|
|
1631
|
+
* ```
|
|
1632
|
+
*/
|
|
1633
|
+
interface IBrokerConfig {
|
|
1634
|
+
/** TCP port. Maps to `MCP_BROKER_PORT`. */
|
|
1635
|
+
port?: number;
|
|
1636
|
+
/** Bind host. Maps to `MCP_BROKER_HOST`. */
|
|
1637
|
+
host?: string;
|
|
1638
|
+
/** Force protocol (`http`/`https`) regardless of cert presence. Maps to `MCP_BROKER_PROTOCOL`. */
|
|
1639
|
+
protocol?: "http" | "https";
|
|
1640
|
+
/** Locale fed to the broker grammar resolver. Maps to `MCP_BROKER_LOCALE`. */
|
|
1641
|
+
locale?: string;
|
|
1642
|
+
/** Bridge stdin/stdout for a Claude-Desktop-style client. Maps to `MCP_BROKER_STDIO_PROVIDER`. */
|
|
1643
|
+
stdioProvider?: string;
|
|
1644
|
+
/** Logical broker name reported by `broker_info`. */
|
|
1645
|
+
brokerName?: string;
|
|
1646
|
+
/**
|
|
1647
|
+
* Browser origins allowed to reach `/<slot>/mcp`.
|
|
1648
|
+
*
|
|
1649
|
+
* Absent means no browser origin is accepted: a request carrying an
|
|
1650
|
+
* `Origin` header gets `403`, one carrying none (Claude Desktop, MCP
|
|
1651
|
+
* Inspector, any server-side SDK) always passes. The MCP specification asks
|
|
1652
|
+
* for this check, since without it any web page loaded in a browser that
|
|
1653
|
+
* can reach the broker could drive it.
|
|
1654
|
+
*
|
|
1655
|
+
* An array lists origins matched **exactly**. An object supplies a regular
|
|
1656
|
+
* expression tested against the whole `Origin` header. Also maps to
|
|
1657
|
+
* `MCP_BROKER_ALLOWED_ORIGINS` (comma-separated list form only; a pattern
|
|
1658
|
+
* needs the config file).
|
|
1659
|
+
*
|
|
1660
|
+
* @example
|
|
1661
|
+
* ```json
|
|
1662
|
+
* { "allowedOrigins": ["https://app.example.com", "http://localhost:5173"] }
|
|
1663
|
+
* { "allowedOrigins": { "pattern": "^https://[a-z0-9-]+\\.example\\.com$" } }
|
|
1664
|
+
* ```
|
|
1665
|
+
*/
|
|
1666
|
+
allowedOrigins?: string[] | {
|
|
1667
|
+
pattern: string;
|
|
1668
|
+
flags?: string;
|
|
1669
|
+
};
|
|
1670
|
+
/**
|
|
1671
|
+
* OAuth 2.1 resource-server authorization. When `enabled` is `true`, every
|
|
1672
|
+
* HTTP client request to a slot must carry a valid `Authorization: Bearer`
|
|
1673
|
+
* token issued for that slot, and the broker publishes Protected Resource
|
|
1674
|
+
* Metadata (RFC 9728). Absent/`false` ⇒ no authentication (trusted-network
|
|
1675
|
+
* mode, the historical behavior).
|
|
1676
|
+
*
|
|
1677
|
+
* Scalars also map to env vars (which win): `MCP_BROKER_AUTH_ENABLED`,
|
|
1678
|
+
* `MCP_BROKER_PUBLIC_BASE_URL`, `MCP_BROKER_JWKS`, `MCP_BROKER_ISSUER`.
|
|
1679
|
+
*/
|
|
1680
|
+
auth?: IBrokerAuthConfig;
|
|
1681
|
+
/** URL paths (override the defaults). */
|
|
1682
|
+
paths?: {
|
|
1683
|
+
provider?: string;
|
|
1684
|
+
providers?: string;
|
|
1685
|
+
client?: string;
|
|
1686
|
+
mcp?: string;
|
|
1687
|
+
sse?: string;
|
|
1688
|
+
messages?: string;
|
|
1689
|
+
};
|
|
1690
|
+
/** TLS material as paths on disk. Resolved against the config file's directory. */
|
|
1691
|
+
tls?: {
|
|
1692
|
+
cert: string;
|
|
1693
|
+
key: string;
|
|
1694
|
+
};
|
|
1695
|
+
/**
|
|
1696
|
+
* Static-file serving alongside the JSON-RPC endpoints. JSON-RPC routes
|
|
1697
|
+
* always take precedence.
|
|
1698
|
+
*/
|
|
1699
|
+
www?: {
|
|
1700
|
+
/** Auto-launch the default browser at the root URL on startup. */
|
|
1701
|
+
open?: boolean;
|
|
1702
|
+
/** URL-prefix → directory mappings. Longest-prefix match wins. */
|
|
1703
|
+
mounts?: Array<{
|
|
1704
|
+
urlPrefix: string;
|
|
1705
|
+
dir: string;
|
|
1706
|
+
}>;
|
|
1707
|
+
};
|
|
1708
|
+
/** Stdio upstream providers spawned by the broker at startup. */
|
|
1709
|
+
stdioUpstreams?: Array<{
|
|
1710
|
+
name: string;
|
|
1711
|
+
command: string;
|
|
1712
|
+
args?: string[];
|
|
1713
|
+
env?: Record<string, string>;
|
|
1714
|
+
/** When `true`, the upstream joins the `_all` aggregate slot once connected. */
|
|
1715
|
+
aggregate?: boolean;
|
|
1716
|
+
}>;
|
|
1717
|
+
/**
|
|
1718
|
+
* Remote MCP servers the broker connects out to and exposes as provider
|
|
1719
|
+
* slots. Each entry is reached by URL (Streamable HTTP / SSE / WebSocket);
|
|
1720
|
+
* local servers should be shipped as `.mcpb` bundles instead.
|
|
1721
|
+
*/
|
|
1722
|
+
mcpServers?: Array<{
|
|
1723
|
+
name: string;
|
|
1724
|
+
url: string;
|
|
1725
|
+
transport?: "streamable-http" | "sse" | "websocket";
|
|
1726
|
+
headers?: Record<string, string>;
|
|
1727
|
+
/** Defaults to `true`; set to `false` to exclude this upstream from the `_all` aggregate slot. */
|
|
1728
|
+
aggregate?: boolean;
|
|
1729
|
+
}>;
|
|
1730
|
+
/**
|
|
1731
|
+
* Local `.mcpb` bundles the broker loads at startup and runs as stdio
|
|
1732
|
+
* provider slots. A bundle is a ZIP with a `manifest.json`; the broker
|
|
1733
|
+
* verifies a detached signature against a trusted public key before
|
|
1734
|
+
* unpacking and spawning it.
|
|
1735
|
+
*/
|
|
1736
|
+
mcpbBundles?: Array<{
|
|
1737
|
+
/** Provider slot name the bundle is bound to. */
|
|
1738
|
+
name: string;
|
|
1739
|
+
/** Path to the `.mcpb` file (resolved against the config file's directory). */
|
|
1740
|
+
path: string;
|
|
1741
|
+
/** Path to the trusted public key (PEM) used to verify the detached signature. */
|
|
1742
|
+
publicKey: string;
|
|
1743
|
+
/** Path to the detached signature file. Defaults to `<path>.sig`. */
|
|
1744
|
+
signature?: string;
|
|
1745
|
+
/** Values substituted into the manifest's `${user_config.*}` placeholders. */
|
|
1746
|
+
userConfig?: Record<string, string | number | boolean | Array<string | number>>;
|
|
1747
|
+
/** Defaults to `true`; set to `false` to exclude this bundle from the `_all` aggregate slot. */
|
|
1748
|
+
aggregate?: boolean;
|
|
1749
|
+
}>;
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* Returned by {@link loadBrokerConfig}. The {@link config} is the parsed JSON;
|
|
1753
|
+
* {@link baseDir} is the directory used to resolve relative paths inside it
|
|
1754
|
+
* (the directory containing the config file when one was found, otherwise
|
|
1755
|
+
* `process.cwd()`).
|
|
1756
|
+
*/
|
|
1757
|
+
interface ILoadedBrokerConfig {
|
|
1758
|
+
config: IBrokerConfig;
|
|
1759
|
+
baseDir: string;
|
|
1760
|
+
/** Absolute path of the config file that was loaded, or `null` if none. */
|
|
1761
|
+
sourcePath: string | null;
|
|
1762
|
+
}
|
|
1763
|
+
/** Default config filename inside {@link DEFAULT_CONFIG_DIR}. */
|
|
1764
|
+
declare const DEFAULT_CONFIG_FILENAME = "config.json";
|
|
1765
|
+
/**
|
|
1766
|
+
* Loads the broker config from a JSON file.
|
|
1767
|
+
*
|
|
1768
|
+
* Discovery order:
|
|
1769
|
+
* 1. The `path` argument when provided (explicit override).
|
|
1770
|
+
* 2. The `MCP_BROKER_CONFIG` env var.
|
|
1771
|
+
* 3. `./.mcp-broker/config.json` relative to `process.cwd()`.
|
|
1772
|
+
* 4. `./mcp-broker.config.json` relative to `process.cwd()` (legacy layout ,
|
|
1773
|
+
* a deprecation warning is written to stderr).
|
|
1774
|
+
*
|
|
1775
|
+
* When no file is found, returns the built-in empty config with
|
|
1776
|
+
* `baseDir = process.cwd()`. On invalid JSON, logs a warning to stderr and
|
|
1777
|
+
* returns the same empty config, never throws.
|
|
1778
|
+
*
|
|
1779
|
+
* Paths inside the config file are intended to be resolved against
|
|
1780
|
+
* {@link ILoadedBrokerConfig.baseDir} by the consumer.
|
|
1781
|
+
*/
|
|
1782
|
+
declare function loadBrokerConfig(path?: string): ILoadedBrokerConfig;
|
|
1783
|
+
/** @deprecated Use {@link IBrokerAuthConfig}. */
|
|
1784
|
+
type BrokerAuthConfig = IBrokerAuthConfig;
|
|
1785
|
+
/** @deprecated Use {@link IBrokerConfig}. */
|
|
1786
|
+
type BrokerConfig = IBrokerConfig;
|
|
1787
|
+
/** @deprecated Use {@link ILoadedBrokerConfig}. */
|
|
1788
|
+
type LoadedBrokerConfig = ILoadedBrokerConfig;
|
|
1789
|
+
|
|
1790
|
+
export { type AccessTokenClaims, type AggregateScopeFilter, type AllowedOrigins, type AuditContext, AuthError, type AuthErrorCode, type AuthorizationAuditConfig, type AuthorizationAuditEvent, type AuthorizationDecision, type AuthorizationDecisionReason, type AuthorizationPolicyConfig, type AuthorizationRequest, type AuthorizationSubject, BROKER_PROVIDER_NAME, type BrokerAuthConfig, type BrokerConfig, type BrokerContext, type BrokerGrammarEntry, BrokerInfoBehavior, type BrokerLocale, type BrokerProviderInfo, type BrokerProviderTransport, BrokerProvidersBehavior, type BrokerUserAgent, type CapabilityClassifier, type ClassifiedCapability, ConfigPolicyEngine, ConfiguredCapabilityClassifier, DEFAULT_CONFIG_FILENAME, DefaultSlotResourceResolver, type DenyPolicy, HttpAuthGuard, type IAuditContext, type IAuthorizationAuditConfig, type IAuthorizationAuditEvent, type IAuthorizationDecision, type IAuthorizationPolicyConfig, type IAuthorizationRequest, type IAuthorizationSubject, type IBrokerAuthConfig, type IBrokerConfig, type IBrokerContext, type IBrokerGrammarEntry, type IBrokerProviderInfo, type ICapabilityClassifier, type IClassifiedCapability, type IDenyPolicy, type IInternalClient, type IJwtAuthOptions, type IJwtValidatorOptions, type ILoadedBrokerConfig, type IMcpOperation, type IMcpbBundleConfig, type IPolicyAssignment, type IPolicyAuthorization, type IPolicyEngine, type IPrincipal, type IProviderAuthenticator, type IProviderPrincipal, type IRemoteUpstreamConfig, type IResolvedAuth, type IRoleDefinition, type ISlotResourceResolver, type IStartBrokerServerOptions, type IStaticMount, type IStdioUpstreamConfig, type ISubjectMapper, type ISubjectMappingConfig, type IUpstream, type IWsTunnelOptions, type InternalClient, type JwtAuthOptions, JwtSubjectMapper, JwtTokenValidator, type JwtValidatorOptions, type LoadedBrokerConfig, type McpOperation, type McpbBundleConfig, PACKAGE_NAME, type PolicyAssignment, type PolicyAuthorization, type PolicyEngine, type Principal, type ProtectedResourceMetadata, type ProviderAuthenticationResult, type ProviderAuthenticator, type ProviderAuthenticatorReturn, type ProviderPrincipal, RemoteUpstream, type RemoteUpstreamConfig, type ResolvedAuth, ResourcePath, ResourcePathPattern, type RoleDefinition, SharedSecretProviderAuthenticator, type SlotResourceResolver, type StartBrokerServerOptions, type StaticMount, StdioUpstream, type StdioUpstreamConfig, type SubjectMapper, type SubjectMappingConfig, SubjectMappingError, type TokenValidator, type Upstream, VERSION, WsTunnel, WsTunnelBuilder, type WsTunnelOptions, authorizationWithEngine, brokerGrammarKey, buildJwtAuth, buildResourceMetadata, compileAuthorizationPolicy, hasAuthorizationPolicies, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerConfig, loadBrokerGrammar, loadMcpbBundle, normalizeProviderAuthentication, providerMayPublish, scopesOf, startBrokerServer, unzipMcpb, validateCapability };
|