@cyanmycelium/mcp-broker 0.2.0 → 0.4.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 (71) hide show
  1. package/.mcp-broker.example/README.md +23 -0
  2. package/.mcp-broker.example/config.json +11 -0
  3. package/README.md +1 -16
  4. package/dist/bin.js +30 -3
  5. package/dist/bin.js.map +1 -1
  6. package/dist/broker/aggregate/aggregate.catalog.d.ts +54 -0
  7. package/dist/broker/aggregate/aggregate.catalog.js +105 -0
  8. package/dist/broker/aggregate/aggregate.catalog.js.map +1 -0
  9. package/dist/broker/aggregate/aggregate.server.d.ts +47 -0
  10. package/dist/broker/aggregate/aggregate.server.js +151 -0
  11. package/dist/broker/aggregate/aggregate.server.js.map +1 -0
  12. package/dist/broker/aggregate/provider.client.session.d.ts +52 -0
  13. package/dist/broker/aggregate/provider.client.session.js +140 -0
  14. package/dist/broker/aggregate/provider.client.session.js.map +1 -0
  15. package/dist/broker/broker.grammars.d.ts +50 -86
  16. package/dist/broker/broker.grammars.js +55 -84
  17. package/dist/broker/broker.grammars.js.map +1 -1
  18. package/dist/broker/broker.server.d.ts +23 -21
  19. package/dist/broker/broker.server.js +33 -71
  20. package/dist/broker/broker.server.js.map +1 -1
  21. package/dist/broker/index.d.ts +2 -2
  22. package/dist/broker/index.js +1 -1
  23. package/dist/broker/index.js.map +1 -1
  24. package/dist/config.d.ts +35 -0
  25. package/dist/config.js.map +1 -1
  26. package/dist/index.d.ts +8 -2
  27. package/dist/index.js +5 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcpb.loader.d.ts +24 -0
  30. package/dist/mcpb.loader.js +161 -0
  31. package/dist/mcpb.loader.js.map +1 -0
  32. package/dist/mcpb.unzip.d.ts +6 -0
  33. package/dist/mcpb.unzip.js +95 -0
  34. package/dist/mcpb.unzip.js.map +1 -0
  35. package/dist/remote.transports.d.ts +16 -0
  36. package/dist/remote.transports.js +297 -0
  37. package/dist/remote.transports.js.map +1 -0
  38. package/dist/remote.upstream.d.ts +36 -0
  39. package/dist/remote.upstream.js +52 -0
  40. package/dist/remote.upstream.js.map +1 -0
  41. package/dist/stdio.upstream.d.ts +4 -1
  42. package/dist/stdio.upstream.js.map +1 -1
  43. package/dist/upstream.d.ts +33 -0
  44. package/dist/upstream.js +2 -0
  45. package/dist/upstream.js.map +1 -0
  46. package/dist/ws.tunnel.builder.d.ts +14 -8
  47. package/dist/ws.tunnel.builder.js +17 -9
  48. package/dist/ws.tunnel.builder.js.map +1 -1
  49. package/dist/ws.tunnel.d.ts +85 -22
  50. package/dist/ws.tunnel.js +201 -82
  51. package/dist/ws.tunnel.js.map +1 -1
  52. package/package.json +3 -2
  53. package/scripts/pack-mcpb.mjs +84 -0
  54. package/scripts/sign-bundle.mjs +61 -0
  55. package/src/bin.ts +32 -3
  56. package/src/broker/aggregate/aggregate.catalog.ts +145 -0
  57. package/src/broker/aggregate/aggregate.server.ts +178 -0
  58. package/src/broker/aggregate/provider.client.session.ts +172 -0
  59. package/src/broker/broker.grammars.ts +74 -122
  60. package/src/broker/broker.server.ts +57 -99
  61. package/src/broker/index.ts +3 -5
  62. package/src/config.ts +37 -0
  63. package/src/index.ts +10 -10
  64. package/src/mcpb.loader.ts +186 -0
  65. package/src/mcpb.unzip.ts +103 -0
  66. package/src/remote.transports.ts +316 -0
  67. package/src/remote.upstream.ts +75 -0
  68. package/src/stdio.upstream.ts +4 -1
  69. package/src/upstream.ts +33 -0
  70. package/src/ws.tunnel.builder.ts +19 -9
  71. package/src/ws.tunnel.ts +258 -99
@@ -1,7 +1,7 @@
1
- import { McpGrammar, McpServerBuilder, LoopbackTransport } from "@cyanmycelium/mcp-core";
1
+ import { McpServerBuilder, LoopbackTransport } from "@cyanmycelium/mcp-core";
2
2
  import { BrokerInfoBehavior } from "./behaviors/broker.behavior.info.js";
3
3
  import { BrokerProvidersBehavior } from "./behaviors/broker.behavior.providers.js";
4
- import { brokerGrammarKey, defaultBrokerLocaleResolver, defaultBrokerUserAgentResolver, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom } from "./broker.grammars.js";
4
+ import { iterAvailableBrokerGrammars, iterBrokerGrammarsFrom } from "./broker.grammars.js";
5
5
  /**
6
6
  * Reserved provider slot name under which the broker exposes itself as an MCP
7
7
  * server. Clients reach it via `<host>/_broker/mcp` (or any other client transport).
@@ -27,80 +27,42 @@ export const BROKER_PROVIDER_NAME = "_broker";
27
27
  * loopback transport to attach to the tunnel.
28
28
  */
29
29
  export async function startBrokerServer(context, options = {}) {
30
- const localeResolver = options.localeResolver ?? defaultBrokerLocaleResolver;
31
- const userAgentResolver = options.userAgentResolver ?? defaultBrokerUserAgentResolver;
32
- const localeSource = options.localeSource ?? (() => process.env["MCP_BROKER_LOCALE"]);
33
30
  const [serverEnd, clientEnd] = LoopbackTransport.createPair();
34
- const builder = new McpServerBuilder().withName(BROKER_PROVIDER_NAME).withTransport(serverEnd).register(new BrokerInfoBehavior(context), new BrokerProvidersBehavior(context));
35
- // Discover every grammar by scanning two directories:
36
- // 1. The packaged grammars shipped with the broker.
37
- // 2. Optionally, a user-supplied directory whose entries are merged
38
- // ON TOP of the packaged ones (local wins on conflicts).
39
- //
40
- // Then build the (userAgent × locale) matrix. Within each user-agent,
41
- // the grammar cascades on top of "default:<locale>" so per-user-agent
42
- // files can stay partial.
43
- const defaults = new Map(); // locale → grammar
44
- const overrides = new Map(); // userAgent → locale → grammar
45
- function ingest(entry, isOverride) {
46
- if (entry.userAgent === "default") {
47
- const existing = defaults.get(entry.locale);
48
- const merged = existing && isOverride ? McpGrammar.merge(existing, entry.grammar) : entry.grammar;
49
- defaults.set(entry.locale, merged);
50
- }
51
- else {
52
- let byLocale = overrides.get(entry.userAgent);
53
- if (!byLocale) {
54
- byLocale = new Map();
55
- overrides.set(entry.userAgent, byLocale);
56
- }
57
- const existing = byLocale.get(entry.locale);
58
- const merged = existing && isOverride ? McpGrammar.merge(existing, entry.grammar) : entry.grammar;
59
- byLocale.set(entry.locale, merged);
60
- }
31
+ // Without an initializer, McpServerBuilder reports `version: "0.0.0"` in the
32
+ // `initialize` handshake. Supply the real package version from the context.
33
+ const builder = new McpServerBuilder()
34
+ .withName(BROKER_PROVIDER_NAME)
35
+ .withTransport(serverEnd)
36
+ .withInitializer({
37
+ initialize: () => ({
38
+ protocolVersion: "2024-11-05",
39
+ serverInfo: { name: BROKER_PROVIDER_NAME, version: context.version },
40
+ }),
41
+ })
42
+ .register(new BrokerInfoBehavior(context), new BrokerProvidersBehavior(context));
43
+ // Register every `(userAgent, locale)` JSON found on disk as a raw
44
+ // grammar layer. The candidate-chain resolution in
45
+ // McpServer.initialize (mcp-core@0.3.0) walks the resolver's chain
46
+ // and merges all matching layers — so partial user-agent files no
47
+ // longer need to be pre-merged with the default-locale baseline at
48
+ // boot. Local overrides come after packaged entries; identical keys
49
+ // get overlaid via the registry's last-write-wins.
50
+ for (const entry of iterAvailableBrokerGrammars()) {
51
+ builder.withGrammar(entry.key, entry.grammar);
61
52
  }
62
- for (const entry of iterAvailableBrokerGrammars())
63
- ingest(entry, false);
64
53
  if (options.localGrammarsDir) {
65
- for (const entry of iterBrokerGrammarsFrom(options.localGrammarsDir))
66
- ingest(entry, true);
67
- }
68
- const availableKeys = new Set();
69
- // Register every "default:<locale>" as-is.
70
- for (const [locale, grammar] of defaults) {
71
- const key = brokerGrammarKey("default", locale);
72
- builder.withGrammar(key, grammar);
73
- availableKeys.add(key);
74
- }
75
- // Register every "<userAgent>:<locale>" as merge(default:<locale>, ua:<locale>).
76
- // The user-agent grammar wins per entry; missing entries cascade from default.
77
- for (const [agent, byLocale] of overrides) {
78
- for (const [locale, uaGrammar] of byLocale) {
79
- const baseline = defaults.get(locale);
80
- const merged = baseline ? McpGrammar.merge(baseline, uaGrammar) : uaGrammar;
81
- const key = brokerGrammarKey(agent, locale);
82
- builder.withGrammar(key, merged);
83
- availableKeys.add(key);
54
+ for (const entry of iterBrokerGrammarsFrom(options.localGrammarsDir)) {
55
+ builder.withGrammar(entry.key, entry.grammar);
84
56
  }
85
57
  }
86
- builder.withGrammarResolver((clientInfo) => {
87
- // localeResolver returns the full fallback chain (most specific first),
88
- // ending with the universal "en". The user-agent axis is the broker's
89
- // own concern: per locale, prefer the user-agent-specific grammar, then
90
- // fall back to the "default" agent.
91
- const locales = localeResolver(localeSource());
92
- const userAgent = userAgentResolver(clientInfo);
93
- const userAgents = userAgent === "default" ? ["default"] : [userAgent, "default"];
94
- for (const locale of locales) {
95
- for (const ua of userAgents) {
96
- const key = brokerGrammarKey(ua, locale);
97
- if (availableKeys.has(key))
98
- return key;
99
- }
100
- }
101
- // None of the candidates is on disk → return an empty key. McpServer
102
- // then falls back to the behavior's baseline descriptions (English).
103
- return "";
58
+ // Wire the resolver via mcp-core's declarative helper. The broker
59
+ // ships sensible defaults (locale from MCP_BROKER_LOCALE env, agents
60
+ // from mcp-core's catalogue, BCP-47 narrowing, default:en fallback);
61
+ // anything the host application sets via `grammarResolverOptions`
62
+ // takes precedence.
63
+ builder.withGrammarResolver({
64
+ localeSource: () => process.env["MCP_BROKER_LOCALE"],
65
+ ...(options.grammarResolverOptions ?? {}),
104
66
  });
105
67
  // No reconnect policy → the McpServer does not attempt to reopen the loopback
106
68
  // when WsTunnel.stop() closes it. Clean shutdown.
@@ -1 +1 @@
1
- {"version":3,"file":"broker.server.js","sourceRoot":"","sources":["../../src/broker/broker.server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"broker.server.js","sourceRoot":"","sources":["../../src/broker/broker.server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAG3F;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAwC9C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACnC,OAAsB,EACtB,UAAoC,EAAE;IAKtC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,iBAAiB,CAAC,UAAU,EAAE,CAAC;IAE9D,6EAA6E;IAC7E,4EAA4E;IAC5E,MAAM,OAAO,GAAG,IAAI,gBAAgB,EAAE;SACjC,QAAQ,CAAC,oBAAoB,CAAC;SAC9B,aAAa,CAAC,SAAS,CAAC;SACxB,eAAe,CAAC;QACb,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;YACf,eAAe,EAAE,YAAY;YAC7B,UAAU,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;SACvE,CAAC;KACL,CAAC;SACD,QAAQ,CAAC,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAI,uBAAuB,CAAC,OAAO,CAAC,CAAC,CAAC;IAErF,mEAAmE;IACnE,mDAAmD;IACnD,mEAAmE;IACnE,kEAAkE;IAClE,mEAAmE;IACnE,oEAAoE;IACpE,mDAAmD;IACnD,KAAK,MAAM,KAAK,IAAI,2BAA2B,EAAE,EAAE,CAAC;QAChD,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAC3B,KAAK,MAAM,KAAK,IAAI,sBAAsB,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACnE,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAClD,CAAC;IACL,CAAC;IAED,kEAAkE;IAClE,qEAAqE;IACrE,qEAAqE;IACrE,kEAAkE;IAClE,oBAAoB;IACpB,OAAO,CAAC,mBAAmB,CAAC;QACxB,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACpD,GAAG,CAAC,OAAO,CAAC,sBAAsB,IAAI,EAAE,CAAC;KAC5C,CAAC,CAAC;IAEH,8EAA8E;IAC9E,kDAAkD;IAClD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAE/B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IAErB,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;AAClD,CAAC"}
@@ -4,6 +4,6 @@ export { BrokerInfoAdapter, BROKER_INFO_URI } from "./adapters/broker.adapter.in
4
4
  export { BrokerProvidersAdapter, PROVIDERS_URI, PROVIDER_URI_TEMPLATE } from "./adapters/broker.adapter.providers.js";
5
5
  export { startBrokerServer, BROKER_PROVIDER_NAME } from "./broker.server.js";
6
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";
7
+ export { brokerBaselineGrammar, brokerBaselinePropertyDescription, brokerBaselineResourceDescription, brokerBaselineResourceName, brokerBaselineResourceTemplateDescription, brokerBaselineResourceTemplateName, brokerBaselineToolDescription, brokerGrammarKey, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar, parseBrokerGrammarStem, } from "./broker.grammars.js";
8
+ export type { BrokerGrammarEntry, BrokerLocale, BrokerUserAgent } from "./broker.grammars.js";
9
9
  export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport } from "./broker.context.js";
@@ -3,5 +3,5 @@ export { BrokerProvidersBehavior } from "./behaviors/broker.behavior.providers.j
3
3
  export { BrokerInfoAdapter, BROKER_INFO_URI } from "./adapters/broker.adapter.info.js";
4
4
  export { BrokerProvidersAdapter, PROVIDERS_URI, PROVIDER_URI_TEMPLATE } from "./adapters/broker.adapter.providers.js";
5
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";
6
+ export { brokerBaselineGrammar, brokerBaselinePropertyDescription, brokerBaselineResourceDescription, brokerBaselineResourceName, brokerBaselineResourceTemplateDescription, brokerBaselineResourceTemplateName, brokerBaselineToolDescription, brokerGrammarKey, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar, parseBrokerGrammarStem, } from "./broker.grammars.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -1 +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"}
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,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACzB,MAAM,sBAAsB,CAAC"}
package/dist/config.d.ts CHANGED
@@ -61,6 +61,41 @@ export interface BrokerConfig {
61
61
  command: string;
62
62
  args?: string[];
63
63
  env?: Record<string, string>;
64
+ /** When `true`, the upstream joins the `_all` aggregate slot once connected. */
65
+ aggregate?: boolean;
66
+ }>;
67
+ /**
68
+ * Remote MCP servers the broker connects out to and exposes as provider
69
+ * slots. Each entry is reached by URL (Streamable HTTP / SSE / WebSocket);
70
+ * local servers should be shipped as `.mcpb` bundles instead.
71
+ */
72
+ mcpServers?: Array<{
73
+ name: string;
74
+ url: string;
75
+ transport?: "streamable-http" | "sse" | "websocket";
76
+ headers?: Record<string, string>;
77
+ /** Defaults to `true`; set to `false` to exclude this upstream from the `_all` aggregate slot. */
78
+ aggregate?: boolean;
79
+ }>;
80
+ /**
81
+ * Local `.mcpb` bundles the broker loads at startup and runs as stdio
82
+ * provider slots. A bundle is a ZIP with a `manifest.json`; the broker
83
+ * verifies a detached signature against a trusted public key before
84
+ * unpacking and spawning it.
85
+ */
86
+ mcpbBundles?: Array<{
87
+ /** Provider slot name the bundle is bound to. */
88
+ name: string;
89
+ /** Path to the `.mcpb` file (resolved against the config file's directory). */
90
+ path: string;
91
+ /** Path to the trusted public key (PEM) used to verify the detached signature. */
92
+ publicKey: string;
93
+ /** Path to the detached signature file. Defaults to `<path>.sig`. */
94
+ signature?: string;
95
+ /** Values substituted into the manifest's `${user_config.*}` placeholders. */
96
+ userConfig?: Record<string, string | number | boolean | Array<string | number>>;
97
+ /** Defaults to `true`; set to `false` to exclude this bundle from the `_all` aggregate slot. */
98
+ aggregate?: boolean;
64
99
  }>;
65
100
  }
66
101
  /**
@@ -1 +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"}
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;AA+H7C,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"}
package/dist/index.d.ts CHANGED
@@ -3,10 +3,16 @@ export { WsTunnelBuilder } from "./ws.tunnel.builder.js";
3
3
  export type { WsTunnelOptions, StaticMount } from "./ws.tunnel.js";
4
4
  export { StdioUpstream } from "./stdio.upstream.js";
5
5
  export type { StdioUpstreamConfig } from "./stdio.upstream.js";
6
+ export { RemoteUpstream } from "./remote.upstream.js";
7
+ export type { RemoteUpstreamConfig } from "./remote.upstream.js";
8
+ export type { Upstream } from "./upstream.js";
9
+ export { loadMcpbBundle } from "./mcpb.loader.js";
10
+ export type { McpbBundleConfig } from "./mcpb.loader.js";
11
+ export { unzipMcpb } from "./mcpb.unzip.js";
6
12
  export { BrokerInfoBehavior, BrokerProvidersBehavior, startBrokerServer, BROKER_PROVIDER_NAME } from "./broker/index.js";
7
13
  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";
14
+ export { brokerGrammarKey, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar } from "./broker/index.js";
15
+ export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport, BrokerLocale, BrokerUserAgent } from "./broker/index.js";
10
16
  export { VERSION, PACKAGE_NAME } from "./version.js";
11
17
  export { loadBrokerConfig, DEFAULT_CONFIG_FILENAME } from "./config.js";
12
18
  export type { BrokerConfig } from "./config.js";
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  export { WsTunnel } from "./ws.tunnel.js";
2
2
  export { WsTunnelBuilder } from "./ws.tunnel.builder.js";
3
3
  export { StdioUpstream } from "./stdio.upstream.js";
4
+ export { RemoteUpstream } from "./remote.upstream.js";
5
+ // `.mcpb` bundle loading — verifies + unpacks a bundle into a stdio upstream.
6
+ export { loadMcpbBundle } from "./mcpb.loader.js";
7
+ export { unzipMcpb } from "./mcpb.unzip.js";
4
8
  // Broker introspection — tier 1.
5
9
  export { BrokerInfoBehavior, BrokerProvidersBehavior, startBrokerServer, BROKER_PROVIDER_NAME } from "./broker/index.js";
6
- export { brokerGrammarKey, defaultBrokerLocaleResolver, defaultBrokerUserAgentResolver, iterAvailableBrokerGrammars, loadBrokerGrammar, resolveBrokerLocale, resolveBrokerUserAgent, } from "./broker/index.js";
10
+ export { brokerGrammarKey, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar } from "./broker/index.js";
7
11
  export { VERSION, PACKAGE_NAME } from "./version.js";
8
12
  // JSON config file used by `bin.ts` at startup. Exported so a programmatic
9
13
  // embedder can re-use the same loader against a custom path.
package/dist/index.js.map CHANGED
@@ -1 +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"}
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;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,8EAA8E;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,iCAAiC;AACjC,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzH,OAAO,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG7H,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,24 @@
1
+ import type { StdioUpstreamConfig } from "./stdio.upstream.js";
2
+ /** A `.mcpb` bundle entry from the broker config file. */
3
+ export interface McpbBundleConfig {
4
+ /** Provider slot name the bundle is bound to. */
5
+ name: string;
6
+ /** Path to the `.mcpb` file. */
7
+ path: string;
8
+ /** Path to the trusted public key (PEM) verifying the detached signature. */
9
+ publicKey: string;
10
+ /** Path to the detached signature file. Defaults to `<path>.sig`. */
11
+ signature?: string;
12
+ /** Values substituted into the manifest's `${user_config.*}` placeholders. */
13
+ userConfig?: Record<string, string | number | boolean | Array<string | number>>;
14
+ /** When `false`, the bundle stays out of the `_all` aggregate slot. Defaults to `true`. */
15
+ aggregate?: boolean;
16
+ }
17
+ /**
18
+ * Verifies, unpacks and resolves a `.mcpb` bundle into a `StdioUpstreamConfig`.
19
+ *
20
+ * @param cfg The bundle entry from the broker config.
21
+ * @param baseDir Directory the bundle paths are resolved against.
22
+ * @returns A ready upstream config, or `null` when the bundle is refused.
23
+ */
24
+ export declare function loadMcpbBundle(cfg: McpbBundleConfig, baseDir: string): Promise<StdioUpstreamConfig | null>;
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Loads a local `.mcpb` bundle into a {@link StdioUpstreamConfig}.
3
+ *
4
+ * A `.mcpb` bundle is a ZIP holding a `manifest.json` whose `server.mcp_config`
5
+ * describes a stdio MCP server process. The broker:
6
+ *
7
+ * 1. verifies a **detached signature** of the `.mcpb` file against a trusted
8
+ * public key (PEM) — integrity *and* provenance, using `node:crypto` only;
9
+ * 2. unpacks the archive;
10
+ * 3. reads the manifest, expands the `mcp_config` placeholders, and produces a
11
+ * `StdioUpstreamConfig` that the existing upstream wiring spawns.
12
+ *
13
+ * The broker stays compatible with the `.mcpb` format without depending on the
14
+ * `@anthropic-ai/mcpb` package: the bundle's *own* (native PKCS#7) signature is
15
+ * never parsed — the detached signature layer is the broker's trust anchor.
16
+ *
17
+ * Any failure (missing files, bad signature, malformed manifest, missing
18
+ * `user_config` value) is logged and yields `null`: the bundle is refused and
19
+ * no process is ever spawned. Never auto-runs an unverified bundle.
20
+ */
21
+ import { createPublicKey, verify, X509Certificate } from "node:crypto";
22
+ import { existsSync, readFileSync, rmSync } from "node:fs";
23
+ import { homedir } from "node:os";
24
+ import { join, resolve, sep } from "node:path";
25
+ import { unzipMcpb } from "./mcpb.unzip.js";
26
+ /** Loads a PEM that holds either an X.509 certificate or a bare public key. */
27
+ function loadPublicKey(pem) {
28
+ if (pem.includes("BEGIN CERTIFICATE")) {
29
+ return new X509Certificate(pem).publicKey;
30
+ }
31
+ return createPublicKey(pem);
32
+ }
33
+ /** Verifies the detached `signature` of `data` against `publicKey`. */
34
+ function verifyDetachedSignature(data, signature, publicKey) {
35
+ // Ed25519/Ed448 are used without a separate hash algorithm; RSA/EC need one.
36
+ const keyType = publicKey.asymmetricKeyType;
37
+ const algorithm = keyType === "ed25519" || keyType === "ed448" ? null : "sha256";
38
+ return verify(algorithm, data, publicKey, signature);
39
+ }
40
+ /** Resolves a single `${...}` placeholder key, or `undefined` when unknown. */
41
+ function resolvePlaceholder(key, dirname, userConfig) {
42
+ if (key === "__dirname")
43
+ return dirname;
44
+ if (key === "HOME")
45
+ return homedir();
46
+ if (key === "DESKTOP")
47
+ return join(homedir(), "Desktop");
48
+ if (key === "DOCUMENTS")
49
+ return join(homedir(), "Documents");
50
+ if (key === "DOWNLOADS")
51
+ return join(homedir(), "Downloads");
52
+ if (key === "pathSeparator" || key === "/")
53
+ return sep;
54
+ if (key.startsWith("user_config.")) {
55
+ const name = key.slice("user_config.".length);
56
+ const value = userConfig?.[name];
57
+ if (value === undefined)
58
+ throw new Error(`missing user_config value: "${name}"`);
59
+ return value;
60
+ }
61
+ return undefined;
62
+ }
63
+ /** Expands placeholders in a scalar string (command, env value). */
64
+ function expandScalar(input, dirname, userConfig) {
65
+ return input.replace(/\$\{([^}]+)\}/g, (match, key) => {
66
+ const value = resolvePlaceholder(key, dirname, userConfig);
67
+ if (value === undefined)
68
+ return match; // unknown placeholder — leave verbatim
69
+ if (Array.isArray(value))
70
+ throw new Error(`placeholder "\${${key}}" is multi-valued and cannot be used here`);
71
+ return String(value);
72
+ });
73
+ }
74
+ /** Expands one manifest argument; a standalone multi-valued placeholder spreads. */
75
+ function expandArg(arg, dirname, userConfig) {
76
+ const standalone = /^\$\{(user_config\.[^}]+)\}$/.exec(arg);
77
+ if (standalone) {
78
+ const value = resolvePlaceholder(standalone[1], dirname, userConfig);
79
+ if (Array.isArray(value))
80
+ return value.map(String);
81
+ return [String(value)];
82
+ }
83
+ return [expandScalar(arg, dirname, userConfig)];
84
+ }
85
+ /**
86
+ * Verifies, unpacks and resolves a `.mcpb` bundle into a `StdioUpstreamConfig`.
87
+ *
88
+ * @param cfg The bundle entry from the broker config.
89
+ * @param baseDir Directory the bundle paths are resolved against.
90
+ * @returns A ready upstream config, or `null` when the bundle is refused.
91
+ */
92
+ export async function loadMcpbBundle(cfg, baseDir) {
93
+ const tag = `[mcp-broker] mcpb bundle "${cfg.name}"`;
94
+ try {
95
+ const mcpbPath = resolve(baseDir, cfg.path);
96
+ const publicKeyPath = resolve(baseDir, cfg.publicKey);
97
+ const signaturePath = cfg.signature ? resolve(baseDir, cfg.signature) : `${mcpbPath}.sig`;
98
+ for (const [label, file] of [
99
+ ["bundle", mcpbPath],
100
+ ["public key", publicKeyPath],
101
+ ["signature", signaturePath],
102
+ ]) {
103
+ if (!existsSync(file)) {
104
+ console.error(`${tag}: ${label} file not found at ${file} — bundle refused.`);
105
+ return null;
106
+ }
107
+ }
108
+ // ── Signature verification (mandatory) ──────────────────────────────
109
+ const bundleBytes = readFileSync(mcpbPath);
110
+ const signatureBytes = readFileSync(signaturePath);
111
+ const publicKey = loadPublicKey(readFileSync(publicKeyPath, "utf8"));
112
+ if (!verifyDetachedSignature(bundleBytes, signatureBytes, publicKey)) {
113
+ console.error(`${tag}: detached signature is invalid for the configured public key — bundle refused.`);
114
+ return null;
115
+ }
116
+ // ── Unpack ──────────────────────────────────────────────────────────
117
+ const outputDir = resolve(baseDir, ".cache", "mcpb", cfg.name);
118
+ rmSync(outputDir, { recursive: true, force: true });
119
+ unzipMcpb(mcpbPath, outputDir);
120
+ // ── Manifest → mcp_config ───────────────────────────────────────────
121
+ const manifestPath = join(outputDir, "manifest.json");
122
+ if (!existsSync(manifestPath)) {
123
+ console.error(`${tag}: manifest.json missing inside the bundle — bundle refused.`);
124
+ return null;
125
+ }
126
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
127
+ const mcpConfig = manifest.server?.mcp_config;
128
+ if (!mcpConfig) {
129
+ console.error(`${tag}: manifest has no server.mcp_config — bundle refused.`);
130
+ return null;
131
+ }
132
+ // Platform-specific overrides replace the base fields when present.
133
+ const override = mcpConfig.platform_overrides?.[process.platform];
134
+ const command = override?.command ?? mcpConfig.command;
135
+ const rawArgs = override?.args ?? mcpConfig.args ?? [];
136
+ const rawEnv = { ...mcpConfig.env, ...override?.env };
137
+ if (!command) {
138
+ console.error(`${tag}: manifest mcp_config has no command — bundle refused.`);
139
+ return null;
140
+ }
141
+ // ── Placeholder expansion ───────────────────────────────────────────
142
+ const expandedCommand = expandScalar(command, outputDir, cfg.userConfig);
143
+ const expandedArgs = rawArgs.flatMap((arg) => expandArg(arg, outputDir, cfg.userConfig));
144
+ const expandedEnv = {};
145
+ for (const [key, value] of Object.entries(rawEnv)) {
146
+ expandedEnv[key] = expandScalar(value, outputDir, cfg.userConfig);
147
+ }
148
+ return {
149
+ name: cfg.name,
150
+ command: expandedCommand,
151
+ args: expandedArgs,
152
+ env: Object.keys(expandedEnv).length > 0 ? expandedEnv : undefined,
153
+ aggregate: cfg.aggregate ?? true,
154
+ };
155
+ }
156
+ catch (err) {
157
+ console.error(`${tag}: ${err.message} — bundle refused.`);
158
+ return null;
159
+ }
160
+ }
161
+ //# sourceMappingURL=mcpb.loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpb.loader.js","sourceRoot":"","sources":["../src/mcpb.loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Extracts every entry of the `.mcpb` archive at `mcpbPath` into `destDir`.
3
+ * `destDir` is created if missing. Entries whose resolved path would escape
4
+ * `destDir` (zip-slip) are rejected.
5
+ */
6
+ export declare function unzipMcpb(mcpbPath: string, destDir: string): void;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Minimal ZIP extractor for `.mcpb` bundles, built on `node:zlib` only.
3
+ *
4
+ * A `.mcpb` bundle is an ordinary ZIP archive. The broker deliberately avoids
5
+ * the `@anthropic-ai/mcpb` package so it stays compatible with the format
6
+ * without being coupled to Anthropic's tooling — hence this small reader.
7
+ *
8
+ * Supports the two compression methods used in practice: stored (0) and
9
+ * deflate (8). ZIP64 archives are rejected with a clear error (`.mcpb` bundles
10
+ * are small and never need it). Any trailing bytes after the End Of Central
11
+ * Directory record — e.g. a native PKCS#7 signature block — are ignored, since
12
+ * extraction is driven entirely by the central directory.
13
+ */
14
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
15
+ import { dirname, isAbsolute, relative, resolve } from "node:path";
16
+ import { inflateRawSync } from "node:zlib";
17
+ const EOCD_SIGNATURE = 0x06054b50;
18
+ const CENTRAL_HEADER_SIGNATURE = 0x02014b50;
19
+ const LOCAL_HEADER_SIGNATURE = 0x04034b50;
20
+ /** Locates the End Of Central Directory record by scanning backwards. */
21
+ function findEocd(buf) {
22
+ // The EOCD is 22 bytes plus a comment of up to 65535 bytes.
23
+ const minPos = Math.max(0, buf.length - 22 - 0xffff);
24
+ for (let pos = buf.length - 22; pos >= minPos; pos--) {
25
+ if (buf.readUInt32LE(pos) === EOCD_SIGNATURE)
26
+ return pos;
27
+ }
28
+ throw new Error("not a ZIP archive (no End Of Central Directory record found)");
29
+ }
30
+ /**
31
+ * Extracts every entry of the `.mcpb` archive at `mcpbPath` into `destDir`.
32
+ * `destDir` is created if missing. Entries whose resolved path would escape
33
+ * `destDir` (zip-slip) are rejected.
34
+ */
35
+ export function unzipMcpb(mcpbPath, destDir) {
36
+ const buf = readFileSync(mcpbPath);
37
+ const eocd = findEocd(buf);
38
+ const totalEntries = buf.readUInt16LE(eocd + 10);
39
+ const centralDirOffset = buf.readUInt32LE(eocd + 16);
40
+ if (centralDirOffset === 0xffffffff || totalEntries === 0xffff) {
41
+ throw new Error("ZIP64 archives are not supported");
42
+ }
43
+ const absDest = resolve(destDir);
44
+ mkdirSync(absDest, { recursive: true });
45
+ let pos = centralDirOffset;
46
+ for (let i = 0; i < totalEntries; i++) {
47
+ if (buf.readUInt32LE(pos) !== CENTRAL_HEADER_SIGNATURE) {
48
+ throw new Error(`corrupt ZIP: bad central directory header at offset ${pos}`);
49
+ }
50
+ const method = buf.readUInt16LE(pos + 10);
51
+ const compressedSize = buf.readUInt32LE(pos + 20);
52
+ const uncompressedSize = buf.readUInt32LE(pos + 24);
53
+ const nameLen = buf.readUInt16LE(pos + 28);
54
+ const extraLen = buf.readUInt16LE(pos + 30);
55
+ const commentLen = buf.readUInt16LE(pos + 32);
56
+ const localHeaderOffset = buf.readUInt32LE(pos + 42);
57
+ const name = buf.toString("utf8", pos + 46, pos + 46 + nameLen);
58
+ pos += 46 + nameLen + extraLen + commentLen;
59
+ if (compressedSize === 0xffffffff || uncompressedSize === 0xffffffff || localHeaderOffset === 0xffffffff) {
60
+ throw new Error("ZIP64 archives are not supported");
61
+ }
62
+ // Resolve the destination path and reject zip-slip escapes.
63
+ const target = resolve(absDest, name);
64
+ const rel = relative(absDest, target);
65
+ if (rel.startsWith("..") || isAbsolute(rel)) {
66
+ throw new Error(`unsafe ZIP entry path (zip-slip): ${name}`);
67
+ }
68
+ // Directory entry.
69
+ if (name.endsWith("/")) {
70
+ mkdirSync(target, { recursive: true });
71
+ continue;
72
+ }
73
+ // Parse the local header to locate the entry's data.
74
+ if (buf.readUInt32LE(localHeaderOffset) !== LOCAL_HEADER_SIGNATURE) {
75
+ throw new Error(`corrupt ZIP: bad local header for "${name}"`);
76
+ }
77
+ const localNameLen = buf.readUInt16LE(localHeaderOffset + 26);
78
+ const localExtraLen = buf.readUInt16LE(localHeaderOffset + 28);
79
+ const dataStart = localHeaderOffset + 30 + localNameLen + localExtraLen;
80
+ const compressed = buf.subarray(dataStart, dataStart + compressedSize);
81
+ let data;
82
+ if (method === 0) {
83
+ data = compressed;
84
+ }
85
+ else if (method === 8) {
86
+ data = inflateRawSync(compressed);
87
+ }
88
+ else {
89
+ throw new Error(`unsupported ZIP compression method ${method} for "${name}"`);
90
+ }
91
+ mkdirSync(dirname(target), { recursive: true });
92
+ writeFileSync(target, data);
93
+ }
94
+ }
95
+ //# sourceMappingURL=mcpb.unzip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpb.unzip.js","sourceRoot":"","sources":["../src/mcpb.unzip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /** Lifecycle + callbacks shared by every remote client transport. */
2
+ export interface RemoteTransport {
3
+ onMessage: ((data: string) => void) | null;
4
+ onOpen: (() => void) | null;
5
+ onClose: (() => void) | null;
6
+ onError: ((error: Error) => void) | null;
7
+ connect(): void;
8
+ send(data: string): void;
9
+ close(): void;
10
+ }
11
+ /** The three supported remote transports. */
12
+ export type RemoteTransportKind = "streamable-http" | "sse" | "websocket";
13
+ /** Builds the transport of the given kind. */
14
+ export declare function createRemoteTransport(url: string, kind: RemoteTransportKind, headers: Record<string, string>): RemoteTransport;
15
+ /** Heuristic transport detection from the URL when none is configured. */
16
+ export declare function detectTransport(url: string): RemoteTransportKind;