@ni-c/mcp-hub 0.10.0 → 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 +388 -0
- package/README.md +77 -12
- package/dist/admin.js +1 -1
- package/dist/admin.js.map +1 -1
- package/dist/auth/api-tokens.js +27 -0
- package/dist/auth/api-tokens.js.map +1 -0
- package/dist/auth/headers.js +22 -1
- package/dist/auth/headers.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/protected-resource.js +41 -0
- package/dist/auth/protected-resource.js.map +1 -0
- package/dist/auth/rate-limit.js +115 -2
- package/dist/auth/rate-limit.js.map +1 -1
- package/dist/auth/redirect-uri.js +33 -1
- package/dist/auth/redirect-uri.js.map +1 -1
- package/dist/auth/registration.js +1 -1
- package/dist/auth/registration.js.map +1 -1
- package/dist/auth/session.js +43 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/store.js +160 -1
- package/dist/auth/store.js.map +1 -1
- package/dist/config.js +55 -2
- 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/hub.js +309 -29
- package/dist/hub.js.map +1 -1
- package/dist/index.js +103 -21
- 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 +246 -40
- package/dist/proxy.js.map +1 -1
- package/dist/stdio.js +71 -6
- package/dist/stdio.js.map +1 -1
- package/dist/subscriptions.js +236 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/supervisor.js +322 -22
- 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 +1 -0
- package/dist/tool-filter.js.map +1 -1
- 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 +1 -1
- package/dist/upstream/auth.js.map +1 -1
- package/dist/upstream/provider.js.map +1 -1
- package/dist/upstream/routes.js +3 -2
- package/dist/upstream/routes.js.map +1 -1
- package/package.json +19 -6
- package/dist/auth/private-key-jwt.js +0 -213
- package/dist/auth/private-key-jwt.js.map +0 -1
- package/dist/auth/provider.js +0 -437
- package/dist/auth/provider.js.map +0 -1
- package/dist/auth/routes.js +0 -249
- package/dist/auth/routes.js.map +0 -1
package/dist/auth/routes.js
DELETED
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
import crypto from 'node:crypto';
|
|
2
|
-
import express, { Router } from 'express';
|
|
3
|
-
import bcrypt from 'bcryptjs';
|
|
4
|
-
import { mcpAuthRouter, createOAuthMetadata } from '@modelcontextprotocol/sdk/server/auth/router.js';
|
|
5
|
-
import { SESSION_TTL_MS } from './provider.js';
|
|
6
|
-
import { renderLoginPage } from './login-page.js';
|
|
7
|
-
import { allowFormActionTo, contentSecurityPolicy } from './headers.js';
|
|
8
|
-
import { isLoopbackOnly } from './redirect-uri.js';
|
|
9
|
-
import { logSafe } from './text.js';
|
|
10
|
-
import { privateKeyJwtAuth } from './private-key-jwt.js';
|
|
11
|
-
import { earlyRateLimit } from './rate-limit.js';
|
|
12
|
-
import { createRegistrationManagementRoutes } from './registration.js';
|
|
13
|
-
const LOGIN_MAX_ATTEMPTS = 10;
|
|
14
|
-
const LOGIN_WINDOW_MS = 15 * 60_000;
|
|
15
|
-
const LOGIN_MAX_ATTEMPTS_TOTAL = 100;
|
|
16
|
-
export class LoginRateLimiter {
|
|
17
|
-
attempts = new Map();
|
|
18
|
-
total = { count: 0, resetAt: 0 };
|
|
19
|
-
isBlocked(ip) {
|
|
20
|
-
if (this.total.resetAt > Date.now() && this.total.count >= LOGIN_MAX_ATTEMPTS_TOTAL)
|
|
21
|
-
return true;
|
|
22
|
-
const entry = this.attempts.get(ip);
|
|
23
|
-
if (!entry || entry.resetAt < Date.now())
|
|
24
|
-
return false;
|
|
25
|
-
return entry.count >= LOGIN_MAX_ATTEMPTS;
|
|
26
|
-
}
|
|
27
|
-
recordFailure(ip) {
|
|
28
|
-
this.sweepExpired(); // entries are otherwise only dropped on a successful login from that exact IP
|
|
29
|
-
const now = Date.now();
|
|
30
|
-
// Behind a reverse proxy req.ip is the proxy for every request, and a
|
|
31
|
-
// spoofable X-Forwarded-For makes the per-IP counter meaningless — this
|
|
32
|
-
// caps the total either way.
|
|
33
|
-
if (this.total.resetAt < now)
|
|
34
|
-
this.total = { count: 1, resetAt: now + LOGIN_WINDOW_MS };
|
|
35
|
-
else
|
|
36
|
-
this.total.count++;
|
|
37
|
-
const entry = this.attempts.get(ip);
|
|
38
|
-
if (!entry || entry.resetAt < now) {
|
|
39
|
-
this.attempts.set(ip, { count: 1, resetAt: now + LOGIN_WINDOW_MS });
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
entry.count++;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
sweepExpired() {
|
|
46
|
-
const now = Date.now();
|
|
47
|
-
for (const [ip, entry] of this.attempts) {
|
|
48
|
-
if (entry.resetAt < now)
|
|
49
|
-
this.attempts.delete(ip);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
reset(ip) {
|
|
53
|
-
this.attempts.delete(ip);
|
|
54
|
-
this.total = { count: 0, resetAt: 0 };
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
export function createAuthRoutes(options) {
|
|
58
|
-
const { provider, externalUrl } = options;
|
|
59
|
-
if (!options.passwordHash && !options.password) {
|
|
60
|
-
throw new Error('Either PASSWORD_HASH (bcrypt) or PASSWORD must be set');
|
|
61
|
-
}
|
|
62
|
-
const issuerUrl = new URL(externalUrl);
|
|
63
|
-
const router = Router();
|
|
64
|
-
const rateLimiter = new LoginRateLimiter();
|
|
65
|
-
// Keep the password login/consent pages and the OAuth token responses out of
|
|
66
|
-
// any shared or browser cache (RFC 6749 §5.1 requires no-store on token
|
|
67
|
-
// responses; the login form has no business being cached either). The CSP
|
|
68
|
-
// and legacy frame header keep an attacker from clickjacking approval or
|
|
69
|
-
// password entry. This application has no legitimate framing use case.
|
|
70
|
-
router.use((_req, res, next) => {
|
|
71
|
-
res.set('Cache-Control', 'no-store');
|
|
72
|
-
res.set('Content-Security-Policy', contentSecurityPolicy());
|
|
73
|
-
res.set('X-Frame-Options', 'DENY');
|
|
74
|
-
res.set('X-Content-Type-Options', 'nosniff');
|
|
75
|
-
res.set('Referrer-Policy', 'no-referrer');
|
|
76
|
-
next();
|
|
77
|
-
});
|
|
78
|
-
// RFC 7592 registration management. It goes first for two reasons: the SDK's
|
|
79
|
-
// registration router is mounted on the /register prefix and answers 405 to
|
|
80
|
-
// anything that is not a POST, and the registration budget below is also
|
|
81
|
-
// prefix-scoped — routine management would otherwise use up a client's
|
|
82
|
-
// ability to register at all. It brings its own, more generous limit.
|
|
83
|
-
if (provider.clientsStore.registerClient) {
|
|
84
|
-
router.use(createRegistrationManagementRoutes({ store: options.store, externalUrl: issuerUrl.href }));
|
|
85
|
-
}
|
|
86
|
-
// These run before the SDK's JSON/form parsers. The SDK applies its own
|
|
87
|
-
// endpoint limits too, but those otherwise happen only after body parsing.
|
|
88
|
-
router.use('/register', earlyRateLimit(60 * 60_000, 20, 200));
|
|
89
|
-
router.use('/authorize', earlyRateLimit(15 * 60_000, 100, 1_000));
|
|
90
|
-
router.use('/token', earlyRateLimit(15 * 60_000, 50, 500));
|
|
91
|
-
router.use('/login', earlyRateLimit(15 * 60_000, 100, 500));
|
|
92
|
-
router.use('/consent', earlyRateLimit(15 * 60_000, 100, 500));
|
|
93
|
-
// Advertised capabilities. The SDK's document knows nothing about Client ID
|
|
94
|
-
// Metadata Documents, so the two fields clients key their registration
|
|
95
|
-
// choice on are added here: client_id_metadata_document_supported is what
|
|
96
|
-
// makes a spec-compliant client prefer CIMD over dynamic registration, and
|
|
97
|
-
// private_key_jwt is how a CIMD client authenticates at the token endpoint —
|
|
98
|
-
// it can hold no shared secret.
|
|
99
|
-
const asMetadata = {
|
|
100
|
-
...createOAuthMetadata({ provider, issuerUrl }),
|
|
101
|
-
...(options.cimd
|
|
102
|
-
? {
|
|
103
|
-
client_id_metadata_document_supported: true,
|
|
104
|
-
token_endpoint_auth_methods_supported: ['client_secret_post', 'none', 'private_key_jwt'],
|
|
105
|
-
token_endpoint_auth_signing_alg_values_supported: ['RS256', 'RS384', 'RS512', 'PS256', 'PS384', 'PS512', 'ES256', 'ES384', 'ES512', 'EdDSA']
|
|
106
|
-
}
|
|
107
|
-
: {})
|
|
108
|
-
};
|
|
109
|
-
if (options.cimd) {
|
|
110
|
-
// Ahead of mcpAuthRouter so it wins the route, and ahead of the SDK's own
|
|
111
|
-
// body parser — which is harmless, because body-parser leaves an
|
|
112
|
-
// already-read request alone and req.body survives into the SDK handler.
|
|
113
|
-
router.use('/token', express.urlencoded({ extended: false }), privateKeyJwtAuth({ resolver: options.cimd, externalUrl: issuerUrl.href, tokenEndpoint: asMetadata.token_endpoint }));
|
|
114
|
-
// mcpAuthRouter serves the root RFC 8414 document itself, so the enriched
|
|
115
|
-
// one has to be registered before it to take precedence.
|
|
116
|
-
router.get('/.well-known/oauth-authorization-server', (_req, res) => {
|
|
117
|
-
res.json(asMetadata);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
if (!provider.clientsStore.registerClient) {
|
|
121
|
-
// With dynamic registration off the SDK never mounts /register, and the
|
|
122
|
-
// request would otherwise fall through to the MCP routes and come back as
|
|
123
|
-
// a 401 — telling a client to authenticate at an endpoint that no longer
|
|
124
|
-
// exists. Say what actually happened instead.
|
|
125
|
-
router.all('/register', (_req, res) => {
|
|
126
|
-
res
|
|
127
|
-
.status(404)
|
|
128
|
-
.json({ error: 'not_found', error_description: 'Dynamic client registration is disabled; use a client ID metadata document' });
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
// Standard AS endpoints: /.well-known/*, /authorize, /token, /register, /revoke
|
|
132
|
-
router.use(mcpAuthRouter({ provider, issuerUrl, resourceName: 'mcp-hub' }));
|
|
133
|
-
// Path-scoped metadata (RFC 9728 §3.1): clients connected to /<name>/mcp look
|
|
134
|
-
// up /.well-known/oauth-protected-resource/<name>/mcp before falling back to
|
|
135
|
-
// the root document, and RFC 8414 has an equivalent path-insertion form for
|
|
136
|
-
// AS metadata. Serve both for any suffix; one AS covers all resources.
|
|
137
|
-
router.get('/.well-known/oauth-authorization-server/{*splat}', (_req, res) => {
|
|
138
|
-
res.json(asMetadata);
|
|
139
|
-
});
|
|
140
|
-
// OIDC Discovery alias: some clients (ChatGPT among them) probe
|
|
141
|
-
// /.well-known/openid-configuration instead of — or before — the RFC 8414
|
|
142
|
-
// path, and the MCP spec requires clients to support both. The RFC 8414
|
|
143
|
-
// document is a compatible answer for the fields such clients read.
|
|
144
|
-
router.get('/.well-known/openid-configuration', (_req, res) => {
|
|
145
|
-
res.json(asMetadata);
|
|
146
|
-
});
|
|
147
|
-
router.get('/.well-known/openid-configuration/{*splat}', (_req, res) => {
|
|
148
|
-
res.json(asMetadata);
|
|
149
|
-
});
|
|
150
|
-
router.get('/.well-known/oauth-protected-resource/{*splat}', (req, res) => {
|
|
151
|
-
const suffix = req.path.replace('/.well-known/oauth-protected-resource', '');
|
|
152
|
-
res.json({
|
|
153
|
-
resource: issuerUrl.origin + suffix,
|
|
154
|
-
authorization_servers: [externalUrl],
|
|
155
|
-
bearer_methods_supported: ['header'],
|
|
156
|
-
resource_name: 'mcp-hub'
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
const checkPassword = (password) => {
|
|
160
|
-
if (options.passwordHash)
|
|
161
|
-
return bcrypt.compareSync(password, options.passwordHash);
|
|
162
|
-
const expected = Buffer.from(options.password);
|
|
163
|
-
const given = Buffer.from(password);
|
|
164
|
-
return expected.length === given.length && crypto.timingSafeEqual(expected, given);
|
|
165
|
-
};
|
|
166
|
-
router.post('/login', express.urlencoded({ extended: false }), async (req, res) => {
|
|
167
|
-
const ip = req.ip ?? 'unknown';
|
|
168
|
-
const { password, request } = req.body;
|
|
169
|
-
const pending = typeof request === 'string' ? provider.decodePendingAuthorization(request) : undefined;
|
|
170
|
-
if (!pending) {
|
|
171
|
-
res.status(400).type('html').send('<p>Authorization request expired. Close this window and connect again.</p>');
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if (rateLimiter.isBlocked(ip)) {
|
|
175
|
-
console.warn(`mcp-hub: login rate limit exceeded from ${logSafe(ip)}`);
|
|
176
|
-
res.status(429).type('html').send('<p>Too many attempts. Try again later.</p>');
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
if (typeof password !== 'string' || !checkPassword(password)) {
|
|
180
|
-
rateLimiter.recordFailure(ip);
|
|
181
|
-
console.warn(`mcp-hub: authentication failure from ${logSafe(ip)}`);
|
|
182
|
-
// The retry form has to reach the same redirect as the first attempt,
|
|
183
|
-
// and say the same things about who is asking.
|
|
184
|
-
const retryClient = await provider.clientsStore.getClient(pending.clientId);
|
|
185
|
-
allowFormActionTo(res, pending.redirectUri);
|
|
186
|
-
res
|
|
187
|
-
.status(401)
|
|
188
|
-
.type('html')
|
|
189
|
-
.send(renderLoginPage(request, pending.redirectUri, {
|
|
190
|
-
clientName: retryClient?.client_name,
|
|
191
|
-
resource: pending.resource,
|
|
192
|
-
clientId: provider.isMetadataDocumentClient(pending.clientId) ? pending.clientId : undefined,
|
|
193
|
-
loopbackOnly: isLoopbackOnly(retryClient?.redirect_uris)
|
|
194
|
-
}, 'Wrong password'));
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
rateLimiter.reset(ip);
|
|
198
|
-
console.log(`mcp-hub: successful login from ${logSafe(ip)}`);
|
|
199
|
-
res.cookie(provider.sessionCookieName, provider.createSessionCookie(), {
|
|
200
|
-
httpOnly: true,
|
|
201
|
-
secure: issuerUrl.protocol === 'https:',
|
|
202
|
-
sameSite: 'lax',
|
|
203
|
-
maxAge: SESSION_TTL_MS,
|
|
204
|
-
path: '/'
|
|
205
|
-
});
|
|
206
|
-
const client = await provider.clientsStore.getClient(pending.clientId);
|
|
207
|
-
if (!client) {
|
|
208
|
-
res.status(400).type('html').send('<p>Unknown client. Close this window and connect again.</p>');
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
provider.approve(client, pending.redirectUri); // typing the password is the consent
|
|
212
|
-
provider.redirectWithCode(client, pending, res);
|
|
213
|
-
});
|
|
214
|
-
// Reached from the consent page when a signed-in user authorizes a client
|
|
215
|
-
// for the first time. Everything here has to hold even though the request
|
|
216
|
-
// may have been triggered by a page the user did not expect to land on.
|
|
217
|
-
router.post('/consent', express.urlencoded({ extended: false }), async (req, res) => {
|
|
218
|
-
const { request, csrf, action } = req.body;
|
|
219
|
-
const pending = typeof request === 'string' ? provider.decodePendingAuthorization(request) : undefined;
|
|
220
|
-
if (!pending) {
|
|
221
|
-
res.status(400).type('html').send('<p>Authorization request expired. Close this window and connect again.</p>');
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
const session = provider.readSessionCookie(req.headers.cookie);
|
|
225
|
-
if (!session) {
|
|
226
|
-
res.status(401).type('html').send('<p>Session expired. Close this window and connect again.</p>');
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
if (!provider.verifyCsrfToken(session, csrf)) {
|
|
230
|
-
console.warn(`mcp-hub: consent with an invalid CSRF token from ${logSafe(req.ip ?? 'unknown')}`);
|
|
231
|
-
res.status(403).type('html').send('<p>Invalid request. Close this window and connect again.</p>');
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
if (action !== 'approve') {
|
|
235
|
-
console.log(`mcp-hub: authorization denied for client ${pending.clientId}`);
|
|
236
|
-
provider.redirectWithError(pending.redirectUri, pending.state, 'access_denied', res);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
const client = await provider.clientsStore.getClient(pending.clientId);
|
|
240
|
-
if (!client) {
|
|
241
|
-
res.status(400).type('html').send('<p>Unknown client. Close this window and connect again.</p>');
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
provider.approve(client, pending.redirectUri);
|
|
245
|
-
provider.redirectWithCode(client, pending, res);
|
|
246
|
-
});
|
|
247
|
-
return router;
|
|
248
|
-
}
|
|
249
|
-
//# sourceMappingURL=routes.js.map
|
package/dist/auth/routes.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/auth/routes.ts"],"names":[],"mappings":"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"}
|