@cyanmycelium/mcp-broker 1.3.0 → 1.3.2
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/README.md +34 -0
- package/dist/bin.js +1 -1
- package/dist/{chunk-BZUZYXVA.js → chunk-J5TN5RYU.js} +40 -5
- package/dist/chunk-J5TN5RYU.js.map +1 -0
- package/dist/grammars/claude/en.json +1 -1
- package/dist/grammars/claude/fr.json +1 -1
- package/dist/grammars/default/en.json +1 -1
- package/dist/grammars/default/fr.json +1 -1
- package/dist/grammars/default/zh.json +1 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +1 -1
- package/package.json +2 -1
- package/scripts/leak-probe.mjs +156 -0
- package/src/broker/aggregate/aggregate.server.ts +10 -0
- package/src/broker/broker.context.ts +23 -1
- package/src/broker/grammars/claude/en.json +1 -1
- package/src/broker/grammars/claude/fr.json +1 -1
- package/src/broker/grammars/default/en.json +1 -1
- package/src/broker/grammars/default/fr.json +1 -1
- package/src/broker/grammars/default/zh.json +1 -1
- package/src/ws/ws.interfaces.ts +6 -0
- package/src/ws/ws.tunnel.ts +34 -4
- package/dist/chunk-BZUZYXVA.js.map +0 -1
package/README.md
CHANGED
|
@@ -232,12 +232,22 @@ Each provider entry from `providers_list` / `provider_status`:
|
|
|
232
232
|
"name": "weather",
|
|
233
233
|
"transport": "ws",
|
|
234
234
|
"connected": true,
|
|
235
|
+
"aggregate": true,
|
|
236
|
+
"connectedSince": "2026-09-14T08:12:03.417Z",
|
|
237
|
+
"connectedForMs": 184211,
|
|
235
238
|
"clientCount": 0,
|
|
236
239
|
"sessionCount": 1,
|
|
237
240
|
"pendingCount": 0
|
|
238
241
|
}
|
|
239
242
|
```
|
|
240
243
|
|
|
244
|
+
- The first six fields are about the **provider**: whether something serves
|
|
245
|
+
the slot, over what, whether it is in `_all`, and since when. A
|
|
246
|
+
`connectedSince` that is always a few seconds old is a provider that keeps
|
|
247
|
+
reconnecting.
|
|
248
|
+
- The three counts are about the slot's **callers**. A connected provider that
|
|
249
|
+
nobody is calling right now reads `clientCount: 0, sessionCount: 0,
|
|
250
|
+
pendingCount: 0`; that is not a fault.
|
|
241
251
|
- `transport` is `ws` (dedicated socket), `ws-multiplex` (shared socket),
|
|
242
252
|
`stdio` (**any** configured upstream: a child process from `stdioUpstreams`,
|
|
243
253
|
a `.mcpb` bundle, *or* a remote URL from `mcpServers`), `loopback`
|
|
@@ -720,6 +730,30 @@ npm start # node dist/bin.js
|
|
|
720
730
|
|
|
721
731
|
Requires Node 20.11+.
|
|
722
732
|
|
|
733
|
+
### Running the broker of this checkout
|
|
734
|
+
|
|
735
|
+
`npm start` runs `dist/bin.js`, the code of the working tree once `npm run
|
|
736
|
+
build` has been run (from `node/`, which builds the provider package first).
|
|
737
|
+
It reads `.mcp-broker/config.json` next to `package.json` when there is one;
|
|
738
|
+
that folder is gitignored, so each checkout keeps its own. A config that makes
|
|
739
|
+
the broker reachable from a device on the LAN and serves this package's `web/`
|
|
740
|
+
(the broker explorer at `/demos/broker-explorer/`) from the same port:
|
|
741
|
+
|
|
742
|
+
```json
|
|
743
|
+
{
|
|
744
|
+
"port": 3000,
|
|
745
|
+
"host": "0.0.0.0",
|
|
746
|
+
"www": { "open": false, "mounts": [{ "urlPrefix": "/", "dir": "../web" }] },
|
|
747
|
+
"allowedOrigins": ["http://localhost:3000", "http://127.0.0.1:3000"]
|
|
748
|
+
}
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
Paths in the file resolve against the file's own directory, hence `../web`.
|
|
752
|
+
Keep the terminal open: the process lives as long as it does. Without the
|
|
753
|
+
file the defaults apply, `0.0.0.0:3000` and no static mount. Every C sample,
|
|
754
|
+
the roundtrip and the soak in [`c/`](https://github.com/pandaGaume/mcp-broker/tree/main/c)
|
|
755
|
+
target this broker, not an installed one.
|
|
756
|
+
|
|
723
757
|
## Releasing
|
|
724
758
|
|
|
725
759
|
The package is published to npm by [`.github/workflows/release-node.yml`](https://github.com/pandaGaume/mcp-broker/blob/main/.github/workflows/release-node.yml), triggered by tags of the form `node-v*`.
|
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { PACKAGE_NAME, VERSION, loadBrokerConfig, WsTunnelBuilder, loadMcpbBundle, BROKER_AGGREGATE_NAME, BROKER_PROVIDER_NAME, resolveOpenTarget } from './chunk-
|
|
2
|
+
import { PACKAGE_NAME, VERSION, loadBrokerConfig, WsTunnelBuilder, loadMcpbBundle, BROKER_AGGREGATE_NAME, BROKER_PROVIDER_NAME, resolveOpenTarget } from './chunk-J5TN5RYU.js';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import open from 'open';
|
|
@@ -3002,6 +3002,15 @@ var AggregateServer = class _AggregateServer {
|
|
|
3002
3002
|
this.removeProvider(name);
|
|
3003
3003
|
}
|
|
3004
3004
|
}
|
|
3005
|
+
/**
|
|
3006
|
+
* Slot names currently contributing to the aggregate, in registration
|
|
3007
|
+
* order. A provider whose handshake failed is not in it: `addProvider`
|
|
3008
|
+
* removed it. This is what `broker_diagnose` reads through
|
|
3009
|
+
* `IBrokerContext.getAggregateInfo()`.
|
|
3010
|
+
*/
|
|
3011
|
+
get providerNames() {
|
|
3012
|
+
return [...this._sessions.keys()];
|
|
3013
|
+
}
|
|
3005
3014
|
/** Removes a provider from the aggregate. */
|
|
3006
3015
|
removeProvider(name) {
|
|
3007
3016
|
const session = this._sessions.get(name);
|
|
@@ -3700,6 +3709,22 @@ var WsTunnel = class {
|
|
|
3700
3709
|
getStdioBridgeTarget() {
|
|
3701
3710
|
return this._options.stdioClient?.providerName ?? null;
|
|
3702
3711
|
}
|
|
3712
|
+
/**
|
|
3713
|
+
* Membership of the `_all` aggregate, for `broker_diagnose`.
|
|
3714
|
+
*
|
|
3715
|
+
* Before `start()` the aggregate server does not exist yet, so an enabled
|
|
3716
|
+
* aggregate reports no provider rather than `undefined`: "cannot be read"
|
|
3717
|
+
* is for a host that has no aggregate at all, not for one that has not
|
|
3718
|
+
* started. Without this accessor the CLI's own broker skipped the
|
|
3719
|
+
* `aggregate-empty` check and told the operator to call tools/list on
|
|
3720
|
+
* `_all` by hand.
|
|
3721
|
+
*/
|
|
3722
|
+
getAggregateInfo() {
|
|
3723
|
+
return {
|
|
3724
|
+
enabled: this._options.enableAggregateProvider !== false,
|
|
3725
|
+
providers: this._aggregateServer?.providerNames ?? []
|
|
3726
|
+
};
|
|
3727
|
+
}
|
|
3703
3728
|
getProvidersInfo() {
|
|
3704
3729
|
const out = [];
|
|
3705
3730
|
for (const [name, state] of this._providers) {
|
|
@@ -3728,10 +3753,14 @@ var WsTunnel = class {
|
|
|
3728
3753
|
transport = "none";
|
|
3729
3754
|
connected = false;
|
|
3730
3755
|
}
|
|
3756
|
+
const since = connected ? state.connectedSinceMs : null;
|
|
3731
3757
|
return {
|
|
3732
3758
|
name,
|
|
3733
3759
|
transport,
|
|
3734
3760
|
connected,
|
|
3761
|
+
aggregate: this._aggregateServer?.providerNames.includes(name) ?? false,
|
|
3762
|
+
connectedSince: since !== null ? new Date(since).toISOString() : null,
|
|
3763
|
+
connectedForMs: since !== null ? Math.max(0, Date.now() - since) : null,
|
|
3735
3764
|
clientCount: state.wsClients.size,
|
|
3736
3765
|
sessionCount: state.sseSessions.size + state.httpSessions.size,
|
|
3737
3766
|
pendingCount: state.pending.size
|
|
@@ -3756,6 +3785,7 @@ var WsTunnel = class {
|
|
|
3756
3785
|
}
|
|
3757
3786
|
const state = this._getOrCreateProviderState(name);
|
|
3758
3787
|
this._loopbackProviders.set(name, transport);
|
|
3788
|
+
state.connectedSinceMs = Date.now();
|
|
3759
3789
|
transport.onMessage = (data) => this._routeFromProvider(state, name, data);
|
|
3760
3790
|
transport.onClose = () => {
|
|
3761
3791
|
this._loopbackProviders.delete(name);
|
|
@@ -3890,9 +3920,10 @@ var WsTunnel = class {
|
|
|
3890
3920
|
const state = this._providers.get(cfg.name);
|
|
3891
3921
|
if (state) this._failProviderDisconnected(state, cfg.name);
|
|
3892
3922
|
};
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3923
|
+
upstream.onOpen = () => {
|
|
3924
|
+
this._getOrCreateProviderState(cfg.name).connectedSinceMs = Date.now();
|
|
3925
|
+
if (cfg.aggregate) void this._aggregateServer?.addProvider(cfg.name);
|
|
3926
|
+
};
|
|
3896
3927
|
this._upstreams.set(cfg.name, upstream);
|
|
3897
3928
|
upstream.connect();
|
|
3898
3929
|
};
|
|
@@ -4880,6 +4911,7 @@ data: ${data}
|
|
|
4880
4911
|
}
|
|
4881
4912
|
const state = this._getOrCreateProviderState(name);
|
|
4882
4913
|
state.ws = ws;
|
|
4914
|
+
state.connectedSinceMs = Date.now();
|
|
4883
4915
|
this._watchProviderSocket(ws);
|
|
4884
4916
|
if (providerPrincipal) {
|
|
4885
4917
|
this._logProviderRegistration(providerPrincipal, name, this._slotResourceResolver.resolve(name), true);
|
|
@@ -5088,6 +5120,7 @@ data: ${data}
|
|
|
5088
5120
|
providerNames.add(name);
|
|
5089
5121
|
const state2 = this._getOrCreateProviderState(name);
|
|
5090
5122
|
state2.ws = ws;
|
|
5123
|
+
state2.connectedSinceMs = Date.now();
|
|
5091
5124
|
if (providerPrincipal) {
|
|
5092
5125
|
this._logProviderRegistration(providerPrincipal, name, this._slotResourceResolver.resolve(name), true);
|
|
5093
5126
|
}
|
|
@@ -5267,6 +5300,7 @@ data: ${data}
|
|
|
5267
5300
|
* close handlers (dedicated WS, multiplexed WS, loopback).
|
|
5268
5301
|
*/
|
|
5269
5302
|
_failProviderDisconnected(state, name) {
|
|
5303
|
+
state.connectedSinceMs = null;
|
|
5270
5304
|
for (const entry of state.pending.values()) {
|
|
5271
5305
|
const error = JSON.stringify({
|
|
5272
5306
|
jsonrpc: "2.0",
|
|
@@ -5297,6 +5331,7 @@ data: ${data}
|
|
|
5297
5331
|
if (!state) {
|
|
5298
5332
|
state = {
|
|
5299
5333
|
ws: null,
|
|
5334
|
+
connectedSinceMs: null,
|
|
5300
5335
|
pending: /* @__PURE__ */ new Map(),
|
|
5301
5336
|
sseSessions: /* @__PURE__ */ new Map(),
|
|
5302
5337
|
httpSessions: /* @__PURE__ */ new Map(),
|
|
@@ -5951,5 +5986,5 @@ function resolveOpenTarget(raw, baseUrl) {
|
|
|
5951
5986
|
}
|
|
5952
5987
|
|
|
5953
5988
|
export { AuthError, BROKER_AGGREGATE_NAME, BROKER_GUIDES, BROKER_GUIDE_MIME_TYPE, BROKER_GUIDE_TOPICS, BROKER_GUIDE_URI_PREFIX, BROKER_GUIDE_URI_TEMPLATE, BROKER_PROVIDER_NAME, BROKER_RESERVED_SLOTS, BrokerDiagnoseAdapter, BrokerDiagnoseBehavior, BrokerGuideAdapter, BrokerGuideBehavior, BrokerInfoBehavior, BrokerProvidersBehavior, ConfigPolicyEngine, ConfiguredCapabilityClassifier, DEFAULT_CONFIG_FILENAME, DefaultSlotResourceResolver, HttpAuthGuard, JwtSubjectMapper, JwtTokenValidator, PACKAGE_NAME, RemoteUpstream, ResourcePath, ResourcePathPattern, SharedSecretProviderAuthenticator, StdioUpstream, SubjectMappingError, VERSION, WsTunnel, WsTunnelBuilder, authorizationWithEngine, brokerGrammarKey, brokerGuide, brokerGuideIndex, brokerGuideTopicFromUri, brokerGuideUri, buildJwtAuth, buildResourceMetadata, compileAuthorizationPolicy, compileProviderAllowedResources, diagnoseBroker, hasAuthorizationPolicies, isReservedBrokerSlot, iterAvailableBrokerGrammars, iterBrokerGrammarsFrom, loadBrokerConfig, loadBrokerGrammar, loadMcpbBundle, normalizeProviderAuthentication, providerMayPublish, providerPublishDecision, resolveOpenTarget, scopesOf, startBrokerServer, unzipMcpb, validateCapability };
|
|
5954
|
-
//# sourceMappingURL=chunk-
|
|
5955
|
-
//# sourceMappingURL=chunk-
|
|
5989
|
+
//# sourceMappingURL=chunk-J5TN5RYU.js.map
|
|
5990
|
+
//# sourceMappingURL=chunk-J5TN5RYU.js.map
|