cdk-serverless 3.2.1 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -0
- package/docs/constructs/assets/hierarchy.js +1 -1
- package/docs/constructs/assets/navigation.js +1 -1
- package/docs/constructs/assets/search.js +1 -1
- package/docs/constructs/classes/McpAuth.html +43 -0
- package/docs/constructs/classes/McpCognitoAuth.html +43 -0
- package/docs/constructs/classes/RestApi.html +6 -3
- package/docs/constructs/classes/SingleTableDatastore.html +1 -1
- package/docs/constructs/classes/Workflow.html +1 -1
- package/docs/constructs/hierarchy.html +1 -1
- package/docs/constructs/index.html +112 -1
- package/docs/constructs/interfaces/McpAuthCognitoOptions.html +17 -0
- package/docs/constructs/interfaces/McpAuthFunctions.html +14 -0
- package/docs/constructs/interfaces/McpAuthGenericOptions.html +11 -0
- package/docs/constructs/interfaces/McpAuthOptions.html +33 -0
- package/docs/constructs/interfaces/McpAuthProps.html +43 -0
- package/docs/constructs/interfaces/McpCognitoAuthProps.html +49 -0
- package/docs/constructs/interfaces/RestApiProps.html +24 -6
- package/docs/constructs/modules.html +1 -1
- package/docs/lambda/index.html +112 -1
- package/docs/projen/index.html +112 -1
- package/lib/constructs/index.d.ts +2 -0
- package/lib/constructs/index.js +3 -1
- package/lib/constructs/mcp-auth.d.ts +117 -0
- package/lib/constructs/mcp-auth.js +127 -0
- package/lib/constructs/mcp-cognito-auth.d.ts +110 -0
- package/lib/constructs/mcp-cognito-auth.js +76 -0
- package/lib/constructs/rest-api.d.ts +136 -0
- package/lib/constructs/rest-api.js +159 -1
- package/lib/mcp-auth/config.d.ts +39 -0
- package/lib/mcp-auth/config.js +3 -0
- package/lib/mcp-auth/handlers/authorization-server.d.ts +7 -0
- package/lib/mcp-auth/handlers/authorization-server.js +34 -0
- package/lib/mcp-auth/handlers/authorize.d.ts +8 -0
- package/lib/mcp-auth/handlers/authorize.js +32 -0
- package/lib/mcp-auth/handlers/index.d.ts +7 -0
- package/lib/mcp-auth/handlers/index.js +24 -0
- package/lib/mcp-auth/handlers/protected-resource.d.ts +7 -0
- package/lib/mcp-auth/handlers/protected-resource.js +26 -0
- package/lib/mcp-auth/handlers/register.d.ts +7 -0
- package/lib/mcp-auth/handlers/register.js +68 -0
- package/lib/mcp-auth/handlers/token.d.ts +8 -0
- package/lib/mcp-auth/handlers/token.js +74 -0
- package/lib/mcp-auth/handlers/types.d.ts +21 -0
- package/lib/mcp-auth/handlers/types.js +3 -0
- package/lib/mcp-auth/handlers/validate-redirect-uris.d.ts +10 -0
- package/lib/mcp-auth/handlers/validate-redirect-uris.js +22 -0
- package/lib/mcp-auth/index.d.ts +3 -0
- package/lib/mcp-auth/index.js +20 -0
- package/lib/mcp-auth/lambda-handlers/authorization-server.handler.d.ts +2 -0
- package/lib/mcp-auth/lambda-handlers/authorization-server.handler.js +23 -0
- package/lib/mcp-auth/lambda-handlers/authorize.handler.d.ts +2 -0
- package/lib/mcp-auth/lambda-handlers/authorize.handler.js +23 -0
- package/lib/mcp-auth/lambda-handlers/env-config.d.ts +7 -0
- package/lib/mcp-auth/lambda-handlers/env-config.js +37 -0
- package/lib/mcp-auth/lambda-handlers/protected-resource.handler.d.ts +2 -0
- package/lib/mcp-auth/lambda-handlers/protected-resource.handler.js +23 -0
- package/lib/mcp-auth/lambda-handlers/register.handler.d.ts +2 -0
- package/lib/mcp-auth/lambda-handlers/register.handler.js +23 -0
- package/lib/mcp-auth/lambda-handlers/token.handler.d.ts +2 -0
- package/lib/mcp-auth/lambda-handlers/token.handler.js +23 -0
- package/lib/mcp-auth/mcp/errors.d.ts +8 -0
- package/lib/mcp-auth/mcp/errors.js +20 -0
- package/lib/mcp-auth/mcp/index.d.ts +4 -0
- package/lib/mcp-auth/mcp/index.js +21 -0
- package/lib/mcp-auth/mcp/jsonrpc.d.ts +21 -0
- package/lib/mcp-auth/mcp/jsonrpc.js +56 -0
- package/lib/mcp-auth/mcp/server.d.ts +9 -0
- package/lib/mcp-auth/mcp/server.js +107 -0
- package/lib/mcp-auth/mcp/types.d.ts +32 -0
- package/lib/mcp-auth/mcp/types.js +3 -0
- package/llm.md +214 -0
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpProtocolError = exports.McpUnauthorizedError = void 0;
|
|
4
|
+
class McpUnauthorizedError extends Error {
|
|
5
|
+
constructor(challenge, message = 'Unauthorized') {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'McpUnauthorizedError';
|
|
8
|
+
this.challenge = challenge;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.McpUnauthorizedError = McpUnauthorizedError;
|
|
12
|
+
class McpProtocolError extends Error {
|
|
13
|
+
constructor(code, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'McpProtocolError';
|
|
16
|
+
this.code = code;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.McpProtocolError = McpProtocolError;
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21jcC1hdXRoL21jcC9lcnJvcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsTUFBYSxvQkFBcUIsU0FBUSxLQUFLO0lBRTdDLFlBQVksU0FBaUIsRUFBRSxPQUFPLEdBQUcsY0FBYztRQUNyRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLHNCQUFzQixDQUFDO1FBQ25DLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO0lBQzdCLENBQUM7Q0FDRjtBQVBELG9EQU9DO0FBRUQsTUFBYSxnQkFBaUIsU0FBUSxLQUFLO0lBRXpDLFlBQVksSUFBWSxFQUFFLE9BQWU7UUFDdkMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxrQkFBa0IsQ0FBQztRQUMvQixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztJQUNuQixDQUFDO0NBQ0Y7QUFQRCw0Q0FPQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjbGFzcyBNY3BVbmF1dGhvcml6ZWRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgcHVibGljIHJlYWRvbmx5IGNoYWxsZW5nZTogc3RyaW5nO1xuICBjb25zdHJ1Y3RvcihjaGFsbGVuZ2U6IHN0cmluZywgbWVzc2FnZSA9ICdVbmF1dGhvcml6ZWQnKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ01jcFVuYXV0aG9yaXplZEVycm9yJztcbiAgICB0aGlzLmNoYWxsZW5nZSA9IGNoYWxsZW5nZTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgTWNwUHJvdG9jb2xFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgcHVibGljIHJlYWRvbmx5IGNvZGU6IG51bWJlcjtcbiAgY29uc3RydWN0b3IoY29kZTogbnVtYmVyLCBtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnTWNwUHJvdG9jb2xFcnJvcic7XG4gICAgdGhpcy5jb2RlID0gY29kZTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./errors"), exports);
|
|
18
|
+
__exportStar(require("./jsonrpc"), exports);
|
|
19
|
+
__exportStar(require("./server"), exports);
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWNwLWF1dGgvbWNwL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyQ0FBeUI7QUFDekIsNENBQTBCO0FBQzFCLDJDQUF5QjtBQUN6QiwwQ0FBd0IiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2Vycm9ycyc7XG5leHBvcnQgKiBmcm9tICcuL2pzb25ycGMnO1xuZXhwb3J0ICogZnJvbSAnLi9zZXJ2ZXInO1xuZXhwb3J0ICogZnJvbSAnLi90eXBlcyc7XG4iXX0=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Standard JSON-RPC error codes. */
|
|
2
|
+
export declare const PARSE_ERROR = -32700;
|
|
3
|
+
export declare const INVALID_REQUEST = -32600;
|
|
4
|
+
export declare const METHOD_NOT_FOUND = -32601;
|
|
5
|
+
export declare const INVALID_PARAMS = -32602;
|
|
6
|
+
export declare const INTERNAL_ERROR = -32603;
|
|
7
|
+
export interface JsonRpcRequest {
|
|
8
|
+
jsonrpc: '2.0';
|
|
9
|
+
id?: unknown;
|
|
10
|
+
method: string;
|
|
11
|
+
params?: unknown;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Validate and parse a JSON-RPC request from a raw body value.
|
|
15
|
+
* Throws McpProtocolError if the body is malformed.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseJsonRpcRequest(body: unknown): JsonRpcRequest;
|
|
18
|
+
/** Build a JSON-RPC success response object. */
|
|
19
|
+
export declare function jsonRpcSuccess(id: unknown, result: unknown): object;
|
|
20
|
+
/** Build a JSON-RPC error response object. */
|
|
21
|
+
export declare function jsonRpcError(id: unknown, code: number, message: string, data?: unknown): object;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.INTERNAL_ERROR = exports.INVALID_PARAMS = exports.METHOD_NOT_FOUND = exports.INVALID_REQUEST = exports.PARSE_ERROR = void 0;
|
|
4
|
+
exports.parseJsonRpcRequest = parseJsonRpcRequest;
|
|
5
|
+
exports.jsonRpcSuccess = jsonRpcSuccess;
|
|
6
|
+
exports.jsonRpcError = jsonRpcError;
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
/** Standard JSON-RPC error codes. */
|
|
9
|
+
exports.PARSE_ERROR = -32700;
|
|
10
|
+
exports.INVALID_REQUEST = -32600;
|
|
11
|
+
exports.METHOD_NOT_FOUND = -32601;
|
|
12
|
+
exports.INVALID_PARAMS = -32602;
|
|
13
|
+
exports.INTERNAL_ERROR = -32603;
|
|
14
|
+
/**
|
|
15
|
+
* Validate and parse a JSON-RPC request from a raw body value.
|
|
16
|
+
* Throws McpProtocolError if the body is malformed.
|
|
17
|
+
*/
|
|
18
|
+
function parseJsonRpcRequest(body) {
|
|
19
|
+
if (body === null || typeof body !== 'object' || Array.isArray(body)) {
|
|
20
|
+
throw new errors_1.McpProtocolError(exports.INVALID_REQUEST, 'Request body must be a JSON object');
|
|
21
|
+
}
|
|
22
|
+
const obj = body;
|
|
23
|
+
if (obj.jsonrpc !== '2.0') {
|
|
24
|
+
throw new errors_1.McpProtocolError(exports.INVALID_REQUEST, 'Invalid or missing jsonrpc version, must be "2.0"');
|
|
25
|
+
}
|
|
26
|
+
if (typeof obj.method !== 'string' || obj.method.length === 0) {
|
|
27
|
+
throw new errors_1.McpProtocolError(exports.INVALID_REQUEST, 'Missing or invalid method field');
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
jsonrpc: '2.0',
|
|
31
|
+
id: obj.id,
|
|
32
|
+
method: obj.method,
|
|
33
|
+
params: obj.params,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Build a JSON-RPC success response object. */
|
|
37
|
+
function jsonRpcSuccess(id, result) {
|
|
38
|
+
return {
|
|
39
|
+
jsonrpc: '2.0',
|
|
40
|
+
id: id ?? null,
|
|
41
|
+
result,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Build a JSON-RPC error response object. */
|
|
45
|
+
function jsonRpcError(id, code, message, data) {
|
|
46
|
+
const error = { code, message };
|
|
47
|
+
if (data !== undefined) {
|
|
48
|
+
error.data = data;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
jsonrpc: '2.0',
|
|
52
|
+
id: id ?? null,
|
|
53
|
+
error,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbnJwYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tY3AtYXV0aC9tY3AvanNvbnJwYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFvQkEsa0RBcUJDO0FBR0Qsd0NBTUM7QUFHRCxvQ0FVQztBQS9ERCxxQ0FBNEM7QUFFNUMscUNBQXFDO0FBQ3hCLFFBQUEsV0FBVyxHQUFHLENBQUMsS0FBSyxDQUFDO0FBQ3JCLFFBQUEsZUFBZSxHQUFHLENBQUMsS0FBSyxDQUFDO0FBQ3pCLFFBQUEsZ0JBQWdCLEdBQUcsQ0FBQyxLQUFLLENBQUM7QUFDMUIsUUFBQSxjQUFjLEdBQUcsQ0FBQyxLQUFLLENBQUM7QUFDeEIsUUFBQSxjQUFjLEdBQUcsQ0FBQyxLQUFLLENBQUM7QUFTckM7OztHQUdHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQUMsSUFBYTtJQUMvQyxJQUFJLElBQUksS0FBSyxJQUFJLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNyRSxNQUFNLElBQUkseUJBQWdCLENBQUMsdUJBQWUsRUFBRSxvQ0FBb0MsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7SUFFRCxNQUFNLEdBQUcsR0FBRyxJQUErQixDQUFDO0lBRTVDLElBQUksR0FBRyxDQUFDLE9BQU8sS0FBSyxLQUFLLEVBQUUsQ0FBQztRQUMxQixNQUFNLElBQUkseUJBQWdCLENBQUMsdUJBQWUsRUFBRSxtREFBbUQsQ0FBQyxDQUFDO0lBQ25HLENBQUM7SUFFRCxJQUFJLE9BQU8sR0FBRyxDQUFDLE1BQU0sS0FBSyxRQUFRLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDOUQsTUFBTSxJQUFJLHlCQUFnQixDQUFDLHVCQUFlLEVBQUUsaUNBQWlDLENBQUMsQ0FBQztJQUNqRixDQUFDO0lBRUQsT0FBTztRQUNMLE9BQU8sRUFBRSxLQUFLO1FBQ2QsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFO1FBQ1YsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNO1FBQ2xCLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTTtLQUNuQixDQUFDO0FBQ0osQ0FBQztBQUVELGdEQUFnRDtBQUNoRCxTQUFnQixjQUFjLENBQUMsRUFBVyxFQUFFLE1BQWU7SUFDekQsT0FBTztRQUNMLE9BQU8sRUFBRSxLQUFLO1FBQ2QsRUFBRSxFQUFFLEVBQUUsSUFBSSxJQUFJO1FBQ2QsTUFBTTtLQUNQLENBQUM7QUFDSixDQUFDO0FBRUQsOENBQThDO0FBQzlDLFNBQWdCLFlBQVksQ0FBQyxFQUFXLEVBQUUsSUFBWSxFQUFFLE9BQWUsRUFBRSxJQUFjO0lBQ3JGLE1BQU0sS0FBSyxHQUE0QixFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUN6RCxJQUFJLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN2QixLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztJQUNwQixDQUFDO0lBQ0QsT0FBTztRQUNMLE9BQU8sRUFBRSxLQUFLO1FBQ2QsRUFBRSxFQUFFLEVBQUUsSUFBSSxJQUFJO1FBQ2QsS0FBSztLQUNOLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTWNwUHJvdG9jb2xFcnJvciB9IGZyb20gJy4vZXJyb3JzJztcblxuLyoqIFN0YW5kYXJkIEpTT04tUlBDIGVycm9yIGNvZGVzLiAqL1xuZXhwb3J0IGNvbnN0IFBBUlNFX0VSUk9SID0gLTMyNzAwO1xuZXhwb3J0IGNvbnN0IElOVkFMSURfUkVRVUVTVCA9IC0zMjYwMDtcbmV4cG9ydCBjb25zdCBNRVRIT0RfTk9UX0ZPVU5EID0gLTMyNjAxO1xuZXhwb3J0IGNvbnN0IElOVkFMSURfUEFSQU1TID0gLTMyNjAyO1xuZXhwb3J0IGNvbnN0IElOVEVSTkFMX0VSUk9SID0gLTMyNjAzO1xuXG5leHBvcnQgaW50ZXJmYWNlIEpzb25ScGNSZXF1ZXN0IHtcbiAganNvbnJwYzogJzIuMCc7XG4gIGlkPzogdW5rbm93bjtcbiAgbWV0aG9kOiBzdHJpbmc7XG4gIHBhcmFtcz86IHVua25vd247XG59XG5cbi8qKlxuICogVmFsaWRhdGUgYW5kIHBhcnNlIGEgSlNPTi1SUEMgcmVxdWVzdCBmcm9tIGEgcmF3IGJvZHkgdmFsdWUuXG4gKiBUaHJvd3MgTWNwUHJvdG9jb2xFcnJvciBpZiB0aGUgYm9keSBpcyBtYWxmb3JtZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUpzb25ScGNSZXF1ZXN0KGJvZHk6IHVua25vd24pOiBKc29uUnBjUmVxdWVzdCB7XG4gIGlmIChib2R5ID09PSBudWxsIHx8IHR5cGVvZiBib2R5ICE9PSAnb2JqZWN0JyB8fCBBcnJheS5pc0FycmF5KGJvZHkpKSB7XG4gICAgdGhyb3cgbmV3IE1jcFByb3RvY29sRXJyb3IoSU5WQUxJRF9SRVFVRVNULCAnUmVxdWVzdCBib2R5IG11c3QgYmUgYSBKU09OIG9iamVjdCcpO1xuICB9XG5cbiAgY29uc3Qgb2JqID0gYm9keSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICBpZiAob2JqLmpzb25ycGMgIT09ICcyLjAnKSB7XG4gICAgdGhyb3cgbmV3IE1jcFByb3RvY29sRXJyb3IoSU5WQUxJRF9SRVFVRVNULCAnSW52YWxpZCBvciBtaXNzaW5nIGpzb25ycGMgdmVyc2lvbiwgbXVzdCBiZSBcIjIuMFwiJyk7XG4gIH1cblxuICBpZiAodHlwZW9mIG9iai5tZXRob2QgIT09ICdzdHJpbmcnIHx8IG9iai5tZXRob2QubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IE1jcFByb3RvY29sRXJyb3IoSU5WQUxJRF9SRVFVRVNULCAnTWlzc2luZyBvciBpbnZhbGlkIG1ldGhvZCBmaWVsZCcpO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBqc29ucnBjOiAnMi4wJyxcbiAgICBpZDogb2JqLmlkLFxuICAgIG1ldGhvZDogb2JqLm1ldGhvZCxcbiAgICBwYXJhbXM6IG9iai5wYXJhbXMsXG4gIH07XG59XG5cbi8qKiBCdWlsZCBhIEpTT04tUlBDIHN1Y2Nlc3MgcmVzcG9uc2Ugb2JqZWN0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGpzb25ScGNTdWNjZXNzKGlkOiB1bmtub3duLCByZXN1bHQ6IHVua25vd24pOiBvYmplY3Qge1xuICByZXR1cm4ge1xuICAgIGpzb25ycGM6ICcyLjAnLFxuICAgIGlkOiBpZCA/PyBudWxsLFxuICAgIHJlc3VsdCxcbiAgfTtcbn1cblxuLyoqIEJ1aWxkIGEgSlNPTi1SUEMgZXJyb3IgcmVzcG9uc2Ugb2JqZWN0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGpzb25ScGNFcnJvcihpZDogdW5rbm93biwgY29kZTogbnVtYmVyLCBtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKTogb2JqZWN0IHtcbiAgY29uc3QgZXJyb3I6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0geyBjb2RlLCBtZXNzYWdlIH07XG4gIGlmIChkYXRhICE9PSB1bmRlZmluZWQpIHtcbiAgICBlcnJvci5kYXRhID0gZGF0YTtcbiAgfVxuICByZXR1cm4ge1xuICAgIGpzb25ycGM6ICcyLjAnLFxuICAgIGlkOiBpZCA/PyBudWxsLFxuICAgIGVycm9yLFxuICB9O1xufVxuIl19
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { McpResponse, McpServerOptions } from './types';
|
|
2
|
+
export interface McpServerHandle {
|
|
3
|
+
handle(body: unknown, headers: Record<string, string | undefined>): Promise<McpResponse>;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Creates an MCP JSON-RPC server that authenticates callers,
|
|
7
|
+
* advertises tools, and dispatches tool invocations.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createMcpServer<TPrincipal>(options: McpServerOptions<TPrincipal>): McpServerHandle;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMcpServer = createMcpServer;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const jsonrpc_1 = require("./jsonrpc");
|
|
6
|
+
/**
|
|
7
|
+
* Creates an MCP JSON-RPC server that authenticates callers,
|
|
8
|
+
* advertises tools, and dispatches tool invocations.
|
|
9
|
+
*/
|
|
10
|
+
function createMcpServer(options) {
|
|
11
|
+
return { handle };
|
|
12
|
+
async function handle(body, headers) {
|
|
13
|
+
// 1. Resolve credentials
|
|
14
|
+
let principal;
|
|
15
|
+
try {
|
|
16
|
+
principal = await options.resolver.resolve(headers);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
if (err instanceof errors_1.McpUnauthorizedError) {
|
|
20
|
+
return {
|
|
21
|
+
statusCode: 401,
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json',
|
|
24
|
+
'WWW-Authenticate': err.challenge,
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({ error: err.message }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
// 2. Parse JSON-RPC request
|
|
32
|
+
let request;
|
|
33
|
+
try {
|
|
34
|
+
request = (0, jsonrpc_1.parseJsonRpcRequest)(body);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
const code = err.code ?? -32600;
|
|
38
|
+
const message = err.message ?? 'Invalid request';
|
|
39
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcError)(null, code, message));
|
|
40
|
+
}
|
|
41
|
+
// 3. Dispatch on method
|
|
42
|
+
const { id, method, params } = request;
|
|
43
|
+
switch (method) {
|
|
44
|
+
case 'initialize':
|
|
45
|
+
return handleInitialize(id, params);
|
|
46
|
+
case 'notifications/initialized':
|
|
47
|
+
return { statusCode: 202, headers: { 'Content-Type': 'application/json' }, body: '' };
|
|
48
|
+
case 'tools/list':
|
|
49
|
+
return handleToolsList(id, principal);
|
|
50
|
+
case 'tools/call':
|
|
51
|
+
return handleToolsCall(id, principal, params);
|
|
52
|
+
default:
|
|
53
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcError)(id, jsonrpc_1.METHOD_NOT_FOUND, `Method not found: ${method}`));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function handleInitialize(id, params) {
|
|
57
|
+
const clientVersion = params?.protocolVersion;
|
|
58
|
+
if (!clientVersion || !options.protocolVersions.includes(clientVersion)) {
|
|
59
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcError)(id, jsonrpc_1.INVALID_PARAMS, `Unsupported protocol version. Supported: ${options.protocolVersions.join(', ')}`));
|
|
60
|
+
}
|
|
61
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcSuccess)(id, {
|
|
62
|
+
protocolVersion: clientVersion,
|
|
63
|
+
capabilities: { tools: {} },
|
|
64
|
+
serverInfo: options.serverInfo,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
async function handleToolsList(id, principal) {
|
|
68
|
+
const tools = await Promise.all(options.tools.map(async (tool) => {
|
|
69
|
+
const description = typeof tool.description === 'function'
|
|
70
|
+
? await tool.description(principal)
|
|
71
|
+
: tool.description;
|
|
72
|
+
return {
|
|
73
|
+
name: tool.name,
|
|
74
|
+
description,
|
|
75
|
+
inputSchema: tool.inputSchema,
|
|
76
|
+
};
|
|
77
|
+
}));
|
|
78
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcSuccess)(id, { tools }));
|
|
79
|
+
}
|
|
80
|
+
async function handleToolsCall(id, principal, params) {
|
|
81
|
+
const p = params;
|
|
82
|
+
const toolName = p?.name;
|
|
83
|
+
if (!toolName) {
|
|
84
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcError)(id, jsonrpc_1.INVALID_PARAMS, 'Missing params.name'));
|
|
85
|
+
}
|
|
86
|
+
const tool = options.tools.find((t) => t.name === toolName);
|
|
87
|
+
if (!tool) {
|
|
88
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcError)(id, jsonrpc_1.INVALID_PARAMS, `Unknown tool: ${toolName}`));
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const result = await tool.invoke(principal, p?.arguments);
|
|
92
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcSuccess)(id, result));
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
const message = err instanceof Error ? err.message : 'Internal error';
|
|
96
|
+
return jsonResponse(200, (0, jsonrpc_1.jsonRpcError)(id, jsonrpc_1.INTERNAL_ERROR, message));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function jsonResponse(statusCode, body) {
|
|
100
|
+
return {
|
|
101
|
+
statusCode,
|
|
102
|
+
headers: { 'Content-Type': 'application/json' },
|
|
103
|
+
body: JSON.stringify(body),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21jcC1hdXRoL21jcC9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFZQSwwQ0E2R0M7QUF6SEQscUNBQWdEO0FBQ2hELHVDQUFnSTtBQU9oSTs7O0dBR0c7QUFDSCxTQUFnQixlQUFlLENBQWEsT0FBcUM7SUFDL0UsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBRWxCLEtBQUssVUFBVSxNQUFNLENBQUMsSUFBYSxFQUFFLE9BQTJDO1FBQzlFLHlCQUF5QjtRQUN6QixJQUFJLFNBQXFCLENBQUM7UUFDMUIsSUFBSSxDQUFDO1lBQ0gsU0FBUyxHQUFHLE1BQU0sT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEQsQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDYixJQUFJLEdBQUcsWUFBWSw2QkFBb0IsRUFBRSxDQUFDO2dCQUN4QyxPQUFPO29CQUNMLFVBQVUsRUFBRSxHQUFHO29CQUNmLE9BQU8sRUFBRTt3QkFDUCxjQUFjLEVBQUUsa0JBQWtCO3dCQUNsQyxrQkFBa0IsRUFBRSxHQUFHLENBQUMsU0FBUztxQkFDbEM7b0JBQ0QsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDO2lCQUM3QyxDQUFDO1lBQ0osQ0FBQztZQUNELE1BQU0sR0FBRyxDQUFDO1FBQ1osQ0FBQztRQUVELDRCQUE0QjtRQUM1QixJQUFJLE9BQU8sQ0FBQztRQUNaLElBQUksQ0FBQztZQUNILE9BQU8sR0FBRyxJQUFBLDZCQUFtQixFQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFBQyxPQUFPLEdBQVksRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxHQUFJLEdBQXlCLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDO1lBQ3ZELE1B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L0MsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDO1NBQzNCLENBQUM7SUFDSixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE1jcFVuYXV0aG9yaXplZEVycm9yIH0gZnJvbSAnLi9lcnJvcnMnO1xuaW1wb3J0IHsganNvblJwY0Vycm9yLCBqc29uUnBjU3VjY2VzcywgSU5URVJOQUxfRVJST1IsIElOVkFMSURfUEFSQU1TLCBNRVRIT0RfTk9UX0ZPVU5ELCBwYXJzZUpzb25ScGNSZXF1ZXN0IH0gZnJvbSAnLi9qc29ucnBjJztcbmltcG9ydCB0eXBlIHsgTWNwUmVzcG9uc2UsIE1jcFNlcnZlck9wdGlvbnMgfSBmcm9tICcuL3R5cGVzJztcblxuZXhwb3J0IGludGVyZmFjZSBNY3BTZXJ2ZXJIYW5kbGUge1xuICBoYW5kbGUoYm9keTogdW5rbm93biwgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPik6IFByb21pc2U8TWNwUmVzcG9uc2U+O1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYW4gTUNQIEpTT04tUlBDIHNlcnZlciB0aGF0IGF1dGhlbnRpY2F0ZXMgY2FsbGVycyxcbiAqIGFkdmVydGlzZXMgdG9vbHMsIGFuZCBkaXNwYXRjaGVzIHRvb2wgaW52b2NhdGlvbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNY3BTZXJ2ZXI8VFByaW5jaXBhbD4ob3B0aW9uczogTWNwU2VydmVyT3B0aW9uczxUUHJpbmNpcGFsPik6IE1jcFNlcnZlckhhbmRsZSB7XG4gIHJldHVybiB7IGhhbmRsZSB9O1xuXG4gIGFzeW5jIGZ1bmN0aW9uIGhhbmRsZShib2R5OiB1bmtub3duLCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+KTogUHJvbWlzZTxNY3BSZXNwb25zZT4ge1xuICAgIC8vIDEuIFJlc29sdmUgY3JlZGVudGlhbHNcbiAgICBsZXQgcHJpbmNpcGFsOiBUUHJpbmNpcGFsO1xuICAgIHRyeSB7XG4gICAgICBwcmluY2lwYWwgPSBhd2FpdCBvcHRpb25zLnJlc29sdmVyLnJlc29sdmUoaGVhZGVycyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoZXJyIGluc3RhbmNlb2YgTWNwVW5hdXRob3JpemVkRXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzdGF0dXNDb2RlOiA0MDEsXG4gICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgICAgICdXV1ctQXV0aGVudGljYXRlJzogZXJyLmNoYWxsZW5nZSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZXJyb3I6IGVyci5tZXNzYWdlIH0pLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cblxuICAgIC8vIDIuIFBhcnNlIEpTT04tUlBDIHJlcXVlc3RcbiAgICBsZXQgcmVxdWVzdDtcbiAgICB0cnkge1xuICAgICAgcmVxdWVzdCA9IHBhcnNlSnNvblJwY1JlcXVlc3QoYm9keSk7XG4gICAgfSBjYXRjaCAoZXJyOiB1bmtub3duKSB7XG4gICAgICBjb25zdCBjb2RlID0gKGVyciBhcyB7IGNvZGU/OiBudW1iZXIgfSkuY29kZSA/PyAtMzI2MDA7XG4gICAgICBjb25zdCBtZXNzYWdlID0gKGVyciBhcyB7IG1lc3NhZ2U/OiBzdHJpbmcgfSkubWVzc2FnZSA/PyAnSW52YWxpZCByZXF1ZXN0JztcbiAgICAgIHJldHVybiBqc29uUmVzcG9uc2UoMjAwLCBqc29uUnBjRXJyb3IobnVsbCwgY29kZSwgbWVzc2FnZSkpO1xuICAgIH1cblxuICAgIC8vIDMuIERpc3BhdGNoIG9uIG1ldGhvZFxuICAgIGNvbnN0IHsgaWQsIG1ldGhvZCwgcGFyYW1zIH0gPSByZXF1ZXN0O1xuXG4gICAgc3dpdGNoIChtZXRob2QpIHtcbiAgICAgIGNhc2UgJ2luaXRpYWxpemUnOlxuICAgICAgICByZXR1cm4gaGFuZGxlSW5pdGlhbGl6ZShpZCwgcGFyYW1zKTtcbiAgICAgIGNhc2UgJ25vdGlmaWNhdGlvbnMvaW5pdGlhbGl6ZWQnOlxuICAgICAgICByZXR1cm4geyBzdGF0dXNDb2RlOiAyMDIsIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9LCBib2R5OiAnJyB9O1xuICAgICAgY2FzZSAndG9vbHMvbGlzdCc6XG4gICAgICAgIHJldHVybiBoYW5kbGVUb29sc0xpc3QoaWQsIHByaW5jaXBhbCk7XG4gICAgICBjYXNlICd0b29scy9jYWxsJzpcbiAgICAgICAgcmV0dXJuIGhhbmRsZVRvb2xzQ2FsbChpZCwgcHJpbmNpcGFsLCBwYXJhbXMpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIGpzb25SZXNwb25zZSgyMDAsIGpzb25ScGNFcnJvcihpZCwgTUVUSE9EX05PVF9GT1VORCwgYE1ldGhvZCBub3QgZm91bmQ6ICR7bWV0aG9kfWApKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBoYW5kbGVJbml0aWFsaXplKGlkOiB1bmtub3duLCBwYXJhbXM6IHVua25vd24pOiBNY3BSZXNwb25zZSB7XG4gICAgY29uc3QgY2xpZW50VmVyc2lvbiA9IChwYXJhbXMgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWQpPy5wcm90b2NvbFZlcnNpb24gYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgaWYgKCFjbGllbnRWZXJzaW9uIHx8ICFvcHRpb25zLnByb3RvY29sVmVyc2lvbnMuaW5jbHVkZXMoY2xpZW50VmVyc2lvbikpIHtcbiAgICAgIHJldHVybiBqc29uUmVzcG9uc2UoMjAwLCBqc29uUnBjRXJyb3IoaWQsIElOVkFMSURfUEFSQU1TLCBgVW5zdXBwb3J0ZWQgcHJvdG9jb2wgdmVyc2lvbi4gU3VwcG9ydGVkOiAke29wdGlvbnMucHJvdG9jb2xWZXJzaW9ucy5qb2luKCcsICcpfWApKTtcbiAgICB9XG5cbiAgICByZXR1cm4ganNvblJlc3BvbnNlKDIwMCwganNvblJwY1N1Y2Nlc3MoaWQsIHtcbiAgICAgIHByb3RvY29sVmVyc2lvbjogY2xpZW50VmVyc2lvbixcbiAgICAgIGNhcGFiaWxpdGllczogeyB0b29sczoge30gfSxcbiAgICAgIHNlcnZlckluZm86IG9wdGlvbnMuc2VydmVySW5mbyxcbiAgICB9KSk7XG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBoYW5kbGVUb29sc0xpc3QoaWQ6IHVua25vd24sIHByaW5jaXBhbDogVFByaW5jaXBhbCk6IFByb21pc2U8TWNwUmVzcG9uc2U+IHtcbiAgICBjb25zdCB0b29scyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgb3B0aW9ucy50b29scy5tYXAoYXN5bmMgKHRvb2wpID0+IHtcbiAgICAgICAgY29uc3QgZGVzY3JpcHRpb24gPSB0eXBlb2YgdG9vbC5kZXNjcmlwdGlvbiA9PT0gJ2Z1bmN0aW9uJ1xuICAgICAgICAgID8gYXdhaXQgdG9vbC5kZXNjcmlwdGlvbihwcmluY2lwYWwpXG4gICAgICAgICAgOiB0b29sLmRlc2NyaXB0aW9uO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5hbWU6IHRvb2wubmFtZSxcbiAgICAgICAgICBkZXNjcmlwdGlvbixcbiAgICAgICAgICBpbnB1dFNjaGVtYTogdG9vbC5pbnB1dFNjaGVtYSxcbiAgICAgICAgfTtcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICByZXR1cm4ganNvblJlc3BvbnNlKDIwMCwganNvblJwY1N1Y2Nlc3MoaWQsIHsgdG9vbHMgfSkpO1xuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gaGFuZGxlVG9vbHNDYWxsKGlkOiB1bmtub3duLCBwcmluY2lwYWw6IFRQcmluY2lwYWwsIHBhcmFtczogdW5rbm93bik6IFByb21pc2U8TWNwUmVzcG9uc2U+IHtcbiAgICBjb25zdCBwID0gcGFyYW1zIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IHRvb2xOYW1lID0gcD8ubmFtZSBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICBpZiAoIXRvb2xOYW1lKSB7XG4gICAgICByZXR1cm4ganNvblJlc3BvbnNlKDIwMCwganNvblJwY0Vycm9yKGlkLCBJTlZBTElEX1BBUkFNUywgJ01pc3NpbmcgcGFyYW1zLm5hbWUnKSk7XG4gICAgfVxuXG4gICAgY29uc3QgdG9vbCA9IG9wdGlvbnMudG9vbHMuZmluZCgodCkgPT4gdC5uYW1lID09PSB0b29sTmFtZSk7XG4gICAgaWYgKCF0b29sKSB7XG4gICAgICByZXR1cm4ganNvblJlc3BvbnNlKDIwMCwganNvblJwY0Vycm9yKGlkLCBJTlZBTElEX1BBUkFNUywgYFVua25vd24gdG9vbDogJHt0b29sTmFtZX1gKSk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRvb2wuaW52b2tlKHByaW5jaXBhbCwgcD8uYXJndW1lbnRzKTtcbiAgICAgIHJldHVybiBqc29uUmVzcG9uc2UoMjAwLCBqc29uUnBjU3VjY2VzcyhpZCwgcmVzdWx0KSk7XG4gICAgfSBjYXRjaCAoZXJyOiB1bmtub3duKSB7XG4gICAgICBjb25zdCBtZXNzYWdlID0gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6ICdJbnRlcm5hbCBlcnJvcic7XG4gICAgICByZXR1cm4ganNvblJlc3BvbnNlKDIwMCwganNvblJwY0Vycm9yKGlkLCBJTlRFUk5BTF9FUlJPUiwgbWVzc2FnZSkpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGpzb25SZXNwb25zZShzdGF0dXNDb2RlOiBudW1iZXIsIGJvZHk6IG9iamVjdCk6IE1jcFJlc3BvbnNlIHtcbiAgICByZXR1cm4ge1xuICAgICAgc3RhdHVzQ29kZSxcbiAgICAgIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9LFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSksXG4gICAgfTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface McpToolResult {
|
|
2
|
+
content: Array<{
|
|
3
|
+
type: 'text';
|
|
4
|
+
text: string;
|
|
5
|
+
}>;
|
|
6
|
+
isError?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface McpToolDefinition<TPrincipal> {
|
|
9
|
+
name: string;
|
|
10
|
+
/** Static text, or resolved per-caller (e.g., personalized source hints). */
|
|
11
|
+
description: string | ((principal: TPrincipal) => Promise<string>);
|
|
12
|
+
inputSchema: object;
|
|
13
|
+
invoke(principal: TPrincipal, args: unknown): Promise<McpToolResult>;
|
|
14
|
+
}
|
|
15
|
+
export interface McpCredentialResolver<TPrincipal> {
|
|
16
|
+
/** Throws McpUnauthorizedError when credentials are missing/invalid. */
|
|
17
|
+
resolve(headers: Record<string, string | undefined>): Promise<TPrincipal>;
|
|
18
|
+
}
|
|
19
|
+
export interface McpServerOptions<TPrincipal> {
|
|
20
|
+
serverInfo: {
|
|
21
|
+
name: string;
|
|
22
|
+
version: string;
|
|
23
|
+
};
|
|
24
|
+
protocolVersions: string[];
|
|
25
|
+
resolver: McpCredentialResolver<TPrincipal>;
|
|
26
|
+
tools: Array<McpToolDefinition<TPrincipal>>;
|
|
27
|
+
}
|
|
28
|
+
export interface McpResponse {
|
|
29
|
+
statusCode: number;
|
|
30
|
+
headers: Record<string, string>;
|
|
31
|
+
body: string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWNwLWF1dGgvbWNwL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgaW50ZXJmYWNlIE1jcFRvb2xSZXN1bHQge1xuICBjb250ZW50OiBBcnJheTx7IHR5cGU6ICd0ZXh0JzsgdGV4dDogc3RyaW5nIH0+O1xuICBpc0Vycm9yPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNY3BUb29sRGVmaW5pdGlvbjxUUHJpbmNpcGFsPiB7XG4gIG5hbWU6IHN0cmluZztcbiAgLyoqIFN0YXRpYyB0ZXh0LCBvciByZXNvbHZlZCBwZXItY2FsbGVyIChlLmcuLCBwZXJzb25hbGl6ZWQgc291cmNlIGhpbnRzKS4gKi9cbiAgZGVzY3JpcHRpb246IHN0cmluZyB8ICgocHJpbmNpcGFsOiBUUHJpbmNpcGFsKSA9PiBQcm9taXNlPHN0cmluZz4pO1xuICBpbnB1dFNjaGVtYTogb2JqZWN0OyAvLyBKU09OIFNjaGVtYVxuICBpbnZva2UocHJpbmNpcGFsOiBUUHJpbmNpcGFsLCBhcmdzOiB1bmtub3duKTogUHJvbWlzZTxNY3BUb29sUmVzdWx0Pjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNY3BDcmVkZW50aWFsUmVzb2x2ZXI8VFByaW5jaXBhbD4ge1xuICAvKiogVGhyb3dzIE1jcFVuYXV0aG9yaXplZEVycm9yIHdoZW4gY3JlZGVudGlhbHMgYXJlIG1pc3NpbmcvaW52YWxpZC4gKi9cbiAgcmVzb2x2ZShoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+KTogUHJvbWlzZTxUUHJpbmNpcGFsPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNY3BTZXJ2ZXJPcHRpb25zPFRQcmluY2lwYWw+IHtcbiAgc2VydmVySW5mbzogeyBuYW1lOiBzdHJpbmc7IHZlcnNpb246IHN0cmluZyB9O1xuICBwcm90b2NvbFZlcnNpb25zOiBzdHJpbmdbXTsgLy8gU3VwcG9ydGVkIHZlcnNpb25zLCBuZXdlc3QgZmlyc3RcbiAgcmVzb2x2ZXI6IE1jcENyZWRlbnRpYWxSZXNvbHZlcjxUUHJpbmNpcGFsPjtcbiAgdG9vbHM6IEFycmF5PE1jcFRvb2xEZWZpbml0aW9uPFRQcmluY2lwYWw+Pjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNY3BSZXNwb25zZSB7XG4gIHN0YXR1c0NvZGU6IG51bWJlcjtcbiAgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgYm9keTogc3RyaW5nO1xufVxuIl19
|
package/llm.md
CHANGED
|
@@ -343,6 +343,220 @@ describe('Integration Tests', () => {
|
|
|
343
343
|
});
|
|
344
344
|
```
|
|
345
345
|
|
|
346
|
+
## MCP Auth
|
|
347
|
+
|
|
348
|
+
MCP Auth is a service-agnostic OAuth façade for the [Model Context Protocol](https://spec.modelcontextprotocol.io). It adds OAuth 2.0 discovery, authorization, token exchange, and dynamic client registration endpoints to your API so MCP clients (Claude, ChatGPT, etc.) can authenticate via standard OAuth flows.
|
|
349
|
+
|
|
350
|
+
### Using with RestApi
|
|
351
|
+
|
|
352
|
+
The easiest way is via the `mcpAuth` prop on `RestApiProps`. It supports two mutually exclusive modes:
|
|
353
|
+
|
|
354
|
+
#### Cognito Mode
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
const api = new RestApi(this, 'Api', {
|
|
358
|
+
apiName: 'MyApi',
|
|
359
|
+
stageName: 'dev',
|
|
360
|
+
definitionFileName: 'openapi.yaml',
|
|
361
|
+
authentication: auth,
|
|
362
|
+
domainName: 'example.com',
|
|
363
|
+
apiHostname: 'api',
|
|
364
|
+
cors: true,
|
|
365
|
+
mcpAuth: {
|
|
366
|
+
cognito: {
|
|
367
|
+
auth: cognitoAuthentication, // CognitoAuthentication construct
|
|
368
|
+
authDomain: 'auth.example.com', // Cognito hosted/custom domain
|
|
369
|
+
},
|
|
370
|
+
serverInfo: { name: 'my-mcp-server', version: '1.0.0' },
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
A dedicated user pool client (auth code + PKCE) is created automatically with callback URLs for known MCP clients.
|
|
376
|
+
|
|
377
|
+
#### Generic Mode
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
const api = new RestApi(this, 'Api', {
|
|
381
|
+
// ...
|
|
382
|
+
mcpAuth: {
|
|
383
|
+
generic: {
|
|
384
|
+
authorizeEndpoint: 'https://auth.example.com/oauth2/authorize',
|
|
385
|
+
tokenEndpoint: 'https://auth.example.com/oauth2/token',
|
|
386
|
+
clientId: 'my-pre-provisioned-client-id',
|
|
387
|
+
},
|
|
388
|
+
serverInfo: { name: 'my-mcp-server', version: '1.0.0' },
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
#### McpAuthOptions
|
|
394
|
+
|
|
395
|
+
| Property | Default | Description |
|
|
396
|
+
|----------|---------|-------------|
|
|
397
|
+
| `cognito` | — | Cognito-specific config (mutually exclusive with `generic`) |
|
|
398
|
+
| `generic` | — | Any OAuth2 provider config (mutually exclusive with `cognito`) |
|
|
399
|
+
| `serverInfo` | *required* | `{ name, version }` returned in MCP `initialize` response |
|
|
400
|
+
| `allowedRedirectUris` | Claude + ChatGPT callbacks | URIs allowed for dynamic client registration |
|
|
401
|
+
| `protocolVersions` | `['2025-11-25', '2025-03-26', '2024-11-05']` | Supported MCP protocol versions |
|
|
402
|
+
| `scopes` | `['openid', 'email', 'profile']` | OAuth scopes advertised in discovery |
|
|
403
|
+
| `stripParameters` | `['resource']` | Params stripped before proxying to upstream |
|
|
404
|
+
| `lambdaOptions` | — | Lambda config for MCP auth handlers |
|
|
405
|
+
|
|
406
|
+
### Auto-Injected Endpoints
|
|
407
|
+
|
|
408
|
+
When `mcpAuth` is configured, 5 anonymous paths are added to the OpenAPI spec:
|
|
409
|
+
|
|
410
|
+
| Method | Path | RFC | Purpose |
|
|
411
|
+
|--------|------|-----|---------|
|
|
412
|
+
| GET | `/.well-known/oauth-protected-resource` | RFC 9728 | Resource metadata discovery |
|
|
413
|
+
| GET | `/.well-known/oauth-authorization-server` | RFC 8414 | Authorization server metadata |
|
|
414
|
+
| GET | `/oauth/authorize` | — | Proxies to upstream authorize endpoint |
|
|
415
|
+
| POST | `/oauth/token` | — | Proxies to upstream token endpoint |
|
|
416
|
+
| POST | `/oauth/register` | RFC 7591 | Dynamic client registration |
|
|
417
|
+
|
|
418
|
+
All endpoints bypass the API authorizer (`security: []`). The API domain is derived from the RestApi's own domain configuration.
|
|
419
|
+
|
|
420
|
+
### Standalone Constructs
|
|
421
|
+
|
|
422
|
+
For use outside `RestApi` (e.g., with HTTP API or custom integration):
|
|
423
|
+
|
|
424
|
+
#### McpCognitoAuth
|
|
425
|
+
|
|
426
|
+
Convenience wrapper that creates a Cognito client + the generic `McpAuth`:
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
import { McpCognitoAuth } from 'cdk-serverless/constructs';
|
|
430
|
+
|
|
431
|
+
const mcpAuth = new McpCognitoAuth(this, 'McpAuth', {
|
|
432
|
+
auth: cognitoAuthentication,
|
|
433
|
+
apiDomain: 'api.example.com',
|
|
434
|
+
authDomain: 'auth.example.com',
|
|
435
|
+
serverInfo: { name: 'my-mcp-server', version: '1.0.0' },
|
|
436
|
+
stageName: 'dev',
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// Access the underlying McpAuth and user pool client
|
|
440
|
+
mcpAuth.mcpAuth.functions; // Lambda functions for each endpoint
|
|
441
|
+
mcpAuth.mcpAuth.mcpEnvVars; // Env vars to inject into your MCP handler
|
|
442
|
+
mcpAuth.userPoolClient; // The created Cognito client
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### McpAuth
|
|
446
|
+
|
|
447
|
+
Service-agnostic construct for any OAuth2 provider:
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
import { McpAuth } from 'cdk-serverless/constructs';
|
|
451
|
+
|
|
452
|
+
const mcpAuth = new McpAuth(this, 'McpAuth', {
|
|
453
|
+
apiDomain: 'api.example.com',
|
|
454
|
+
authorizeEndpoint: 'https://auth.example.com/oauth2/authorize',
|
|
455
|
+
tokenEndpoint: 'https://auth.example.com/oauth2/token',
|
|
456
|
+
allowedRedirectUris: ['https://claude.ai/oauth/callback'],
|
|
457
|
+
clientId: 'my-client-id',
|
|
458
|
+
serverInfo: { name: 'my-mcp-server', version: '1.0.0' },
|
|
459
|
+
stageName: 'dev',
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// Wire functions into your own API Gateway
|
|
463
|
+
mcpAuth.functions.protectedResource; // GET /.well-known/oauth-protected-resource
|
|
464
|
+
mcpAuth.functions.authorizationServer; // GET /.well-known/oauth-authorization-server
|
|
465
|
+
mcpAuth.functions.authorize; // GET /oauth/authorize
|
|
466
|
+
mcpAuth.functions.token; // POST /oauth/token
|
|
467
|
+
mcpAuth.functions.register; // POST /oauth/register
|
|
468
|
+
|
|
469
|
+
// Inject env vars into your MCP RPC handler Lambda
|
|
470
|
+
mcpAuth.mcpEnvVars; // { MCP_API_DOMAIN, MCP_AUTHORIZE_ENDPOINT, ... }
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Runtime Module (`src/mcp-auth/`)
|
|
474
|
+
|
|
475
|
+
The `mcp-auth` package provides runtime utilities for building MCP tool servers:
|
|
476
|
+
|
|
477
|
+
#### MCP JSON-RPC Server
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
import { createMcpServer } from 'cdk-serverless/mcp-auth';
|
|
481
|
+
|
|
482
|
+
interface MyPrincipal {
|
|
483
|
+
userId: string;
|
|
484
|
+
email: string;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const server = createMcpServer<MyPrincipal>({
|
|
488
|
+
serverInfo: { name: 'my-server', version: '1.0.0' },
|
|
489
|
+
protocolVersions: ['2025-11-25', '2025-03-26', '2024-11-05'],
|
|
490
|
+
resolver: {
|
|
491
|
+
async resolve(headers) {
|
|
492
|
+
// Validate Bearer token, return principal or throw McpUnauthorizedError
|
|
493
|
+
const token = headers.authorization?.replace('Bearer ', '');
|
|
494
|
+
if (!token) throw new McpUnauthorizedError('Missing token', 'Bearer');
|
|
495
|
+
return verifyToken(token);
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
tools: [
|
|
499
|
+
{
|
|
500
|
+
name: 'get_items',
|
|
501
|
+
description: 'List items for the authenticated user',
|
|
502
|
+
inputSchema: { type: 'object', properties: { limit: { type: 'number' } } },
|
|
503
|
+
async invoke(principal, args) {
|
|
504
|
+
const items = await getItemsForUser(principal.userId);
|
|
505
|
+
return { content: [{ type: 'text', text: JSON.stringify(items) }] };
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
// In your Lambda handler:
|
|
512
|
+
export const handler = async (event: APIGatewayProxyEvent) => {
|
|
513
|
+
const body = JSON.parse(event.body ?? '{}');
|
|
514
|
+
const headers = event.headers as Record<string, string | undefined>;
|
|
515
|
+
const response = await server.handle(body, headers);
|
|
516
|
+
return response;
|
|
517
|
+
};
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
#### Key Types
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
// Tool definition — register tools with the server
|
|
524
|
+
interface McpToolDefinition<TPrincipal> {
|
|
525
|
+
name: string;
|
|
526
|
+
description: string | ((principal: TPrincipal) => Promise<string>);
|
|
527
|
+
inputSchema: object; // JSON Schema
|
|
528
|
+
invoke(principal: TPrincipal, args: unknown): Promise<McpToolResult>;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Credential resolver — authenticate incoming requests
|
|
532
|
+
interface McpCredentialResolver<TPrincipal> {
|
|
533
|
+
resolve(headers: Record<string, string | undefined>): Promise<TPrincipal>;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Server options
|
|
537
|
+
interface McpServerOptions<TPrincipal> {
|
|
538
|
+
serverInfo: { name: string; version: string };
|
|
539
|
+
protocolVersions: string[];
|
|
540
|
+
resolver: McpCredentialResolver<TPrincipal>;
|
|
541
|
+
tools: Array<McpToolDefinition<TPrincipal>>;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Runtime config (read from Lambda env vars)
|
|
545
|
+
interface McpAuthConfig {
|
|
546
|
+
apiDomain: string;
|
|
547
|
+
authorizeEndpoint: string;
|
|
548
|
+
tokenEndpoint: string;
|
|
549
|
+
allowedRedirectUris: string[];
|
|
550
|
+
clientId: string;
|
|
551
|
+
serverInfo: { name: string; version: string };
|
|
552
|
+
protocolVersions: string[];
|
|
553
|
+
scopes?: string[];
|
|
554
|
+
stripParameters?: string[];
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
The server handles the JSON-RPC protocol (`initialize`, `notifications/initialized`, `tools/list`, `tools/call`), credential resolution via the `McpCredentialResolver`, and per-tool dispatch with typed principals.
|
|
559
|
+
|
|
346
560
|
## Common Workflows
|
|
347
561
|
|
|
348
562
|
### Creating a New Serverless Project
|