@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/web/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# `node/web/`: broker instance UI
|
|
2
|
+
|
|
3
|
+
Static web UI served by the broker. No build step: plain ES modules and CSS,
|
|
4
|
+
served as-is over the broker's static mount.
|
|
5
|
+
|
|
6
|
+
## Layout
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
web/
|
|
10
|
+
├── index.html ← launcher: shown when the broker starts
|
|
11
|
+
├── broker-self-mcp.html ← explainer: the _broker slot, _all aggregate, .mcpb bundles
|
|
12
|
+
├── css/
|
|
13
|
+
│ └── styles.css ← common stylesheet (shared by all pages)
|
|
14
|
+
├── js/
|
|
15
|
+
│ └── lib/
|
|
16
|
+
│ └── broker-tunnel.js ← common reusable lib (shared by demos)
|
|
17
|
+
├── assets/
|
|
18
|
+
│ └── logo.png
|
|
19
|
+
└── demos/
|
|
20
|
+
├── DemoPlaceholder.html ← stand-in for demos not bundled yet
|
|
21
|
+
├── provider-tunnel/ ← one self-contained folder per demo
|
|
22
|
+
│ ├── index.html
|
|
23
|
+
│ ├── css/
|
|
24
|
+
│ │ └── app.css
|
|
25
|
+
│ └── js/
|
|
26
|
+
│ ├── app.js
|
|
27
|
+
│ └── toolbox-server.js
|
|
28
|
+
├── broker-explorer/ ← MCP client connecting to a broker slot
|
|
29
|
+
│ ├── index.html
|
|
30
|
+
│ ├── css/
|
|
31
|
+
│ │ └── app.css
|
|
32
|
+
│ └── js/
|
|
33
|
+
│ ├── app.js
|
|
34
|
+
│ └── mcp-ws-client.js
|
|
35
|
+
└── oauth-lab/ <- OAuth 2.1 and policy demonstration
|
|
36
|
+
├── index.html
|
|
37
|
+
├── config.json
|
|
38
|
+
├── css/app.css
|
|
39
|
+
├── js/app.js
|
|
40
|
+
└── server/
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Conventions
|
|
44
|
+
|
|
45
|
+
- **`index.html`** is the launcher. The broker opens it on start (`www.open`).
|
|
46
|
+
It links the bundled demos and the broker's own endpoints.
|
|
47
|
+
- **`broker-self-mcp.html`** is a root-level explainer page (not a demo): the
|
|
48
|
+
`_broker` introspection slot, the `_all` aggregate, and loading signed
|
|
49
|
+
`.mcpb` bundles. Linked from the launcher's "Broker self-MCP" card.
|
|
50
|
+
- **`css/` and `js/` at the root hold only common, shared assets.**
|
|
51
|
+
`css/styles.css` is the sitewide stylesheet; `js/lib/broker-tunnel.js` is
|
|
52
|
+
the reusable, zero-dependency broker connection module.
|
|
53
|
+
- **Each demo lives in its own folder under `demos/`** with its own
|
|
54
|
+
`index.html`, `css/`, and `js/`. A demo may import shared code from the root
|
|
55
|
+
`js/` (e.g. `../../../js/lib/broker-tunnel.js`).
|
|
56
|
+
- **`demos/DemoPlaceholder.html`** is the stand-in linked from the launcher
|
|
57
|
+
for demos that are not packaged yet. It reads `?slot=<name>` to label itself.
|
|
58
|
+
|
|
59
|
+
## Bundled demos
|
|
60
|
+
|
|
61
|
+
- **`demos/provider-tunnel/`**, hosts an MCP server (official
|
|
62
|
+
`@modelcontextprotocol/sdk`) and tunnels it to the broker over a WebSocket.
|
|
63
|
+
Proves the broker is implementation-agnostic: a server built with the
|
|
64
|
+
reference SDK tunnels through unchanged. The only broker-specific code is
|
|
65
|
+
`js/lib/broker-tunnel.js`.
|
|
66
|
+
- **`demos/broker-explorer/`**: the client side: connects a browser MCP
|
|
67
|
+
client to a broker slot (`_broker`, `_all`, or any provider), lists its
|
|
68
|
+
tools and calls them live. The MCP-over-WebSocket client is isolated in
|
|
69
|
+
`js/mcp-ws-client.js`. Paired with the `broker-self-mcp.html` explainer.
|
|
70
|
+
- **`demos/oauth-lab/`** is a complete local OAuth 2.1 environment with
|
|
71
|
+
Authorization Code and PKCE, JWT and JWKS validation, audience-bound access
|
|
72
|
+
tokens, hierarchical roles, explicit denies, protected MCP calls, and a live
|
|
73
|
+
authorization audit. Run it with `npm run demo:oauth` from `node/`.
|
|
74
|
+
|
|
75
|
+
## Serving it
|
|
76
|
+
|
|
77
|
+
Point a `www` mount at this folder from a broker config:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"www": {
|
|
82
|
+
"open": true,
|
|
83
|
+
"mounts": [{ "urlPrefix": "/", "dir": "../web" }]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
(`../web` is resolved against the config file's directory, e.g. `.mcp-broker/`.)
|
|
89
|
+
|
|
90
|
+
Or with an environment variable, from the `node/` directory:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
MCP_BROKER_WWW_DIR=web npm start
|
|
94
|
+
```
|
|
Binary file
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Broker self-MCP · @cyanmycelium/mcp-broker</title>
|
|
7
|
+
<meta name="description" content="The broker is itself an MCP server: the _broker introspection slot, the _all aggregate, and loading signed .mcpb bundles." />
|
|
8
|
+
<link rel="icon" type="image/png" href="assets/logo.png" />
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap">
|
|
12
|
+
<link rel="stylesheet" href="css/styles.css" />
|
|
13
|
+
<style>
|
|
14
|
+
/* The hero here is an explainer header, a touch shorter than the docs hero. */
|
|
15
|
+
.hero { padding: 72px 0 56px; }
|
|
16
|
+
.hero-mark { margin-bottom: 20px; }
|
|
17
|
+
.hero-mark img { width: 72px; height: 72px; }
|
|
18
|
+
|
|
19
|
+
/* Endpoints, quick reference grid, shared look with the launcher page. */
|
|
20
|
+
.endpoints {
|
|
21
|
+
display: grid;
|
|
22
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
23
|
+
gap: 12px;
|
|
24
|
+
margin-top: 20px;
|
|
25
|
+
}
|
|
26
|
+
.endpoint {
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
gap: 6px;
|
|
30
|
+
padding: 14px 16px;
|
|
31
|
+
background: var(--bg-elev-1);
|
|
32
|
+
border: 1px solid var(--rule);
|
|
33
|
+
border-radius: 6px;
|
|
34
|
+
}
|
|
35
|
+
.endpoint .label {
|
|
36
|
+
font-family: var(--font-mono);
|
|
37
|
+
font-size: 10px;
|
|
38
|
+
letter-spacing: 0.16em;
|
|
39
|
+
color: var(--blue);
|
|
40
|
+
text-transform: uppercase;
|
|
41
|
+
}
|
|
42
|
+
.endpoint .url {
|
|
43
|
+
font-family: var(--font-mono);
|
|
44
|
+
font-size: 13px;
|
|
45
|
+
color: var(--fg);
|
|
46
|
+
word-break: break-all;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Tool list: the broker's three built-in introspection tools. */
|
|
50
|
+
.tools {
|
|
51
|
+
display: grid;
|
|
52
|
+
gap: 10px;
|
|
53
|
+
margin: 24px 0 8px;
|
|
54
|
+
}
|
|
55
|
+
.tool {
|
|
56
|
+
display: grid;
|
|
57
|
+
grid-template-columns: minmax(0, 220px) 1fr;
|
|
58
|
+
gap: 16px;
|
|
59
|
+
padding: 14px 16px;
|
|
60
|
+
background: var(--bg-elev-1);
|
|
61
|
+
border: 1px solid var(--rule);
|
|
62
|
+
border-radius: 6px;
|
|
63
|
+
align-items: baseline;
|
|
64
|
+
}
|
|
65
|
+
.tool .name {
|
|
66
|
+
font-family: var(--font-mono);
|
|
67
|
+
font-size: 13px;
|
|
68
|
+
color: var(--blue);
|
|
69
|
+
word-break: break-all;
|
|
70
|
+
}
|
|
71
|
+
.tool .desc { color: var(--fg-muted); font-size: 14px; line-height: 1.5; }
|
|
72
|
+
@media (max-width: 640px) {
|
|
73
|
+
.tool { grid-template-columns: 1fr; gap: 4px; }
|
|
74
|
+
}
|
|
75
|
+
</style>
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
|
|
79
|
+
<!-- ============================== TOPBAR ============================== -->
|
|
80
|
+
<header class="topbar">
|
|
81
|
+
<div class="shell topbar-inner">
|
|
82
|
+
<a class="brand" href="/">
|
|
83
|
+
<img class="brand-mark" src="assets/logo.png" alt="" aria-hidden="true" />
|
|
84
|
+
<span>@cyanmycelium/mcp-broker</span>
|
|
85
|
+
</a>
|
|
86
|
+
<nav class="topbar-links">
|
|
87
|
+
<a href="/">← Back to launcher</a>
|
|
88
|
+
<a href="#all">The _all slot</a>
|
|
89
|
+
<a href="#bundles">.mcpb bundles</a>
|
|
90
|
+
<a href="demos/broker-explorer/">Explorer demo</a>
|
|
91
|
+
<a href="https://github.com/pandaGaume/mcp-broker" target="_blank" rel="noopener">GitHub →</a>
|
|
92
|
+
</nav>
|
|
93
|
+
</div>
|
|
94
|
+
</header>
|
|
95
|
+
|
|
96
|
+
<main>
|
|
97
|
+
|
|
98
|
+
<!-- ================================ HERO =============================== -->
|
|
99
|
+
<section class="hero">
|
|
100
|
+
<div class="shell">
|
|
101
|
+
<div class="hero-mark"><img src="assets/logo.png" alt="" /></div>
|
|
102
|
+
|
|
103
|
+
<div class="eyebrow"><span class="dot"></span>broker · self-mcp</div>
|
|
104
|
+
|
|
105
|
+
<h1 class="hero-title">The broker is its own MCP server.</h1>
|
|
106
|
+
|
|
107
|
+
<p class="hero-sub">
|
|
108
|
+
Beyond tunnelling other servers, the broker exposes a reserved slot,
|
|
109
|
+
<code class="inline">_broker</code>, that answers MCP itself: and an
|
|
110
|
+
aggregate slot, <code class="inline">_all</code>, that unions every
|
|
111
|
+
connected provider into one server.
|
|
112
|
+
</p>
|
|
113
|
+
|
|
114
|
+
<div class="hero-cta">
|
|
115
|
+
<a class="btn btn-primary" href="demos/broker-explorer/">Open the explorer demo →</a>
|
|
116
|
+
<a class="btn btn-secondary" href="https://github.com/pandaGaume/mcp-broker/tree/main/docs" target="_blank" rel="noopener">Docs</a>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</section>
|
|
120
|
+
|
|
121
|
+
<!-- ============================ _broker SLOT =========================== -->
|
|
122
|
+
<section id="broker">
|
|
123
|
+
<div class="shell">
|
|
124
|
+
<div class="section-num">01 - The _broker slot</div>
|
|
125
|
+
<h2>Introspect the broker over MCP</h2>
|
|
126
|
+
|
|
127
|
+
<p class="intro">
|
|
128
|
+
The reserved <code class="inline">_broker</code> slot is an in-process MCP
|
|
129
|
+
server. Point any MCP client at it (MCP Inspector, Claude, your own) to
|
|
130
|
+
inspect the broker's identity and the providers currently tunnelled in.
|
|
131
|
+
</p>
|
|
132
|
+
|
|
133
|
+
<div class="tools">
|
|
134
|
+
<div class="tool">
|
|
135
|
+
<span class="name">broker_info</span>
|
|
136
|
+
<span class="desc">Reports the broker's identity, version and configuration.</span>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="tool">
|
|
139
|
+
<span class="name">providers_list</span>
|
|
140
|
+
<span class="desc">Lists the provider slots currently registered with the broker.</span>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="tool">
|
|
143
|
+
<span class="name">provider_status</span>
|
|
144
|
+
<span class="desc">Reports the connection status of a given provider slot.</span>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<p class="caption">Reachable on every client transport, see the endpoints below.</p>
|
|
149
|
+
</div>
|
|
150
|
+
</section>
|
|
151
|
+
|
|
152
|
+
<!-- ============================== _all SLOT ============================ -->
|
|
153
|
+
<section id="all">
|
|
154
|
+
<div class="shell">
|
|
155
|
+
<div class="section-num">02 - The _all aggregate</div>
|
|
156
|
+
<h2>One slot, every provider</h2>
|
|
157
|
+
|
|
158
|
+
<p class="intro">
|
|
159
|
+
The reserved <code class="inline">_all</code> slot presents the union of
|
|
160
|
+
every opted-in provider's tools and prompts as a single MCP server.
|
|
161
|
+
Aggregated names are provider-prefixed with a <code class="inline">-</code>
|
|
162
|
+
separator, so a <code class="inline">forecast</code> tool from a
|
|
163
|
+
<code class="inline">weather</code> provider appears as
|
|
164
|
+
<code class="inline">weather-forecast</code>.
|
|
165
|
+
</p>
|
|
166
|
+
|
|
167
|
+
<p>
|
|
168
|
+
The broker's own introspection tools are aggregated in too: under
|
|
169
|
+
<code class="inline">_all</code> they appear as
|
|
170
|
+
<code class="inline">_broker-broker_info</code>,
|
|
171
|
+
<code class="inline">_broker-providers_list</code> and
|
|
172
|
+
<code class="inline">_broker-provider_status</code>. A client pinned to
|
|
173
|
+
<code class="inline">_all</code> therefore sees the whole broker, its
|
|
174
|
+
meta tools plus every tunnelled provider, through one connection.
|
|
175
|
+
</p>
|
|
176
|
+
|
|
177
|
+
<div class="conclusion">
|
|
178
|
+
Config-discovered upstreams (<code class="inline">mcpServers</code> and
|
|
179
|
+
<code class="inline">mcpbBundles</code>) join <code class="inline">_all</code>
|
|
180
|
+
automatically. Set <code class="inline">"aggregate": false</code> on an
|
|
181
|
+
entry to keep it on its own slot only.
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</section>
|
|
185
|
+
|
|
186
|
+
<!-- ============================ .mcpb BUNDLES =========================== -->
|
|
187
|
+
<section id="bundles">
|
|
188
|
+
<div class="shell">
|
|
189
|
+
<div class="section-num">03 - Loading .mcpb bundles</div>
|
|
190
|
+
<h2>Run a packaged server as a provider</h2>
|
|
191
|
+
|
|
192
|
+
<p class="intro">
|
|
193
|
+
The broker loads local <code class="inline">.mcpb</code> bundles listed in
|
|
194
|
+
its config and runs them as stdio provider slots. Before a bundle is
|
|
195
|
+
unpacked or spawned, the broker verifies a <strong>detached signature</strong>
|
|
196
|
+
against a trusted public key: an unverified bundle is refused, never run.
|
|
197
|
+
</p>
|
|
198
|
+
|
|
199
|
+
<div class="code-wrap">
|
|
200
|
+
<div class="code-head">
|
|
201
|
+
<span class="lang">JSON · .mcp-broker/config.json</span>
|
|
202
|
+
<button class="copy-btn" data-copy-block>Copy</button>
|
|
203
|
+
</div>
|
|
204
|
+
<pre><code><span class="tk-pu">{</span>
|
|
205
|
+
<span class="tk-p">"mcpbBundles"</span><span class="tk-pu">: [{</span>
|
|
206
|
+
<span class="tk-p">"name"</span><span class="tk-pu">:</span> <span class="tk-s">"weather"</span><span class="tk-pu">,</span>
|
|
207
|
+
<span class="tk-p">"path"</span><span class="tk-pu">:</span> <span class="tk-s">"bundles/weather.mcpb"</span><span class="tk-pu">,</span>
|
|
208
|
+
<span class="tk-p">"publicKey"</span><span class="tk-pu">:</span> <span class="tk-s">"bundles/mcpb-signing.pub.pem"</span><span class="tk-pu">,</span>
|
|
209
|
+
<span class="tk-p">"signature"</span><span class="tk-pu">:</span> <span class="tk-s">"bundles/weather.mcpb.sig"</span><span class="tk-pu">,</span>
|
|
210
|
+
<span class="tk-p">"aggregate"</span><span class="tk-pu">:</span> <span class="tk-k">true</span> <span class="tk-c">// default; false keeps it off _all</span>
|
|
211
|
+
<span class="tk-pu">}]</span>
|
|
212
|
+
<span class="tk-pu">}</span>
|
|
213
|
+
</code></pre>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<p>
|
|
217
|
+
Sign bundles with the bundled helper, Node built-ins only, no OpenSSL
|
|
218
|
+
and no dependency on Anthropic's <code class="inline">mcpb</code> CLI:
|
|
219
|
+
</p>
|
|
220
|
+
|
|
221
|
+
<div class="code-wrap">
|
|
222
|
+
<div class="code-head">
|
|
223
|
+
<span class="lang">Bash · from node/</span>
|
|
224
|
+
<button class="copy-btn" data-copy-block>Copy</button>
|
|
225
|
+
</div>
|
|
226
|
+
<pre><code><span class="tk-c"># generate an Ed25519 signing key pair</span>
|
|
227
|
+
node scripts/sign-bundle.mjs keygen bundles
|
|
228
|
+
|
|
229
|
+
<span class="tk-c"># produce the detached signature next to the bundle</span>
|
|
230
|
+
node scripts/sign-bundle.mjs sign bundles/weather.mcpb bundles/mcpb-signing.key.pem
|
|
231
|
+
</code></pre>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<p class="caption">
|
|
235
|
+
Keep the private key out of version control. The broker only ever needs
|
|
236
|
+
the public key referenced by <code class="inline">publicKey</code>.
|
|
237
|
+
</p>
|
|
238
|
+
</div>
|
|
239
|
+
</section>
|
|
240
|
+
|
|
241
|
+
<!-- ============================ ENDPOINTS ============================== -->
|
|
242
|
+
<section id="endpoints">
|
|
243
|
+
<div class="shell">
|
|
244
|
+
<div class="section-num">04 - Endpoints</div>
|
|
245
|
+
<h2>Where to connect</h2>
|
|
246
|
+
|
|
247
|
+
<p class="intro">
|
|
248
|
+
Both reserved slots are reachable on every client transport. Swap
|
|
249
|
+
<code class="inline">_broker</code> for <code class="inline">_all</code>
|
|
250
|
+
(or any provider slot name) in the paths below.
|
|
251
|
+
</p>
|
|
252
|
+
|
|
253
|
+
<div class="endpoints">
|
|
254
|
+
<div class="endpoint">
|
|
255
|
+
<span class="label">Broker · Streamable HTTP</span>
|
|
256
|
+
<span class="url">http://localhost:3000/_broker/mcp</span>
|
|
257
|
+
</div>
|
|
258
|
+
<div class="endpoint">
|
|
259
|
+
<span class="label">Aggregate · Streamable HTTP</span>
|
|
260
|
+
<span class="url">http://localhost:3000/_all/mcp</span>
|
|
261
|
+
</div>
|
|
262
|
+
<div class="endpoint">
|
|
263
|
+
<span class="label">Broker · Raw WebSocket</span>
|
|
264
|
+
<span class="url">ws://localhost:3000/_broker</span>
|
|
265
|
+
</div>
|
|
266
|
+
<div class="endpoint">
|
|
267
|
+
<span class="label">Aggregate · Raw WebSocket</span>
|
|
268
|
+
<span class="url">ws://localhost:3000/_all</span>
|
|
269
|
+
</div>
|
|
270
|
+
<div class="endpoint">
|
|
271
|
+
<span class="label">Broker · Legacy SSE</span>
|
|
272
|
+
<span class="url">http://localhost:3000/_broker/sse</span>
|
|
273
|
+
</div>
|
|
274
|
+
<div class="endpoint">
|
|
275
|
+
<span class="label">Aggregate · Legacy SSE</span>
|
|
276
|
+
<span class="url">http://localhost:3000/_all/sse</span>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
</section>
|
|
281
|
+
|
|
282
|
+
</main>
|
|
283
|
+
|
|
284
|
+
<!-- ================================ FOOTER ============================= -->
|
|
285
|
+
<footer>
|
|
286
|
+
<div class="shell footer-inner">
|
|
287
|
+
<div class="footer-links">
|
|
288
|
+
<a href="https://github.com/pandaGaume/mcp-broker" target="_blank" rel="noopener">github.com/pandaGaume/mcp-broker</a>
|
|
289
|
+
<a href="https://npmjs.com/package/@cyanmycelium/mcp-broker" target="_blank" rel="noopener">npmjs.com/package/@cyanmycelium/mcp-broker</a>
|
|
290
|
+
<a href="https://github.com/pandaGaume/mcp-broker/tree/main/docs" target="_blank" rel="noopener">Docs</a>
|
|
291
|
+
</div>
|
|
292
|
+
<div>© CyanMycelium · Apache-2.0</div>
|
|
293
|
+
</div>
|
|
294
|
+
</footer>
|
|
295
|
+
|
|
296
|
+
<div class="toast" id="toast">Copied to clipboard</div>
|
|
297
|
+
|
|
298
|
+
<script>
|
|
299
|
+
/* ---- toast + copy plumbing (mirrors the launcher page) ----------- */
|
|
300
|
+
const toast = document.getElementById('toast');
|
|
301
|
+
let toastTimer;
|
|
302
|
+
function showToast(msg) {
|
|
303
|
+
toast.textContent = msg || 'Copied to clipboard';
|
|
304
|
+
toast.classList.add('show');
|
|
305
|
+
clearTimeout(toastTimer);
|
|
306
|
+
toastTimer = setTimeout(() => toast.classList.remove('show'), 1600);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
document.querySelectorAll('[data-copy-block]').forEach((btn) => {
|
|
310
|
+
btn.addEventListener('click', async () => {
|
|
311
|
+
const wrap = btn.closest('.code-wrap');
|
|
312
|
+
const pre = wrap.querySelector('pre');
|
|
313
|
+
try {
|
|
314
|
+
await navigator.clipboard.writeText(pre.innerText);
|
|
315
|
+
btn.classList.add('copied');
|
|
316
|
+
const orig = btn.textContent;
|
|
317
|
+
btn.textContent = '✓ Copied';
|
|
318
|
+
setTimeout(() => { btn.textContent = orig; btn.classList.remove('copied'); }, 1400);
|
|
319
|
+
} catch (e) {
|
|
320
|
+
showToast('Copy failed');
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
document.querySelectorAll('a[href^="#"]').forEach((a) => {
|
|
326
|
+
a.addEventListener('click', (e) => {
|
|
327
|
+
const id = a.getAttribute('href').slice(1);
|
|
328
|
+
const el = document.getElementById(id);
|
|
329
|
+
if (!el) return;
|
|
330
|
+
e.preventDefault();
|
|
331
|
+
window.scrollTo({ top: el.offsetTop - 70, behavior: 'smooth' });
|
|
332
|
+
history.replaceState(null, '', '#' + id);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
</script>
|
|
336
|
+
|
|
337
|
+
</body>
|
|
338
|
+
</html>
|