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.
- 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/lambda/handler.js +15 -4
- 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
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
|