@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.
- package/.mcp-broker.example/README.md +23 -0
- package/.mcp-broker.example/config.json +11 -0
- package/README.md +1 -16
- package/dist/bin.js +30 -3
- package/dist/bin.js.map +1 -1
- package/dist/broker/aggregate/aggregate.catalog.d.ts +54 -0
- package/dist/broker/aggregate/aggregate.catalog.js +105 -0
- package/dist/broker/aggregate/aggregate.catalog.js.map +1 -0
- package/dist/broker/aggregate/aggregate.server.d.ts +47 -0
- package/dist/broker/aggregate/aggregate.server.js +151 -0
- package/dist/broker/aggregate/aggregate.server.js.map +1 -0
- package/dist/broker/aggregate/provider.client.session.d.ts +52 -0
- package/dist/broker/aggregate/provider.client.session.js +140 -0
- package/dist/broker/aggregate/provider.client.session.js.map +1 -0
- package/dist/broker/broker.grammars.d.ts +50 -86
- package/dist/broker/broker.grammars.js +55 -84
- package/dist/broker/broker.grammars.js.map +1 -1
- package/dist/broker/broker.server.d.ts +23 -21
- package/dist/broker/broker.server.js +33 -71
- package/dist/broker/broker.server.js.map +1 -1
- package/dist/broker/index.d.ts +2 -2
- package/dist/broker/index.js +1 -1
- package/dist/broker/index.js.map +1 -1
- package/dist/config.d.ts +35 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/mcpb.loader.d.ts +24 -0
- package/dist/mcpb.loader.js +161 -0
- package/dist/mcpb.loader.js.map +1 -0
- package/dist/mcpb.unzip.d.ts +6 -0
- package/dist/mcpb.unzip.js +95 -0
- package/dist/mcpb.unzip.js.map +1 -0
- package/dist/remote.transports.d.ts +16 -0
- package/dist/remote.transports.js +297 -0
- package/dist/remote.transports.js.map +1 -0
- package/dist/remote.upstream.d.ts +36 -0
- package/dist/remote.upstream.js +52 -0
- package/dist/remote.upstream.js.map +1 -0
- package/dist/stdio.upstream.d.ts +4 -1
- package/dist/stdio.upstream.js.map +1 -1
- package/dist/upstream.d.ts +33 -0
- package/dist/upstream.js +2 -0
- package/dist/upstream.js.map +1 -0
- package/dist/ws.tunnel.builder.d.ts +14 -8
- package/dist/ws.tunnel.builder.js +17 -9
- package/dist/ws.tunnel.builder.js.map +1 -1
- package/dist/ws.tunnel.d.ts +85 -22
- package/dist/ws.tunnel.js +201 -82
- package/dist/ws.tunnel.js.map +1 -1
- package/package.json +3 -2
- package/scripts/pack-mcpb.mjs +84 -0
- package/scripts/sign-bundle.mjs +61 -0
- package/src/bin.ts +32 -3
- package/src/broker/aggregate/aggregate.catalog.ts +145 -0
- package/src/broker/aggregate/aggregate.server.ts +178 -0
- package/src/broker/aggregate/provider.client.session.ts +172 -0
- package/src/broker/broker.grammars.ts +74 -122
- package/src/broker/broker.server.ts +57 -99
- package/src/broker/index.ts +3 -5
- package/src/config.ts +37 -0
- package/src/index.ts +10 -10
- package/src/mcpb.loader.ts +186 -0
- package/src/mcpb.unzip.ts +103 -0
- package/src/remote.transports.ts +316 -0
- package/src/remote.upstream.ts +75 -0
- package/src/stdio.upstream.ts +4 -1
- package/src/upstream.ts +33 -0
- package/src/ws.tunnel.builder.ts +19 -9
- package/src/ws.tunnel.ts +258 -99
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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":"AAAA,OAAO,EAAE,
|
|
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"}
|
package/dist/broker/index.d.ts
CHANGED
|
@@ -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,
|
|
8
|
-
export type {
|
|
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";
|
package/dist/broker/index.js
CHANGED
|
@@ -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,
|
|
6
|
+
export { brokerBaselineGrammar, brokerBaselinePropertyDescription, brokerBaselineResourceDescription, brokerBaselineResourceName, brokerBaselineResourceTemplateDescription, brokerBaselineResourceTemplateName, brokerBaselineToolDescription, brokerGrammarKey, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar, parseBrokerGrammarStem, } from "./broker.grammars.js";
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/dist/broker/index.js.map
CHANGED
|
@@ -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,
|
|
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
|
/**
|
package/dist/config.js.map
CHANGED
|
@@ -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;
|
|
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,
|
|
9
|
-
export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport, BrokerLocale,
|
|
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,
|
|
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;
|
|
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;
|