@cyanmycelium/mcp-broker 0.3.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/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 +21 -70
- 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/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/ws.tunnel.d.ts +18 -20
- package/dist/ws.tunnel.js +1 -3
- package/dist/ws.tunnel.js.map +1 -1
- package/package.json +2 -2
- package/src/broker/broker.grammars.ts +74 -122
- package/src/broker/broker.server.ts +44 -97
- package/src/broker/index.ts +3 -5
- package/src/index.ts +2 -10
- package/src/ws.tunnel.ts +19 -25
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { IMcpServer, IMessageTransport } from "@cyanmycelium/mcp-core";
|
|
1
|
+
import { McpServerBuilder, LoopbackTransport } from "@cyanmycelium/mcp-core";
|
|
2
|
+
import type { GrammarResolverOptions, IMcpServer, IMessageTransport } from "@cyanmycelium/mcp-core";
|
|
3
3
|
import { BrokerInfoBehavior } from "./behaviors/broker.behavior.info.js";
|
|
4
4
|
import { BrokerProvidersBehavior } from "./behaviors/broker.behavior.providers.js";
|
|
5
|
-
import {
|
|
6
|
-
import type { BrokerLocaleResolver, BrokerUserAgent, BrokerUserAgentResolver } from "./broker.grammars.js";
|
|
5
|
+
import { iterAvailableBrokerGrammars, iterBrokerGrammarsFrom } from "./broker.grammars.js";
|
|
7
6
|
import type { BrokerContext } from "./broker.context.js";
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -22,32 +21,33 @@ export const BROKER_PROVIDER_NAME = "_broker";
|
|
|
22
21
|
*/
|
|
23
22
|
export interface StartBrokerServerOptions {
|
|
24
23
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Source of the raw locale string fed to the locale resolver. Defaults
|
|
40
|
-
* to `process.env.MCP_BROKER_LOCALE`. Override when the locale lives
|
|
41
|
-
* somewhere else (config file, session metadata, HTTP header proxy, ...).
|
|
24
|
+
* Overrides for the built-in grammar resolver from `@cyanmycelium/mcp-core`.
|
|
25
|
+
*
|
|
26
|
+
* The broker installs sensible defaults: `localeSource` reads
|
|
27
|
+
* `process.env.MCP_BROKER_LOCALE`, the `agents` map uses the mcp-core
|
|
28
|
+
* defaults (`claude`, `gpt`, `mistral`, `copilot`, `default`), the
|
|
29
|
+
* narrowing chain is BCP-47-style, and `fallbackKey` is `default:en`
|
|
30
|
+
* so the baseline grammar always matches as last resort.
|
|
31
|
+
*
|
|
32
|
+
* Pass partial overrides here to inject a custom `localeSource` (e.g.
|
|
33
|
+
* pull from an HTTP header proxied by your transport), enable the
|
|
34
|
+
* `versionFrom` dimension, or extend the `agents` map with additional
|
|
35
|
+
* LLM families. Anything you omit keeps the broker default.
|
|
42
36
|
*/
|
|
43
|
-
|
|
37
|
+
grammarResolverOptions?: Partial<GrammarResolverOptions>;
|
|
44
38
|
|
|
45
39
|
/**
|
|
46
40
|
* Path to a user-supplied grammars directory whose `<userAgent>/<locale>.json`
|
|
47
|
-
* files are
|
|
48
|
-
*
|
|
41
|
+
* files are registered **in addition to** the packaged grammars.
|
|
42
|
+
*
|
|
43
|
+
* Both packaged and local entries are registered raw against the server
|
|
44
|
+
* via `withGrammar(brokerGrammarKey(ua, locale), grammar)`. The
|
|
45
|
+
* candidate-chain resolution implemented by `McpServer.initialize` in
|
|
46
|
+
* mcp-core@0.3.0 then walks the chain and merges the four layers
|
|
47
|
+
* (behavior, adapter, static, store) for the first matching key —
|
|
48
|
+
* the old hand-rolled pre-merge cascade is no longer needed.
|
|
49
49
|
*
|
|
50
|
-
* When `undefined` (default), only the packaged grammars are
|
|
50
|
+
* When `undefined` (default), only the packaged grammars are loaded.
|
|
51
51
|
*/
|
|
52
52
|
localGrammarsDir?: string;
|
|
53
53
|
}
|
|
@@ -75,10 +75,6 @@ export async function startBrokerServer(
|
|
|
75
75
|
server: IMcpServer;
|
|
76
76
|
clientTransport: IMessageTransport;
|
|
77
77
|
}> {
|
|
78
|
-
const localeResolver = options.localeResolver ?? defaultBrokerLocaleResolver;
|
|
79
|
-
const userAgentResolver = options.userAgentResolver ?? defaultBrokerUserAgentResolver;
|
|
80
|
-
const localeSource = options.localeSource ?? (() => process.env["MCP_BROKER_LOCALE"]);
|
|
81
|
-
|
|
82
78
|
const [serverEnd, clientEnd] = LoopbackTransport.createPair();
|
|
83
79
|
|
|
84
80
|
// Without an initializer, McpServerBuilder reports `version: "0.0.0"` in the
|
|
@@ -94,79 +90,30 @@ export async function startBrokerServer(
|
|
|
94
90
|
})
|
|
95
91
|
.register(new BrokerInfoBehavior(context), new BrokerProvidersBehavior(context));
|
|
96
92
|
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const overrides = new Map<BrokerUserAgent, Map<string, McpGrammar>>(); // userAgent → locale → grammar
|
|
107
|
-
|
|
108
|
-
function ingest(entry: { userAgent: BrokerUserAgent; locale: string; grammar: McpGrammar }, isOverride: boolean): void {
|
|
109
|
-
if (entry.userAgent === "default") {
|
|
110
|
-
const existing = defaults.get(entry.locale);
|
|
111
|
-
const merged = existing && isOverride ? McpGrammar.merge(existing, entry.grammar) : entry.grammar;
|
|
112
|
-
defaults.set(entry.locale, merged);
|
|
113
|
-
} else {
|
|
114
|
-
let byLocale = overrides.get(entry.userAgent);
|
|
115
|
-
if (!byLocale) {
|
|
116
|
-
byLocale = new Map();
|
|
117
|
-
overrides.set(entry.userAgent, byLocale);
|
|
118
|
-
}
|
|
119
|
-
const existing = byLocale.get(entry.locale);
|
|
120
|
-
const merged = existing && isOverride ? McpGrammar.merge(existing, entry.grammar) : entry.grammar;
|
|
121
|
-
byLocale.set(entry.locale, merged);
|
|
122
|
-
}
|
|
93
|
+
// Register every `(userAgent, locale)` JSON found on disk as a raw
|
|
94
|
+
// grammar layer. The candidate-chain resolution in
|
|
95
|
+
// McpServer.initialize (mcp-core@0.3.0) walks the resolver's chain
|
|
96
|
+
// and merges all matching layers — so partial user-agent files no
|
|
97
|
+
// longer need to be pre-merged with the default-locale baseline at
|
|
98
|
+
// boot. Local overrides come after packaged entries; identical keys
|
|
99
|
+
// get overlaid via the registry's last-write-wins.
|
|
100
|
+
for (const entry of iterAvailableBrokerGrammars()) {
|
|
101
|
+
builder.withGrammar(entry.key, entry.grammar);
|
|
123
102
|
}
|
|
124
|
-
|
|
125
|
-
for (const entry of iterAvailableBrokerGrammars()) ingest(entry, false);
|
|
126
103
|
if (options.localGrammarsDir) {
|
|
127
|
-
for (const entry of iterBrokerGrammarsFrom(options.localGrammarsDir))
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const availableKeys = new Set<string>();
|
|
131
|
-
|
|
132
|
-
// Register every "default:<locale>" as-is.
|
|
133
|
-
for (const [locale, grammar] of defaults) {
|
|
134
|
-
const key = brokerGrammarKey("default", locale);
|
|
135
|
-
builder.withGrammar(key, grammar);
|
|
136
|
-
availableKeys.add(key);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Register every "<userAgent>:<locale>" as merge(default:<locale>, ua:<locale>).
|
|
140
|
-
// The user-agent grammar wins per entry; missing entries cascade from default.
|
|
141
|
-
for (const [agent, byLocale] of overrides) {
|
|
142
|
-
for (const [locale, uaGrammar] of byLocale) {
|
|
143
|
-
const baseline = defaults.get(locale);
|
|
144
|
-
const merged = baseline ? McpGrammar.merge(baseline, uaGrammar) : uaGrammar;
|
|
145
|
-
const key = brokerGrammarKey(agent, locale);
|
|
146
|
-
builder.withGrammar(key, merged);
|
|
147
|
-
availableKeys.add(key);
|
|
104
|
+
for (const entry of iterBrokerGrammarsFrom(options.localGrammarsDir)) {
|
|
105
|
+
builder.withGrammar(entry.key, entry.grammar);
|
|
148
106
|
}
|
|
149
107
|
}
|
|
150
108
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
for (const locale of locales) {
|
|
161
|
-
for (const ua of userAgents) {
|
|
162
|
-
const key = brokerGrammarKey(ua, locale);
|
|
163
|
-
if (availableKeys.has(key)) return key;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// None of the candidates is on disk → return an empty key. McpServer
|
|
168
|
-
// then falls back to the behavior's baseline descriptions (English).
|
|
169
|
-
return "";
|
|
109
|
+
// Wire the resolver via mcp-core's declarative helper. The broker
|
|
110
|
+
// ships sensible defaults (locale from MCP_BROKER_LOCALE env, agents
|
|
111
|
+
// from mcp-core's catalogue, BCP-47 narrowing, default:en fallback);
|
|
112
|
+
// anything the host application sets via `grammarResolverOptions`
|
|
113
|
+
// takes precedence.
|
|
114
|
+
builder.withGrammarResolver({
|
|
115
|
+
localeSource: () => process.env["MCP_BROKER_LOCALE"],
|
|
116
|
+
...(options.grammarResolverOptions ?? {}),
|
|
170
117
|
});
|
|
171
118
|
|
|
172
119
|
// No reconnect policy → the McpServer does not attempt to reopen the loopback
|
package/src/broker/index.ts
CHANGED
|
@@ -13,12 +13,10 @@ export {
|
|
|
13
13
|
brokerBaselineResourceTemplateName,
|
|
14
14
|
brokerBaselineToolDescription,
|
|
15
15
|
brokerGrammarKey,
|
|
16
|
-
defaultBrokerLocaleResolver,
|
|
17
|
-
defaultBrokerUserAgentResolver,
|
|
18
16
|
iterAvailableBrokerGrammars,
|
|
17
|
+
iterBrokerGrammarsFrom,
|
|
19
18
|
loadBrokerGrammar,
|
|
20
|
-
|
|
21
|
-
resolveBrokerUserAgent,
|
|
19
|
+
parseBrokerGrammarStem,
|
|
22
20
|
} from "./broker.grammars.js";
|
|
23
|
-
export type {
|
|
21
|
+
export type { BrokerGrammarEntry, BrokerLocale, BrokerUserAgent } from "./broker.grammars.js";
|
|
24
22
|
export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport } from "./broker.context.js";
|
package/src/index.ts
CHANGED
|
@@ -15,16 +15,8 @@ export { unzipMcpb } from "./mcpb.unzip.js";
|
|
|
15
15
|
// Broker introspection — tier 1.
|
|
16
16
|
export { BrokerInfoBehavior, BrokerProvidersBehavior, startBrokerServer, BROKER_PROVIDER_NAME } from "./broker/index.js";
|
|
17
17
|
export type { StartBrokerServerOptions } from "./broker/index.js";
|
|
18
|
-
export {
|
|
19
|
-
|
|
20
|
-
defaultBrokerLocaleResolver,
|
|
21
|
-
defaultBrokerUserAgentResolver,
|
|
22
|
-
iterAvailableBrokerGrammars,
|
|
23
|
-
loadBrokerGrammar,
|
|
24
|
-
resolveBrokerLocale,
|
|
25
|
-
resolveBrokerUserAgent,
|
|
26
|
-
} from "./broker/index.js";
|
|
27
|
-
export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport, BrokerLocale, BrokerLocaleResolver, BrokerUserAgent, BrokerUserAgentResolver } from "./broker/index.js";
|
|
18
|
+
export { brokerGrammarKey, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerGrammar } from "./broker/index.js";
|
|
19
|
+
export type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport, BrokerLocale, BrokerUserAgent } from "./broker/index.js";
|
|
28
20
|
|
|
29
21
|
export { VERSION, PACKAGE_NAME } from "./version.js";
|
|
30
22
|
|
package/src/ws.tunnel.ts
CHANGED
|
@@ -5,12 +5,12 @@ import * as nodePath from "path";
|
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
6
|
import type { IncomingMessage, ServerResponse } from "http";
|
|
7
7
|
import { WebSocket, WebSocketServer } from "ws";
|
|
8
|
-
import type { IMessageTransport, IMcpServer } from "@cyanmycelium/mcp-core";
|
|
8
|
+
import type { GrammarResolverOptions, IMessageTransport, IMcpServer } from "@cyanmycelium/mcp-core";
|
|
9
9
|
import { StdioUpstream, type StdioUpstreamConfig } from "./stdio.upstream.js";
|
|
10
10
|
import { RemoteUpstream, type RemoteUpstreamConfig } from "./remote.upstream.js";
|
|
11
11
|
import type { Upstream } from "./upstream.js";
|
|
12
12
|
import { startBrokerServer, BROKER_PROVIDER_NAME } from "./broker/index.js";
|
|
13
|
-
import type { BrokerContext,
|
|
13
|
+
import type { BrokerContext, BrokerProviderInfo, BrokerProviderTransport } from "./broker/index.js";
|
|
14
14
|
import { AggregateServer } from "./broker/aggregate/aggregate.server.js";
|
|
15
15
|
import { VERSION, PACKAGE_NAME } from "./version.js";
|
|
16
16
|
|
|
@@ -257,30 +257,26 @@ export interface WsTunnelOptions {
|
|
|
257
257
|
brokerName?: string;
|
|
258
258
|
|
|
259
259
|
/**
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
*
|
|
268
|
-
* family. Defaults to `defaultBrokerUserAgentResolver` (substring match on
|
|
269
|
-
* `clientInfo.name` against known LLM families).
|
|
270
|
-
*/
|
|
271
|
-
brokerUserAgentResolver?: BrokerUserAgentResolver;
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Custom source of the raw locale string fed to the locale resolver.
|
|
275
|
-
* Defaults to `() => process.env.MCP_BROKER_LOCALE`. Override when the
|
|
276
|
-
* locale should come from a config file, HTTP header, etc.
|
|
260
|
+
* Overrides for the embedded broker server's grammar resolver — passed
|
|
261
|
+
* straight through to `mcp-core`'s `grammarResolverFromOptions`. The
|
|
262
|
+
* broker installs its own default `localeSource` (reads
|
|
263
|
+
* `process.env.MCP_BROKER_LOCALE`); anything you set here wins.
|
|
264
|
+
*
|
|
265
|
+
* Use this to inject a custom `localeSource` (e.g. read from an HTTP
|
|
266
|
+
* header proxied by your transport), enable the optional `versionFrom`
|
|
267
|
+
* dimension, or extend the `agents` map with additional LLM families.
|
|
277
268
|
*/
|
|
278
|
-
|
|
269
|
+
brokerGrammarResolverOptions?: Partial<GrammarResolverOptions>;
|
|
279
270
|
|
|
280
271
|
/**
|
|
281
272
|
* Path to a user-supplied grammars directory whose `<userAgent>/<locale>.json`
|
|
282
|
-
* files are
|
|
283
|
-
* broker server. Typically pointed at `.mcp-broker/grammars/`.
|
|
273
|
+
* files are registered alongside the packaged grammars used by the
|
|
274
|
+
* embedded broker server. Typically pointed at `.mcp-broker/grammars/`.
|
|
275
|
+
*
|
|
276
|
+
* The candidate-chain resolution in `McpServer.initialize`
|
|
277
|
+
* (mcp-core@0.3.0) handles cascade across user-agent and locale
|
|
278
|
+
* dimensions, so partial files no longer need to be pre-merged with a
|
|
279
|
+
* baseline.
|
|
284
280
|
*/
|
|
285
281
|
brokerLocalGrammarsDir?: string;
|
|
286
282
|
}
|
|
@@ -662,9 +658,7 @@ export class WsTunnel implements BrokerContext {
|
|
|
662
658
|
private async _maybeStartBrokerServer(): Promise<void> {
|
|
663
659
|
if (this._options.enableBrokerProvider === false) return;
|
|
664
660
|
const { server, clientTransport } = await startBrokerServer(this, {
|
|
665
|
-
|
|
666
|
-
userAgentResolver: this._options.brokerUserAgentResolver,
|
|
667
|
-
localeSource: this._options.brokerLocaleSource,
|
|
661
|
+
grammarResolverOptions: this._options.brokerGrammarResolverOptions,
|
|
668
662
|
localGrammarsDir: this._options.brokerLocalGrammarsDir,
|
|
669
663
|
});
|
|
670
664
|
this._brokerServer = server;
|