cdk-serverless 3.2.0 → 3.3.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.
Files changed (74) 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/lambda/handler.js +15 -4
  31. package/lib/mcp-auth/config.d.ts +39 -0
  32. package/lib/mcp-auth/config.js +3 -0
  33. package/lib/mcp-auth/handlers/authorization-server.d.ts +7 -0
  34. package/lib/mcp-auth/handlers/authorization-server.js +34 -0
  35. package/lib/mcp-auth/handlers/authorize.d.ts +8 -0
  36. package/lib/mcp-auth/handlers/authorize.js +32 -0
  37. package/lib/mcp-auth/handlers/index.d.ts +7 -0
  38. package/lib/mcp-auth/handlers/index.js +24 -0
  39. package/lib/mcp-auth/handlers/protected-resource.d.ts +7 -0
  40. package/lib/mcp-auth/handlers/protected-resource.js +26 -0
  41. package/lib/mcp-auth/handlers/register.d.ts +7 -0
  42. package/lib/mcp-auth/handlers/register.js +68 -0
  43. package/lib/mcp-auth/handlers/token.d.ts +8 -0
  44. package/lib/mcp-auth/handlers/token.js +74 -0
  45. package/lib/mcp-auth/handlers/types.d.ts +21 -0
  46. package/lib/mcp-auth/handlers/types.js +3 -0
  47. package/lib/mcp-auth/handlers/validate-redirect-uris.d.ts +10 -0
  48. package/lib/mcp-auth/handlers/validate-redirect-uris.js +22 -0
  49. package/lib/mcp-auth/index.d.ts +3 -0
  50. package/lib/mcp-auth/index.js +20 -0
  51. package/lib/mcp-auth/lambda-handlers/authorization-server.handler.d.ts +2 -0
  52. package/lib/mcp-auth/lambda-handlers/authorization-server.handler.js +23 -0
  53. package/lib/mcp-auth/lambda-handlers/authorize.handler.d.ts +2 -0
  54. package/lib/mcp-auth/lambda-handlers/authorize.handler.js +23 -0
  55. package/lib/mcp-auth/lambda-handlers/env-config.d.ts +7 -0
  56. package/lib/mcp-auth/lambda-handlers/env-config.js +37 -0
  57. package/lib/mcp-auth/lambda-handlers/protected-resource.handler.d.ts +2 -0
  58. package/lib/mcp-auth/lambda-handlers/protected-resource.handler.js +23 -0
  59. package/lib/mcp-auth/lambda-handlers/register.handler.d.ts +2 -0
  60. package/lib/mcp-auth/lambda-handlers/register.handler.js +23 -0
  61. package/lib/mcp-auth/lambda-handlers/token.handler.d.ts +2 -0
  62. package/lib/mcp-auth/lambda-handlers/token.handler.js +23 -0
  63. package/lib/mcp-auth/mcp/errors.d.ts +8 -0
  64. package/lib/mcp-auth/mcp/errors.js +20 -0
  65. package/lib/mcp-auth/mcp/index.d.ts +4 -0
  66. package/lib/mcp-auth/mcp/index.js +21 -0
  67. package/lib/mcp-auth/mcp/jsonrpc.d.ts +21 -0
  68. package/lib/mcp-auth/mcp/jsonrpc.js +56 -0
  69. package/lib/mcp-auth/mcp/server.d.ts +9 -0
  70. package/lib/mcp-auth/mcp/server.js +107 -0
  71. package/lib/mcp-auth/mcp/types.d.ts +32 -0
  72. package/lib/mcp-auth/mcp/types.js +3 -0
  73. package/llm.md +214 -0
  74. package/package.json +1 -1
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.0",
102
+ "version": "3.3.0",
103
103
  "jest": {
104
104
  "coverageProvider": "v8",
105
105
  "testMatch": [