@ni-c/mcp-hub 0.9.2 → 0.11.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/CHANGELOG.md +619 -0
- package/README.md +189 -64
- package/dist/admin.js +232 -8
- package/dist/admin.js.map +1 -1
- package/dist/auth/address.js +89 -0
- package/dist/auth/address.js.map +1 -0
- package/dist/auth/api-tokens.js +27 -0
- package/dist/auth/api-tokens.js.map +1 -0
- package/dist/auth/cimd.js +367 -0
- package/dist/auth/cimd.js.map +1 -0
- package/dist/auth/consent-page.js +4 -7
- package/dist/auth/consent-page.js.map +1 -1
- package/dist/auth/headers.js +22 -1
- package/dist/auth/headers.js.map +1 -1
- package/dist/auth/login-page.js +4 -7
- package/dist/auth/login-page.js.map +1 -1
- package/dist/auth/oidc/adapter.js +135 -0
- package/dist/auth/oidc/adapter.js.map +1 -0
- package/dist/auth/oidc/interactions.js +187 -0
- package/dist/auth/oidc/interactions.js.map +1 -0
- package/dist/auth/oidc/mount.js +144 -0
- package/dist/auth/oidc/mount.js.map +1 -0
- package/dist/auth/oidc/provider.js +440 -0
- package/dist/auth/oidc/provider.js.map +1 -0
- package/dist/auth/oidc/quirks.js +234 -0
- package/dist/auth/oidc/quirks.js.map +1 -0
- package/dist/auth/oidc/verifier.js +121 -0
- package/dist/auth/oidc/verifier.js.map +1 -0
- package/dist/auth/page.js +22 -0
- package/dist/auth/page.js.map +1 -1
- package/dist/auth/pinned-fetch.js +129 -0
- package/dist/auth/pinned-fetch.js.map +1 -0
- package/dist/auth/protected-resource.js +41 -0
- package/dist/auth/protected-resource.js.map +1 -0
- package/dist/auth/rate-limit.js +156 -0
- package/dist/auth/rate-limit.js.map +1 -0
- package/dist/auth/redirect-uri.js +90 -0
- package/dist/auth/redirect-uri.js.map +1 -0
- package/dist/auth/registration.js +146 -0
- package/dist/auth/registration.js.map +1 -0
- package/dist/auth/session.js +43 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/signed-token.js +49 -0
- package/dist/auth/signed-token.js.map +1 -0
- package/dist/auth/store.js +516 -5
- package/dist/auth/store.js.map +1 -1
- package/dist/auth/text.js +51 -0
- package/dist/auth/text.js.map +1 -0
- package/dist/config.js +184 -5
- package/dist/config.js.map +1 -1
- package/dist/docker-proxy/policy.js +1 -0
- package/dist/docker-proxy/policy.js.map +1 -1
- package/dist/docker-proxy/server.js +1 -0
- package/dist/docker-proxy/server.js.map +1 -1
- package/dist/elicitation.js +0 -0
- package/dist/elicitation.js.map +1 -0
- package/dist/forward.js +0 -0
- package/dist/forward.js.map +1 -0
- package/dist/health.js +22 -3
- package/dist/health.js.map +1 -1
- package/dist/hub.js +337 -29
- package/dist/hub.js.map +1 -1
- package/dist/index.js +218 -23
- package/dist/index.js.map +1 -1
- package/dist/limits.js +13 -1
- package/dist/limits.js.map +1 -1
- package/dist/mcp-limits.js +14 -2
- package/dist/mcp-limits.js.map +1 -1
- package/dist/proxy.js +262 -34
- package/dist/proxy.js.map +1 -1
- package/dist/stdio.js +97 -7
- package/dist/stdio.js.map +1 -1
- package/dist/subscriptions.js +236 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/supervisor.js +472 -28
- package/dist/supervisor.js.map +1 -1
- package/dist/timings.js +61 -0
- package/dist/timings.js.map +1 -0
- package/dist/tool-filter.js +59 -0
- package/dist/tool-filter.js.map +1 -0
- package/dist/transports/docker.js.map +1 -1
- package/dist/transports/stream.js +33 -20
- package/dist/transports/stream.js.map +1 -1
- package/dist/upstream/auth.js +435 -0
- package/dist/upstream/auth.js.map +1 -0
- package/dist/upstream/login.js +94 -0
- package/dist/upstream/login.js.map +1 -0
- package/dist/upstream/provider.js +286 -0
- package/dist/upstream/provider.js.map +1 -0
- package/dist/upstream/routes.js +97 -0
- package/dist/upstream/routes.js.map +1 -0
- package/package.json +23 -7
- package/dist/auth/provider.js +0 -380
- package/dist/auth/provider.js.map +0 -1
- package/dist/auth/routes.js +0 -223
- package/dist/auth/routes.js.map +0 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { booleanEnv, nonNegativeIntegerEnv, positiveIntegerEnv } from './mcp-limits.js';
|
|
2
|
+
/**
|
|
3
|
+
* Carrying a child's change notifications to the client that asked for them.
|
|
4
|
+
*
|
|
5
|
+
* On the 2026-07-28 revision a client opens a notification stream with
|
|
6
|
+
* `subscriptions/listen` and names the event types it wants. The state that
|
|
7
|
+
* makes this work is the open HTTP response, not a session table — which is the
|
|
8
|
+
* only reason a stateless gateway can carry it at all. It is the same property
|
|
9
|
+
* that made elicitation forwardable: nothing is remembered between requests
|
|
10
|
+
* that is not held by a socket somebody is still holding open.
|
|
11
|
+
*
|
|
12
|
+
* The SDK owns the downstream wire: acknowledgment first, per-stream filtering,
|
|
13
|
+
* `subscriptionId` stamping, teardown, keepalive. What this module owns is the
|
|
14
|
+
* half the SDK cannot know about — that behind one route sits a child process
|
|
15
|
+
* the hub may have put to sleep, and that several clients share it.
|
|
16
|
+
*
|
|
17
|
+
* Two consequences shape everything below:
|
|
18
|
+
*
|
|
19
|
+
* 1. The event bus is publish-only. It never reports which URIs a stream asked
|
|
20
|
+
* for, so the hub reads the filter off the request itself and keeps its own
|
|
21
|
+
* book. That book is what tells the upstream side which URIs to subscribe to.
|
|
22
|
+
* 2. One bus serves a whole route. A `publish` reaches every open stream on it,
|
|
23
|
+
* not just the one that prompted it — so a resync meant for a client that
|
|
24
|
+
* just connected also nudges the others. Harmless (they re-read a list they
|
|
25
|
+
* already had) and damped by the debounce, but it is a real property and it
|
|
26
|
+
* is documented rather than hidden.
|
|
27
|
+
*/
|
|
28
|
+
/** Global off switch, mirroring `MCP_ELICITATION`. */
|
|
29
|
+
export const SUBSCRIPTIONS_ENABLED = booleanEnv('MCP_SUBSCRIPTIONS', true);
|
|
30
|
+
/** Open listen streams one route will serve before refusing the next. */
|
|
31
|
+
export const MAX_SUBSCRIPTIONS = positiveIntegerEnv('MCP_MAX_SUBSCRIPTIONS', 1024);
|
|
32
|
+
/**
|
|
33
|
+
* URIs one `subscriptions/listen` filter may name.
|
|
34
|
+
*
|
|
35
|
+
* Every URI becomes an upstream subscription the hub has to hold and reconcile,
|
|
36
|
+
* so an unbounded list is a way to make the hub do unbounded work on one
|
|
37
|
+
* request. Well above what a resource picker produces, far below what a script
|
|
38
|
+
* could ask for.
|
|
39
|
+
*/
|
|
40
|
+
export const MAX_SUBSCRIPTION_URIS = positiveIntegerEnv('MCP_SUBSCRIPTION_MAX_URIS', 64);
|
|
41
|
+
/** SSE comment-frame keepalive for listen streams; `0` disables it. */
|
|
42
|
+
export const KEEPALIVE_MS = nonNegativeIntegerEnv('MCP_SUBSCRIPTION_KEEPALIVE_MS', 15_000);
|
|
43
|
+
/**
|
|
44
|
+
* How long change events are collected before they are delivered.
|
|
45
|
+
*
|
|
46
|
+
* A child that rewrites its resource list in a loop would otherwise turn one
|
|
47
|
+
* upstream storm into one downstream storm per connected client. Within the
|
|
48
|
+
* window, repeats of the same event collapse to one — which is exactly what the
|
|
49
|
+
* notification means anyway: "read it again", not "here is what changed".
|
|
50
|
+
* `0` disables the window and delivers each event as it arrives.
|
|
51
|
+
*/
|
|
52
|
+
export const DEBOUNCE_MS = nonNegativeIntegerEnv('MCP_SUBSCRIPTION_DEBOUNCE_MS', 250);
|
|
53
|
+
/**
|
|
54
|
+
* How long one listen stream may stay open; `0` lets it live as long as the
|
|
55
|
+
* socket does.
|
|
56
|
+
*
|
|
57
|
+
* This is a reaper for clients that go away without closing anything, not a
|
|
58
|
+
* protocol feature. The specification's graceful closure — answering the
|
|
59
|
+
* original request with a completion result before closing — is not reachable
|
|
60
|
+
* from here: the SDK owns the stream and exposes no hook for it. So the stream
|
|
61
|
+
* simply ends, which the client sees as the same unexpected disconnect it would
|
|
62
|
+
* see from an HTTP timeout, and reconnects. Spec-legal, and named as what it is
|
|
63
|
+
* rather than dressed up as the graceful variant.
|
|
64
|
+
*/
|
|
65
|
+
export const MAX_STREAM_MS = nonNegativeIntegerEnv('MCP_SUBSCRIPTION_MAX_MS', 30 * 60_000);
|
|
66
|
+
/** True unless an operator said otherwise, globally or for this server. */
|
|
67
|
+
export function subscriptionsAllowed(config) {
|
|
68
|
+
return SUBSCRIPTIONS_ENABLED && config.subscriptions !== 'off';
|
|
69
|
+
}
|
|
70
|
+
/** Whether a parsed request body is a `subscriptions/listen` call. */
|
|
71
|
+
export function isListenRequest(body) {
|
|
72
|
+
if (Array.isArray(body))
|
|
73
|
+
return body.some(entry => isListenRequest(entry));
|
|
74
|
+
return typeof body === 'object' && body !== null && body.method === 'subscriptions/listen';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Reads the filter off a parsed request body.
|
|
78
|
+
*
|
|
79
|
+
* Deliberately forgiving: this is not the validator. The SDK parses the request
|
|
80
|
+
* properly a moment later and owns every error answer, so anything malformed
|
|
81
|
+
* here just yields an empty demand and is rejected downstream with the SDK's
|
|
82
|
+
* own message. Reading it early buys one thing only — knowing which URIs to
|
|
83
|
+
* hold upstream before the stream opens.
|
|
84
|
+
*/
|
|
85
|
+
export function parseListenFilter(body) {
|
|
86
|
+
const empty = {
|
|
87
|
+
toolsListChanged: false,
|
|
88
|
+
promptsListChanged: false,
|
|
89
|
+
resourcesListChanged: false,
|
|
90
|
+
resourceSubscriptions: []
|
|
91
|
+
};
|
|
92
|
+
if (Array.isArray(body)) {
|
|
93
|
+
// A batch may not contain a listen at all; if it does, take the first.
|
|
94
|
+
const listen = body.find(entry => isListenRequest(entry));
|
|
95
|
+
return listen ? parseListenFilter(listen) : empty;
|
|
96
|
+
}
|
|
97
|
+
if (typeof body !== 'object' || body === null)
|
|
98
|
+
return empty;
|
|
99
|
+
const params = body.params;
|
|
100
|
+
if (typeof params !== 'object' || params === null)
|
|
101
|
+
return empty;
|
|
102
|
+
const notifications = params.notifications;
|
|
103
|
+
if (typeof notifications !== 'object' || notifications === null)
|
|
104
|
+
return empty;
|
|
105
|
+
const filter = notifications;
|
|
106
|
+
const uris = Array.isArray(filter.resourceSubscriptions)
|
|
107
|
+
? filter.resourceSubscriptions.filter((uri) => typeof uri === 'string')
|
|
108
|
+
: [];
|
|
109
|
+
return {
|
|
110
|
+
toolsListChanged: filter.toolsListChanged === true,
|
|
111
|
+
promptsListChanged: filter.promptsListChanged === true,
|
|
112
|
+
resourcesListChanged: filter.resourcesListChanged === true,
|
|
113
|
+
// Deduplicated here so the cap counts distinct resources, not repetitions
|
|
114
|
+
// of one, and so the upstream union below never holds the same URI twice.
|
|
115
|
+
resourceSubscriptions: [...new Set(uris)]
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export class SubscriptionRegistry {
|
|
119
|
+
notifier;
|
|
120
|
+
options;
|
|
121
|
+
leases = new Map();
|
|
122
|
+
pending = new Map();
|
|
123
|
+
nextId = 1;
|
|
124
|
+
timer;
|
|
125
|
+
closed = false;
|
|
126
|
+
constructor(notifier, options = {}) {
|
|
127
|
+
this.notifier = notifier;
|
|
128
|
+
this.options = options;
|
|
129
|
+
}
|
|
130
|
+
/** Open listen streams on this route, for the `maxSubscriptions` ceiling. */
|
|
131
|
+
get size() {
|
|
132
|
+
return this.leases.size;
|
|
133
|
+
}
|
|
134
|
+
/** The union of every live lease. Empty when nobody is listening. */
|
|
135
|
+
demand() {
|
|
136
|
+
const uris = new Set();
|
|
137
|
+
let tools = false;
|
|
138
|
+
let prompts = false;
|
|
139
|
+
let resources = false;
|
|
140
|
+
for (const filter of this.leases.values()) {
|
|
141
|
+
tools ||= filter.toolsListChanged;
|
|
142
|
+
prompts ||= filter.promptsListChanged;
|
|
143
|
+
resources ||= filter.resourcesListChanged;
|
|
144
|
+
for (const uri of filter.resourceSubscriptions)
|
|
145
|
+
uris.add(uri);
|
|
146
|
+
}
|
|
147
|
+
return { toolsListChanged: tools, promptsListChanged: prompts, resourcesListChanged: resources, uris: [...uris] };
|
|
148
|
+
}
|
|
149
|
+
acquire(filter) {
|
|
150
|
+
const id = this.nextId++;
|
|
151
|
+
this.leases.set(id, filter);
|
|
152
|
+
this.options.onDemandChange?.();
|
|
153
|
+
return {
|
|
154
|
+
release: () => {
|
|
155
|
+
// Idempotent: the release is wired to both `finish` and `close` on the
|
|
156
|
+
// response, and a stream that ends normally fires both.
|
|
157
|
+
if (!this.leases.delete(id))
|
|
158
|
+
return;
|
|
159
|
+
this.options.onDemandChange?.();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/** Hand one upstream change event to every stream that opted in. */
|
|
164
|
+
publish(event) {
|
|
165
|
+
if (this.closed)
|
|
166
|
+
return;
|
|
167
|
+
const debounceMs = this.options.debounceMs ?? DEBOUNCE_MS;
|
|
168
|
+
if (debounceMs <= 0) {
|
|
169
|
+
this.deliver(event);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.pending.set(event.kind === 'resource_updated' ? `${event.kind}:${event.uri}` : event.kind, event);
|
|
173
|
+
if (this.timer)
|
|
174
|
+
return;
|
|
175
|
+
this.timer = setTimeout(() => this.flush(), debounceMs);
|
|
176
|
+
// Never a reason to hold the process open for a coalescing window.
|
|
177
|
+
this.timer.unref();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Tell every listener to read everything it is watching again.
|
|
181
|
+
*
|
|
182
|
+
* Sent after a child wakes or restarts, because the hub held no upstream
|
|
183
|
+
* subscription while it was gone and cannot know what happened in the
|
|
184
|
+
* meantime. A `resources/updated` here does not claim the resource changed —
|
|
185
|
+
* it says "read it again", which is all the notification ever meant, and it
|
|
186
|
+
* is the only way to make the gap at the end of a nap recoverable rather than
|
|
187
|
+
* silent.
|
|
188
|
+
*/
|
|
189
|
+
resync() {
|
|
190
|
+
const demand = this.demand();
|
|
191
|
+
if (demand.toolsListChanged)
|
|
192
|
+
this.publish({ kind: 'tools_list_changed' });
|
|
193
|
+
if (demand.promptsListChanged)
|
|
194
|
+
this.publish({ kind: 'prompts_list_changed' });
|
|
195
|
+
if (demand.resourcesListChanged)
|
|
196
|
+
this.publish({ kind: 'resources_list_changed' });
|
|
197
|
+
for (const uri of demand.uris)
|
|
198
|
+
this.publish({ kind: 'resource_updated', uri });
|
|
199
|
+
}
|
|
200
|
+
flush() {
|
|
201
|
+
this.timer = undefined;
|
|
202
|
+
const events = [...this.pending.values()];
|
|
203
|
+
this.pending.clear();
|
|
204
|
+
for (const event of events)
|
|
205
|
+
this.deliver(event);
|
|
206
|
+
}
|
|
207
|
+
deliver(event) {
|
|
208
|
+
if (this.closed)
|
|
209
|
+
return;
|
|
210
|
+
// No filtering here on purpose: the SDK delivers each event only to the
|
|
211
|
+
// streams whose filter asked for it. Publishing one nobody wants costs a
|
|
212
|
+
// function call and reaches no client.
|
|
213
|
+
switch (event.kind) {
|
|
214
|
+
case 'tools_list_changed':
|
|
215
|
+
this.notifier.toolsChanged();
|
|
216
|
+
return;
|
|
217
|
+
case 'prompts_list_changed':
|
|
218
|
+
this.notifier.promptsChanged();
|
|
219
|
+
return;
|
|
220
|
+
case 'resources_list_changed':
|
|
221
|
+
this.notifier.resourcesChanged();
|
|
222
|
+
return;
|
|
223
|
+
case 'resource_updated':
|
|
224
|
+
this.notifier.resourceUpdated(event.uri);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
close() {
|
|
229
|
+
this.closed = true;
|
|
230
|
+
clearTimeout(this.timer);
|
|
231
|
+
this.timer = undefined;
|
|
232
|
+
this.pending.clear();
|
|
233
|
+
this.leases.clear();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=subscriptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"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"}
|