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.
Files changed (73) hide show
  1. package/README.md +111 -0
  2. package/docs/constructs/assets/hierarchy.js +1 -1
  3. package/docs/constructs/assets/navigation.js +1 -1
  4. package/docs/constructs/assets/search.js +1 -1
  5. package/docs/constructs/classes/McpAuth.html +43 -0
  6. package/docs/constructs/classes/McpCognitoAuth.html +43 -0
  7. package/docs/constructs/classes/RestApi.html +6 -3
  8. package/docs/constructs/classes/SingleTableDatastore.html +1 -1
  9. package/docs/constructs/classes/Workflow.html +1 -1
  10. package/docs/constructs/hierarchy.html +1 -1
  11. package/docs/constructs/index.html +112 -1
  12. package/docs/constructs/interfaces/McpAuthCognitoOptions.html +17 -0
  13. package/docs/constructs/interfaces/McpAuthFunctions.html +14 -0
  14. package/docs/constructs/interfaces/McpAuthGenericOptions.html +11 -0
  15. package/docs/constructs/interfaces/McpAuthOptions.html +33 -0
  16. package/docs/constructs/interfaces/McpAuthProps.html +43 -0
  17. package/docs/constructs/interfaces/McpCognitoAuthProps.html +49 -0
  18. package/docs/constructs/interfaces/RestApiProps.html +24 -6
  19. package/docs/constructs/modules.html +1 -1
  20. package/docs/lambda/index.html +112 -1
  21. package/docs/projen/index.html +112 -1
  22. package/lib/constructs/index.d.ts +2 -0
  23. package/lib/constructs/index.js +3 -1
  24. package/lib/constructs/mcp-auth.d.ts +117 -0
  25. package/lib/constructs/mcp-auth.js +127 -0
  26. package/lib/constructs/mcp-cognito-auth.d.ts +110 -0
  27. package/lib/constructs/mcp-cognito-auth.js +76 -0
  28. package/lib/constructs/rest-api.d.ts +136 -0
  29. package/lib/constructs/rest-api.js +159 -1
  30. package/lib/mcp-auth/config.d.ts +39 -0
  31. package/lib/mcp-auth/config.js +3 -0
  32. package/lib/mcp-auth/handlers/authorization-server.d.ts +7 -0
  33. package/lib/mcp-auth/handlers/authorization-server.js +34 -0
  34. package/lib/mcp-auth/handlers/authorize.d.ts +8 -0
  35. package/lib/mcp-auth/handlers/authorize.js +32 -0
  36. package/lib/mcp-auth/handlers/index.d.ts +7 -0
  37. package/lib/mcp-auth/handlers/index.js +24 -0
  38. package/lib/mcp-auth/handlers/protected-resource.d.ts +7 -0
  39. package/lib/mcp-auth/handlers/protected-resource.js +26 -0
  40. package/lib/mcp-auth/handlers/register.d.ts +7 -0
  41. package/lib/mcp-auth/handlers/register.js +68 -0
  42. package/lib/mcp-auth/handlers/token.d.ts +8 -0
  43. package/lib/mcp-auth/handlers/token.js +74 -0
  44. package/lib/mcp-auth/handlers/types.d.ts +21 -0
  45. package/lib/mcp-auth/handlers/types.js +3 -0
  46. package/lib/mcp-auth/handlers/validate-redirect-uris.d.ts +10 -0
  47. package/lib/mcp-auth/handlers/validate-redirect-uris.js +22 -0
  48. package/lib/mcp-auth/index.d.ts +3 -0
  49. package/lib/mcp-auth/index.js +20 -0
  50. package/lib/mcp-auth/lambda-handlers/authorization-server.handler.d.ts +2 -0
  51. package/lib/mcp-auth/lambda-handlers/authorization-server.handler.js +23 -0
  52. package/lib/mcp-auth/lambda-handlers/authorize.handler.d.ts +2 -0
  53. package/lib/mcp-auth/lambda-handlers/authorize.handler.js +23 -0
  54. package/lib/mcp-auth/lambda-handlers/env-config.d.ts +7 -0
  55. package/lib/mcp-auth/lambda-handlers/env-config.js +37 -0
  56. package/lib/mcp-auth/lambda-handlers/protected-resource.handler.d.ts +2 -0
  57. package/lib/mcp-auth/lambda-handlers/protected-resource.handler.js +23 -0
  58. package/lib/mcp-auth/lambda-handlers/register.handler.d.ts +2 -0
  59. package/lib/mcp-auth/lambda-handlers/register.handler.js +23 -0
  60. package/lib/mcp-auth/lambda-handlers/token.handler.d.ts +2 -0
  61. package/lib/mcp-auth/lambda-handlers/token.handler.js +23 -0
  62. package/lib/mcp-auth/mcp/errors.d.ts +8 -0
  63. package/lib/mcp-auth/mcp/errors.js +20 -0
  64. package/lib/mcp-auth/mcp/index.d.ts +4 -0
  65. package/lib/mcp-auth/mcp/index.js +21 -0
  66. package/lib/mcp-auth/mcp/jsonrpc.d.ts +21 -0
  67. package/lib/mcp-auth/mcp/jsonrpc.js +56 -0
  68. package/lib/mcp-auth/mcp/server.d.ts +9 -0
  69. package/lib/mcp-auth/mcp/server.js +107 -0
  70. package/lib/mcp-auth/mcp/types.d.ts +32 -0
  71. package/lib/mcp-auth/mcp/types.js +3 -0
  72. package/llm.md +214 -0
  73. 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,4 @@
1
+ export * from './errors';
2
+ export * from './jsonrpc';
3
+ export * from './server';
4
+ export * from './types';
@@ -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
package/package.json CHANGED
@@ -99,7 +99,7 @@
99
99
  "publishConfig": {
100
100
  "access": "public"
101
101
  },
102
- "version": "3.2.1",
102
+ "version": "3.3.1",
103
103
  "jest": {
104
104
  "coverageProvider": "v8",
105
105
  "testMatch": [