@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
@@ -0,0 +1,32 @@
1
+ {
2
+ "tools": {
3
+ "broker_info": {
4
+ "description": "Returns the broker's name, version, uptime, host, port, TLS status, and configured URL paths."
5
+ },
6
+ "providers_list": {
7
+ "description": "Returns every provider slot known to the broker (connected and disconnected), with transport kind, client count, and pending request count."
8
+ },
9
+ "provider_status": {
10
+ "description": "Returns the status of one provider slot identified by name. Errors if the slot does not exist.",
11
+ "properties": {
12
+ "name": "Exact provider name (case-sensitive)."
13
+ }
14
+ }
15
+ },
16
+ "resources": {
17
+ "broker://info": {
18
+ "name": "Broker info",
19
+ "description": "Broker identity, version, uptime, and listening configuration."
20
+ },
21
+ "broker://providers": {
22
+ "name": "Broker providers",
23
+ "description": "List of every provider slot known to the broker, including disconnected ones."
24
+ }
25
+ },
26
+ "templates": {
27
+ "broker://providers/{name}": {
28
+ "name": "Broker provider",
29
+ "description": "Snapshot of one specific provider slot, addressed by its name."
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "tools": {
3
+ "broker_info": {
4
+ "description": "Retourne le nom, la version, l'uptime, l'hôte, le port, l'état TLS et les chemins URL du broker."
5
+ },
6
+ "providers_list": {
7
+ "description": "Liste tous les emplacements de providers connus du broker (connectés et déconnectés), avec leur type de transport, leur nombre de clients et le nombre de requêtes en attente."
8
+ },
9
+ "provider_status": {
10
+ "description": "Retourne l'état d'un emplacement de provider identifié par son nom. Échoue si le provider n'existe pas.",
11
+ "properties": {
12
+ "name": "Nom exact du provider (sensible à la casse)."
13
+ }
14
+ }
15
+ },
16
+ "resources": {
17
+ "broker://info": {
18
+ "name": "Informations du broker",
19
+ "description": "Identité, version, uptime et configuration d'écoute du broker."
20
+ },
21
+ "broker://providers": {
22
+ "name": "Providers du broker",
23
+ "description": "Liste de tous les emplacements de providers connus du broker, y compris les déconnectés."
24
+ }
25
+ },
26
+ "templates": {
27
+ "broker://providers/{name}": {
28
+ "name": "Provider du broker",
29
+ "description": "Snapshot d'un emplacement de provider spécifique, identifié par son nom."
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "tools": {
3
+ "broker_info": {
4
+ "description": "返回 broker 的名称、版本、运行时间、主机、端口、TLS 状态和已配置的 URL 路径。"
5
+ },
6
+ "providers_list": {
7
+ "description": "列出 broker 已知的所有 provider 槽位(已连接和未连接),包括传输类型、客户端数量和待处理请求数量。"
8
+ },
9
+ "provider_status": {
10
+ "description": "返回由名称标识的某个 provider 槽位的状态。如果槽位不存在则返回错误。",
11
+ "properties": {
12
+ "name": "provider 的精确名称(区分大小写)。"
13
+ }
14
+ }
15
+ },
16
+ "resources": {
17
+ "broker://info": {
18
+ "name": "Broker 信息",
19
+ "description": "Broker 的身份、版本、运行时间和监听配置。"
20
+ },
21
+ "broker://providers": {
22
+ "name": "Broker Providers",
23
+ "description": "Broker 已知的所有 provider 槽位列表,包括未连接的。"
24
+ }
25
+ },
26
+ "templates": {
27
+ "broker://providers/{name}": {
28
+ "name": "Broker Provider",
29
+ "description": "指定名称的 provider 槽位快照。"
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,9 @@
1
+ export { BrokerInfoBehavior } from "./behaviors/broker.behavior.info.js";
2
+ export { BrokerProvidersBehavior } from "./behaviors/broker.behavior.providers.js";
3
+ export { BrokerInfoAdapter, BROKER_INFO_URI } from "./adapters/broker.adapter.info.js";
4
+ export { BrokerProvidersAdapter, PROVIDERS_URI, PROVIDER_URI_TEMPLATE } from "./adapters/broker.adapter.providers.js";
5
+ export { startBrokerServer, BROKER_PROVIDER_NAME } from "./broker.server.js";
6
+ export type { StartBrokerServerOptions } from "./broker.server.js";
7
+ export { brokerBaselineGrammar, brokerBaselinePropertyDescription, brokerBaselineResourceDescription, brokerBaselineResourceName, brokerBaselineResourceTemplateDescription, brokerBaselineResourceTemplateName, brokerBaselineToolDescription, brokerGrammarKey, defaultBrokerLocaleResolver, defaultBrokerUserAgentResolver, iterAvailableBrokerGrammars, loadBrokerGrammar, resolveBrokerLocale, resolveBrokerUserAgent, } from "./broker.grammars.js";
8
+ export type { BrokerLocale, BrokerLocaleResolver, BrokerUserAgent, BrokerUserAgentResolver } from "./broker.grammars.js";
9
+ export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport } from "./broker.context.js";
@@ -0,0 +1,7 @@
1
+ export { BrokerInfoBehavior } from "./behaviors/broker.behavior.info.js";
2
+ export { BrokerProvidersBehavior } from "./behaviors/broker.behavior.providers.js";
3
+ export { BrokerInfoAdapter, BROKER_INFO_URI } from "./adapters/broker.adapter.info.js";
4
+ export { BrokerProvidersAdapter, PROVIDERS_URI, PROVIDER_URI_TEMPLATE } from "./adapters/broker.adapter.providers.js";
5
+ export { startBrokerServer, BROKER_PROVIDER_NAME } from "./broker.server.js";
6
+ export { brokerBaselineGrammar, brokerBaselinePropertyDescription, brokerBaselineResourceDescription, brokerBaselineResourceName, brokerBaselineResourceTemplateDescription, brokerBaselineResourceTemplateName, brokerBaselineToolDescription, brokerGrammarKey, defaultBrokerLocaleResolver, defaultBrokerUserAgentResolver, iterAvailableBrokerGrammars, loadBrokerGrammar, resolveBrokerLocale, resolveBrokerUserAgent, } from "./broker.grammars.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/broker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AACtH,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE7E,OAAO,EACH,qBAAqB,EACrB,iCAAiC,EACjC,iCAAiC,EACjC,0BAA0B,EAC1B,yCAAyC,EACzC,kCAAkC,EAClC,6BAA6B,EAC7B,gBAAgB,EAChB,2BAA2B,EAC3B,8BAA8B,EAC9B,2BAA2B,EAC3B,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACzB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Shape of the optional JSON config file consumed by `bin.ts` at startup.
3
+ * Every field is optional. Environment variables (`MCP_BROKER_*`) always win
4
+ * over file values, and file values win over the built-in defaults.
5
+ *
6
+ * @example
7
+ * ```json
8
+ * {
9
+ * "port": 3001,
10
+ * "locale": "fr",
11
+ * "tls": { "cert": "certs/cert.pem", "key": "certs/key.pem" },
12
+ * "stdioUpstreams": [
13
+ * { "name": "fs", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"] }
14
+ * ]
15
+ * }
16
+ * ```
17
+ */
18
+ export interface BrokerConfig {
19
+ /** TCP port. Maps to `MCP_BROKER_PORT`. */
20
+ port?: number;
21
+ /** Bind host. Maps to `MCP_BROKER_HOST`. */
22
+ host?: string;
23
+ /** Force protocol (`http`/`https`) regardless of cert presence. Maps to `MCP_BROKER_PROTOCOL`. */
24
+ protocol?: "http" | "https";
25
+ /** Locale fed to the broker grammar resolver. Maps to `MCP_BROKER_LOCALE`. */
26
+ locale?: string;
27
+ /** Bridge stdin/stdout for a Claude-Desktop-style client. Maps to `MCP_BROKER_STDIO_PROVIDER`. */
28
+ stdioProvider?: string;
29
+ /** Logical broker name reported by `broker_info`. */
30
+ brokerName?: string;
31
+ /** URL paths (override the defaults). */
32
+ paths?: {
33
+ provider?: string;
34
+ providers?: string;
35
+ client?: string;
36
+ mcp?: string;
37
+ sse?: string;
38
+ messages?: string;
39
+ };
40
+ /** TLS material as paths on disk. Resolved against the config file's directory. */
41
+ tls?: {
42
+ cert: string;
43
+ key: string;
44
+ };
45
+ /**
46
+ * Static-file serving alongside the JSON-RPC endpoints. JSON-RPC routes
47
+ * always take precedence.
48
+ */
49
+ www?: {
50
+ /** Auto-launch the default browser at the root URL on startup. */
51
+ open?: boolean;
52
+ /** URL-prefix → directory mappings. Longest-prefix match wins. */
53
+ mounts?: Array<{
54
+ urlPrefix: string;
55
+ dir: string;
56
+ }>;
57
+ };
58
+ /** Stdio upstream providers spawned by the broker at startup. */
59
+ stdioUpstreams?: Array<{
60
+ name: string;
61
+ command: string;
62
+ args?: string[];
63
+ env?: Record<string, string>;
64
+ }>;
65
+ }
66
+ /**
67
+ * Returned by {@link loadBrokerConfig}. The {@link config} is the parsed JSON;
68
+ * {@link baseDir} is the directory used to resolve relative paths inside it
69
+ * (the directory containing the config file when one was found, otherwise
70
+ * `process.cwd()`).
71
+ */
72
+ export interface LoadedBrokerConfig {
73
+ config: BrokerConfig;
74
+ baseDir: string;
75
+ /** Absolute path of the config file that was loaded, or `null` if none. */
76
+ sourcePath: string | null;
77
+ }
78
+ /** Default folder name (relative to `process.cwd()`) holding broker-local files. */
79
+ export declare const DEFAULT_CONFIG_DIR = ".mcp-broker";
80
+ /** Default config filename inside {@link DEFAULT_CONFIG_DIR}. */
81
+ export declare const DEFAULT_CONFIG_FILENAME = "config.json";
82
+ /** Legacy flat config filename at the cwd root (pre-`.mcp-broker/` layout). */
83
+ export declare const LEGACY_CONFIG_FILENAME = "mcp-broker.config.json";
84
+ /**
85
+ * Loads the broker config from a JSON file.
86
+ *
87
+ * Discovery order:
88
+ * 1. The `path` argument when provided (explicit override).
89
+ * 2. The `MCP_BROKER_CONFIG` env var.
90
+ * 3. `./.mcp-broker/config.json` relative to `process.cwd()`.
91
+ * 4. `./mcp-broker.config.json` relative to `process.cwd()` (legacy layout —
92
+ * a deprecation warning is written to stderr).
93
+ *
94
+ * When no file is found, returns the built-in empty config with
95
+ * `baseDir = process.cwd()`. On invalid JSON, logs a warning to stderr and
96
+ * returns the same empty config — never throws.
97
+ *
98
+ * Paths inside the config file are intended to be resolved against
99
+ * {@link LoadedBrokerConfig.baseDir} by the consumer.
100
+ */
101
+ export declare function loadBrokerConfig(path?: string): LoadedBrokerConfig;
package/dist/config.js ADDED
@@ -0,0 +1,61 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ /** Default folder name (relative to `process.cwd()`) holding broker-local files. */
4
+ export const DEFAULT_CONFIG_DIR = ".mcp-broker";
5
+ /** Default config filename inside {@link DEFAULT_CONFIG_DIR}. */
6
+ export const DEFAULT_CONFIG_FILENAME = "config.json";
7
+ /** Legacy flat config filename at the cwd root (pre-`.mcp-broker/` layout). */
8
+ export const LEGACY_CONFIG_FILENAME = "mcp-broker.config.json";
9
+ /**
10
+ * Loads the broker config from a JSON file.
11
+ *
12
+ * Discovery order:
13
+ * 1. The `path` argument when provided (explicit override).
14
+ * 2. The `MCP_BROKER_CONFIG` env var.
15
+ * 3. `./.mcp-broker/config.json` relative to `process.cwd()`.
16
+ * 4. `./mcp-broker.config.json` relative to `process.cwd()` (legacy layout —
17
+ * a deprecation warning is written to stderr).
18
+ *
19
+ * When no file is found, returns the built-in empty config with
20
+ * `baseDir = process.cwd()`. On invalid JSON, logs a warning to stderr and
21
+ * returns the same empty config — never throws.
22
+ *
23
+ * Paths inside the config file are intended to be resolved against
24
+ * {@link LoadedBrokerConfig.baseDir} by the consumer.
25
+ */
26
+ export function loadBrokerConfig(path) {
27
+ const cwd = process.cwd();
28
+ const envPath = process.env["MCP_BROKER_CONFIG"];
29
+ let sourcePath = null;
30
+ if (path) {
31
+ sourcePath = resolve(cwd, path);
32
+ }
33
+ else if (envPath) {
34
+ sourcePath = resolve(cwd, envPath);
35
+ }
36
+ else {
37
+ const modern = resolve(cwd, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME);
38
+ const legacy = resolve(cwd, LEGACY_CONFIG_FILENAME);
39
+ if (existsSync(modern)) {
40
+ sourcePath = modern;
41
+ }
42
+ else if (existsSync(legacy)) {
43
+ sourcePath = legacy;
44
+ process.stderr.write(`[mcp-broker] Using legacy config at ${legacy}. ` + `Move it to ${resolve(cwd, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME)} ` + `to silence this warning.\n`);
45
+ }
46
+ }
47
+ if (!sourcePath || !existsSync(sourcePath)) {
48
+ return { config: {}, baseDir: cwd, sourcePath: null };
49
+ }
50
+ const baseDir = dirname(sourcePath);
51
+ try {
52
+ const raw = readFileSync(sourcePath, "utf-8");
53
+ const config = JSON.parse(raw);
54
+ return { config, baseDir, sourcePath };
55
+ }
56
+ catch (err) {
57
+ process.stderr.write(`[mcp-broker] Failed to parse config file at ${sourcePath}: ${err.message}\n`);
58
+ return { config: {}, baseDir: cwd, sourcePath: null };
59
+ }
60
+ }
61
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0F7C,oFAAoF;AACpF,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAC;AAEhD,iEAAiE;AACjE,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AAErD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAE/D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAEjD,IAAI,UAAU,GAAkB,IAAI,CAAC;IAErC,IAAI,IAAI,EAAE,CAAC;QACP,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;SAAM,IAAI,OAAO,EAAE,CAAC;QACjB,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;SAAM,CAAC;QACJ,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;QACzE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;QACpD,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACrB,UAAU,GAAG,MAAM,CAAC;QACxB,CAAC;aAAM,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,UAAU,GAAG,MAAM,CAAC;YACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,uCAAuC,MAAM,IAAI,GAAG,cAAc,OAAO,CAAC,GAAG,EAAE,kBAAkB,EAAE,uBAAuB,CAAC,GAAG,GAAG,4BAA4B,CAChK,CAAC;QACN,CAAC;IACL,CAAC;IAED,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAEpC,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;QAC/C,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+CAA+C,UAAU,KAAM,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC/G,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC1D,CAAC;AACL,CAAC"}
@@ -0,0 +1,12 @@
1
+ export { WsTunnel } from "./ws.tunnel.js";
2
+ export { WsTunnelBuilder } from "./ws.tunnel.builder.js";
3
+ export type { WsTunnelOptions, StaticMount } from "./ws.tunnel.js";
4
+ export { StdioUpstream } from "./stdio.upstream.js";
5
+ export type { StdioUpstreamConfig } from "./stdio.upstream.js";
6
+ export { BrokerInfoBehavior, BrokerProvidersBehavior, startBrokerServer, BROKER_PROVIDER_NAME } from "./broker/index.js";
7
+ export type { StartBrokerServerOptions } from "./broker/index.js";
8
+ export { brokerGrammarKey, defaultBrokerLocaleResolver, defaultBrokerUserAgentResolver, iterAvailableBrokerGrammars, loadBrokerGrammar, resolveBrokerLocale, resolveBrokerUserAgent, } from "./broker/index.js";
9
+ export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport, BrokerLocale, BrokerLocaleResolver, BrokerUserAgent, BrokerUserAgentResolver } from "./broker/index.js";
10
+ export { VERSION, PACKAGE_NAME } from "./version.js";
11
+ export { loadBrokerConfig, DEFAULT_CONFIG_FILENAME } from "./config.js";
12
+ export type { BrokerConfig } from "./config.js";
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { WsTunnel } from "./ws.tunnel.js";
2
+ export { WsTunnelBuilder } from "./ws.tunnel.builder.js";
3
+ export { StdioUpstream } from "./stdio.upstream.js";
4
+ // Broker introspection — tier 1.
5
+ export { BrokerInfoBehavior, BrokerProvidersBehavior, startBrokerServer, BROKER_PROVIDER_NAME } from "./broker/index.js";
6
+ export { brokerGrammarKey, defaultBrokerLocaleResolver, defaultBrokerUserAgentResolver, iterAvailableBrokerGrammars, loadBrokerGrammar, resolveBrokerLocale, resolveBrokerUserAgent, } from "./broker/index.js";
7
+ export { VERSION, PACKAGE_NAME } from "./version.js";
8
+ // JSON config file used by `bin.ts` at startup. Exported so a programmatic
9
+ // embedder can re-use the same loader against a custom path.
10
+ export { loadBrokerConfig, DEFAULT_CONFIG_FILENAME } from "./config.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,iCAAiC;AACjC,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzH,OAAO,EACH,gBAAgB,EAChB,2BAA2B,EAC3B,8BAA8B,EAC9B,2BAA2B,EAC3B,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAErD,2EAA2E;AAC3E,6DAA6D;AAC7D,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,42 @@
1
+ export interface StdioUpstreamConfig {
2
+ /** Logical name of this provider (matched against incoming WebSocket provider names). */
3
+ name: string;
4
+ /** Executable to spawn (e.g. `"node"`, `"python"`, an absolute path). */
5
+ command: string;
6
+ /** Arguments passed to the command. */
7
+ args?: string[];
8
+ /** Extra environment variables merged with `process.env`. */
9
+ env?: NodeJS.ProcessEnv;
10
+ }
11
+ /**
12
+ * Manages a stdio-based MCP server process.
13
+ * JSON-RPC messages are exchanged over the child process stdin/stdout using
14
+ * newline-delimited framing (matching the MCP SDK stdio transport).
15
+ *
16
+ * One instance per configured provider. The broker uses this to bridge
17
+ * WebSocket/SSE/HTTP clients to local MCP server processes.
18
+ */
19
+ export declare class StdioUpstream {
20
+ readonly name: string;
21
+ private readonly _config;
22
+ private _proc;
23
+ private _buffer;
24
+ private _open;
25
+ private _stopped;
26
+ /** Called when a complete JSON-RPC line arrives from the process stdout. */
27
+ onMessage: ((data: string) => void) | null;
28
+ /** Called when the process has started and stdin is writable. */
29
+ onOpen: (() => void) | null;
30
+ /** Called when the process exits (cleanly or otherwise). */
31
+ onClose: (() => void) | null;
32
+ /** Called on spawn or runtime errors. */
33
+ onError: ((error: Error) => void) | null;
34
+ constructor(config: StdioUpstreamConfig);
35
+ get isOpen(): boolean;
36
+ /** Spawns the child process and wires up stdio listeners. */
37
+ connect(): void;
38
+ /** Sends a JSON-RPC message to the process stdin (appends newline). */
39
+ send(data: string): void;
40
+ /** Kills the child process and prevents further reconnection attempts. */
41
+ close(): void;
42
+ }
@@ -0,0 +1,85 @@
1
+ import { spawn } from "node:child_process";
2
+ // ---------------------------------------------------------------------------
3
+ // StdioUpstream
4
+ // ---------------------------------------------------------------------------
5
+ /**
6
+ * Manages a stdio-based MCP server process.
7
+ * JSON-RPC messages are exchanged over the child process stdin/stdout using
8
+ * newline-delimited framing (matching the MCP SDK stdio transport).
9
+ *
10
+ * One instance per configured provider. The broker uses this to bridge
11
+ * WebSocket/SSE/HTTP clients to local MCP server processes.
12
+ */
13
+ export class StdioUpstream {
14
+ name;
15
+ _config;
16
+ _proc = null;
17
+ _buffer = "";
18
+ _open = false;
19
+ _stopped = false;
20
+ /** Called when a complete JSON-RPC line arrives from the process stdout. */
21
+ onMessage = null;
22
+ /** Called when the process has started and stdin is writable. */
23
+ onOpen = null;
24
+ /** Called when the process exits (cleanly or otherwise). */
25
+ onClose = null;
26
+ /** Called on spawn or runtime errors. */
27
+ onError = null;
28
+ constructor(config) {
29
+ this.name = config.name;
30
+ this._config = config;
31
+ }
32
+ get isOpen() {
33
+ return this._open;
34
+ }
35
+ /** Spawns the child process and wires up stdio listeners. */
36
+ connect() {
37
+ this._stopped = false;
38
+ const { command, args = [], env } = this._config;
39
+ this._proc = spawn(command, args, {
40
+ env: { ...process.env, ...env },
41
+ stdio: ["pipe", "pipe", "inherit"],
42
+ });
43
+ this._proc.on("error", (err) => {
44
+ this._open = false;
45
+ this.onError?.(new Error(`StdioUpstream "${this.name}": process error — ${err.message}`));
46
+ });
47
+ this._proc.on("spawn", () => {
48
+ this._open = true;
49
+ this.onOpen?.();
50
+ });
51
+ this._proc.stdout.on("data", (chunk) => {
52
+ this._buffer += chunk.toString("utf8");
53
+ let nl;
54
+ while ((nl = this._buffer.indexOf("\n")) !== -1) {
55
+ const line = this._buffer.slice(0, nl).trim();
56
+ this._buffer = this._buffer.slice(nl + 1);
57
+ if (line)
58
+ this.onMessage?.(line);
59
+ }
60
+ });
61
+ this._proc.on("close", (code) => {
62
+ this._open = false;
63
+ this._proc = null;
64
+ this.onClose?.();
65
+ if (!this._stopped) {
66
+ this.onError?.(new Error(`StdioUpstream "${this.name}": process exited with code ${code ?? "null"}`));
67
+ }
68
+ });
69
+ }
70
+ /** Sends a JSON-RPC message to the process stdin (appends newline). */
71
+ send(data) {
72
+ if (!this._open || !this._proc?.stdin?.writable)
73
+ return;
74
+ this._proc.stdin.write(data + "\n", "utf8");
75
+ }
76
+ /** Kills the child process and prevents further reconnection attempts. */
77
+ close() {
78
+ this._stopped = true;
79
+ this._open = false;
80
+ this._proc?.stdin?.end();
81
+ this._proc?.kill();
82
+ this._proc = null;
83
+ }
84
+ }
85
+ //# sourceMappingURL=stdio.upstream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.upstream.js","sourceRoot":"","sources":["../src/stdio.upstream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const VERSION: string;
2
+ export declare const PACKAGE_NAME: string;
@@ -0,0 +1,9 @@
1
+ import { createRequire } from "module";
2
+ // Resolves the package's own version from package.json without bundler help.
3
+ // Works both for the compiled dist/version.js (one level below package.json)
4
+ // and for tsc's source-level resolution from src/version.ts.
5
+ const require = createRequire(import.meta.url);
6
+ const pkg = require("../package.json");
7
+ export const VERSION = pkg.version;
8
+ export const PACKAGE_NAME = pkg.name;
9
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAEvC,6EAA6E;AAC7E,6EAA6E;AAC7E,6DAA6D;AAC7D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAsC,CAAC;AAE5E,MAAM,CAAC,MAAM,OAAO,GAAW,GAAG,CAAC,OAAO,CAAC;AAC3C,MAAM,CAAC,MAAM,YAAY,GAAW,GAAG,CAAC,IAAI,CAAC"}
@@ -0,0 +1,133 @@
1
+ import { WsTunnel } from "./ws.tunnel.js";
2
+ /**
3
+ * Fluent builder that constructs a configured {@link WsTunnel}.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * const tunnel = new WsTunnelBuilder()
8
+ * .withPort(3000)
9
+ * .withHost("localhost")
10
+ * .withStaticMount("/", "/abs/path/to/www")
11
+ * .build();
12
+ *
13
+ * await tunnel.start();
14
+ * console.log("Broker listening on ws://localhost:3000");
15
+ * console.log(" Provider connects to: ws://localhost:3000/provider/<name>");
16
+ * console.log(" Clients connect to: ws://localhost:3000/<name>");
17
+ * ```
18
+ */
19
+ export declare class WsTunnelBuilder {
20
+ private _port;
21
+ private _host;
22
+ private _providerPath;
23
+ private _providersPath;
24
+ private _clientPath;
25
+ private _ssePath;
26
+ private _messagesPath;
27
+ private _mcpPath;
28
+ private _samplesIndexPath;
29
+ private _staticMounts;
30
+ private _stdioUpstreams;
31
+ private _stdioClient;
32
+ private _tls;
33
+ private _brokerLocalGrammarsDir;
34
+ /** Sets the TCP port the broker listens on. */
35
+ withPort(port: number): this;
36
+ /**
37
+ * Sets the host/interface to bind to.
38
+ * @default "0.0.0.0" (all interfaces)
39
+ */
40
+ withHost(host: string): this;
41
+ /**
42
+ * Sets the URL path the MCP provider connects to.
43
+ * @default "/provider"
44
+ */
45
+ withProviderPath(path: string): this;
46
+ /**
47
+ * Sets the URL path for multiplexed provider connections.
48
+ * Multiple providers share a single WebSocket using the envelope protocol.
49
+ * @default "/providers"
50
+ */
51
+ withProvidersPath(path: string): this;
52
+ /**
53
+ * Sets the URL path MCP clients connect to.
54
+ * @default "/"
55
+ */
56
+ withClientPath(path: string): this;
57
+ /**
58
+ * Sets the URL path for the SSE stream (legacy Claude transport, GET).
59
+ * @default "/sse"
60
+ */
61
+ withSsePath(path: string): this;
62
+ /**
63
+ * Sets the URL path for JSON-RPC POST requests (legacy Claude transport).
64
+ * @default "/messages"
65
+ */
66
+ withMessagesPath(path: string): this;
67
+ /**
68
+ * Sets the URL path for the Streamable HTTP transport (MCP 2025-03-26).
69
+ * MCP Inspector and other 2025+ clients POST JSON-RPC here.
70
+ * @default "/mcp"
71
+ */
72
+ withMcpPath(path: string): this;
73
+ /**
74
+ * Sets the URL path that returns a `{ files: string[] }` listing of the
75
+ * `samples/` subdirectory under the root static mount.
76
+ * @default "/__samples_index__"
77
+ */
78
+ withSamplesIndexPath(path: string): this;
79
+ /**
80
+ * Adds a static-file mount served over plain HTTP.
81
+ * Can be called multiple times; longest-prefix match wins at runtime.
82
+ *
83
+ * @param urlPrefix URL prefix that triggers this mount (e.g. `"/"` or `"/bundle"`).
84
+ * @param dir Absolute path to the directory to serve.
85
+ */
86
+ withStaticMount(urlPrefix: string, dir: string): this;
87
+ /**
88
+ * Registers a stdio upstream provider. The broker will spawn the given
89
+ * command and bridge its stdin/stdout as an MCP transport.
90
+ * Clients reach it using `name` directly (e.g. `/<name>/mcp`).
91
+ *
92
+ * Can be called multiple times to register multiple providers.
93
+ *
94
+ * @param name Provider name (must be unique across all upstream types).
95
+ * @param command Executable to spawn.
96
+ * @param args Arguments passed to the command.
97
+ * @param env Extra environment variables merged with `process.env`.
98
+ */
99
+ withStdioUpstream(name: string, command: string, args?: string[], env?: NodeJS.ProcessEnv): this;
100
+ /**
101
+ * Enables the stdio client transport. The broker will read JSON-RPC from
102
+ * `process.stdin` and write responses to `process.stdout`, bridging Claude
103
+ * Desktop (or any stdio MCP client) to the named provider.
104
+ *
105
+ * All console output is automatically redirected to stderr in this mode so
106
+ * stdout stays clean for the JSON-RPC stream.
107
+ *
108
+ * @param providerName The provider the stdio client maps to.
109
+ */
110
+ withStdioClient(providerName: string): this;
111
+ /**
112
+ * Enables HTTPS/WSS mode by supplying PEM-encoded certificate and key strings directly.
113
+ * Call this when you already have the PEM content in memory.
114
+ */
115
+ withTls(cert: string, key: string): this;
116
+ /**
117
+ * Enables HTTPS/WSS mode by reading the certificate and key from the given file paths.
118
+ * Files are read synchronously at call time.
119
+ *
120
+ * @param certPath Path to the PEM certificate file (e.g. `fullchain.pem`).
121
+ * @param keyPath Path to the PEM private-key file (e.g. `privkey.pem`).
122
+ */
123
+ withTlsFiles(certPath: string, keyPath: string): this;
124
+ /**
125
+ * Sets the path to a user-supplied grammars directory whose
126
+ * `<userAgent>/<locale>.json` files are merged on top of the packaged
127
+ * grammars used by the embedded broker server (the reserved `_broker`
128
+ * provider slot). Typically pointed at `.mcp-broker/grammars/`.
129
+ */
130
+ withBrokerLocalGrammarsDir(dir: string): this;
131
+ /** Constructs and returns a configured {@link WsTunnel}. */
132
+ build(): WsTunnel;
133
+ }