@mcpolyglot/core 0.1.0 → 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/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/oauth.test.d.ts +2 -0
- package/dist/__tests__/oauth.test.d.ts.map +1 -0
- package/dist/__tests__/oauth.test.js +158 -0
- package/dist/__tests__/oauth.test.js.map +1 -0
- package/dist/__tests__/streamable-http.test.d.ts +2 -0
- package/dist/__tests__/streamable-http.test.d.ts.map +1 -0
- package/dist/__tests__/streamable-http.test.js +64 -0
- package/dist/__tests__/streamable-http.test.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -5
- package/dist/server.js.map +1 -1
- package/dist/tool.d.ts +12 -3
- package/dist/tool.d.ts.map +1 -1
- package/dist/tool.js.map +1 -1
- package/dist/transports/oauth.d.ts +56 -0
- package/dist/transports/oauth.d.ts.map +1 -0
- package/dist/transports/oauth.js +65 -0
- package/dist/transports/oauth.js.map +1 -0
- package/dist/transports/streamable-http.d.ts +26 -2
- package/dist/transports/streamable-http.d.ts.map +1 -1
- package/dist/transports/streamable-http.js +78 -14
- package/dist/transports/streamable-http.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
import { exportJWK, generateKeyPair, SignJWT } from 'jose';
|
|
4
|
+
import { createOAuthVerifier } from '../transports/oauth.js';
|
|
5
|
+
async function makeKey(kid) {
|
|
6
|
+
const { publicKey, privateKey } = await generateKeyPair('RS256');
|
|
7
|
+
const publicJwk = await exportJWK(publicKey);
|
|
8
|
+
publicJwk.kid = kid;
|
|
9
|
+
publicJwk.alg = 'RS256';
|
|
10
|
+
publicJwk.use = 'sig';
|
|
11
|
+
return { privateKey, publicJwk, kid };
|
|
12
|
+
}
|
|
13
|
+
async function sign(key, claims, opts) {
|
|
14
|
+
const jwt = new SignJWT(claims)
|
|
15
|
+
.setProtectedHeader({ alg: 'RS256', kid: key.kid })
|
|
16
|
+
.setIssuedAt()
|
|
17
|
+
.setIssuer(opts.issuer)
|
|
18
|
+
.setAudience(opts.audience);
|
|
19
|
+
if (opts.expiresIn)
|
|
20
|
+
jwt.setExpirationTime(opts.expiresIn);
|
|
21
|
+
return jwt.sign(key.privateKey);
|
|
22
|
+
}
|
|
23
|
+
describe('createOAuthVerifier', () => {
|
|
24
|
+
let server;
|
|
25
|
+
let port;
|
|
26
|
+
let issuer;
|
|
27
|
+
let audience;
|
|
28
|
+
let key;
|
|
29
|
+
let otherKey;
|
|
30
|
+
let jwks;
|
|
31
|
+
beforeAll(async () => {
|
|
32
|
+
key = await makeKey('test-key-1');
|
|
33
|
+
otherKey = await makeKey('test-key-2');
|
|
34
|
+
jwks = { keys: [key.publicJwk] };
|
|
35
|
+
server = createServer((req, res) => {
|
|
36
|
+
if (req.url === '/jwks.json') {
|
|
37
|
+
res.statusCode = 200;
|
|
38
|
+
res.setHeader('content-type', 'application/json');
|
|
39
|
+
res.end(JSON.stringify(jwks));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
res.statusCode = 404;
|
|
43
|
+
res.end();
|
|
44
|
+
});
|
|
45
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', () => resolve()));
|
|
46
|
+
port = server.address().port;
|
|
47
|
+
issuer = `http://127.0.0.1:${port}`;
|
|
48
|
+
audience = 'mcpolyglot-test';
|
|
49
|
+
});
|
|
50
|
+
afterAll(async () => {
|
|
51
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
52
|
+
});
|
|
53
|
+
it('accepts a well-formed token', async () => {
|
|
54
|
+
const verifier = createOAuthVerifier({
|
|
55
|
+
issuer,
|
|
56
|
+
audience,
|
|
57
|
+
jwksUri: `${issuer}/jwks.json`,
|
|
58
|
+
});
|
|
59
|
+
const token = await sign(key, { sub: 'alice' }, { issuer, audience, expiresIn: '5m' });
|
|
60
|
+
const result = await verifier.verify(token);
|
|
61
|
+
expect(result.ok).toBe(true);
|
|
62
|
+
if (result.ok) {
|
|
63
|
+
expect(result.sub).toBe('alice');
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it('rejects a token with the wrong issuer', async () => {
|
|
67
|
+
const verifier = createOAuthVerifier({
|
|
68
|
+
issuer,
|
|
69
|
+
audience,
|
|
70
|
+
jwksUri: `${issuer}/jwks.json`,
|
|
71
|
+
});
|
|
72
|
+
const token = await sign(key, { sub: 'alice' }, { issuer: 'https://evil.example', audience, expiresIn: '5m' });
|
|
73
|
+
const result = await verifier.verify(token);
|
|
74
|
+
expect(result).toEqual({ ok: false, reason: 'claim_validation_failed' });
|
|
75
|
+
});
|
|
76
|
+
it('rejects a token with the wrong audience', async () => {
|
|
77
|
+
const verifier = createOAuthVerifier({
|
|
78
|
+
issuer,
|
|
79
|
+
audience,
|
|
80
|
+
jwksUri: `${issuer}/jwks.json`,
|
|
81
|
+
});
|
|
82
|
+
const token = await sign(key, { sub: 'alice' }, { issuer, audience: 'someone-else', expiresIn: '5m' });
|
|
83
|
+
const result = await verifier.verify(token);
|
|
84
|
+
expect(result).toEqual({ ok: false, reason: 'claim_validation_failed' });
|
|
85
|
+
});
|
|
86
|
+
it('rejects an expired token', async () => {
|
|
87
|
+
const verifier = createOAuthVerifier({
|
|
88
|
+
issuer,
|
|
89
|
+
audience,
|
|
90
|
+
jwksUri: `${issuer}/jwks.json`,
|
|
91
|
+
// No clock tolerance, so a token in the past fails immediately.
|
|
92
|
+
clockToleranceSeconds: 0,
|
|
93
|
+
});
|
|
94
|
+
// jose accepts negative expiresIn / past timestamps via setExpirationTime.
|
|
95
|
+
const jwt = new SignJWT({ sub: 'alice' })
|
|
96
|
+
.setProtectedHeader({ alg: 'RS256', kid: key.kid })
|
|
97
|
+
.setIssuedAt(Math.floor(Date.now() / 1000) - 600)
|
|
98
|
+
.setIssuer(issuer)
|
|
99
|
+
.setAudience(audience)
|
|
100
|
+
.setExpirationTime(Math.floor(Date.now() / 1000) - 60);
|
|
101
|
+
const token = await jwt.sign(key.privateKey);
|
|
102
|
+
const result = await verifier.verify(token);
|
|
103
|
+
expect(result).toEqual({ ok: false, reason: 'token_expired' });
|
|
104
|
+
});
|
|
105
|
+
it('rejects a token signed by an unknown key', async () => {
|
|
106
|
+
const verifier = createOAuthVerifier({
|
|
107
|
+
issuer,
|
|
108
|
+
audience,
|
|
109
|
+
jwksUri: `${issuer}/jwks.json`,
|
|
110
|
+
});
|
|
111
|
+
// Signed by a key whose JWK is not in the JWKS.
|
|
112
|
+
const token = await sign(otherKey, { sub: 'alice' }, { issuer, audience, expiresIn: '5m' });
|
|
113
|
+
const result = await verifier.verify(token);
|
|
114
|
+
expect(result.ok).toBe(false);
|
|
115
|
+
if (!result.ok) {
|
|
116
|
+
// jose can surface this as either no matching key or signature failure
|
|
117
|
+
// depending on whether the kid matches; both are acceptable rejections.
|
|
118
|
+
expect(['unknown_key', 'signature_invalid']).toContain(result.reason);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
it('rejects garbage as `invalid_token`', async () => {
|
|
122
|
+
const verifier = createOAuthVerifier({
|
|
123
|
+
issuer,
|
|
124
|
+
audience,
|
|
125
|
+
jwksUri: `${issuer}/jwks.json`,
|
|
126
|
+
});
|
|
127
|
+
const result = await verifier.verify('not.a.jwt');
|
|
128
|
+
expect(result.ok).toBe(false);
|
|
129
|
+
if (!result.ok)
|
|
130
|
+
expect(result.reason).toBe('invalid_token');
|
|
131
|
+
});
|
|
132
|
+
it('defaults the JWKS URI to issuer/.well-known/jwks.json', async () => {
|
|
133
|
+
// Hot-swap the route on the test server to serve the default path.
|
|
134
|
+
const altServer = createServer((req, res) => {
|
|
135
|
+
if (req.url === '/.well-known/jwks.json') {
|
|
136
|
+
res.statusCode = 200;
|
|
137
|
+
res.setHeader('content-type', 'application/json');
|
|
138
|
+
res.end(JSON.stringify(jwks));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
res.statusCode = 404;
|
|
142
|
+
res.end();
|
|
143
|
+
});
|
|
144
|
+
await new Promise((resolve) => altServer.listen(0, '127.0.0.1', () => resolve()));
|
|
145
|
+
const altPort = altServer.address().port;
|
|
146
|
+
const altIssuer = `http://127.0.0.1:${altPort}`;
|
|
147
|
+
try {
|
|
148
|
+
const verifier = createOAuthVerifier({ issuer: altIssuer, audience });
|
|
149
|
+
const token = await sign(key, { sub: 'alice' }, { issuer: altIssuer, audience, expiresIn: '5m' });
|
|
150
|
+
const result = await verifier.verify(token);
|
|
151
|
+
expect(result.ok).toBe(true);
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
await new Promise((resolve) => altServer.close(() => resolve()));
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
//# sourceMappingURL=oauth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.test.js","sourceRoot":"","sources":["../../src/__tests__/oauth.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-http.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/streamable-http.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { Server as McpServer } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StreamableHttpTransport } from '../transports/streamable-http.js';
|
|
4
|
+
// Silence the JSON banner the transport emits to stderr during tests.
|
|
5
|
+
const silentLogger = { info: () => { }, warn: () => { } };
|
|
6
|
+
async function fetchStatus(url, init) {
|
|
7
|
+
const res = await fetch(url, init);
|
|
8
|
+
const body = await res.text();
|
|
9
|
+
return { status: res.status, body };
|
|
10
|
+
}
|
|
11
|
+
describe('StreamableHttpTransport', () => {
|
|
12
|
+
let transport;
|
|
13
|
+
let mcpServer;
|
|
14
|
+
let baseUrl = '';
|
|
15
|
+
afterEach(async () => {
|
|
16
|
+
if (transport)
|
|
17
|
+
await transport.stop();
|
|
18
|
+
transport = undefined;
|
|
19
|
+
mcpServer = undefined;
|
|
20
|
+
baseUrl = '';
|
|
21
|
+
});
|
|
22
|
+
async function boot(opts) {
|
|
23
|
+
mcpServer = new McpServer({ name: 'mcpolyglot-test', version: '0.0.0' }, { capabilities: { tools: {} } });
|
|
24
|
+
transport = new StreamableHttpTransport({
|
|
25
|
+
...opts,
|
|
26
|
+
logger: silentLogger,
|
|
27
|
+
});
|
|
28
|
+
await transport.start(mcpServer);
|
|
29
|
+
// We bind on port 0 so the OS picks; recover the real port from the
|
|
30
|
+
// listening socket. Field access is intentional — the public class
|
|
31
|
+
// doesn't expose the address since the CLI already knows it.
|
|
32
|
+
const httpServer = transport
|
|
33
|
+
.httpServer;
|
|
34
|
+
baseUrl = `http://${opts.host}:${httpServer.address().port}`;
|
|
35
|
+
}
|
|
36
|
+
it('serves /healthz without auth', async () => {
|
|
37
|
+
await boot({ host: '127.0.0.1', port: 0, auth: { kind: 'bearer', token: 'shh' } });
|
|
38
|
+
const res = await fetchStatus(`${baseUrl}/healthz`);
|
|
39
|
+
expect(res.status).toBe(200);
|
|
40
|
+
expect(JSON.parse(res.body)).toEqual({ ok: true });
|
|
41
|
+
});
|
|
42
|
+
it('rejects requests without a Bearer header', async () => {
|
|
43
|
+
await boot({ host: '127.0.0.1', port: 0, auth: { kind: 'bearer', token: 'shh' } });
|
|
44
|
+
const res = await fetchStatus(`${baseUrl}/mcp`, { method: 'POST' });
|
|
45
|
+
expect(res.status).toBe(401);
|
|
46
|
+
expect(JSON.parse(res.body).reason).toBe('missing_bearer');
|
|
47
|
+
});
|
|
48
|
+
it('rejects a wrong bearer token', async () => {
|
|
49
|
+
await boot({ host: '127.0.0.1', port: 0, auth: { kind: 'bearer', token: 'shh' } });
|
|
50
|
+
const res = await fetchStatus(`${baseUrl}/mcp`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: { authorization: 'Bearer not-shh' },
|
|
53
|
+
});
|
|
54
|
+
expect(res.status).toBe(401);
|
|
55
|
+
expect(JSON.parse(res.body).reason).toBe('invalid_token');
|
|
56
|
+
});
|
|
57
|
+
it('exposes the auto-generated bearer token in `bearerToken`', async () => {
|
|
58
|
+
await boot({ host: '127.0.0.1', port: 0 });
|
|
59
|
+
expect(transport.authKind).toBe('bearer');
|
|
60
|
+
expect(typeof transport.bearerToken).toBe('string');
|
|
61
|
+
expect(transport.bearerToken.length).toBeGreaterThan(16);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=streamable-http.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamable-http.test.js","sourceRoot":"","sources":["../../src/__tests__/streamable-http.test.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { randomUUID, createHash } from 'node:crypto';
|
|
2
2
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
3
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
-
import {
|
|
4
|
+
import { z } from 'zod';
|
|
5
5
|
import { DEFAULT_SCOPES, } from './tool.js';
|
|
6
|
-
import { McpolyglotError,
|
|
6
|
+
import { McpolyglotError, TimeoutError } from './errors.js';
|
|
7
7
|
/**
|
|
8
8
|
* MCP server that wires connectors + security hooks + a transport.
|
|
9
9
|
*
|
|
@@ -49,7 +49,7 @@ export class McpolyglotServer {
|
|
|
49
49
|
tools: Array.from(this.tools.values()).map((t) => ({
|
|
50
50
|
name: t.name,
|
|
51
51
|
description: t.description,
|
|
52
|
-
inputSchema:
|
|
52
|
+
inputSchema: z.toJSONSchema(t.inputSchema, { target: 'draft-7' }),
|
|
53
53
|
})),
|
|
54
54
|
}));
|
|
55
55
|
this.server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
@@ -147,9 +147,11 @@ export class McpolyglotServer {
|
|
|
147
147
|
catch (err) {
|
|
148
148
|
const e = err;
|
|
149
149
|
errorEntry = { code: e.code ?? 'internal_error', message: e.message };
|
|
150
|
-
|
|
150
|
+
// Policy rejections (scope, read-only, rate limit, timeout) are tool errors the model
|
|
151
|
+
// can read and correct, not protocol failures.
|
|
152
|
+
if (err instanceof McpolyglotError && isPolicyRejection(err.code)) {
|
|
151
153
|
return {
|
|
152
|
-
content: [{ type: 'text', text: e.message }],
|
|
154
|
+
content: [{ type: 'text', text: `${err.code}: ${e.message}` }],
|
|
153
155
|
isError: true,
|
|
154
156
|
metadata: { durationMs: Date.now() - started },
|
|
155
157
|
};
|
|
@@ -172,6 +174,9 @@ export class McpolyglotServer {
|
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
}
|
|
177
|
+
function isPolicyRejection(code) {
|
|
178
|
+
return code.startsWith('forbidden.') || code === 'rate_limited' || code === 'timeout';
|
|
179
|
+
}
|
|
175
180
|
function hashArgs(args) {
|
|
176
181
|
return createHash('sha256')
|
|
177
182
|
.update(JSON.stringify(args ?? {}))
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AACnG,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/tool.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Loose Zod schema type used as the default bound on `ToolDefinition` /
|
|
4
|
+
* `ToolHandler`. We deliberately type the output as `any` so a connector
|
|
5
|
+
* defining `inputSchema: z.object({ name: z.string() })` can write
|
|
6
|
+
* `handler: ({ name }) => ...` without an explicit generic — the destructure
|
|
7
|
+
* remains permissive while runtime parsing still enforces the schema.
|
|
8
|
+
*/
|
|
9
|
+
export type AnyZodSchema = z.ZodType<any>;
|
|
10
|
+
export type ZodInfer<S extends AnyZodSchema> = z.infer<S>;
|
|
2
11
|
/** Every scope mcpolyglot understands. New scopes must be added here so the Zod config schema accepts them. */
|
|
3
12
|
export declare const ALL_SCOPES: readonly ["schema:read", "tables:read", "tables:write", "query:raw", "http:call"];
|
|
4
13
|
/** A capability a tool requires from the calling session. Checked by `ScopeGuard`. */
|
|
@@ -55,7 +64,7 @@ export interface ToolExecCtx {
|
|
|
55
64
|
* Handler signature for a tool. Args are pre-validated against `ToolDefinition.inputSchema`,
|
|
56
65
|
* so the function receives a parsed, typed value — no defensive validation needed.
|
|
57
66
|
*/
|
|
58
|
-
export type ToolHandler<S extends
|
|
67
|
+
export type ToolHandler<S extends AnyZodSchema = AnyZodSchema> = (args: ZodInfer<S>, ctx: ToolExecCtx) => Promise<ToolResult>;
|
|
59
68
|
/**
|
|
60
69
|
* The contract every connector returns from `listPrimitiveTools()` /
|
|
61
70
|
* `generatePerEntityTools()`. The `handler` is the only point where the connector
|
|
@@ -75,7 +84,7 @@ export type ToolHandler<S extends ZodTypeAny = ZodTypeAny> = (args: ZodInfer<S>,
|
|
|
75
84
|
* };
|
|
76
85
|
* ```
|
|
77
86
|
*/
|
|
78
|
-
export interface ToolDefinition<S extends
|
|
87
|
+
export interface ToolDefinition<S extends AnyZodSchema = AnyZodSchema> {
|
|
79
88
|
/** Globally-unique tool name. By convention: `<connector.id>.<verb>`. */
|
|
80
89
|
name: string;
|
|
81
90
|
/** Human-readable description shown to the model in `tools/list`. */
|
package/dist/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"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"}
|
package/dist/tool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../src/tool.ts"],"names":[],"mappings":"AAYA,+GAA+G;AAC/G,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,aAAa;IACb,aAAa;IACb,cAAc;IACd,WAAW;IACX,WAAW;CACH,CAAC;AAKX,8EAA8E;AAC9E,MAAM,CAAC,MAAM,cAAc,GAAqB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type JWTPayload } from 'jose';
|
|
2
|
+
export interface OAuthVerifierOptions {
|
|
3
|
+
/** OIDC issuer URL. Required. Token `iss` must match exactly. */
|
|
4
|
+
issuer: string;
|
|
5
|
+
/** Expected `aud` claim. Required. */
|
|
6
|
+
audience: string;
|
|
7
|
+
/**
|
|
8
|
+
* JWKS endpoint. If omitted, defaults to `${issuer}/.well-known/jwks.json`,
|
|
9
|
+
* which matches the convention used by Auth0, Okta, Keycloak, AWS Cognito,
|
|
10
|
+
* and most other OIDC providers.
|
|
11
|
+
*/
|
|
12
|
+
jwksUri?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Allowed clock skew, in seconds, when checking `exp` / `nbf`. Defaults to 30s
|
|
15
|
+
* — enough to absorb NTP drift between issuer and verifier without weakening
|
|
16
|
+
* expiry semantics.
|
|
17
|
+
*/
|
|
18
|
+
clockToleranceSeconds?: number;
|
|
19
|
+
}
|
|
20
|
+
/** Successful verification carries the subject and the full payload. */
|
|
21
|
+
export interface OAuthVerifyOk {
|
|
22
|
+
ok: true;
|
|
23
|
+
sub?: string;
|
|
24
|
+
payload: JWTPayload;
|
|
25
|
+
}
|
|
26
|
+
/** Failed verification carries a stable reason code suitable for logs / 401s. */
|
|
27
|
+
export interface OAuthVerifyErr {
|
|
28
|
+
ok: false;
|
|
29
|
+
/**
|
|
30
|
+
* Stable, machine-readable reason. Mapped from the `code` jose throws
|
|
31
|
+
* (e.g. `ERR_JWT_EXPIRED`) so callers can render `error_description`
|
|
32
|
+
* without leaking stack traces.
|
|
33
|
+
*/
|
|
34
|
+
reason: string;
|
|
35
|
+
}
|
|
36
|
+
export type OAuthVerifyResult = OAuthVerifyOk | OAuthVerifyErr;
|
|
37
|
+
export interface OAuthVerifier {
|
|
38
|
+
/** Validate a Bearer token's signature, issuer, audience, and timing. */
|
|
39
|
+
verify(token: string): Promise<OAuthVerifyResult>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build an OAuth bearer-token verifier backed by a remote JWKS. The JWKS is
|
|
43
|
+
* fetched on first use and cached / rotated by `jose` automatically (default
|
|
44
|
+
* 10-minute cooldown, 30-second timeout). Verification enforces:
|
|
45
|
+
*
|
|
46
|
+
* - signature against a JWKS-resolved key
|
|
47
|
+
* - `iss` exact-match
|
|
48
|
+
* - `aud` exact-match
|
|
49
|
+
* - `exp` / `nbf` within `clockToleranceSeconds`
|
|
50
|
+
*
|
|
51
|
+
* The verifier is intentionally minimal: scope mapping (e.g. translating an
|
|
52
|
+
* OAuth `scope` claim into the mcpolyglot scope set) is the caller's job, not
|
|
53
|
+
* the transport's. The transport's only contract is "the bearer is valid".
|
|
54
|
+
*/
|
|
55
|
+
export declare function createOAuthVerifier(opts: OAuthVerifierOptions): OAuthVerifier;
|
|
56
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/transports/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,UAAU,EAAwB,MAAM,MAAM,CAAC;AAE5F,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,KAAK,CAAC;IACV;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,cAAc,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACnD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,aAAa,CAmB7E"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createRemoteJWKSet, jwtVerify } from 'jose';
|
|
2
|
+
/**
|
|
3
|
+
* Build an OAuth bearer-token verifier backed by a remote JWKS. The JWKS is
|
|
4
|
+
* fetched on first use and cached / rotated by `jose` automatically (default
|
|
5
|
+
* 10-minute cooldown, 30-second timeout). Verification enforces:
|
|
6
|
+
*
|
|
7
|
+
* - signature against a JWKS-resolved key
|
|
8
|
+
* - `iss` exact-match
|
|
9
|
+
* - `aud` exact-match
|
|
10
|
+
* - `exp` / `nbf` within `clockToleranceSeconds`
|
|
11
|
+
*
|
|
12
|
+
* The verifier is intentionally minimal: scope mapping (e.g. translating an
|
|
13
|
+
* OAuth `scope` claim into the mcpolyglot scope set) is the caller's job, not
|
|
14
|
+
* the transport's. The transport's only contract is "the bearer is valid".
|
|
15
|
+
*/
|
|
16
|
+
export function createOAuthVerifier(opts) {
|
|
17
|
+
const jwksUri = opts.jwksUri ?? defaultJwksUri(opts.issuer);
|
|
18
|
+
const jwks = createRemoteJWKSet(new URL(jwksUri));
|
|
19
|
+
const clockTolerance = opts.clockToleranceSeconds ?? 30;
|
|
20
|
+
return {
|
|
21
|
+
async verify(token) {
|
|
22
|
+
try {
|
|
23
|
+
const result = await jwtVerify(token, jwks, {
|
|
24
|
+
issuer: opts.issuer,
|
|
25
|
+
audience: opts.audience,
|
|
26
|
+
clockTolerance,
|
|
27
|
+
});
|
|
28
|
+
return { ok: true, sub: result.payload.sub, payload: result.payload };
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
return { ok: false, reason: classifyError(e) };
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Strip a trailing slash from issuer before joining the JWKS path. */
|
|
37
|
+
function defaultJwksUri(issuer) {
|
|
38
|
+
return `${issuer.replace(/\/$/, '')}/.well-known/jwks.json`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Map `jose` errors and other failures to a small, stable set of reason
|
|
42
|
+
* strings. Anything we don't recognize collapses to `invalid_token` so we
|
|
43
|
+
* never leak verifier internals into a 401 response.
|
|
44
|
+
*/
|
|
45
|
+
function classifyError(e) {
|
|
46
|
+
if (typeof e === 'object' && e !== null && 'code' in e) {
|
|
47
|
+
const code = String(e.code);
|
|
48
|
+
switch (code) {
|
|
49
|
+
case 'ERR_JWT_EXPIRED':
|
|
50
|
+
return 'token_expired';
|
|
51
|
+
case 'ERR_JWT_CLAIM_VALIDATION_FAILED':
|
|
52
|
+
return 'claim_validation_failed';
|
|
53
|
+
case 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED':
|
|
54
|
+
return 'signature_invalid';
|
|
55
|
+
case 'ERR_JWKS_NO_MATCHING_KEY':
|
|
56
|
+
return 'unknown_key';
|
|
57
|
+
case 'ERR_JWKS_TIMEOUT':
|
|
58
|
+
return 'jwks_unavailable';
|
|
59
|
+
default:
|
|
60
|
+
return 'invalid_token';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return 'invalid_token';
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/transports/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAyC,MAAM,MAAM,CAAC;AA8C5F;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAA0B;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,IAAI,CAAC,qBAAqB,IAAI,EAAE,CAAC;IAExD,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAAa;YACxB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAoB,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;oBAC3D,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,cAAc;iBACf,CAAC,CAAC;gBACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;YACxE,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,SAAS,cAAc,CAAC,MAAc;IACpC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,wBAAwB,CAAC;AAC9D,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,CAAU;IAC/B,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,MAAM,CAAE,CAAuB,CAAC,IAAI,CAAC,CAAC;QACnD,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,iBAAiB;gBACpB,OAAO,eAAe,CAAC;YACzB,KAAK,iCAAiC;gBACpC,OAAO,yBAAyB,CAAC;YACnC,KAAK,uCAAuC;gBAC1C,OAAO,mBAAmB,CAAC;YAC7B,KAAK,0BAA0B;gBAC7B,OAAO,aAAa,CAAC;YACvB,KAAK,kBAAkB;gBACrB,OAAO,kBAAkB,CAAC;YAC5B;gBACE,OAAO,eAAe,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC"}
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import type { Server as McpServer } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
2
|
import type { Transport } from '../transport.js';
|
|
3
|
+
import { type OAuthVerifierOptions } from './oauth.js';
|
|
4
|
+
/** Bearer-token mode: a fixed shared secret on the `Authorization` header. */
|
|
5
|
+
export interface BearerAuthOptions {
|
|
6
|
+
kind: 'bearer';
|
|
7
|
+
/** Pre-shared bearer token. Auto-generated if omitted. */
|
|
8
|
+
token?: string;
|
|
9
|
+
}
|
|
10
|
+
/** OAuth mode: signature + claim verification against a JWKS. */
|
|
11
|
+
export interface OAuthAuthOptions extends OAuthVerifierOptions {
|
|
12
|
+
kind: 'oauth';
|
|
13
|
+
}
|
|
14
|
+
export type HttpAuthOptions = BearerAuthOptions | OAuthAuthOptions;
|
|
3
15
|
export interface StreamableHttpTransportOptions {
|
|
4
16
|
host: string;
|
|
5
17
|
port: number;
|
|
6
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Auth strategy. Defaults to `{ kind: 'bearer' }` (auto-generated token)
|
|
20
|
+
* for back-compat with the original API.
|
|
21
|
+
*/
|
|
22
|
+
auth?: HttpAuthOptions;
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Pass `auth: { kind: 'bearer', token }` instead. Retained so
|
|
25
|
+
* existing callers (and the CLI's `--http` flag without OAuth config)
|
|
26
|
+
* keep working unchanged.
|
|
27
|
+
*/
|
|
7
28
|
bearerToken?: string;
|
|
8
29
|
/** Where to log server startup banner / auth-failure events. Stderr by default. */
|
|
9
30
|
logger?: {
|
|
@@ -13,9 +34,12 @@ export interface StreamableHttpTransportOptions {
|
|
|
13
34
|
}
|
|
14
35
|
export declare class StreamableHttpTransport implements Transport {
|
|
15
36
|
readonly kind: "http";
|
|
16
|
-
|
|
37
|
+
/** Bearer token in use, or `undefined` when running in OAuth mode. */
|
|
38
|
+
readonly bearerToken: string | undefined;
|
|
39
|
+
readonly authKind: 'bearer' | 'oauth';
|
|
17
40
|
private readonly host;
|
|
18
41
|
private readonly port;
|
|
42
|
+
private readonly auth;
|
|
19
43
|
private readonly logger;
|
|
20
44
|
private inner?;
|
|
21
45
|
private httpServer?;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamable-http.d.ts","sourceRoot":"","sources":["../../src/transports/streamable-http.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"streamable-http.d.ts","sourceRoot":"","sources":["../../src/transports/streamable-http.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAA2C,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEhG,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC5D,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAEnE,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAC9D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAC/D,CAAC;CACH;AAMD,qBAAa,uBAAwB,YAAW,SAAS;IACvD,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwD;IAC/E,OAAO,CAAC,KAAK,CAAC,CAAgC;IAC9C,OAAO,CAAC,UAAU,CAAC,CAAa;gBAEpB,IAAI,EAAE,8BAA8B;IAc1C,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAkDvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YASb,MAAM;YAyBN,SAAS;CAwBxB"}
|