@kieksme/mcp-http-kit 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +197 -2
- package/SECURITY.md +19 -0
- package/dist/auth/bearer.d.ts +14 -0
- package/dist/auth/bearer.d.ts.map +1 -0
- package/dist/auth/bearer.js +43 -0
- package/dist/auth/bearer.js.map +1 -0
- package/dist/auth/context.d.ts +7 -0
- package/dist/auth/context.d.ts.map +1 -0
- package/dist/auth/context.js +46 -0
- package/dist/auth/context.js.map +1 -0
- package/dist/auth/index.d.ts +25 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +34 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth.d.ts +25 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +161 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +201 -0
- package/dist/config.js.map +1 -0
- package/dist/http/app.d.ts +32 -0
- package/dist/http/app.d.ts.map +1 -0
- package/dist/http/app.js +127 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/host-guard.d.ts +22 -0
- package/dist/http/host-guard.d.ts.map +1 -0
- package/dist/http/host-guard.js +46 -0
- package/dist/http/host-guard.js.map +1 -0
- package/dist/http/index.d.ts +4 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +4 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/node.d.ts +36 -0
- package/dist/http/node.d.ts.map +1 -0
- package/dist/http/node.js +74 -0
- package/dist/http/node.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/start.d.ts +16 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +84 -0
- package/dist/start.js.map +1 -0
- package/dist/test/helpers.d.ts +35 -0
- package/dist/test/helpers.d.ts.map +1 -0
- package/dist/test/helpers.js +171 -0
- package/dist/test/helpers.js.map +1 -0
- package/dist/test/index.d.ts +2 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +2 -0
- package/dist/test/index.js.map +1 -0
- package/dist/types.d.ts +123 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/upstream.d.ts +17 -0
- package/dist/upstream.d.ts.map +1 -0
- package/dist/upstream.js +49 -0
- package/dist/upstream.js.map +1 -0
- package/docs/migration.md +125 -0
- package/package.json +87 -4
- package/templates/Dockerfile +46 -0
- package/templates/railway.json +13 -0
- package/templates/server.json +79 -0
- package/templates/smithery.yaml +31 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/http/node.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { loadConfig, isLocalhostHostname, resolveHealthPaths, type LoadConfigOptions, } from './config.js';
|
|
2
|
+
export { authenticateRequest, unauthorizedWwwAuthenticate, verifyBearerToken, extractBearerToken, verifyOAuthAccessToken, buildProtectedResourceMetadata, oauthWwwAuthenticate, resourceMetadataUrl, clearOAuthJwksCache, type AuthenticateResult, type AuthenticateOptions, } from './auth/index.js';
|
|
3
|
+
export { toAuthInfo, fromAuthInfo } from './auth/context.js';
|
|
4
|
+
export { createMcpHttpApp, protectedResourceMetadataPath, checkHostAndOrigin, normalizeHostname, createNodeHttpServer, createNodeRequestListener, handleWithKitApp, type McpHttpApp, type McpHttpAppOptions, type HostGuardConfig, type HostGuardResult, type NodeHttpServerOptions, } from './http/index.js';
|
|
5
|
+
export { startMcpServer } from './start.js';
|
|
6
|
+
export { resolveUpstreamCredential, parseUpstreamCredentialMode, assertHeaderModeAllowed, type UpstreamCredentialResult, } from './upstream.js';
|
|
7
|
+
export type { TransportMode, AuthMode, UpstreamCredentialMode, BearerAuthConfig, OAuthAuthConfig, NoneAuthConfig, AuthConfig, HttpListenConfig, HealthInfo, HealthInfoProvider, KitConfig, AuthContext, RequestContext, ServerFactory, UpstreamCredentialOptions, StartMcpServerOptions, StartedServer, } from './types.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,8BAA8B,EAC9B,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,6BAA6B,EAC7B,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,aAAa,EACb,QAAQ,EACR,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,cAAc,EACd,aAAa,EACb,yBAAyB,EACzB,qBAAqB,EACrB,aAAa,GACd,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { loadConfig, isLocalhostHostname, resolveHealthPaths, } from './config.js';
|
|
2
|
+
export { authenticateRequest, unauthorizedWwwAuthenticate, verifyBearerToken, extractBearerToken, verifyOAuthAccessToken, buildProtectedResourceMetadata, oauthWwwAuthenticate, resourceMetadataUrl, clearOAuthJwksCache, } from './auth/index.js';
|
|
3
|
+
export { toAuthInfo, fromAuthInfo } from './auth/context.js';
|
|
4
|
+
export { createMcpHttpApp, protectedResourceMetadataPath, checkHostAndOrigin, normalizeHostname, createNodeHttpServer, createNodeRequestListener, handleWithKitApp, } from './http/index.js';
|
|
5
|
+
export { startMcpServer } from './start.js';
|
|
6
|
+
export { resolveUpstreamCredential, parseUpstreamCredentialMode, assertHeaderModeAllowed, } from './upstream.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,kBAAkB,GAEnB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,8BAA8B,EAC9B,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,GAGpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,gBAAgB,EAChB,6BAA6B,EAC7B,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,GAMjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,GAExB,MAAM,eAAe,CAAC"}
|
package/dist/start.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { StartedServer, StartMcpServerOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Start an MCP server over stdio or stateless Streamable HTTP based on config.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* await startMcpServer({
|
|
7
|
+
* createServer: (ctx) => {
|
|
8
|
+
* const server = new McpServer({ name: 'demo', version: '1.0.0' });
|
|
9
|
+
* // register tools; ctx.auth.scopes available for oauth
|
|
10
|
+
* return server;
|
|
11
|
+
* },
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function startMcpServer(options: StartMcpServerOptions): Promise<StartedServer>;
|
|
16
|
+
//# sourceMappingURL=start.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,aAAa,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAOlF;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC,CAqE3F"}
|
package/dist/start.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { serveStdio } from '@modelcontextprotocol/server/stdio';
|
|
2
|
+
import { loadConfig } from './config.js';
|
|
3
|
+
import { createMcpHttpApp } from './http/app.js';
|
|
4
|
+
import { createNodeHttpServer } from './http/node.js';
|
|
5
|
+
function publicUrl(config) {
|
|
6
|
+
const host = config.http.host === '0.0.0.0' ? '127.0.0.1' : config.http.host;
|
|
7
|
+
return `http://${host}:${config.http.port}${config.http.path}`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Start an MCP server over stdio or stateless Streamable HTTP based on config.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* await startMcpServer({
|
|
14
|
+
* createServer: (ctx) => {
|
|
15
|
+
* const server = new McpServer({ name: 'demo', version: '1.0.0' });
|
|
16
|
+
* // register tools; ctx.auth.scopes available for oauth
|
|
17
|
+
* return server;
|
|
18
|
+
* },
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export async function startMcpServer(options) {
|
|
23
|
+
const config = options.config ?? loadConfig(options.env ?? process.env);
|
|
24
|
+
for (const warning of config.warnings) {
|
|
25
|
+
console.warn(`[mcp-http-kit] ${warning}`);
|
|
26
|
+
}
|
|
27
|
+
if (config.transport === 'stdio') {
|
|
28
|
+
const handle = serveStdio(() => options.createServer({
|
|
29
|
+
auth: { mode: 'none', scopes: [] },
|
|
30
|
+
headers: new Headers(),
|
|
31
|
+
url: new URL('stdio://local'),
|
|
32
|
+
era: 'modern',
|
|
33
|
+
}));
|
|
34
|
+
const close = async () => {
|
|
35
|
+
await handle.close();
|
|
36
|
+
};
|
|
37
|
+
if (options.signal) {
|
|
38
|
+
if (options.signal.aborted)
|
|
39
|
+
await close();
|
|
40
|
+
else
|
|
41
|
+
options.signal.addEventListener('abort', () => void close(), { once: true });
|
|
42
|
+
}
|
|
43
|
+
return { close, config };
|
|
44
|
+
}
|
|
45
|
+
const app = createMcpHttpApp({
|
|
46
|
+
createServer: options.createServer,
|
|
47
|
+
config,
|
|
48
|
+
...(options.getHealthInfo ? { getHealthInfo: options.getHealthInfo } : {}),
|
|
49
|
+
});
|
|
50
|
+
const server = createNodeHttpServer({ app, config });
|
|
51
|
+
await new Promise((resolve, reject) => {
|
|
52
|
+
server.once('error', reject);
|
|
53
|
+
server.listen(config.http.port, config.http.host, () => resolve());
|
|
54
|
+
});
|
|
55
|
+
const url = publicUrl(config);
|
|
56
|
+
options.onListening?.({ host: config.http.host, port: config.http.port, url });
|
|
57
|
+
let closing;
|
|
58
|
+
const close = async () => {
|
|
59
|
+
if (closing)
|
|
60
|
+
return closing;
|
|
61
|
+
closing = (async () => {
|
|
62
|
+
await new Promise((resolve, reject) => {
|
|
63
|
+
server.close(error => (error ? reject(error) : resolve()));
|
|
64
|
+
});
|
|
65
|
+
await app.close();
|
|
66
|
+
})();
|
|
67
|
+
return closing;
|
|
68
|
+
};
|
|
69
|
+
const onSignal = () => {
|
|
70
|
+
void close().finally(() => {
|
|
71
|
+
// allow process to exit after graceful shutdown
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
process.once('SIGTERM', onSignal);
|
|
75
|
+
process.once('SIGINT', onSignal);
|
|
76
|
+
if (options.signal) {
|
|
77
|
+
if (options.signal.aborted)
|
|
78
|
+
await close();
|
|
79
|
+
else
|
|
80
|
+
options.signal.addEventListener('abort', () => void close(), { once: true });
|
|
81
|
+
}
|
|
82
|
+
return { close, url, config };
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { McpHttpApp } from '../http/app.js';
|
|
2
|
+
import type { KitConfig } from '../types.js';
|
|
3
|
+
export type KitHttpTestClient = {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
health: () => Promise<Response>;
|
|
6
|
+
mcp: (init?: RequestInit & {
|
|
7
|
+
token?: string;
|
|
8
|
+
host?: string;
|
|
9
|
+
origin?: string;
|
|
10
|
+
}) => Promise<Response>;
|
|
11
|
+
fetch: (path: string, init?: RequestInit) => Promise<Response>;
|
|
12
|
+
};
|
|
13
|
+
/** Parse a Streamable HTTP MCP response (JSON body or SSE `data:` frames). */
|
|
14
|
+
export declare function readMcpJsonResponse(response: Response): Promise<unknown>;
|
|
15
|
+
/** In-process client against a kit `McpHttpApp.fetch` (no real listen required). */
|
|
16
|
+
export declare function createAppTestClient(app: McpHttpApp, config: KitConfig): KitHttpTestClient;
|
|
17
|
+
export type KitContractAssertions = {
|
|
18
|
+
/** GET /health without auth → 200 */
|
|
19
|
+
healthUnauthenticated: () => Promise<void>;
|
|
20
|
+
/** POST /mcp without token → 401 (+ WWW-Authenticate) */
|
|
21
|
+
unauthorizedWithoutToken: () => Promise<void>;
|
|
22
|
+
/** Bad Host → 403 (health stays 200 even with bad Host) */
|
|
23
|
+
forbiddenOnBadHost: () => Promise<void>;
|
|
24
|
+
/** Bad Origin → 403 on MCP path */
|
|
25
|
+
forbiddenOnBadOrigin: () => Promise<void>;
|
|
26
|
+
/** initialize + tools/list round-trip with a valid token */
|
|
27
|
+
initializeAndListTools: (token: string) => Promise<{
|
|
28
|
+
tools: unknown[];
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Reusable HTTP contract checks servers can call from their own vitest suites.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createKitContractAssertions(client: KitHttpTestClient, config: KitConfig): KitContractAssertions;
|
|
35
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/test/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpG,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChE,CAAC;AAEF,8EAA8E;AAC9E,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAsB9E;AAED,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,GAAG,iBAAiB,CA6BzF;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,qCAAqC;IACrC,qBAAqB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,yDAAyD;IACzD,wBAAwB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,2DAA2D;IAC3D,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,mCAAmC;IACnC,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,4DAA4D;IAC5D,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CAC1E,CAAC;AAEF;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,SAAS,GAChB,qBAAqB,CAoHvB"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/** Parse a Streamable HTTP MCP response (JSON body or SSE `data:` frames). */
|
|
2
|
+
export async function readMcpJsonResponse(response) {
|
|
3
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
4
|
+
const text = await response.text();
|
|
5
|
+
if (contentType.includes('application/json') || text.trimStart().startsWith('{')) {
|
|
6
|
+
return JSON.parse(text);
|
|
7
|
+
}
|
|
8
|
+
// SSE: take the last JSON payload from data: lines
|
|
9
|
+
const payloads = [];
|
|
10
|
+
for (const line of text.split(/\r?\n/)) {
|
|
11
|
+
if (!line.startsWith('data:'))
|
|
12
|
+
continue;
|
|
13
|
+
const data = line.slice(5).trim();
|
|
14
|
+
if (!data || data === '[DONE]')
|
|
15
|
+
continue;
|
|
16
|
+
try {
|
|
17
|
+
payloads.push(JSON.parse(data));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// ignore non-JSON data frames
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (payloads.length === 0) {
|
|
24
|
+
throw new Error(`No JSON payload in MCP response (${contentType}): ${text.slice(0, 200)}`);
|
|
25
|
+
}
|
|
26
|
+
return payloads[payloads.length - 1];
|
|
27
|
+
}
|
|
28
|
+
/** In-process client against a kit `McpHttpApp.fetch` (no real listen required). */
|
|
29
|
+
export function createAppTestClient(app, config) {
|
|
30
|
+
const originHost = config.http.allowedHosts[0] ?? '127.0.0.1';
|
|
31
|
+
const baseUrl = `http://${originHost}:${config.http.port}`;
|
|
32
|
+
const fetch = (path, init) => {
|
|
33
|
+
const headers = new Headers(init?.headers);
|
|
34
|
+
if (!headers.has('host'))
|
|
35
|
+
headers.set('host', originHost);
|
|
36
|
+
return app.fetch(new Request(`${baseUrl}${path}`, { ...init, headers }));
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
baseUrl,
|
|
40
|
+
health: () => fetch(config.http.healthPath, { method: 'GET' }),
|
|
41
|
+
mcp: (init = {}) => {
|
|
42
|
+
const headers = new Headers(init.headers);
|
|
43
|
+
if (init.token)
|
|
44
|
+
headers.set('authorization', `Bearer ${init.token}`);
|
|
45
|
+
if (init.host)
|
|
46
|
+
headers.set('host', init.host);
|
|
47
|
+
if (init.origin)
|
|
48
|
+
headers.set('origin', init.origin);
|
|
49
|
+
if (!headers.has('accept')) {
|
|
50
|
+
headers.set('accept', 'application/json, text/event-stream');
|
|
51
|
+
}
|
|
52
|
+
if (!headers.has('content-type') && init.body) {
|
|
53
|
+
headers.set('content-type', 'application/json');
|
|
54
|
+
}
|
|
55
|
+
const { token: _t, host: _h, origin: _o, ...rest } = init;
|
|
56
|
+
return fetch(config.http.path, { method: 'POST', ...rest, headers });
|
|
57
|
+
},
|
|
58
|
+
fetch,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Reusable HTTP contract checks servers can call from their own vitest suites.
|
|
63
|
+
*/
|
|
64
|
+
export function createKitContractAssertions(client, config) {
|
|
65
|
+
return {
|
|
66
|
+
async healthUnauthenticated() {
|
|
67
|
+
for (const path of config.http.healthPaths) {
|
|
68
|
+
const response = await client.fetch(path, { method: 'GET' });
|
|
69
|
+
if (response.status !== 200) {
|
|
70
|
+
throw new Error(`Expected ${path} 200, got ${response.status}`);
|
|
71
|
+
}
|
|
72
|
+
const body = (await response.json());
|
|
73
|
+
if (body.status !== 'ok') {
|
|
74
|
+
throw new Error(`Expected health status ok on ${path}, got ${JSON.stringify(body)}`);
|
|
75
|
+
}
|
|
76
|
+
// Health must ignore Host allowlist (Railway probes).
|
|
77
|
+
const evil = await client.fetch(path, {
|
|
78
|
+
method: 'GET',
|
|
79
|
+
headers: { host: 'evil.example' },
|
|
80
|
+
});
|
|
81
|
+
if (evil.status !== 200) {
|
|
82
|
+
throw new Error(`Expected ${path} 200 with bad Host, got ${evil.status}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
async unauthorizedWithoutToken() {
|
|
87
|
+
if (config.auth.mode === 'none')
|
|
88
|
+
return;
|
|
89
|
+
const response = await client.mcp({
|
|
90
|
+
body: JSON.stringify({
|
|
91
|
+
jsonrpc: '2.0',
|
|
92
|
+
id: 1,
|
|
93
|
+
method: 'initialize',
|
|
94
|
+
params: {
|
|
95
|
+
protocolVersion: '2025-06-18',
|
|
96
|
+
capabilities: {},
|
|
97
|
+
clientInfo: { name: 'kit-test', version: '0' },
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
});
|
|
101
|
+
if (response.status !== 401) {
|
|
102
|
+
throw new Error(`Expected 401 without token, got ${response.status}`);
|
|
103
|
+
}
|
|
104
|
+
if (!response.headers.get('www-authenticate')) {
|
|
105
|
+
throw new Error('Expected WWW-Authenticate header on 401');
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
async forbiddenOnBadHost() {
|
|
109
|
+
const token = config.auth.mode === 'bearer' ? config.auth.tokens[0] : 'dummy';
|
|
110
|
+
const response = await client.mcp({
|
|
111
|
+
host: 'evil.example',
|
|
112
|
+
...(token ? { token } : {}),
|
|
113
|
+
body: '{}',
|
|
114
|
+
});
|
|
115
|
+
if (response.status !== 403) {
|
|
116
|
+
throw new Error(`Expected 403 for bad Host, got ${response.status}`);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
async forbiddenOnBadOrigin() {
|
|
120
|
+
const token = config.auth.mode === 'bearer' ? config.auth.tokens[0] : 'dummy';
|
|
121
|
+
const response = await client.mcp({
|
|
122
|
+
...(token ? { token } : {}),
|
|
123
|
+
origin: 'https://evil.example',
|
|
124
|
+
body: '{}',
|
|
125
|
+
});
|
|
126
|
+
if (response.status !== 403) {
|
|
127
|
+
throw new Error(`Expected 403 for bad Origin, got ${response.status}`);
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
async initializeAndListTools(token) {
|
|
131
|
+
const initBody = {
|
|
132
|
+
jsonrpc: '2.0',
|
|
133
|
+
id: 1,
|
|
134
|
+
method: 'initialize',
|
|
135
|
+
params: {
|
|
136
|
+
protocolVersion: '2025-06-18',
|
|
137
|
+
capabilities: {},
|
|
138
|
+
clientInfo: { name: 'kit-test', version: '0' },
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
const initResponse = await client.mcp({
|
|
142
|
+
token,
|
|
143
|
+
body: JSON.stringify(initBody),
|
|
144
|
+
});
|
|
145
|
+
if (!initResponse.ok) {
|
|
146
|
+
throw new Error(`initialize failed: ${initResponse.status} ${await initResponse.text()}`);
|
|
147
|
+
}
|
|
148
|
+
await readMcpJsonResponse(initResponse);
|
|
149
|
+
const listBody = {
|
|
150
|
+
jsonrpc: '2.0',
|
|
151
|
+
id: 2,
|
|
152
|
+
method: 'tools/list',
|
|
153
|
+
params: {},
|
|
154
|
+
};
|
|
155
|
+
const listResponse = await client.mcp({
|
|
156
|
+
token,
|
|
157
|
+
headers: {
|
|
158
|
+
'mcp-protocol-version': '2025-06-18',
|
|
159
|
+
},
|
|
160
|
+
body: JSON.stringify(listBody),
|
|
161
|
+
});
|
|
162
|
+
if (!listResponse.ok) {
|
|
163
|
+
throw new Error(`tools/list failed: ${listResponse.status} ${await listResponse.text()}`);
|
|
164
|
+
}
|
|
165
|
+
const payload = (await readMcpJsonResponse(listResponse));
|
|
166
|
+
const tools = payload.result?.tools ?? payload.tools ?? [];
|
|
167
|
+
return { tools };
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/test/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,mBAAmB,GAGpB,MAAM,cAAc,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { AuthInfo, McpServer, Server } from '@modelcontextprotocol/server';
|
|
3
|
+
/** Transport selected by `MCP_TRANSPORT`. */
|
|
4
|
+
export type TransportMode = 'stdio' | 'http';
|
|
5
|
+
/** Authentication strategy for Streamable HTTP. */
|
|
6
|
+
export type AuthMode = 'bearer' | 'oauth' | 'none';
|
|
7
|
+
/** How upstream service credentials are resolved per request. */
|
|
8
|
+
export type UpstreamCredentialMode = 'env' | 'header';
|
|
9
|
+
export type BearerAuthConfig = {
|
|
10
|
+
mode: 'bearer';
|
|
11
|
+
/** Accepted bearer tokens (rotation-friendly). */
|
|
12
|
+
tokens: string[];
|
|
13
|
+
};
|
|
14
|
+
export type OAuthAuthConfig = {
|
|
15
|
+
mode: 'oauth';
|
|
16
|
+
/** Canonical resource identifier (usually the public MCP URL). */
|
|
17
|
+
resource: string;
|
|
18
|
+
/** Authorization server issuer URLs (RFC 9728 `authorization_servers`). */
|
|
19
|
+
authorizationServers: string[];
|
|
20
|
+
/** Expected JWT audience values (resource indicator and/or explicit aud). */
|
|
21
|
+
audiences: string[];
|
|
22
|
+
/** Optional JWKS URL override; otherwise derived from AS metadata / well-known. */
|
|
23
|
+
jwksUrl?: string;
|
|
24
|
+
/** Required scopes (all must be present). Empty = any scope / no scope check. */
|
|
25
|
+
requiredScopes: string[];
|
|
26
|
+
/** Scopes advertised in protected-resource metadata. */
|
|
27
|
+
scopesSupported: string[];
|
|
28
|
+
};
|
|
29
|
+
export type NoneAuthConfig = {
|
|
30
|
+
mode: 'none';
|
|
31
|
+
/** Must be true when binding beyond localhost. */
|
|
32
|
+
allowPublic: boolean;
|
|
33
|
+
};
|
|
34
|
+
export type AuthConfig = BearerAuthConfig | OAuthAuthConfig | NoneAuthConfig;
|
|
35
|
+
export type HttpListenConfig = {
|
|
36
|
+
host: string;
|
|
37
|
+
port: number;
|
|
38
|
+
/** MCP endpoint path (default `/mcp`). */
|
|
39
|
+
path: string;
|
|
40
|
+
/** Primary unauthenticated health path (default `/health`). */
|
|
41
|
+
healthPath: string;
|
|
42
|
+
/**
|
|
43
|
+
* Extra health paths served like `healthPath` (e.g. `/healthz`).
|
|
44
|
+
* Always includes `healthPath`; duplicates are removed.
|
|
45
|
+
*/
|
|
46
|
+
healthPaths: string[];
|
|
47
|
+
allowedHosts: string[];
|
|
48
|
+
allowedOrigins: string[];
|
|
49
|
+
/** Max request body size in bytes. */
|
|
50
|
+
maxBodyBytes: number;
|
|
51
|
+
/** When true, GET/DELETE on the MCP path are forwarded (default: 405). */
|
|
52
|
+
enableSessionMethods: boolean;
|
|
53
|
+
};
|
|
54
|
+
/** Extra fields merged into the JSON health response (alongside `status: "ok"`). */
|
|
55
|
+
export type HealthInfo = Record<string, unknown>;
|
|
56
|
+
/** Optional hook to enrich `/health` (and aliases) with version, tool counts, etc. */
|
|
57
|
+
export type HealthInfoProvider = () => HealthInfo | Promise<HealthInfo>;
|
|
58
|
+
export type KitConfig = {
|
|
59
|
+
transport: TransportMode;
|
|
60
|
+
http: HttpListenConfig;
|
|
61
|
+
auth: AuthConfig;
|
|
62
|
+
/** Realm used in WWW-Authenticate for bearer. */
|
|
63
|
+
realm: string;
|
|
64
|
+
/** Warnings emitted while loading (e.g. deprecated env aliases). */
|
|
65
|
+
warnings: string[];
|
|
66
|
+
};
|
|
67
|
+
/** Auth context attached to an accepted HTTP request. */
|
|
68
|
+
export type AuthContext = {
|
|
69
|
+
mode: AuthMode;
|
|
70
|
+
/** Bearer token or access token string when present. */
|
|
71
|
+
token?: string;
|
|
72
|
+
/** JWT `sub` (oauth) when available. */
|
|
73
|
+
subject?: string;
|
|
74
|
+
/** Granted scopes (oauth) or empty for bearer/none. */
|
|
75
|
+
scopes: string[];
|
|
76
|
+
/** Raw JWT claims (oauth only). */
|
|
77
|
+
claims?: Record<string, unknown>;
|
|
78
|
+
};
|
|
79
|
+
export type RequestContext = {
|
|
80
|
+
auth: AuthContext;
|
|
81
|
+
headers: Headers;
|
|
82
|
+
/** Absolute request URL. */
|
|
83
|
+
url: URL;
|
|
84
|
+
/** Protocol era from the SDK factory (`modern` | `legacy`). */
|
|
85
|
+
era: 'legacy' | 'modern';
|
|
86
|
+
/** SDK pass-through auth info (scopes available to `requireScopes` / tool handlers). */
|
|
87
|
+
authInfo?: AuthInfo;
|
|
88
|
+
};
|
|
89
|
+
export type ServerFactory = (context: RequestContext) => McpServer | Server | Promise<McpServer | Server>;
|
|
90
|
+
export type UpstreamCredentialOptions = {
|
|
91
|
+
mode: UpstreamCredentialMode;
|
|
92
|
+
/** Env var used when `mode === 'env'`. */
|
|
93
|
+
envVar: string;
|
|
94
|
+
/** Header name used when `mode === 'header'` (e.g. `X-Contabo-Api-Key`). */
|
|
95
|
+
headerName: string;
|
|
96
|
+
/** Current kit auth mode — header mode is refused when auth is `none`. */
|
|
97
|
+
authMode: AuthMode;
|
|
98
|
+
env?: NodeJS.ProcessEnv;
|
|
99
|
+
};
|
|
100
|
+
export type NodeHttpRequest = IncomingMessage;
|
|
101
|
+
export type NodeHttpResponse = ServerResponse;
|
|
102
|
+
export type StartMcpServerOptions = {
|
|
103
|
+
createServer: ServerFactory;
|
|
104
|
+
/** Pre-loaded config; defaults to `loadConfig()`. */
|
|
105
|
+
config?: KitConfig;
|
|
106
|
+
env?: NodeJS.ProcessEnv;
|
|
107
|
+
/** Optional hook fired after the HTTP server starts listening. */
|
|
108
|
+
onListening?: (info: {
|
|
109
|
+
host: string;
|
|
110
|
+
port: number;
|
|
111
|
+
url: string;
|
|
112
|
+
}) => void;
|
|
113
|
+
/** Optional extra fields for the health JSON body (merged under `status: "ok"`). */
|
|
114
|
+
getHealthInfo?: HealthInfoProvider;
|
|
115
|
+
signal?: AbortSignal;
|
|
116
|
+
};
|
|
117
|
+
export type StartedServer = {
|
|
118
|
+
close: () => Promise<void>;
|
|
119
|
+
/** Present in HTTP mode. */
|
|
120
|
+
url?: string;
|
|
121
|
+
config: KitConfig;
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEhF,6CAA6C;AAC7C,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7C,mDAAmD;AACnD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAEnD,iEAAiE;AACjE,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEtD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,kDAAkD;IAClD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,6EAA6E;IAC7E,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,wDAAwD;IACxD,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,gBAAgB,GAAG,eAAe,GAAG,cAAc,CAAC;AAE7E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,oBAAoB,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,sFAAsF;AACtF,MAAM,MAAM,kBAAkB,GAAG,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAExE,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE,aAAa,CAAC;IACzB,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,yDAAyD;AACzD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,GAAG,EAAE,GAAG,CAAC;IACT,+DAA+D;IAC/D,GAAG,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,cAAc,KACpB,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;AAEtD,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,EAAE,QAAQ,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC;AAC9C,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAE9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,EAAE,aAAa,CAAC;IAC5B,qDAAqD;IACrD,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,kEAAkE;IAClE,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1E,oFAAoF;IACpF,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AuthMode, UpstreamCredentialMode, UpstreamCredentialOptions } from './types.js';
|
|
2
|
+
export type UpstreamCredentialResult = {
|
|
3
|
+
mode: UpstreamCredentialMode;
|
|
4
|
+
value: string;
|
|
5
|
+
source: 'env' | 'header';
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Resolve per-request upstream credentials (e.g. `X-Contabo-Api-Key`).
|
|
9
|
+
*
|
|
10
|
+
* Header mode is refused when kit auth is `none` — otherwise anyone could
|
|
11
|
+
* smuggle upstream keys through an open endpoint.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveUpstreamCredential(headers: Headers | Record<string, string | string[] | undefined>, options: UpstreamCredentialOptions): UpstreamCredentialResult;
|
|
14
|
+
export declare function parseUpstreamCredentialMode(raw: string | undefined, fallback?: UpstreamCredentialMode): UpstreamCredentialMode;
|
|
15
|
+
/** Guard used by servers that expose a documented `X-<Service>-*` header. */
|
|
16
|
+
export declare function assertHeaderModeAllowed(authMode: AuthMode): void;
|
|
17
|
+
//# sourceMappingURL=upstream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream.d.ts","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE9F,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC1B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EAChE,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,CAsB1B;AAED,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,GAAE,sBAA8B,GACvC,sBAAsB,CAKxB;AAED,6EAA6E;AAC7E,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAIhE"}
|
package/dist/upstream.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve per-request upstream credentials (e.g. `X-Contabo-Api-Key`).
|
|
3
|
+
*
|
|
4
|
+
* Header mode is refused when kit auth is `none` — otherwise anyone could
|
|
5
|
+
* smuggle upstream keys through an open endpoint.
|
|
6
|
+
*/
|
|
7
|
+
export function resolveUpstreamCredential(headers, options) {
|
|
8
|
+
const { mode, envVar, headerName, authMode, env = process.env } = options;
|
|
9
|
+
if (mode === 'header' && authMode === 'none') {
|
|
10
|
+
throw new Error('Upstream credential mode "header" is not allowed when MCP_AUTH_MODE=none');
|
|
11
|
+
}
|
|
12
|
+
if (mode === 'env') {
|
|
13
|
+
const value = env[envVar]?.trim();
|
|
14
|
+
if (!value) {
|
|
15
|
+
throw new Error(`${envVar} is required when upstream credential mode is "env"`);
|
|
16
|
+
}
|
|
17
|
+
return { mode: 'env', value, source: 'env' };
|
|
18
|
+
}
|
|
19
|
+
const raw = getHeader(headers, headerName);
|
|
20
|
+
if (!raw?.trim()) {
|
|
21
|
+
throw new Error(`Missing required upstream credential header: ${headerName}`);
|
|
22
|
+
}
|
|
23
|
+
return { mode: 'header', value: raw.trim(), source: 'header' };
|
|
24
|
+
}
|
|
25
|
+
export function parseUpstreamCredentialMode(raw, fallback = 'env') {
|
|
26
|
+
if (!raw)
|
|
27
|
+
return fallback;
|
|
28
|
+
const value = raw.trim().toLowerCase();
|
|
29
|
+
if (value === 'env' || value === 'header')
|
|
30
|
+
return value;
|
|
31
|
+
throw new Error(`Upstream credential mode must be env|header (got ${JSON.stringify(raw)})`);
|
|
32
|
+
}
|
|
33
|
+
/** Guard used by servers that expose a documented `X-<Service>-*` header. */
|
|
34
|
+
export function assertHeaderModeAllowed(authMode) {
|
|
35
|
+
if (authMode === 'none') {
|
|
36
|
+
throw new Error('Header-based upstream credentials require bearer or oauth auth');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getHeader(headers, name) {
|
|
40
|
+
if (typeof headers.get === 'function') {
|
|
41
|
+
return headers.get(name) ?? undefined;
|
|
42
|
+
}
|
|
43
|
+
const record = headers;
|
|
44
|
+
const direct = record[name] ?? record[name.toLowerCase()];
|
|
45
|
+
if (Array.isArray(direct))
|
|
46
|
+
return direct[0];
|
|
47
|
+
return direct;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=upstream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream.js","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAgE,EAChE,OAAkC;IAElC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;IAE1E,IAAI,IAAI,KAAK,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,qDAAqD,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gDAAgD,UAAU,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,GAAuB,EACvB,WAAmC,KAAK;IAExC,IAAI,CAAC,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACvC,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,IAAI,KAAK,CAAC,oDAAoD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC9F,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,uBAAuB,CAAC,QAAkB;IACxD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAChB,OAAgE,EAChE,IAAY;IAEZ,IAAI,OAAQ,OAAmB,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;QACnD,OAAQ,OAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;IACrD,CAAC;IACD,MAAM,MAAM,GAAG,OAAwD,CAAC;IACxE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|