@cyanmycelium/mcp-broker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/.mcp-broker.example/README.md +53 -0
  2. package/.mcp-broker.example/config.json +32 -0
  3. package/.mcp-broker.example/grammars/claude/fr.json +7 -0
  4. package/LICENSE +201 -0
  5. package/README.md +253 -0
  6. package/dist/bin.d.ts +2 -0
  7. package/dist/bin.js +208 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/broker/adapters/broker.adapter.info.d.ts +16 -0
  10. package/dist/broker/adapters/broker.adapter.info.js +43 -0
  11. package/dist/broker/adapters/broker.adapter.info.js.map +1 -0
  12. package/dist/broker/adapters/broker.adapter.providers.d.ts +18 -0
  13. package/dist/broker/adapters/broker.adapter.providers.js +61 -0
  14. package/dist/broker/adapters/broker.adapter.providers.js.map +1 -0
  15. package/dist/broker/behaviors/broker.behavior.info.d.ts +15 -0
  16. package/dist/broker/behaviors/broker.behavior.info.js +41 -0
  17. package/dist/broker/behaviors/broker.behavior.info.js.map +1 -0
  18. package/dist/broker/behaviors/broker.behavior.providers.d.ts +19 -0
  19. package/dist/broker/behaviors/broker.behavior.providers.js +69 -0
  20. package/dist/broker/behaviors/broker.behavior.providers.js.map +1 -0
  21. package/dist/broker/broker.context.d.ts +59 -0
  22. package/dist/broker/broker.context.js +2 -0
  23. package/dist/broker/broker.context.js.map +1 -0
  24. package/dist/broker/broker.grammars.d.ts +166 -0
  25. package/dist/broker/broker.grammars.js +258 -0
  26. package/dist/broker/broker.grammars.js.map +1 -0
  27. package/dist/broker/broker.server.d.ts +64 -0
  28. package/dist/broker/broker.server.js +111 -0
  29. package/dist/broker/broker.server.js.map +1 -0
  30. package/dist/broker/grammars/claude/en.json +16 -0
  31. package/dist/broker/grammars/claude/fr.json +16 -0
  32. package/dist/broker/grammars/default/en.json +32 -0
  33. package/dist/broker/grammars/default/fr.json +32 -0
  34. package/dist/broker/grammars/default/zh.json +32 -0
  35. package/dist/broker/index.d.ts +9 -0
  36. package/dist/broker/index.js +7 -0
  37. package/dist/broker/index.js.map +1 -0
  38. package/dist/config.d.ts +101 -0
  39. package/dist/config.js +61 -0
  40. package/dist/config.js.map +1 -0
  41. package/dist/index.d.ts +12 -0
  42. package/dist/index.js +11 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/stdio.upstream.d.ts +42 -0
  45. package/dist/stdio.upstream.js +85 -0
  46. package/dist/stdio.upstream.js.map +1 -0
  47. package/dist/version.d.ts +2 -0
  48. package/dist/version.js +9 -0
  49. package/dist/version.js.map +1 -0
  50. package/dist/ws.tunnel.builder.d.ts +133 -0
  51. package/dist/ws.tunnel.builder.js +197 -0
  52. package/dist/ws.tunnel.builder.js.map +1 -0
  53. package/dist/ws.tunnel.d.ts +310 -0
  54. package/dist/ws.tunnel.js +971 -0
  55. package/dist/ws.tunnel.js.map +1 -0
  56. package/package.json +86 -0
  57. package/scripts/copy-assets.mjs +34 -0
  58. package/scripts/gen-cert.mjs +94 -0
  59. package/src/bin.ts +231 -0
  60. package/src/broker/adapters/broker.adapter.info.ts +46 -0
  61. package/src/broker/adapters/broker.adapter.providers.ts +67 -0
  62. package/src/broker/behaviors/broker.behavior.info.ts +46 -0
  63. package/src/broker/behaviors/broker.behavior.providers.ts +82 -0
  64. package/src/broker/broker.context.ts +75 -0
  65. package/src/broker/broker.grammars.ts +336 -0
  66. package/src/broker/broker.server.ts +168 -0
  67. package/src/broker/grammars/claude/en.json +16 -0
  68. package/src/broker/grammars/claude/fr.json +16 -0
  69. package/src/broker/grammars/default/en.json +32 -0
  70. package/src/broker/grammars/default/fr.json +32 -0
  71. package/src/broker/grammars/default/zh.json +32 -0
  72. package/src/broker/index.ts +24 -0
  73. package/src/config.ts +155 -0
  74. package/src/index.ts +26 -0
  75. package/src/stdio.upstream.ts +114 -0
  76. package/src/version.ts +10 -0
  77. package/src/ws.tunnel.builder.ts +214 -0
  78. package/src/ws.tunnel.ts +1269 -0
package/dist/bin.js ADDED
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standalone entry-point that starts the mcp-broker WebSocket server.
4
+ *
5
+ * ## Configuration sources (highest priority first)
6
+ *
7
+ * 1. Environment variables (`MCP_BROKER_*`).
8
+ * 2. JSON config file. Resolved in order:
9
+ * a. `MCP_BROKER_CONFIG` env var.
10
+ * b. `./.mcp-broker/config.json` in the current working directory.
11
+ * c. `./mcp-broker.config.json` (legacy, with a deprecation warning).
12
+ * 3. Built-in defaults.
13
+ *
14
+ * ## Path resolution
15
+ *
16
+ * - Env-var paths (`MCP_BROKER_*_DIR`, `MCP_BROKER_TLS_*`) are resolved
17
+ * against `process.cwd()`.
18
+ * - Config-file paths (`tls.cert`, `www.mounts[*].dir`, `stdioUpstreams[*]`)
19
+ * are resolved against the **config file's directory** — so a config in
20
+ * `./.mcp-broker/config.json` referring to `"certs/cert.pem"` points at
21
+ * `./.mcp-broker/certs/cert.pem`. The folder is self-contained.
22
+ *
23
+ * ## Local grammar overrides
24
+ *
25
+ * When `.mcp-broker/grammars/<userAgent>/<locale>.json` files exist next to
26
+ * the config file, they are merged **on top of** the packaged grammars. Lets
27
+ * users customize tool/resource descriptions for their organization without
28
+ * forking the package.
29
+ *
30
+ * ## Environment variables
31
+ *
32
+ * | Variable | Default | Notes |
33
+ * |--------------------------------|----------|--------------------------------------------------------|
34
+ * | MCP_BROKER_CONFIG | (none) | Path to a JSON config file (see above). |
35
+ * | MCP_BROKER_PORT | 3000 | |
36
+ * | MCP_BROKER_HOST | 0.0.0.0 | |
37
+ * | MCP_BROKER_PROVIDER_PATH | /provider| Prefix for provider WS |
38
+ * | MCP_BROKER_CLIENT_PATH | / | Prefix for raw WS clients |
39
+ * | MCP_BROKER_MCP_PATH | /mcp | Suffix for Streamable HTTP transport |
40
+ * | MCP_BROKER_WWW_DIR | (none) | Ergonomic shortcut: mount this directory at "/" |
41
+ * | MCP_BROKER_BUNDLE_DIR | (none) | Ergonomic shortcut: mount this directory at "/bundle" |
42
+ * | MCP_BROKER_OPEN | (unset) | "1" to auto-launch the default browser at the root URL |
43
+ * | MCP_BROKER_TLS_CERT | (none) | Path to a PEM TLS certificate |
44
+ * | MCP_BROKER_TLS_KEY | (none) | Path to a PEM private key |
45
+ * | MCP_BROKER_PROTOCOL | auto | "http" to force plain, "https" to force TLS, otherwise |
46
+ * | | | TLS is enabled iff cert+key are both set |
47
+ * | MCP_BROKER_STDIO_PROVIDER | (none) | When set, stdin/stdout carry JSON-RPC for the named |
48
+ * | | | provider (Claude Desktop bridge). |
49
+ * | MCP_BROKER_LOCALE | en | Locale used for tool descriptions on the `_broker` |
50
+ * | | | slot. ISO 639-1 base; regional variants accepted. |
51
+ */
52
+ import * as fs from "fs";
53
+ import * as path from "path";
54
+ import open from "open";
55
+ import { WsTunnelBuilder } from "./index.js";
56
+ import { loadBrokerConfig } from "./config.js";
57
+ // ---------------------------------------------------------------------------
58
+ // Configuration
59
+ // ---------------------------------------------------------------------------
60
+ const { config, baseDir } = loadBrokerConfig();
61
+ const cwd = process.cwd();
62
+ /**
63
+ * Fills an env var from the config file when the env var is not already set.
64
+ * Used for **non-path** scalars — path-bearing fields are read directly so
65
+ * they can be resolved against `baseDir` (config file's directory) instead
66
+ * of `cwd` (deploy environment).
67
+ */
68
+ function envFromConfig(envName, configValue) {
69
+ if (configValue === undefined || configValue === null)
70
+ return;
71
+ if (process.env[envName] !== undefined && process.env[envName] !== "")
72
+ return;
73
+ process.env[envName] = String(configValue);
74
+ }
75
+ envFromConfig("MCP_BROKER_PORT", config.port);
76
+ envFromConfig("MCP_BROKER_HOST", config.host);
77
+ envFromConfig("MCP_BROKER_PROTOCOL", config.protocol);
78
+ envFromConfig("MCP_BROKER_LOCALE", config.locale);
79
+ envFromConfig("MCP_BROKER_STDIO_PROVIDER", config.stdioProvider);
80
+ envFromConfig("MCP_BROKER_PROVIDER_PATH", config.paths?.provider);
81
+ envFromConfig("MCP_BROKER_CLIENT_PATH", config.paths?.client);
82
+ envFromConfig("MCP_BROKER_MCP_PATH", config.paths?.mcp);
83
+ envFromConfig("MCP_BROKER_OPEN", config.www?.open === true ? "1" : undefined);
84
+ const stdioProvider = process.env["MCP_BROKER_STDIO_PROVIDER"];
85
+ // In stdio mode stdout is reserved for JSON-RPC — redirect all console output to stderr.
86
+ if (stdioProvider) {
87
+ const toStderr = (...args) => process.stderr.write(args.join(" ") + "\n");
88
+ console.log = toStderr;
89
+ console.info = toStderr;
90
+ console.warn = toStderr;
91
+ console.error = toStderr;
92
+ }
93
+ const port = parseInt(process.env["MCP_BROKER_PORT"] ?? "3000", 10);
94
+ const host = process.env["MCP_BROKER_HOST"];
95
+ const providerPath = process.env["MCP_BROKER_PROVIDER_PATH"] ?? "/provider";
96
+ const clientPath = process.env["MCP_BROKER_CLIENT_PATH"] ?? "/";
97
+ const mcpPath = process.env["MCP_BROKER_MCP_PATH"] ?? "/mcp";
98
+ const ssePath = config.paths?.sse ?? "/sse";
99
+ // ── TLS material ─────────────────────────────────────────────────────────────
100
+ // Env var (relative to cwd) wins over config (relative to baseDir).
101
+ const 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;
102
+ const 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;
103
+ const protocolOverride = process.env["MCP_BROKER_PROTOCOL"]?.toLowerCase();
104
+ if (protocolOverride !== undefined && protocolOverride !== "http" && protocolOverride !== "https") {
105
+ console.error(`[mcp-broker] Invalid MCP_BROKER_PROTOCOL="${protocolOverride}". Use "http" or "https".`);
106
+ process.exit(1);
107
+ }
108
+ if (protocolOverride === "https" && (!tlsCertPath || !tlsKeyPath)) {
109
+ console.error("[mcp-broker] MCP_BROKER_PROTOCOL=https requires TLS cert+key (via config.tls or MCP_BROKER_TLS_CERT/KEY).");
110
+ process.exit(1);
111
+ }
112
+ const useTls = protocolOverride === "http" ? false : protocolOverride === "https" ? true : !!(tlsCertPath && tlsKeyPath);
113
+ // ── Env-var static mount shortcuts (relative to cwd) ─────────────────────────
114
+ const envWwwDir = process.env["MCP_BROKER_WWW_DIR"] ? path.resolve(cwd, process.env["MCP_BROKER_WWW_DIR"]) : null;
115
+ const envBundleDir = process.env["MCP_BROKER_BUNDLE_DIR"] ? path.resolve(cwd, process.env["MCP_BROKER_BUNDLE_DIR"]) : null;
116
+ // ---------------------------------------------------------------------------
117
+ // Server bootstrap
118
+ // ---------------------------------------------------------------------------
119
+ async function main() {
120
+ // Local grammar overrides: when `<baseDir>/grammars/` exists, the broker
121
+ // server merges those JSON files on top of the packaged grammars.
122
+ const localGrammarsDir = path.join(baseDir, "grammars");
123
+ const hasLocalGrammars = fs.existsSync(localGrammarsDir);
124
+ const builder = new WsTunnelBuilder().withPort(port).withProviderPath(providerPath).withClientPath(clientPath).withMcpPath(mcpPath);
125
+ if (host) {
126
+ builder.withHost(host);
127
+ }
128
+ if (useTls) {
129
+ builder.withTlsFiles(tlsCertPath, tlsKeyPath);
130
+ }
131
+ // ── Static mounts ────────────────────────────────────────────────────────
132
+ // First the env-var shortcuts (relative to cwd), then the config `www.mounts`
133
+ // (relative to baseDir). Order matters: /bundle before / so the prefix router
134
+ // can distinguish them. Subsequent registrations contribute additional mounts;
135
+ // longest-prefix match wins at runtime.
136
+ if (envBundleDir && fs.existsSync(envBundleDir)) {
137
+ builder.withStaticMount("/bundle", envBundleDir);
138
+ }
139
+ if (envWwwDir && fs.existsSync(envWwwDir)) {
140
+ builder.withStaticMount("/", envWwwDir);
141
+ }
142
+ if (config.www?.mounts) {
143
+ for (const mount of config.www.mounts) {
144
+ const abs = path.resolve(baseDir, mount.dir);
145
+ if (fs.existsSync(abs)) {
146
+ builder.withStaticMount(mount.urlPrefix, abs);
147
+ }
148
+ else {
149
+ console.warn(`[mcp-broker] www.mounts entry "${mount.urlPrefix}" → ${abs} skipped (directory not found).`);
150
+ }
151
+ }
152
+ }
153
+ // ── Stdio upstreams ──────────────────────────────────────────────────────
154
+ if (config.stdioUpstreams) {
155
+ for (const u of config.stdioUpstreams) {
156
+ builder.withStdioUpstream(u.name, u.command, u.args, u.env);
157
+ }
158
+ }
159
+ if (stdioProvider) {
160
+ builder.withStdioClient(stdioProvider);
161
+ }
162
+ if (hasLocalGrammars) {
163
+ builder.withBrokerLocalGrammarsDir(localGrammarsDir);
164
+ }
165
+ const tunnel = builder.build();
166
+ await tunnel.start();
167
+ // ── Startup banner ──────────────────────────────────────────────────────
168
+ const httpScheme = useTls ? "https" : "http";
169
+ const wsScheme = useTls ? "wss" : "ws";
170
+ const hr = "─".repeat(64);
171
+ const localhost = `${httpScheme}://localhost:${port}`;
172
+ const mcpSuffix = mcpPath.replace(/^\//, "");
173
+ const sseSuffix = ssePath.replace(/^\//, "");
174
+ const hasWwwRoot = !!(envWwwDir && fs.existsSync(envWwwDir)) || (config.www?.mounts ?? []).some((m) => m.urlPrefix === "/");
175
+ console.log();
176
+ console.log(`⚙️ mcp-broker started${useTls ? " (TLS)" : ""}`);
177
+ console.log(hr);
178
+ console.log(`📡 Provider WebSocket ${wsScheme}://localhost:${port}${providerPath}/<name>`);
179
+ console.log(`🔌 MCP (Streamable HTTP) ${localhost}/<name>/${mcpSuffix}`);
180
+ console.log(`📺 Legacy SSE ${localhost}/<name>/${sseSuffix}`);
181
+ if (hasLocalGrammars) {
182
+ console.log(`🌐 Local grammars ${localGrammarsDir}`);
183
+ }
184
+ console.log(hr);
185
+ console.log(` Press Ctrl+C to stop.`);
186
+ console.log();
187
+ // Auto-launch browser only if explicitly opted in via MCP_BROKER_OPEN=1
188
+ // AND a mount at "/" is configured.
189
+ if (hasWwwRoot && process.env["MCP_BROKER_OPEN"] === "1") {
190
+ const url = `${localhost}/`;
191
+ console.log(`🚀 Opening browser: ${url}`);
192
+ console.log();
193
+ await open(url);
194
+ }
195
+ // ── Signal handlers ─────────────────────────────────────────────────────
196
+ const shutdown = async (signal) => {
197
+ console.log(`\n⛔ ${signal} received — shutting down…`);
198
+ await tunnel.stop();
199
+ process.exit(0);
200
+ };
201
+ process.on("SIGINT", () => void shutdown("SIGINT"));
202
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
203
+ }
204
+ main().catch((err) => {
205
+ console.error("[mcp-broker] Fatal error:", err);
206
+ process.exit(1);
207
+ });
208
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { McpAdapterBase } from "@cyanmycelium/mcp-core";
2
+ import type { McpResourceContent, McpToolResult } from "@cyanmycelium/mcp-core";
3
+ import type { BrokerContext } from "../broker.context.js";
4
+ /** URI of the static resource backing the `broker_info` snapshot. */
5
+ export declare const BROKER_INFO_URI = "broker://info";
6
+ /**
7
+ * Read-only adapter that produces a snapshot of the broker's identity and
8
+ * configuration. Backed by the live {@link BrokerContext}.
9
+ */
10
+ export declare class BrokerInfoAdapter extends McpAdapterBase {
11
+ private readonly _context;
12
+ constructor(_context: BrokerContext);
13
+ readResourceAsync(uri: string): Promise<McpResourceContent | undefined>;
14
+ executeToolAsync(_uri: string, toolName: string, _args: Record<string, unknown>): Promise<McpToolResult>;
15
+ private _snapshot;
16
+ }
@@ -0,0 +1,43 @@
1
+ import { McpAdapterBase, McpToolResults } from "@cyanmycelium/mcp-core";
2
+ /** URI of the static resource backing the `broker_info` snapshot. */
3
+ export const BROKER_INFO_URI = "broker://info";
4
+ /**
5
+ * Read-only adapter that produces a snapshot of the broker's identity and
6
+ * configuration. Backed by the live {@link BrokerContext}.
7
+ */
8
+ export class BrokerInfoAdapter extends McpAdapterBase {
9
+ _context;
10
+ constructor(_context) {
11
+ super("broker");
12
+ this._context = _context;
13
+ }
14
+ async readResourceAsync(uri) {
15
+ if (uri !== BROKER_INFO_URI)
16
+ return undefined;
17
+ return {
18
+ uri,
19
+ mimeType: "application/json",
20
+ text: JSON.stringify(this._snapshot()),
21
+ };
22
+ }
23
+ async executeToolAsync(_uri, toolName, _args) {
24
+ if (toolName !== "broker_info") {
25
+ return McpToolResults.error(`Unknown tool: ${toolName}`);
26
+ }
27
+ return McpToolResults.json(this._snapshot());
28
+ }
29
+ _snapshot() {
30
+ const c = this._context;
31
+ return {
32
+ name: c.name,
33
+ version: c.version,
34
+ startedAt: c.startedAt?.toISOString() ?? null,
35
+ uptimeSeconds: c.uptimeSeconds,
36
+ host: c.host ?? "0.0.0.0",
37
+ port: c.port,
38
+ tls: c.tls,
39
+ paths: c.paths,
40
+ };
41
+ }
42
+ }
43
+ //# sourceMappingURL=broker.adapter.info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.adapter.info.js","sourceRoot":"","sources":["../../../src/broker/adapters/broker.adapter.info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAIxE,qEAAqE;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,eAAe,CAAC;AAE/C;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,cAAc;IACpB;IAA7B,YAA6B,QAAuB;QAChD,KAAK,CAAC,QAAQ,CAAC,CAAC;QADS,aAAQ,GAAR,QAAQ,CAAe;IAEpD,CAAC;IAEM,KAAK,CAAC,iBAAiB,CAAC,GAAW;QACtC,IAAI,GAAG,KAAK,eAAe;YAAE,OAAO,SAAS,CAAC;QAC9C,OAAO;YACH,GAAG;YACH,QAAQ,EAAE,kBAAkB;YAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;SACzC,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,gBAAgB,CAAC,IAAY,EAAE,QAAgB,EAAE,KAA8B;QACxF,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;YAC7B,OAAO,cAAc,CAAC,KAAK,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACjD,CAAC;IAEO,SAAS;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QACxB,OAAO;YACH,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,IAAI;YAC7C,aAAa,EAAE,CAAC,CAAC,aAAa;YAC9B,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,SAAS;YACzB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,KAAK,EAAE,CAAC,CAAC,KAAK;SACjB,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,18 @@
1
+ import { McpAdapterBase } from "@cyanmycelium/mcp-core";
2
+ import type { McpResourceContent, McpToolResult } from "@cyanmycelium/mcp-core";
3
+ import type { BrokerContext } from "../broker.context.js";
4
+ /** URI of the static resource that lists every provider slot. */
5
+ export declare const PROVIDERS_URI = "broker://providers";
6
+ /** RFC 6570 URI template for one specific provider slot. */
7
+ export declare const PROVIDER_URI_TEMPLATE = "broker://providers/{name}";
8
+ /**
9
+ * Adapter that exposes the broker's current provider slots, both as a list
10
+ * (read of `broker://providers`) and individually (`broker://providers/<name>`).
11
+ */
12
+ export declare class BrokerProvidersAdapter extends McpAdapterBase {
13
+ private readonly _context;
14
+ constructor(_context: BrokerContext);
15
+ readResourceAsync(uri: string): Promise<McpResourceContent | undefined>;
16
+ executeToolAsync(_uri: string, toolName: string, args: Record<string, unknown>): Promise<McpToolResult>;
17
+ private _listSnapshot;
18
+ }
@@ -0,0 +1,61 @@
1
+ import { McpAdapterBase, McpToolResults } from "@cyanmycelium/mcp-core";
2
+ /** URI of the static resource that lists every provider slot. */
3
+ export const PROVIDERS_URI = "broker://providers";
4
+ /** RFC 6570 URI template for one specific provider slot. */
5
+ export const PROVIDER_URI_TEMPLATE = "broker://providers/{name}";
6
+ /**
7
+ * Adapter that exposes the broker's current provider slots, both as a list
8
+ * (read of `broker://providers`) and individually (`broker://providers/<name>`).
9
+ */
10
+ export class BrokerProvidersAdapter extends McpAdapterBase {
11
+ _context;
12
+ constructor(_context) {
13
+ super("broker");
14
+ this._context = _context;
15
+ }
16
+ async readResourceAsync(uri) {
17
+ if (uri === PROVIDERS_URI) {
18
+ return {
19
+ uri,
20
+ mimeType: "application/json",
21
+ text: JSON.stringify(this._listSnapshot()),
22
+ };
23
+ }
24
+ // broker://providers/<name>
25
+ const match = /^broker:\/\/providers\/([^/]+)$/.exec(uri);
26
+ if (match) {
27
+ const name = decodeURIComponent(match[1]);
28
+ const info = this._context.getProviderInfo(name);
29
+ if (!info)
30
+ return undefined;
31
+ return {
32
+ uri,
33
+ mimeType: "application/json",
34
+ text: JSON.stringify(info),
35
+ };
36
+ }
37
+ return undefined;
38
+ }
39
+ async executeToolAsync(_uri, toolName, args) {
40
+ switch (toolName) {
41
+ case "providers_list":
42
+ return McpToolResults.json(this._listSnapshot());
43
+ case "provider_status": {
44
+ const name = typeof args.name === "string" ? args.name : "";
45
+ if (!name)
46
+ return McpToolResults.error('Missing required argument: "name" (string).');
47
+ const info = this._context.getProviderInfo(name);
48
+ if (!info)
49
+ return McpToolResults.error(`Unknown provider: "${name}".`);
50
+ return McpToolResults.json(info);
51
+ }
52
+ default:
53
+ return McpToolResults.error(`Unknown tool: ${toolName}`);
54
+ }
55
+ }
56
+ _listSnapshot() {
57
+ const providers = this._context.getProvidersInfo();
58
+ return { count: providers.length, providers };
59
+ }
60
+ }
61
+ //# sourceMappingURL=broker.adapter.providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.adapter.providers.js","sourceRoot":"","sources":["../../../src/broker/adapters/broker.adapter.providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAIxE,iEAAiE;AACjE,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAElD,4DAA4D;AAC5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AAEjE;;;GAGG;AACH,MAAM,OAAO,sBAAuB,SAAQ,cAAc;IACzB;IAA7B,YAA6B,QAAuB;QAChD,KAAK,CAAC,QAAQ,CAAC,CAAC;QADS,aAAQ,GAAR,QAAQ,CAAe;IAEpD,CAAC;IAEM,KAAK,CAAC,iBAAiB,CAAC,GAAW;QACtC,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YACxB,OAAO;gBACH,GAAG;gBACH,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;aAC7C,CAAC;QACN,CAAC;QAED,4BAA4B;QAC5B,MAAM,KAAK,GAAG,iCAAiC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,IAAI,KAAK,EAAE,CAAC;YACR,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YAC5B,OAAO;gBACH,GAAG;gBACH,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC7B,CAAC;QACN,CAAC;QAED,OAAO,SAAS,CAAC;IACrB,CAAC;IAEM,KAAK,CAAC,gBAAgB,CAAC,IAAY,EAAE,QAAgB,EAAE,IAA6B;QACvF,QAAQ,QAAQ,EAAE,CAAC;YACf,KAAK,gBAAgB;gBACjB,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;YAErD,KAAK,iBAAiB,CAAC,CAAC,CAAC;gBACrB,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5D,IAAI,CAAC,IAAI;oBAAE,OAAO,cAAc,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;gBACtF,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;gBACjD,IAAI,CAAC,IAAI;oBAAE,OAAO,cAAc,CAAC,KAAK,CAAC,sBAAsB,IAAI,IAAI,CAAC,CAAC;gBACvE,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,CAAC;YAED;gBACI,OAAO,cAAc,CAAC,KAAK,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;QACjE,CAAC;IACL,CAAC;IAEO,aAAa;QACjB,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC;QACnD,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;IAClD,CAAC;CACJ"}
@@ -0,0 +1,15 @@
1
+ import { McpBehavior } from "@cyanmycelium/mcp-core";
2
+ import type { McpResource, McpTool } from "@cyanmycelium/mcp-core";
3
+ import type { BrokerContext } from "../broker.context.js";
4
+ /**
5
+ * Exposes basic broker identity (name, version, uptime, listening config) as
6
+ * one tool (`broker_info`) and one resource (`broker://info`).
7
+ *
8
+ * An MCP agent typically calls `broker_info` first to learn who it is talking to.
9
+ */
10
+ export declare class BrokerInfoBehavior extends McpBehavior {
11
+ static readonly NAMESPACE = "broker";
12
+ constructor(context: BrokerContext);
13
+ protected _buildResources(): McpResource[];
14
+ protected _buildTools(): McpTool[];
15
+ }
@@ -0,0 +1,41 @@
1
+ import { McpBehavior } from "@cyanmycelium/mcp-core";
2
+ import { BROKER_INFO_URI, BrokerInfoAdapter } from "../adapters/broker.adapter.info.js";
3
+ import { brokerBaselineResourceDescription, brokerBaselineResourceName, brokerBaselineToolDescription } from "../broker.grammars.js";
4
+ /**
5
+ * Exposes basic broker identity (name, version, uptime, listening config) as
6
+ * one tool (`broker_info`) and one resource (`broker://info`).
7
+ *
8
+ * An MCP agent typically calls `broker_info` first to learn who it is talking to.
9
+ */
10
+ export class BrokerInfoBehavior extends McpBehavior {
11
+ static NAMESPACE = "broker";
12
+ constructor(context) {
13
+ super(new BrokerInfoAdapter(context), {
14
+ namespace: BrokerInfoBehavior.NAMESPACE,
15
+ });
16
+ }
17
+ _buildResources() {
18
+ return [
19
+ {
20
+ uri: BROKER_INFO_URI,
21
+ name: brokerBaselineResourceName(BROKER_INFO_URI),
22
+ mimeType: "application/json",
23
+ description: brokerBaselineResourceDescription(BROKER_INFO_URI),
24
+ },
25
+ ];
26
+ }
27
+ _buildTools() {
28
+ return [
29
+ {
30
+ name: "broker_info",
31
+ description: brokerBaselineToolDescription("broker_info"),
32
+ inputSchema: {
33
+ type: "object",
34
+ properties: {},
35
+ additionalProperties: false,
36
+ },
37
+ },
38
+ ];
39
+ }
40
+ }
41
+ //# sourceMappingURL=broker.behavior.info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.behavior.info.js","sourceRoot":"","sources":["../../../src/broker/behaviors/broker.behavior.info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACxF,OAAO,EAAE,iCAAiC,EAAE,0BAA0B,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAGrI;;;;;GAKG;AACH,MAAM,OAAO,kBAAmB,SAAQ,WAAW;IACxC,MAAM,CAAU,SAAS,GAAG,QAAQ,CAAC;IAE5C,YAAY,OAAsB;QAC9B,KAAK,CAAC,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE;YAClC,SAAS,EAAE,kBAAkB,CAAC,SAAS;SAC1C,CAAC,CAAC;IACP,CAAC;IAEkB,eAAe;QAC9B,OAAO;YACH;gBACI,GAAG,EAAE,eAAe;gBACpB,IAAI,EAAE,0BAA0B,CAAC,eAAe,CAAC;gBACjD,QAAQ,EAAE,kBAAkB;gBAC5B,WAAW,EAAE,iCAAiC,CAAC,eAAe,CAAC;aAClE;SACJ,CAAC;IACN,CAAC;IAEkB,WAAW;QAC1B,OAAO;YACH;gBACI,IAAI,EAAE,aAAa;gBACnB,WAAW,EAAE,6BAA6B,CAAC,aAAa,CAAC;gBACzD,WAAW,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE;oBACd,oBAAoB,EAAE,KAAK;iBAC9B;aACJ;SACJ,CAAC;IACN,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { McpBehavior } from "@cyanmycelium/mcp-core";
2
+ import type { McpResource, McpResourceTemplate, McpTool } from "@cyanmycelium/mcp-core";
3
+ import type { BrokerContext } from "../broker.context.js";
4
+ /**
5
+ * Exposes the broker's provider slots so an MCP agent can discover what is
6
+ * currently routable behind the broker, with two tools:
7
+ *
8
+ * - `providers_list` — every slot (including disconnected ones).
9
+ * - `provider_status({ name })` — detail on one slot.
10
+ *
11
+ * Plus matching resources at `broker://providers` and `broker://providers/<name>`.
12
+ */
13
+ export declare class BrokerProvidersBehavior extends McpBehavior {
14
+ static readonly NAMESPACE = "broker_providers";
15
+ constructor(context: BrokerContext);
16
+ protected _buildResources(): McpResource[];
17
+ protected _buildTemplate(): McpResourceTemplate[];
18
+ protected _buildTools(): McpTool[];
19
+ }
@@ -0,0 +1,69 @@
1
+ import { McpBehavior } from "@cyanmycelium/mcp-core";
2
+ import { BrokerProvidersAdapter, PROVIDERS_URI, PROVIDER_URI_TEMPLATE } from "../adapters/broker.adapter.providers.js";
3
+ import { brokerBaselinePropertyDescription, brokerBaselineResourceDescription, brokerBaselineResourceName, brokerBaselineResourceTemplateDescription, brokerBaselineResourceTemplateName, brokerBaselineToolDescription, } from "../broker.grammars.js";
4
+ /**
5
+ * Exposes the broker's provider slots so an MCP agent can discover what is
6
+ * currently routable behind the broker, with two tools:
7
+ *
8
+ * - `providers_list` — every slot (including disconnected ones).
9
+ * - `provider_status({ name })` — detail on one slot.
10
+ *
11
+ * Plus matching resources at `broker://providers` and `broker://providers/<name>`.
12
+ */
13
+ export class BrokerProvidersBehavior extends McpBehavior {
14
+ static NAMESPACE = "broker_providers";
15
+ constructor(context) {
16
+ super(new BrokerProvidersAdapter(context), {
17
+ namespace: BrokerProvidersBehavior.NAMESPACE,
18
+ });
19
+ }
20
+ _buildResources() {
21
+ return [
22
+ {
23
+ uri: PROVIDERS_URI,
24
+ name: brokerBaselineResourceName(PROVIDERS_URI),
25
+ mimeType: "application/json",
26
+ description: brokerBaselineResourceDescription(PROVIDERS_URI),
27
+ },
28
+ ];
29
+ }
30
+ _buildTemplate() {
31
+ return [
32
+ {
33
+ uriTemplate: PROVIDER_URI_TEMPLATE,
34
+ name: brokerBaselineResourceTemplateName(PROVIDER_URI_TEMPLATE),
35
+ mimeType: "application/json",
36
+ description: brokerBaselineResourceTemplateDescription(PROVIDER_URI_TEMPLATE),
37
+ },
38
+ ];
39
+ }
40
+ _buildTools() {
41
+ return [
42
+ {
43
+ name: "providers_list",
44
+ description: brokerBaselineToolDescription("providers_list"),
45
+ inputSchema: {
46
+ type: "object",
47
+ properties: {},
48
+ additionalProperties: false,
49
+ },
50
+ },
51
+ {
52
+ name: "provider_status",
53
+ description: brokerBaselineToolDescription("provider_status"),
54
+ inputSchema: {
55
+ type: "object",
56
+ properties: {
57
+ name: {
58
+ type: "string",
59
+ description: brokerBaselinePropertyDescription("provider_status", "name"),
60
+ },
61
+ },
62
+ required: ["name"],
63
+ additionalProperties: false,
64
+ },
65
+ },
66
+ ];
67
+ }
68
+ }
69
+ //# sourceMappingURL=broker.behavior.providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.behavior.providers.js","sourceRoot":"","sources":["../../../src/broker/behaviors/broker.behavior.providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACvH,OAAO,EACH,iCAAiC,EACjC,iCAAiC,EACjC,0BAA0B,EAC1B,yCAAyC,EACzC,kCAAkC,EAClC,6BAA6B,GAChC,MAAM,uBAAuB,CAAC;AAG/B;;;;;;;;GAQG;AACH,MAAM,OAAO,uBAAwB,SAAQ,WAAW;IAC7C,MAAM,CAAU,SAAS,GAAG,kBAAkB,CAAC;IAEtD,YAAY,OAAsB;QAC9B,KAAK,CAAC,IAAI,sBAAsB,CAAC,OAAO,CAAC,EAAE;YACvC,SAAS,EAAE,uBAAuB,CAAC,SAAS;SAC/C,CAAC,CAAC;IACP,CAAC;IAEkB,eAAe;QAC9B,OAAO;YACH;gBACI,GAAG,EAAE,aAAa;gBAClB,IAAI,EAAE,0BAA0B,CAAC,aAAa,CAAC;gBAC/C,QAAQ,EAAE,kBAAkB;gBAC5B,WAAW,EAAE,iCAAiC,CAAC,aAAa,CAAC;aAChE;SACJ,CAAC;IACN,CAAC;IAEkB,cAAc;QAC7B,OAAO;YACH;gBACI,WAAW,EAAE,qBAAqB;gBAClC,IAAI,EAAE,kCAAkC,CAAC,qBAAqB,CAAC;gBAC/D,QAAQ,EAAE,kBAAkB;gBAC5B,WAAW,EAAE,yCAAyC,CAAC,qBAAqB,CAAC;aAChF;SACJ,CAAC;IACN,CAAC;IAEkB,WAAW;QAC1B,OAAO;YACH;gBACI,IAAI,EAAE,gBAAgB;gBACtB,WAAW,EAAE,6BAA6B,CAAC,gBAAgB,CAAC;gBAC5D,WAAW,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE;oBACd,oBAAoB,EAAE,KAAK;iBAC9B;aACJ;YACD;gBACI,IAAI,EAAE,iBAAiB;gBACvB,WAAW,EAAE,6BAA6B,CAAC,iBAAiB,CAAC;gBAC7D,WAAW,EAAE;oBACT,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACR,IAAI,EAAE;4BACF,IAAI,EAAE,QAAQ;4BACd,WAAW,EAAE,iCAAiC,CAAC,iBAAiB,EAAE,MAAM,CAAC;yBAC5E;qBACJ;oBACD,QAAQ,EAAE,CAAC,MAAM,CAAC;oBAClB,oBAAoB,EAAE,KAAK;iBAC9B;aACJ;SACJ,CAAC;IACN,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Read-only view of the broker's runtime state, exposed to broker behaviors.
3
+ *
4
+ * Decouples the behaviors from the concrete `WsTunnel` class, making them
5
+ * unit-testable and reusable (e.g. a future .NET-backed context).
6
+ */
7
+ export interface BrokerContext {
8
+ /** Package version (from package.json). */
9
+ readonly version: string;
10
+ /** Logical broker name reported to MCP clients. */
11
+ readonly name: string;
12
+ /** Timestamp of the most recent successful `start()`, or `null` if never started. */
13
+ readonly startedAt: Date | null;
14
+ /** Seconds since `startedAt`, or `0` if not running. */
15
+ readonly uptimeSeconds: number;
16
+ /** Bind host. `undefined` means default (`0.0.0.0`). */
17
+ readonly host: string | undefined;
18
+ /** TCP port the broker is listening on. */
19
+ readonly port: number;
20
+ /** Whether TLS is active for the HTTP/WS server. */
21
+ readonly tls: boolean;
22
+ /** All configured URL paths, with defaults already substituted. */
23
+ readonly paths: {
24
+ provider: string;
25
+ providers: string;
26
+ client: string;
27
+ mcp: string;
28
+ sse: string;
29
+ messages: string;
30
+ };
31
+ /** Snapshot of every known provider slot, including disconnected ones. */
32
+ getProvidersInfo(): BrokerProviderInfo[];
33
+ /** Snapshot of a single provider slot, or `undefined` if the name is unknown. */
34
+ getProviderInfo(name: string): BrokerProviderInfo | undefined;
35
+ }
36
+ /**
37
+ * Transport kind currently feeding a provider slot.
38
+ *
39
+ * - `ws`: dedicated WebSocket provider (`/provider/<name>`).
40
+ * - `ws-multiplex`: multiplexed WebSocket envelope on `/providers`.
41
+ * - `stdio`: child process spawned at broker startup.
42
+ * - `loopback`: in-process transport (e.g. the broker exposing itself as `_broker`).
43
+ * - `none`: the slot was referenced by a client but no provider has attached yet.
44
+ */
45
+ export type BrokerProviderTransport = "ws" | "ws-multiplex" | "stdio" | "loopback" | "none";
46
+ export interface BrokerProviderInfo {
47
+ /** Slot name as advertised on `/<name>/...` endpoints. */
48
+ name: string;
49
+ /** Which transport is currently feeding the slot. */
50
+ transport: BrokerProviderTransport;
51
+ /** `true` iff the slot is reachable for routing right now. */
52
+ connected: boolean;
53
+ /** Number of raw-WebSocket MCP clients on this slot. */
54
+ clientCount: number;
55
+ /** Number of long-lived sessions (SSE + Streamable HTTP GET streams). */
56
+ sessionCount: number;
57
+ /** Number of in-flight JSON-RPC requests awaiting a response. */
58
+ pendingCount: number;
59
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=broker.context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.context.js","sourceRoot":"","sources":["../../src/broker/broker.context.ts"],"names":[],"mappings":""}