@cyanmycelium/mcp-broker 1.0.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp-broker.example/README.md +3 -3
- package/README.md +6 -2
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +224 -253
- 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 -22
- package/dist/index.js +2 -18
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
- 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 +3 -3
- package/src/auth/auth.types.ts +34 -59
- package/src/auth/http.auth.ts +18 -22
- package/src/auth/index.ts +12 -12
- package/src/auth/jwt.validator.ts +3 -3
- package/src/auth/provider.auth.ts +1 -1
- package/src/auth/resource.metadata.ts +14 -21
- package/src/authorization/audit.ts +2 -2
- package/src/authorization/capability.classifier.ts +1 -1
- package/src/authorization/index.ts +13 -13
- package/src/authorization/policy.engine.ts +3 -3
- package/src/authorization/policy.types.ts +1 -1
- package/src/authorization/runtime.ts +5 -5
- package/src/authorization/slot.resource.ts +1 -1
- package/src/authorization/subject.mapper.ts +1 -1
- package/src/bin.ts +86 -8
- package/src/broker/adapters/broker.adapter.info.ts +1 -1
- package/src/broker/adapters/broker.adapter.providers.ts +1 -1
- package/src/broker/aggregate/aggregate.catalog.ts +1 -1
- package/src/broker/aggregate/aggregate.server.ts +7 -7
- package/src/broker/aggregate/provider.client.session.ts +2 -2
- package/src/broker/behaviors/broker.behavior.info.ts +3 -3
- package/src/broker/behaviors/broker.behavior.providers.ts +5 -5
- package/src/broker/broker.grammars.ts +9 -9
- package/src/broker/broker.server.ts +6 -6
- 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 +25 -3
- package/src/index.ts +24 -24
- package/src/{mcpb.loader.ts → mcpb/mcpb.loader.ts} +11 -11
- package/src/{mcpb.unzip.ts → mcpb/mcpb.unzip.ts} +2 -2
- package/src/remote.transports.ts +3 -3
- package/src/remote.upstream.ts +3 -3
- package/src/stdio.upstream.ts +2 -2
- package/src/upstream.ts +2 -2
- package/src/ws/ws.interfaces.ts +357 -0
- package/src/{ws.tunnel.builder.ts → ws/ws.tunnel.builder.ts} +28 -5
- package/src/{ws.tunnel.ts → ws/ws.tunnel.ts} +231 -467
- package/web/README.md +3 -3
- package/web/broker-self-mcp.html +9 -9
- package/web/css/styles.css +1 -1
- package/web/demos/DemoPlaceholder.html +6 -6
- package/web/demos/broker-explorer/css/app.css +1 -1
- package/web/demos/broker-explorer/index.html +2 -2
- package/web/demos/broker-explorer/js/app.js +4 -4
- package/web/demos/broker-explorer/js/mcp-ws-client.js +2 -2
- package/web/demos/oauth-lab/README.md +26 -0
- package/web/demos/oauth-lab/config.json +1 -0
- package/web/demos/oauth-lab/js/app.js +40 -16
- package/web/demos/oauth-lab/server/smoke-test.mjs +57 -10
- package/web/demos/provider-tunnel/css/app.css +1 -1
- package/web/demos/provider-tunnel/index.html +3 -3
- package/web/demos/provider-tunnel/js/app.js +10 -10
- package/web/demos/provider-tunnel/js/toolbox-server.js +5 -5
- package/web/index.html +11 -11
- package/web/js/lib/broker-tunnel.js +12 -12
- package/dist/auth/auth.config.d.ts +0 -40
- package/dist/auth/auth.config.js +0 -62
- package/dist/auth/auth.config.js.map +0 -1
- package/dist/auth/auth.types.d.ts +0 -119
- package/dist/auth/auth.types.js +0 -38
- package/dist/auth/auth.types.js.map +0 -1
- package/dist/auth/http.auth.d.ts +0 -51
- package/dist/auth/http.auth.js +0 -121
- package/dist/auth/http.auth.js.map +0 -1
- package/dist/auth/index.d.ts +0 -16
- package/dist/auth/index.js +0 -12
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/jwt.validator.d.ts +0 -35
- package/dist/auth/jwt.validator.js +0 -46
- package/dist/auth/jwt.validator.js.map +0 -1
- package/dist/auth/provider.auth.d.ts +0 -51
- package/dist/auth/provider.auth.js +0 -80
- package/dist/auth/provider.auth.js.map +0 -1
- package/dist/auth/resource.metadata.d.ts +0 -32
- package/dist/auth/resource.metadata.js +0 -26
- package/dist/auth/resource.metadata.js.map +0 -1
- package/dist/authorization/audit.d.ts +0 -14
- package/dist/authorization/audit.js +0 -20
- package/dist/authorization/audit.js.map +0 -1
- package/dist/authorization/capability.classifier.d.ts +0 -30
- package/dist/authorization/capability.classifier.js +0 -85
- package/dist/authorization/capability.classifier.js.map +0 -1
- package/dist/authorization/index.d.ts +0 -13
- package/dist/authorization/index.js +0 -8
- package/dist/authorization/index.js.map +0 -1
- package/dist/authorization/policy.engine.d.ts +0 -11
- package/dist/authorization/policy.engine.js +0 -192
- package/dist/authorization/policy.engine.js.map +0 -1
- package/dist/authorization/policy.types.d.ts +0 -92
- package/dist/authorization/policy.types.js +0 -2
- package/dist/authorization/policy.types.js.map +0 -1
- package/dist/authorization/resource.path.d.ts +0 -27
- package/dist/authorization/resource.path.js +0 -122
- package/dist/authorization/resource.path.js.map +0 -1
- package/dist/authorization/runtime.d.ts +0 -22
- package/dist/authorization/runtime.js +0 -34
- package/dist/authorization/runtime.js.map +0 -1
- package/dist/authorization/slot.resource.d.ts +0 -12
- package/dist/authorization/slot.resource.js +0 -41
- package/dist/authorization/slot.resource.js.map +0 -1
- package/dist/authorization/subject.mapper.d.ts +0 -15
- package/dist/authorization/subject.mapper.js +0 -67
- package/dist/authorization/subject.mapper.js.map +0 -1
- 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 -66
- package/dist/broker/aggregate/aggregate.catalog.js +0 -119
- package/dist/broker/aggregate/aggregate.catalog.js.map +0 -1
- package/dist/broker/aggregate/aggregate.server.d.ts +0 -66
- package/dist/broker/aggregate/aggregate.server.js +0 -257
- 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 -63
- 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 -132
- 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 -68
- 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 -182
- package/dist/config.js +0 -61
- package/dist/config.js.map +0 -1
- package/dist/mcpb.loader.d.ts +0 -26
- 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 -18
- package/dist/remote.transports.js +0 -297
- package/dist/remote.transports.js.map +0 -1
- package/dist/remote.upstream.d.ts +0 -38
- package/dist/remote.upstream.js +0 -52
- package/dist/remote.upstream.js.map +0 -1
- package/dist/stdio.upstream.d.ts +0 -47
- package/dist/stdio.upstream.js +0 -85
- package/dist/stdio.upstream.js.map +0 -1
- package/dist/upstream.d.ts +0 -35
- 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 -176
- package/dist/ws.tunnel.builder.js +0 -271
- package/dist/ws.tunnel.builder.js.map +0 -1
- package/dist/ws.tunnel.d.ts +0 -455
- package/dist/ws.tunnel.js +0 -1425
- 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
|
@@ -31,7 +31,7 @@ Property-by-property educational guides:
|
|
|
31
31
|
└── index.html
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
A ready-made instance UI lives at [`node/web/`](../web/)
|
|
34
|
+
A ready-made instance UI lives at [`node/web/`](../web/), point a `www`
|
|
35
35
|
mount at it (`"dir": "../web"`) to serve it. See [`node/web/README.md`](../web/README.md).
|
|
36
36
|
|
|
37
37
|
## Path resolution
|
|
@@ -41,14 +41,14 @@ config file** (i.e. `.mcp-broker/`). So `"certs/cert.pem"` in the config
|
|
|
41
41
|
points at `.mcp-broker/certs/cert.pem`. The folder is self-contained.
|
|
42
42
|
|
|
43
43
|
Env vars (`MCP_BROKER_TLS_CERT`, `MCP_BROKER_WWW_DIR`, ...) are still
|
|
44
|
-
resolved against `process.cwd()
|
|
44
|
+
resolved against `process.cwd()`: they are the deploy-time override
|
|
45
45
|
mechanism and not tied to the config file's location.
|
|
46
46
|
|
|
47
47
|
## `.mcpb` bundles
|
|
48
48
|
|
|
49
49
|
`mcpbBundles` entries load local `.mcpb` bundles as stdio provider slots.
|
|
50
50
|
Each bundle is verified against a **detached signature** before it is
|
|
51
|
-
unpacked and run
|
|
51
|
+
unpacked and run: the broker never spawns an unverified bundle.
|
|
52
52
|
|
|
53
53
|
1. Generate a signing key pair (once):
|
|
54
54
|
`node ../scripts/sign-bundle.mjs keygen bundles`
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ The broker starts on `http://localhost:3000` by default.
|
|
|
32
32
|
|
|
33
33
|
Two sources, env vars **always win** over the file. The file is the static baseline you ship with the broker; env vars are deploy-specific overrides.
|
|
34
34
|
|
|
35
|
-
### Option A
|
|
35
|
+
### Option A: `.mcp-broker/` folder (recommended)
|
|
36
36
|
|
|
37
37
|
Drop a `.mcp-broker/` folder next to where you launch the broker. Paths
|
|
38
38
|
inside `config.json` are resolved against this folder, so it stays
|
|
@@ -79,7 +79,7 @@ cp -r node_modules/@cyanmycelium/mcp-broker/.mcp-broker.example .mcp-broker
|
|
|
79
79
|
|
|
80
80
|
Full reference (every field, defaults, recipes, grammar overrides): **[docs/config.md](docs/config.md)**.
|
|
81
81
|
|
|
82
|
-
### Option B
|
|
82
|
+
### Option B: Environment variables
|
|
83
83
|
|
|
84
84
|
| Variable | Default | Notes |
|
|
85
85
|
|---|---|---|
|
|
@@ -111,6 +111,10 @@ providers, and filter the `_all` aggregate per caller.
|
|
|
111
111
|
|
|
112
112
|
Enabled via the `auth` config block (or env vars). Minimal `.mcp-broker/config.json`:
|
|
113
113
|
|
|
114
|
+
The resource paths below use a compact ISA-95 / IEC 62264-aligned industrial
|
|
115
|
+
profile. The engine remains domain-neutral, does not claim full ISA-95
|
|
116
|
+
compliance, and can map UMD-style namespaces through `slotResources`.
|
|
117
|
+
|
|
114
118
|
```json
|
|
115
119
|
{
|
|
116
120
|
"auth": {
|
package/dist/bin.d.ts
CHANGED
package/dist/bin.js
CHANGED
|
@@ -1,77 +1,63 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
import { loadMcpbBundle } from "./mcpb.loader.js";
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
// Configuration
|
|
60
|
-
// ---------------------------------------------------------------------------
|
|
61
|
-
const { config, baseDir } = loadBrokerConfig();
|
|
62
|
-
const cwd = process.cwd();
|
|
63
|
-
/**
|
|
64
|
-
* Fills an env var from the config file when the env var is not already set.
|
|
65
|
-
* Used for **non-path** scalars — path-bearing fields are read directly so
|
|
66
|
-
* they can be resolved against `baseDir` (config file's directory) instead
|
|
67
|
-
* of `cwd` (deploy environment).
|
|
68
|
-
*/
|
|
2
|
+
import { PACKAGE_NAME, VERSION, loadBrokerConfig, WsTunnelBuilder, loadMcpbBundle } from './chunk-FTDKH2C4.js';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import open from 'open';
|
|
6
|
+
|
|
7
|
+
var argv = process.argv.slice(2);
|
|
8
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
9
|
+
printHelp();
|
|
10
|
+
process.exit(0);
|
|
11
|
+
}
|
|
12
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
13
|
+
process.stdout.write(`${PACKAGE_NAME} ${VERSION}
|
|
14
|
+
`);
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
function printHelp() {
|
|
18
|
+
process.stdout.write(
|
|
19
|
+
`
|
|
20
|
+
${PACKAGE_NAME} ${VERSION}
|
|
21
|
+
WebSocket-based Model Context Protocol broker.
|
|
22
|
+
|
|
23
|
+
USAGE
|
|
24
|
+
npx @cyanmycelium/mcp-broker Start the broker (foreground)
|
|
25
|
+
npx @cyanmycelium/mcp-broker --help Show this help
|
|
26
|
+
npx @cyanmycelium/mcp-broker --version Print the version
|
|
27
|
+
|
|
28
|
+
The broker takes no positional arguments. Configure it with a
|
|
29
|
+
.mcp-broker/config.json file or MCP_BROKER_* environment variables
|
|
30
|
+
(env vars win over the file).
|
|
31
|
+
|
|
32
|
+
COMMON ENVIRONMENT VARIABLES
|
|
33
|
+
MCP_BROKER_CONFIG Path to a JSON config file
|
|
34
|
+
MCP_BROKER_PORT TCP port (default 3000)
|
|
35
|
+
MCP_BROKER_HOST Bind interface (default 0.0.0.0)
|
|
36
|
+
MCP_BROKER_PROTOCOL "http" | "https" (default: auto from TLS)
|
|
37
|
+
MCP_BROKER_TLS_CERT PEM certificate path (enables HTTPS/WSS)
|
|
38
|
+
MCP_BROKER_TLS_KEY PEM private key path
|
|
39
|
+
MCP_BROKER_STDIO_PROVIDER Bridge stdin/stdout to this provider (Claude Desktop)
|
|
40
|
+
MCP_BROKER_LOCALE Locale for _broker tool descriptions (default en)
|
|
41
|
+
MCP_BROKER_ALLOWED_ORIGINS Comma-separated browser origins allowed on /<slot>/mcp
|
|
42
|
+
|
|
43
|
+
AUTHORIZATION (OAuth 2.1, opt-in)
|
|
44
|
+
MCP_BROKER_AUTH_ENABLED "1" to require bearer tokens on client endpoints
|
|
45
|
+
MCP_BROKER_PUBLIC_BASE_URL Public origin, e.g. https://mcp.example.com
|
|
46
|
+
MCP_BROKER_JWKS Authorization server JWKS URL
|
|
47
|
+
MCP_BROKER_ISSUER Expected token issuer
|
|
48
|
+
MCP_BROKER_PROVIDER_SECRET Shared secret required from providers
|
|
49
|
+
|
|
50
|
+
Full reference: https://github.com/pandaGaume/mcp-broker/tree/main/node
|
|
51
|
+
|
|
52
|
+
`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
var { config, baseDir } = loadBrokerConfig();
|
|
56
|
+
var cwd = process.cwd();
|
|
69
57
|
function envFromConfig(envName, configValue) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return;
|
|
74
|
-
process.env[envName] = String(configValue);
|
|
58
|
+
if (configValue === void 0 || configValue === null) return;
|
|
59
|
+
if (process.env[envName] !== void 0 && process.env[envName] !== "") return;
|
|
60
|
+
process.env[envName] = String(configValue);
|
|
75
61
|
}
|
|
76
62
|
envFromConfig("MCP_BROKER_PORT", config.port);
|
|
77
63
|
envFromConfig("MCP_BROKER_HOST", config.host);
|
|
@@ -81,204 +67,189 @@ envFromConfig("MCP_BROKER_STDIO_PROVIDER", config.stdioProvider);
|
|
|
81
67
|
envFromConfig("MCP_BROKER_PROVIDER_PATH", config.paths?.provider);
|
|
82
68
|
envFromConfig("MCP_BROKER_CLIENT_PATH", config.paths?.client);
|
|
83
69
|
envFromConfig("MCP_BROKER_MCP_PATH", config.paths?.mcp);
|
|
84
|
-
envFromConfig("MCP_BROKER_OPEN", config.www?.open === true ? "1" :
|
|
85
|
-
envFromConfig("MCP_BROKER_AUTH_ENABLED", config.auth?.enabled === true ? "1" :
|
|
70
|
+
envFromConfig("MCP_BROKER_OPEN", config.www?.open === true ? "1" : void 0);
|
|
71
|
+
envFromConfig("MCP_BROKER_AUTH_ENABLED", config.auth?.enabled === true ? "1" : void 0);
|
|
86
72
|
envFromConfig("MCP_BROKER_PUBLIC_BASE_URL", config.auth?.publicBaseUrl);
|
|
87
73
|
envFromConfig("MCP_BROKER_JWKS", config.auth?.jwks);
|
|
88
74
|
envFromConfig("MCP_BROKER_ISSUER", config.auth?.issuer);
|
|
89
75
|
envFromConfig("MCP_BROKER_PROVIDER_SECRET", config.auth?.providerSecret);
|
|
90
|
-
|
|
91
|
-
// In stdio mode stdout is reserved for JSON-RPC — redirect all console output to stderr.
|
|
76
|
+
var stdioProvider = process.env["MCP_BROKER_STDIO_PROVIDER"];
|
|
92
77
|
if (stdioProvider) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
78
|
+
const toStderr = (...args) => process.stderr.write(args.join(" ") + "\n");
|
|
79
|
+
console.log = toStderr;
|
|
80
|
+
console.info = toStderr;
|
|
81
|
+
console.warn = toStderr;
|
|
82
|
+
console.error = toStderr;
|
|
98
83
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
console.error(`[mcp-broker] Invalid MCP_BROKER_PROTOCOL="${protocolOverride}". Use "http" or "https".`);
|
|
112
|
-
process.exit(1);
|
|
84
|
+
var port = parseInt(process.env["MCP_BROKER_PORT"] ?? "3000", 10);
|
|
85
|
+
var host = process.env["MCP_BROKER_HOST"];
|
|
86
|
+
var providerPath = process.env["MCP_BROKER_PROVIDER_PATH"] ?? "/provider";
|
|
87
|
+
var clientPath = process.env["MCP_BROKER_CLIENT_PATH"] ?? "/";
|
|
88
|
+
var mcpPath = process.env["MCP_BROKER_MCP_PATH"] ?? "/mcp";
|
|
89
|
+
var ssePath = config.paths?.sse ?? "/sse";
|
|
90
|
+
var tlsCertPath = process.env["MCP_BROKER_TLS_CERT"] ? path.resolve(cwd, process.env["MCP_BROKER_TLS_CERT"]) : config.tls?.cert ? path.resolve(baseDir, config.tls.cert) : null;
|
|
91
|
+
var tlsKeyPath = process.env["MCP_BROKER_TLS_KEY"] ? path.resolve(cwd, process.env["MCP_BROKER_TLS_KEY"]) : config.tls?.key ? path.resolve(baseDir, config.tls.key) : null;
|
|
92
|
+
var protocolOverride = process.env["MCP_BROKER_PROTOCOL"]?.toLowerCase();
|
|
93
|
+
if (protocolOverride !== void 0 && protocolOverride !== "http" && protocolOverride !== "https") {
|
|
94
|
+
console.error(`[mcp-broker] Invalid MCP_BROKER_PROTOCOL="${protocolOverride}". Use "http" or "https".`);
|
|
95
|
+
process.exit(1);
|
|
113
96
|
}
|
|
114
97
|
if (protocolOverride === "https" && (!tlsCertPath || !tlsKeyPath)) {
|
|
115
|
-
|
|
116
|
-
|
|
98
|
+
console.error("[mcp-broker] MCP_BROKER_PROTOCOL=https requires TLS cert+key (via config.tls or MCP_BROKER_TLS_CERT/KEY).");
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
var useTls = protocolOverride === "http" ? false : protocolOverride === "https" ? true : !!(tlsCertPath && tlsKeyPath);
|
|
102
|
+
var envOrigins = process.env["MCP_BROKER_ALLOWED_ORIGINS"]?.split(",").map((origin) => origin.trim()).filter(Boolean);
|
|
103
|
+
var allowedOrigins;
|
|
104
|
+
if (envOrigins?.length) {
|
|
105
|
+
allowedOrigins = envOrigins;
|
|
106
|
+
} else if (Array.isArray(config.allowedOrigins)) {
|
|
107
|
+
allowedOrigins = config.allowedOrigins;
|
|
108
|
+
} else if (config.allowedOrigins) {
|
|
109
|
+
try {
|
|
110
|
+
allowedOrigins = new RegExp(config.allowedOrigins.pattern, config.allowedOrigins.flags);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error(`[mcp-broker] Ignoring allowedOrigins.pattern: ${err.message}`);
|
|
113
|
+
}
|
|
117
114
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const envWwwDir = process.env["MCP_BROKER_WWW_DIR"] ? path.resolve(cwd, process.env["MCP_BROKER_WWW_DIR"]) : null;
|
|
121
|
-
const envBundleDir = process.env["MCP_BROKER_BUNDLE_DIR"] ? path.resolve(cwd, process.env["MCP_BROKER_BUNDLE_DIR"]) : null;
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
|
-
// Server bootstrap
|
|
124
|
-
// ---------------------------------------------------------------------------
|
|
115
|
+
var envWwwDir = process.env["MCP_BROKER_WWW_DIR"] ? path.resolve(cwd, process.env["MCP_BROKER_WWW_DIR"]) : null;
|
|
116
|
+
var envBundleDir = process.env["MCP_BROKER_BUNDLE_DIR"] ? path.resolve(cwd, process.env["MCP_BROKER_BUNDLE_DIR"]) : null;
|
|
125
117
|
async function main() {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
118
|
+
const localGrammarsDir = path.join(baseDir, "grammars");
|
|
119
|
+
const hasLocalGrammars = fs.existsSync(localGrammarsDir);
|
|
120
|
+
const builder = new WsTunnelBuilder().withPort(port).withProviderPath(providerPath).withClientPath(clientPath).withMcpPath(mcpPath);
|
|
121
|
+
if (host) {
|
|
122
|
+
builder.withHost(host);
|
|
123
|
+
}
|
|
124
|
+
if (useTls) {
|
|
125
|
+
builder.withTlsFiles(tlsCertPath, tlsKeyPath);
|
|
126
|
+
}
|
|
127
|
+
if (allowedOrigins) {
|
|
128
|
+
builder.withAllowedOrigins(allowedOrigins);
|
|
129
|
+
}
|
|
130
|
+
if (envBundleDir && fs.existsSync(envBundleDir)) {
|
|
131
|
+
builder.withStaticMount("/bundle", envBundleDir);
|
|
132
|
+
}
|
|
133
|
+
if (envWwwDir && fs.existsSync(envWwwDir)) {
|
|
134
|
+
builder.withStaticMount("/", envWwwDir);
|
|
135
|
+
}
|
|
136
|
+
if (config.www?.mounts) {
|
|
137
|
+
for (const mount of config.www.mounts) {
|
|
138
|
+
const abs = path.resolve(baseDir, mount.dir);
|
|
139
|
+
if (fs.existsSync(abs)) {
|
|
140
|
+
builder.withStaticMount(mount.urlPrefix, abs);
|
|
141
|
+
} else {
|
|
142
|
+
console.warn(`[mcp-broker] www.mounts entry "${mount.urlPrefix}" \u2192 ${abs} skipped (directory not found).`);
|
|
143
|
+
}
|
|
147
144
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
145
|
+
}
|
|
146
|
+
if (config.stdioUpstreams) {
|
|
147
|
+
for (const u of config.stdioUpstreams) {
|
|
148
|
+
builder.withStdioUpstream({
|
|
149
|
+
name: u.name,
|
|
150
|
+
command: u.command,
|
|
151
|
+
args: u.args,
|
|
152
|
+
env: u.env,
|
|
153
|
+
aggregate: u.aggregate
|
|
154
|
+
});
|
|
158
155
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
name: u.name,
|
|
164
|
-
command: u.command,
|
|
165
|
-
args: u.args,
|
|
166
|
-
env: u.env,
|
|
167
|
-
aggregate: u.aggregate,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
156
|
+
}
|
|
157
|
+
if (config.mcpServers) {
|
|
158
|
+
for (const s of config.mcpServers) {
|
|
159
|
+
builder.withRemoteUpstream({ ...s, aggregate: s.aggregate ?? true });
|
|
170
160
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
161
|
+
}
|
|
162
|
+
if (config.mcpbBundles) {
|
|
163
|
+
for (const b of config.mcpbBundles) {
|
|
164
|
+
const upstream = await loadMcpbBundle(b, baseDir);
|
|
165
|
+
if (upstream) {
|
|
166
|
+
builder.withStdioUpstream(upstream);
|
|
167
|
+
}
|
|
178
168
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
169
|
+
}
|
|
170
|
+
if (stdioProvider) {
|
|
171
|
+
builder.withStdioClient(stdioProvider);
|
|
172
|
+
}
|
|
173
|
+
if (hasLocalGrammars) {
|
|
174
|
+
builder.withBrokerLocalGrammarsDir(localGrammarsDir);
|
|
175
|
+
}
|
|
176
|
+
const authEnabledEnv = process.env["MCP_BROKER_AUTH_ENABLED"];
|
|
177
|
+
const authEnabled = authEnabledEnv === "1" || authEnabledEnv === "true";
|
|
178
|
+
if (authEnabled) {
|
|
179
|
+
const publicBaseUrl = process.env["MCP_BROKER_PUBLIC_BASE_URL"];
|
|
180
|
+
const jwks = process.env["MCP_BROKER_JWKS"];
|
|
181
|
+
const issuer = process.env["MCP_BROKER_ISSUER"];
|
|
182
|
+
const authorizationServers = config.auth?.authorizationServers ?? (issuer ? [issuer] : []);
|
|
183
|
+
if (!publicBaseUrl || !jwks || authorizationServers.length === 0) {
|
|
184
|
+
console.error(
|
|
185
|
+
"[mcp-broker] auth.enabled requires publicBaseUrl, jwks, and at least one authorizationServers entry (or issuer). Set them via config.auth or MCP_BROKER_PUBLIC_BASE_URL / MCP_BROKER_JWKS / MCP_BROKER_ISSUER."
|
|
186
|
+
);
|
|
187
|
+
process.exit(1);
|
|
190
188
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
await tunnel.start();
|
|
241
|
-
// ── Startup banner ──────────────────────────────────────────────────────
|
|
242
|
-
const httpScheme = useTls ? "https" : "http";
|
|
243
|
-
const wsScheme = useTls ? "wss" : "ws";
|
|
244
|
-
const hr = "─".repeat(64);
|
|
245
|
-
const localhost = `${httpScheme}://localhost:${port}`;
|
|
246
|
-
const mcpSuffix = mcpPath.replace(/^\//, "");
|
|
247
|
-
const sseSuffix = ssePath.replace(/^\//, "");
|
|
248
|
-
const hasWwwRoot = !!(envWwwDir && fs.existsSync(envWwwDir)) || (config.www?.mounts ?? []).some((m) => m.urlPrefix === "/");
|
|
189
|
+
builder.withJwtAuth({
|
|
190
|
+
publicBaseUrl,
|
|
191
|
+
authorizationServers,
|
|
192
|
+
jwksUri: jwks,
|
|
193
|
+
issuer,
|
|
194
|
+
scopesSupported: config.auth?.scopesSupported,
|
|
195
|
+
requiredScopes: config.auth?.requiredScopes,
|
|
196
|
+
perSlotScopes: config.auth?.perSlotScopes,
|
|
197
|
+
providerScopes: config.auth?.providerScopes,
|
|
198
|
+
subjectMapping: config.auth?.subjectMapping,
|
|
199
|
+
roles: config.auth?.roles,
|
|
200
|
+
assignments: config.auth?.assignments,
|
|
201
|
+
denies: config.auth?.denies,
|
|
202
|
+
slotResources: config.auth?.slotResources,
|
|
203
|
+
toolCapabilities: config.auth?.toolCapabilities,
|
|
204
|
+
providerToolCapabilities: config.auth?.providerToolCapabilities,
|
|
205
|
+
audit: config.auth?.audit
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const providerSecret = process.env["MCP_BROKER_PROVIDER_SECRET"];
|
|
209
|
+
if (providerSecret) {
|
|
210
|
+
builder.withProviderSecret(providerSecret);
|
|
211
|
+
}
|
|
212
|
+
const tunnel = builder.build();
|
|
213
|
+
await tunnel.start();
|
|
214
|
+
const httpScheme = useTls ? "https" : "http";
|
|
215
|
+
const wsScheme = useTls ? "wss" : "ws";
|
|
216
|
+
const hr = "\u2500".repeat(64);
|
|
217
|
+
const localhost = `${httpScheme}://localhost:${port}`;
|
|
218
|
+
const mcpSuffix = mcpPath.replace(/^\//, "");
|
|
219
|
+
const sseSuffix = ssePath.replace(/^\//, "");
|
|
220
|
+
const hasWwwRoot = !!(envWwwDir && fs.existsSync(envWwwDir)) || (config.www?.mounts ?? []).some((m) => m.urlPrefix === "/");
|
|
221
|
+
console.log();
|
|
222
|
+
console.log(`\u2699\uFE0F mcp-broker started${useTls ? " (TLS)" : ""}`);
|
|
223
|
+
console.log(hr);
|
|
224
|
+
console.log(`\u{1F4E1} Provider WebSocket ${wsScheme}://localhost:${port}${providerPath}/<name>`);
|
|
225
|
+
console.log(`\u{1F50C} MCP (Streamable HTTP) ${localhost}/<name>/${mcpSuffix}`);
|
|
226
|
+
console.log(`\u{1F4FA} Legacy SSE ${localhost}/<name>/${sseSuffix}`);
|
|
227
|
+
if (hasLocalGrammars) {
|
|
228
|
+
console.log(`\u{1F310} Local grammars ${localGrammarsDir}`);
|
|
229
|
+
}
|
|
230
|
+
console.log(`\u{1F510} Authorization ${authEnabled ? "OAuth 2.1 (Bearer required)" : "disabled (trusted network only)"}`);
|
|
231
|
+
console.log(`\u{1F6E1}\uFE0F Provider auth ${providerSecret ? "shared secret required" : "disabled"}`);
|
|
232
|
+
console.log(hr);
|
|
233
|
+
console.log(` Press Ctrl+C to stop.`);
|
|
234
|
+
console.log();
|
|
235
|
+
if (hasWwwRoot && process.env["MCP_BROKER_OPEN"] === "1") {
|
|
236
|
+
const url = `${localhost}/`;
|
|
237
|
+
console.log(`\u{1F680} Opening browser: ${url}`);
|
|
249
238
|
console.log();
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
console.log(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
console.log(hr);
|
|
261
|
-
console.log(` Press Ctrl+C to stop.`);
|
|
262
|
-
console.log();
|
|
263
|
-
// Auto-launch browser only if explicitly opted in via MCP_BROKER_OPEN=1
|
|
264
|
-
// AND a mount at "/" is configured.
|
|
265
|
-
if (hasWwwRoot && process.env["MCP_BROKER_OPEN"] === "1") {
|
|
266
|
-
const url = `${localhost}/`;
|
|
267
|
-
console.log(`🚀 Opening browser: ${url}`);
|
|
268
|
-
console.log();
|
|
269
|
-
await open(url);
|
|
270
|
-
}
|
|
271
|
-
// ── Signal handlers ─────────────────────────────────────────────────────
|
|
272
|
-
const shutdown = async (signal) => {
|
|
273
|
-
console.log(`\n⛔ ${signal} received — shutting down…`);
|
|
274
|
-
await tunnel.stop();
|
|
275
|
-
process.exit(0);
|
|
276
|
-
};
|
|
277
|
-
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
278
|
-
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
239
|
+
await open(url);
|
|
240
|
+
}
|
|
241
|
+
const shutdown = async (signal) => {
|
|
242
|
+
console.log(`
|
|
243
|
+
\u26D4 ${signal} received, shutting down\u2026`);
|
|
244
|
+
await tunnel.stop();
|
|
245
|
+
process.exit(0);
|
|
246
|
+
};
|
|
247
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
248
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
279
249
|
}
|
|
280
250
|
main().catch((err) => {
|
|
281
|
-
|
|
282
|
-
|
|
251
|
+
console.error("[mcp-broker] Fatal error:", err);
|
|
252
|
+
process.exit(1);
|
|
283
253
|
});
|
|
254
|
+
//# sourceMappingURL=bin.js.map
|
|
284
255
|
//# sourceMappingURL=bin.js.map
|