@aws/nx-plugin-mcp 1.0.0-rc.2 → 1.0.0-rc.21

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 (70) hide show
  1. package/bin/aws-nx-mcp.js +5919 -4776
  2. package/docs/guides/agentcore-gateway.mdx +240 -0
  3. package/docs/guides/connection/agentcore-gateway-gateway.mdx +154 -0
  4. package/docs/guides/connection/agentcore-gateway-mcp.mdx +134 -0
  5. package/docs/guides/connection/py-agent-a2a.mdx +8 -5
  6. package/docs/guides/connection/py-agent-dynamodb.mdx +116 -0
  7. package/docs/guides/connection/py-agent-gateway.mdx +161 -0
  8. package/docs/guides/connection/py-agent-mcp.mdx +7 -4
  9. package/docs/guides/connection/py-fast-api-dynamodb.mdx +56 -0
  10. package/docs/guides/connection/py-mcp-server-dynamodb.mdx +116 -0
  11. package/docs/guides/connection/react-smithy.mdx +1 -1
  12. package/docs/guides/connection/react-trpc.mdx +1 -1
  13. package/docs/guides/connection/smithy-dynamodb.mdx +68 -0
  14. package/docs/guides/connection/smithy-rdb.mdx +1 -1
  15. package/docs/guides/connection/trpc-dynamodb.mdx +62 -0
  16. package/docs/guides/connection/trpc-rdb.mdx +1 -1
  17. package/docs/guides/connection/ts-agent-a2a.mdx +8 -5
  18. package/docs/guides/connection/ts-agent-dynamodb.mdx +128 -0
  19. package/docs/guides/connection/ts-agent-gateway.mdx +152 -0
  20. package/docs/guides/connection/ts-agent-mcp.mdx +7 -4
  21. package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +125 -0
  22. package/docs/guides/connection.mdx +89 -0
  23. package/docs/guides/docker-bundling.mdx +13 -7
  24. package/docs/guides/fastapi.mdx +213 -3
  25. package/docs/guides/license.mdx +264 -109
  26. package/docs/guides/local-development.mdx +76 -0
  27. package/docs/guides/nx-generator.mdx +5 -0
  28. package/docs/guides/py-agent.mdx +42 -3
  29. package/docs/guides/py-dynamodb.mdx +449 -0
  30. package/docs/guides/py-mcp-server.mdx +5 -1
  31. package/docs/guides/react-website-auth.mdx +15 -0
  32. package/docs/guides/react-website.mdx +12 -4
  33. package/docs/guides/trpc.mdx +8 -8
  34. package/docs/guides/ts-agent.mdx +40 -2
  35. package/docs/guides/ts-dynamodb.mdx +158 -0
  36. package/docs/guides/ts-mcp-server.mdx +5 -1
  37. package/docs/guides/ts-rdb.mdx +58 -10
  38. package/docs/guides/ts-smithy-api.mdx +148 -3
  39. package/docs/guides/typescript-project.mdx +5 -10
  40. package/docs/guides/workspace.mdx +8 -2
  41. package/docs/snippets/api/type-safe-api-integrations.mdx +31 -0
  42. package/docs/snippets/api/waf-configuration.mdx +1 -1
  43. package/docs/snippets/connection/dynamodb-local-development.mdx +7 -0
  44. package/docs/snippets/connection/lambda-dynamodb-access.mdx +80 -0
  45. package/docs/snippets/connection/py-dynamodb-local-development.mdx +7 -0
  46. package/docs/snippets/dynamodb/deploying-table.mdx +171 -0
  47. package/docs/snippets/dynamodb/gsi-config.mdx +38 -0
  48. package/docs/snippets/dynamodb/infrastructure.mdx +33 -0
  49. package/docs/snippets/dynamodb/serve-local-start.mdx +13 -0
  50. package/docs/snippets/dynamodb/serve-local-windows.mdx +15 -0
  51. package/docs/snippets/mcp/config.mdx +1 -1
  52. package/docs/snippets/required-prerequisites.mdx +1 -1
  53. package/generators.json +100 -1
  54. package/package.json +1 -1
  55. package/src/agentcore-gateway/gateway-connection/schema.json +26 -0
  56. package/src/agentcore-gateway/mcp-connection/schema.json +26 -0
  57. package/src/agentcore-gateway/schema.json +65 -0
  58. package/src/license/schema.json +6 -0
  59. package/src/preset/schema.json +5 -0
  60. package/src/py/agent/gateway-connection/schema.json +26 -0
  61. package/src/py/dynamodb/agent-connection/schema.json +22 -0
  62. package/src/py/dynamodb/fast-api-connection/schema.json +18 -0
  63. package/src/py/dynamodb/mcp-server-connection/schema.json +22 -0
  64. package/src/py/dynamodb/schema.json +70 -0
  65. package/src/ts/agent/gateway-connection/schema.json +26 -0
  66. package/src/ts/dynamodb/agent-connection/schema.json +22 -0
  67. package/src/ts/dynamodb/mcp-server-connection/schema.json +22 -0
  68. package/src/ts/dynamodb/schema.json +70 -0
  69. package/src/ts/dynamodb/smithy-connection/schema.json +18 -0
  70. package/src/ts/dynamodb/trpc-connection/schema.json +18 -0
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: FastAPI
3
3
  description: Reference documentation for FastAPI
4
- generator: py#fast-api
4
+ generator: py#api
5
5
  when:
6
6
  framework: [fastapi]
7
7
  ---
@@ -26,11 +26,11 @@ The FastAPI generator creates a new FastAPI with AWS CDK or Terraform infrastruc
26
26
 
27
27
  You can generate a new FastAPI in two ways:
28
28
 
29
- <RunGenerator generator="py#fast-api" />
29
+ <RunGenerator generator="py#api" requiredParameters={{ framework: 'fastapi' }} />
30
30
 
31
31
  ### Options
32
32
 
33
- <GeneratorParameters generator="py#fast-api" />
33
+ <GeneratorParameters generator="py#api" />
34
34
 
35
35
  <Snippet name="api/api-choice-note" />
36
36
 
@@ -185,6 +185,216 @@ Unhandled exceptions are caught by the middleware and:
185
185
  It's recommended to specify response models for your API operations for better code generation if using the `connection` generator. <Link path="guides/connection/react-fastapi#errors">See here for more details</Link>.
186
186
  :::
187
187
 
188
+ ### Accessing the Calling User
189
+
190
+ When your API is protected by authentication, your route handlers often need to know who is calling. The generated FastAPI runs inside AWS Lambda via the [Lambda Web Adapter](https://github.com/awslabs/aws-lambda-web-adapter), which forwards the API Gateway request context as JSON on the `x-amzn-request-context` header. You can read it from the FastAPI `Request` to extract the caller's identity.
191
+
192
+ As an example, let's add a `/me` endpoint that returns details about the calling user. We'll implement the extraction as a [FastAPI dependency](https://fastapi.tiangolo.com/tutorial/dependencies/) so it can be reused across routes. The shape of the request context — and therefore how you extract the identity — depends on both your selected `auth` method and whether you deployed a REST or HTTP API.
193
+
194
+ <OptionFilter when={{ auth: 'iam' }} description="Identity extraction for IAM-authenticated APIs">
195
+ For `IAM` authentication, we look up the caller in Cognito using the sub extracted from the API Gateway request context. Create `identity.py` alongside `main.py`:
196
+
197
+ <Tabs syncKey="http-rest">
198
+ <TabItem label="REST API" _filter={{ infra: 'rest-lambda' }}>
199
+ ```python
200
+ import json
201
+ import os
202
+ from typing import Annotated
203
+
204
+ from boto3 import client
205
+ from fastapi import Depends, HTTPException, Request
206
+ from pydantic import BaseModel
207
+
208
+ cognito = client("cognito-idp")
209
+
210
+
211
+ class Identity(BaseModel):
212
+ sub: str
213
+ username: str
214
+
215
+
216
+ def get_identity(request: Request) -> Identity:
217
+ # The Lambda Web Adapter forwards the API Gateway request context as JSON
218
+ request_context_header = request.headers.get("x-amzn-request-context")
219
+ if not request_context_header:
220
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
221
+
222
+ request_context = json.loads(request_context_header)
223
+ provider = request_context.get("identity", {}).get("cognitoAuthenticationProvider")
224
+
225
+ sub = provider.split(":")[-1] if provider else None
226
+ if not sub:
227
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
228
+
229
+ users = cognito.list_users(
230
+ # Assumes user pool id is configured in lambda environment
231
+ UserPoolId=os.environ["USER_POOL_ID"],
232
+ Limit=1,
233
+ Filter=f'sub="{sub}"',
234
+ ).get("Users", [])
235
+
236
+ if len(users) != 1:
237
+ raise HTTPException(status_code=403, detail=f"No user found with subjectId {sub}")
238
+
239
+ return Identity(sub=sub, username=users[0]["Username"])
240
+
241
+
242
+ CurrentUser = Annotated[Identity, Depends(get_identity)]
243
+ ```
244
+ </TabItem>
245
+ <TabItem label="HTTP API" _filter={{ infra: 'http-lambda' }}>
246
+ ```python
247
+ import json
248
+ import os
249
+ from typing import Annotated
250
+
251
+ from boto3 import client
252
+ from fastapi import Depends, HTTPException, Request
253
+ from pydantic import BaseModel
254
+
255
+ cognito = client("cognito-idp")
256
+
257
+
258
+ class Identity(BaseModel):
259
+ sub: str
260
+ username: str
261
+
262
+
263
+ def get_identity(request: Request) -> Identity:
264
+ # The Lambda Web Adapter forwards the API Gateway request context as JSON
265
+ request_context_header = request.headers.get("x-amzn-request-context")
266
+ if not request_context_header:
267
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
268
+
269
+ request_context = json.loads(request_context_header)
270
+ amr = (
271
+ request_context.get("authorizer", {})
272
+ .get("iam", {})
273
+ .get("cognitoIdentity", {})
274
+ .get("amr", [])
275
+ )
276
+ sign_in = next((s for s in amr if ":CognitoSignIn:" in s), None)
277
+ sub = sign_in.split(":")[-1] if sign_in else None
278
+
279
+ if not sub:
280
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
281
+
282
+ users = cognito.list_users(
283
+ # Assumes user pool id is configured in lambda environment
284
+ UserPoolId=os.environ["USER_POOL_ID"],
285
+ Limit=1,
286
+ Filter=f'sub="{sub}"',
287
+ ).get("Users", [])
288
+
289
+ if len(users) != 1:
290
+ raise HTTPException(status_code=403, detail=f"No user found with subjectId {sub}")
291
+
292
+ return Identity(sub=sub, username=users[0]["Username"])
293
+
294
+
295
+ CurrentUser = Annotated[Identity, Depends(get_identity)]
296
+ ```
297
+ </TabItem>
298
+ </Tabs>
299
+ </OptionFilter>
300
+
301
+ <OptionFilter when={{ auth: 'cognito' }} description="Identity extraction for Cognito-authenticated APIs">
302
+ With `auth: 'cognito'`, the API Gateway Cognito User Pools authorizer verifies the JWT that the caller supplies in the `Authorization` header and places the verified claims on the request context.
303
+
304
+ Create `identity.py` alongside `main.py`:
305
+
306
+ <Tabs syncKey="http-rest">
307
+ <TabItem label="REST API" _filter={{ infra: 'rest-lambda' }}>
308
+ ```python
309
+ import json
310
+ from typing import Annotated
311
+
312
+ from fastapi import Depends, HTTPException, Request
313
+ from pydantic import BaseModel
314
+
315
+
316
+ class Identity(BaseModel):
317
+ sub: str
318
+ username: str
319
+
320
+
321
+ def get_identity(request: Request) -> Identity:
322
+ # The Lambda Web Adapter forwards the API Gateway request context as JSON
323
+ request_context_header = request.headers.get("x-amzn-request-context")
324
+ if not request_context_header:
325
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
326
+
327
+ request_context = json.loads(request_context_header)
328
+ claims = request_context.get("authorizer", {}).get("claims", {})
329
+
330
+ sub = claims.get("sub")
331
+ username = claims.get("username")
332
+
333
+ if not sub or not username:
334
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
335
+
336
+ return Identity(sub=sub, username=username)
337
+
338
+
339
+ CurrentUser = Annotated[Identity, Depends(get_identity)]
340
+ ```
341
+ </TabItem>
342
+ <TabItem label="HTTP API" _filter={{ infra: 'http-lambda' }}>
343
+ HTTP APIs use a JWT authorizer which places the verified claims under `authorizer.jwt.claims`:
344
+
345
+ ```python
346
+ import json
347
+ from typing import Annotated
348
+
349
+ from fastapi import Depends, HTTPException, Request
350
+ from pydantic import BaseModel
351
+
352
+
353
+ class Identity(BaseModel):
354
+ sub: str
355
+ username: str
356
+
357
+
358
+ def get_identity(request: Request) -> Identity:
359
+ # The Lambda Web Adapter forwards the API Gateway request context as JSON
360
+ request_context_header = request.headers.get("x-amzn-request-context")
361
+ if not request_context_header:
362
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
363
+
364
+ request_context = json.loads(request_context_header)
365
+ claims = request_context.get("authorizer", {}).get("jwt", {}).get("claims", {})
366
+
367
+ sub = claims.get("sub")
368
+ username = claims.get("username")
369
+
370
+ if not sub or not username:
371
+ raise HTTPException(status_code=403, detail="Unable to determine calling user")
372
+
373
+ return Identity(sub=sub, username=username)
374
+
375
+
376
+ CurrentUser = Annotated[Identity, Depends(get_identity)]
377
+ ```
378
+ </TabItem>
379
+ </Tabs>
380
+
381
+ :::tip[No token verification required]
382
+ You don't need any JWT-verification library here — the API Gateway Cognito User Pools authorizer has already verified the signature, issuer, scopes, and expiry by the time your Lambda runs. If any of those checks fail, API Gateway returns `401 Unauthorized` and your handler is never invoked.
383
+ :::
384
+ </OptionFilter>
385
+
386
+ You can then inject the `CurrentUser` dependency into any route that needs the caller's identity:
387
+
388
+ ```python
389
+ from .identity import CurrentUser, Identity
390
+ from .init import app, tracer
391
+
392
+ @app.get("/me")
393
+ @tracer.capture_method
394
+ def me(identity: CurrentUser) -> Identity:
395
+ return identity
396
+ ```
397
+
188
398
  <OptionFilter when={{ infra: 'rest-lambda' }} description="Streaming — REST API only">
189
399
  ### Streaming
190
400