@aws/nx-plugin-mcp 1.0.0-rc.95 → 1.0.0-rc.97

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 (66) hide show
  1. package/bin/aws-nx-mcp.js +61 -14
  2. package/docs/get_started/existing-project.mdx +6 -3
  3. package/docs/get_started/quick-start.mdx +8 -0
  4. package/docs/get_started/tutorials/dungeon-game/1.mdx +12 -14
  5. package/docs/get_started/tutorials/dungeon-game/2.mdx +10 -2
  6. package/docs/get_started/tutorials/dungeon-game/3.mdx +4 -0
  7. package/docs/get_started/tutorials/dungeon-game/4.mdx +2 -2
  8. package/docs/guides/agentcore-gateway.mdx +4 -2
  9. package/docs/guides/agentcore-harness.mdx +2 -1
  10. package/docs/guides/astro-docs.mdx +25 -7
  11. package/docs/guides/connection/py-agent-a2a.mdx +2 -0
  12. package/docs/guides/connection/py-agent-dynamodb.mdx +1 -1
  13. package/docs/guides/connection/py-agent-gateway.mdx +3 -0
  14. package/docs/guides/connection/py-agent-mcp.mdx +18 -4
  15. package/docs/guides/connection/py-agent-rdb.mdx +5 -4
  16. package/docs/guides/connection/py-fast-api-dynamodb.mdx +1 -1
  17. package/docs/guides/connection/py-fast-api-rdb.mdx +7 -2
  18. package/docs/guides/connection/py-mcp-server-dynamodb.mdx +1 -1
  19. package/docs/guides/connection/py-mcp-server-rdb.mdx +6 -6
  20. package/docs/guides/connection/react-agui.mdx +34 -25
  21. package/docs/guides/connection/react-fastapi.mdx +114 -116
  22. package/docs/guides/connection/react-py-agent.mdx +4 -0
  23. package/docs/guides/connection/react-smithy.mdx +152 -98
  24. package/docs/guides/connection/react-trpc.mdx +13 -6
  25. package/docs/guides/connection/smithy-dynamodb.mdx +2 -8
  26. package/docs/guides/connection/smithy-rdb.mdx +3 -6
  27. package/docs/guides/connection/trpc-rdb.mdx +6 -6
  28. package/docs/guides/connection/ts-agent-a2a.mdx +4 -4
  29. package/docs/guides/connection/ts-agent-dynamodb.mdx +13 -11
  30. package/docs/guides/connection/ts-agent-gateway.mdx +2 -0
  31. package/docs/guides/connection/ts-agent-mcp.mdx +19 -7
  32. package/docs/guides/connection/ts-agent-rdb.mdx +2 -2
  33. package/docs/guides/connection/ts-mcp-server-dynamodb.mdx +11 -7
  34. package/docs/guides/connection/ts-mcp-server-rdb.mdx +4 -3
  35. package/docs/guides/docker-bundling.mdx +23 -3
  36. package/docs/guides/fastapi.mdx +16 -5
  37. package/docs/guides/py-agent.mdx +129 -54
  38. package/docs/guides/py-mcp-server.mdx +3 -1
  39. package/docs/guides/py-rdb.mdx +13 -4
  40. package/docs/guides/python-lambda-function.mdx +8 -8
  41. package/docs/guides/python-project.mdx +28 -25
  42. package/docs/guides/react-website-auth.mdx +8 -8
  43. package/docs/guides/react-website.mdx +46 -27
  44. package/docs/guides/runtime-config.mdx +24 -4
  45. package/docs/guides/security.mdx +1 -1
  46. package/docs/guides/terraform-project.mdx +8 -2
  47. package/docs/guides/trpc.mdx +96 -12
  48. package/docs/guides/ts-agent.mdx +17 -3
  49. package/docs/guides/ts-dcr-proxy.mdx +24 -6
  50. package/docs/guides/ts-lambda-function.mdx +7 -1
  51. package/docs/guides/ts-mcp-server.mdx +45 -15
  52. package/docs/guides/ts-rdb.mdx +9 -2
  53. package/docs/guides/ts-smithy-api.mdx +76 -7
  54. package/docs/guides/typescript-infrastructure.mdx +24 -10
  55. package/docs/guides/typescript-project.mdx +12 -5
  56. package/docs/guides/workspace.mdx +21 -9
  57. package/docs/snippets/api/type-safe-api-integrations.mdx +2 -0
  58. package/docs/snippets/connection/a2a-infrastructure.mdx +3 -0
  59. package/docs/snippets/connection/infra-project-prerequisite.mdx +8 -0
  60. package/docs/snippets/connection/strands-agent-rdb-ssl-requirements.mdx +1 -1
  61. package/docs/snippets/connection/ts-lambda-rdb-ssl-requirements.mdx +1 -1
  62. package/docs/snippets/connection/ts-mcp-server-rdb-ssl-requirements.mdx +1 -1
  63. package/docs/snippets/required-prerequisites.mdx +1 -1
  64. package/package.json +1 -1
  65. package/src/init/schema.json +5 -0
  66. package/src/py/project/schema.json +3 -1
@@ -43,16 +43,10 @@ Import entity factories from the DynamoDB package and use them inside your opera
43
43
 
44
44
  ```ts title="packages/api/src/operations/list-examples.ts"
45
45
  import { createExampleEntity } from '@my-scope/my-table';
46
- import {
47
- ListExamplesOperationInput,
48
- ListExamplesOperationOutput,
49
- } from '../generated/ssdk/index.js';
50
46
  import { ServiceContext } from '../context.js';
47
+ import { ListExamples as ListExamplesOperation } from '../generated/ssdk/index.js';
51
48
 
52
- export const listExamples = async (
53
- _input: ListExamplesOperationInput,
54
- _ctx: ServiceContext,
55
- ): Promise<ListExamplesOperationOutput> => {
49
+ export const ListExamples: ListExamplesOperation<ServiceContext> = async () => {
56
50
  const entity = await createExampleEntity();
57
51
  const result = await entity.scan.go();
58
52
  return { items: result.data };
@@ -89,14 +89,11 @@ export const lambdaHandler = async (event: APIGatewayProxyEvent) => {
89
89
 
90
90
  Access `db` from the context in your operation implementations:
91
91
 
92
- ```ts title="packages/api/src/operations/list-users.ts" {8}
93
- import { ListUsersOperationInput, ListUsersOperationOutput } from '../generated/ssdk/index.js';
92
+ ```ts title="packages/api/src/operations/list-users.ts" {5}
94
93
  import { ServiceContext } from '../context.js';
94
+ import { ListUsers as ListUsersOperation } from '../generated/ssdk/index.js';
95
95
 
96
- export const listUsers = async (
97
- input: ListUsersOperationInput,
98
- ctx: ServiceContext,
99
- ): Promise<ListUsersOperationOutput> => {
96
+ export const ListUsers: ListUsersOperation<ServiceContext> = async (input, ctx) => {
100
97
  const users = await ctx.myDb.user.findMany();
101
98
  return { users };
102
99
  };
@@ -35,13 +35,14 @@ Select your tRPC API project as the source and your relational database project
35
35
 
36
36
  ## Generator Output
37
37
 
38
- The generator creates a middleware file in your tRPC API project:
38
+ The generator creates a middleware file in your tRPC API project, and adds it to the tRPC context:
39
39
 
40
40
  <FileTree>
41
41
 
42
42
  - packages/api/src
43
43
  - middleware
44
44
  - \<db-name>.ts tRPC plugin exposing the Prisma client in procedure context
45
+ - init.ts The database's context interface added to `Context`
45
46
 
46
47
  </FileTree>
47
48
 
@@ -53,12 +54,11 @@ Additionally, it updates your tRPC API's `dev` target to start the database auto
53
54
 
54
55
  Add the generated plugin to your tRPC router so all procedures using it gain access to the database:
55
56
 
56
- ```ts title="packages/api/src/router.ts" {2,5}
57
+ ```ts title="packages/api/src/router.ts" {2,4}
57
58
  import { t } from './init.js';
58
59
  import { createMyDbPlugin } from './middleware/my-db.js';
59
60
 
60
- export const authenticatedProcedure = t.procedure
61
- .concat(createMyDbPlugin());
61
+ export const dbProcedure = t.procedure.concat(createMyDbPlugin());
62
62
  ```
63
63
 
64
64
  ### Access the Database in Procedures
@@ -67,9 +67,9 @@ The plugin merges `IMyDbContext` into your procedure context, making `myDb` avai
67
67
 
68
68
  ```ts title="packages/api/src/procedures/users.ts" {7-8}
69
69
  import { z } from 'zod';
70
- import { authenticatedProcedure } from '../router.js';
70
+ import { dbProcedure } from '../router.js';
71
71
 
72
- export const listUsers = authenticatedProcedure
72
+ export const listUsers = dbProcedure
73
73
  .output(z.array(z.object({ id: z.string(), name: z.string() })))
74
74
  .query(async ({ ctx }) => {
75
75
  // ctx.myDb is the Prisma client — typed as Awaited<ReturnType<typeof getPrisma>>
@@ -73,8 +73,8 @@ import { Agent, tool } from '@strands-agents/sdk';
73
73
  import { RemoteAgentClientStrands } from '@my-scope/agent-connection';
74
74
  import { z } from 'zod';
75
75
 
76
- export const getAgent = async (sessionId: string) => {
77
- const remoteAgent = await RemoteAgentClientStrands.create(sessionId);
76
+ export const getAgent = async () => {
77
+ const remoteAgent = await RemoteAgentClientStrands.create();
78
78
  const remoteAgentTool = tool({
79
79
  name: 'askRemoteAgent',
80
80
  description: 'Delegate a question to the remote RemoteAgent A2A agent and return its reply.',
@@ -88,9 +88,9 @@ export const getAgent = async (sessionId: string) => {
88
88
  };
89
89
  ```
90
90
 
91
- The `sessionId` parameter is plumbed through from the caller, ensuring consistency for [Bedrock AgentCore Observability](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability.html).
91
+ The AgentCore session ID is propagated to the remote agent automatically via the `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header, so `create()` takes no arguments: the agent server binds the inbound request's session into an [`AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) context (`enterSessionContext` in the generated `router.ts`, or `runWithSessionId` in the A2A/AG-UI session middleware), and the connection client's fetch in `agentcore-fetch.ts` stamps it on every outbound call — ensuring consistency for [Bedrock AgentCore Observability](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability.html).
92
92
 
93
- Under the hood, `RemoteAgentClientStrands.create(sessionId)` returns a Strands `A2AAgent` configured with a SigV4-signing `clientFactory` when deployed to AWS, and a plain `http://localhost:<port>/` endpoint when `LOCAL_DEV=true`. The signing and endpoint resolution live in the framework-agnostic `agentcore-a2a-client-config.ts`; only the thin `agentcore-a2a-client-strands.ts` depends on Strands.
93
+ Under the hood, `RemoteAgentClientStrands.create()` returns a Strands `A2AAgent` configured with a SigV4-signing `clientFactory` when deployed to AWS, and a plain `http://localhost:<port>/` endpoint when `LOCAL_DEV=true`. The signing and endpoint resolution live in the framework-agnostic `agentcore-a2a-client-config.ts`; only the thin `agentcore-a2a-client-strands.ts` depends on Strands.
94
94
 
95
95
  ## Infrastructure
96
96
 
@@ -43,21 +43,23 @@ Import entity factories from the DynamoDB package and use them inside your agent
43
43
 
44
44
  ```ts title="packages/my-service/src/my-agent/agent.ts"
45
45
  import { createExampleEntity } from '@my-scope/my-table';
46
+ import { z } from 'zod';
47
+
48
+ const listExamples = tool({
49
+ name: 'list_examples',
50
+ description: 'List all example items',
51
+ inputSchema: z.object({}),
52
+ callback: async () => {
53
+ const entity = await createExampleEntity();
54
+ const result = await entity.scan.go();
55
+ return result.data;
56
+ },
57
+ });
46
58
 
47
59
  export const getAgent = async () => {
48
60
  // ...
49
61
  return new Agent({
50
- tools: [
51
- tool({
52
- name: 'list_examples',
53
- description: 'List all example items',
54
- func: async () => {
55
- const entity = await createExampleEntity();
56
- const result = await entity.scan.go();
57
- return result.data;
58
- },
59
- }),
60
- ],
62
+ tools: [listExamples],
61
63
  });
62
64
  };
63
65
  ```
@@ -51,6 +51,8 @@ The generator emits shared core client files into your `agent-connection` packag
51
51
  - src
52
52
  - core/
53
53
  - agentcore-endpoints.ts Framework-agnostic ARN/URL resolution
54
+ - agentcore-fetch.ts Framework-agnostic SigV4 / JWT / session-forwarding fetch
55
+ - agentcore-transport.ts Shared AgentCore transport plumbing
54
56
  - agentcore-gateway-mcp-transport.ts Framework-agnostic Gateway MCP transport
55
57
  - agentcore-gateway-mcp-client-strands.ts Strands MCP client for the deployed Gateway
56
58
  - app/
@@ -13,6 +13,7 @@ import RunGenerator from '@components/run-generator.astro';
13
13
  import GeneratorParameters from '@components/generator-parameters.astro';
14
14
  import NxCommands from '@components/nx-commands.astro';
15
15
  import Infrastructure from '@components/infrastructure.astro';
16
+ import Snippet from '@components/snippet.astro';
16
17
 
17
18
  The `connection` generator can connect your <Link path="guides/ts-agent">TypeScript Agent</Link> to an MCP server (either <Link path="guides/ts-mcp-server">TypeScript</Link> or <Link path="guides/py-mcp-server">Python</Link>).
18
19
 
@@ -51,6 +52,7 @@ The generator creates a shared `agent-connection` package and modifies your agen
51
52
  - core
52
53
  - agentcore-endpoints.ts Framework-agnostic ARN/URL resolution
53
54
  - agentcore-fetch.ts Framework-agnostic SigV4 / JWT / session-forwarding fetch
55
+ - agentcore-transport.ts Shared AgentCore transport plumbing
54
56
  - agentcore-mcp-transport.ts Framework-agnostic MCP transport
55
57
  - agentcore-mcp-client-strands.ts Strands MCP client wrapping the transport
56
58
  - index.ts Exports all clients
@@ -72,8 +74,8 @@ The generator transforms your agent's `agent.ts` to use the MCP server's tools:
72
74
  import { Agent, tool } from '@strands-agents/sdk';
73
75
  import { MyMcpServerClientStrands } from '@my-scope/agent-connection';
74
76
 
75
- export const getAgent = async (sessionId: string) => {
76
- const myMcpServerClient = await MyMcpServerClientStrands.create(sessionId);
77
+ export const getAgent = async () => {
78
+ const myMcpServerClient = await MyMcpServerClientStrands.create();
77
79
  return new Agent({
78
80
  systemPrompt: '...',
79
81
  tools: [myMcpServerClient],
@@ -81,10 +83,12 @@ export const getAgent = async (sessionId: string) => {
81
83
  };
82
84
  ```
83
85
 
84
- The `sessionId` parameter is plumbed through from the caller, ensuring consistency for [Bedrock AgentCore Observability](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability.html).
86
+ The AgentCore session ID is propagated to the MCP server automatically via the `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header, so `create()` takes no arguments: the agent server binds the inbound request's session into an [`AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) context (`enterSessionContext` in the generated `router.ts`, or `runWithSessionId` in the A2A/AG-UI session middleware), and the connection client's fetch in `agentcore-fetch.ts` stamps it on every outbound call — ensuring consistency for [Bedrock AgentCore Observability](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability.html).
85
87
 
86
88
  ## Infrastructure
87
89
 
90
+ <Snippet name="connection/infra-project-prerequisite" />
91
+
88
92
  <Infrastructure>
89
93
  <Fragment slot="cdk">
90
94
  After running the connection generator, you need to grant the agent permission to invoke the MCP server:
@@ -97,12 +101,14 @@ const myAgent = new MyAgent(this, 'MyAgent');
97
101
  mcpServer.grantInvokeAccess(myAgent);
98
102
  ```
99
103
 
104
+ `grantInvokeAccess` wires up the AgentCore invoke actions (`InvokeAgentRuntime`, `InvokeAgentRuntimeForUser` and `InvokeAgentRuntimeWithWebSocketStream`) on the MCP server's runtime ARN.
105
+
100
106
  The MCP server's AgentCore runtime ARN is automatically registered in the `agentcore` namespace of <Link path="guides/runtime-config">Runtime Configuration</Link> by the generated CDK construct, so the agent can discover it at runtime.
101
107
  </Fragment>
102
108
  <Fragment slot="terraform">
103
109
  After running the connection generator, you need to grant the agent permission to invoke the MCP server in your Terraform configuration:
104
110
 
105
- ```hcl title="packages/infra/src/main.tf" {9-25}
111
+ ```hcl title="packages/infra/src/main.tf" {9-31}
106
112
  module "inventory_mcp_server" {
107
113
  source = "../../common/terraform/src/app/mcp-servers/inventory-mcp"
108
114
  }
@@ -117,9 +123,15 @@ resource "aws_iam_policy" "agent_invoke_mcp" {
117
123
  policy = jsonencode({
118
124
  Version = "2012-10-17"
119
125
  Statement = [{
120
- Effect = "Allow"
121
- Action = "bedrock-agentcore:InvokeAgent"
122
- Resource = module.inventory_mcp_server.agent_core_runtime_arn
126
+ Effect = "Allow"
127
+ Action = [
128
+ "bedrock-agentcore:InvokeAgentRuntime",
129
+ "bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream",
130
+ ]
131
+ Resource = [
132
+ module.inventory_mcp_server.agent_core_runtime_arn,
133
+ "${module.inventory_mcp_server.agent_core_runtime_arn}/*",
134
+ ]
123
135
  }]
124
136
  })
125
137
  }
@@ -36,13 +36,13 @@ Select your Agent project as the source and your relational database project as
36
36
 
37
37
  ## Generator Output
38
38
 
39
- The generator modifies two files in your agent's source directory:
39
+ The generator modifies the following files in your agent's source directory:
40
40
 
41
41
  <FileTree>
42
42
 
43
43
  - packages/my-service/src/my-agent
44
44
  - agent.ts Prisma client fetched inside `getAgent` and available to tools
45
- - Dockerfile RDS CA bundle installed for SSL connections to Aurora
45
+ - Dockerfile RDS CA bundle installed for SSL connections to Aurora (only when the agent's `infra` is `agentcore-ecr`)
46
46
 
47
47
  </FileTree>
48
48
 
@@ -47,13 +47,17 @@ import { createExampleEntity } from '@my-scope/my-table';
47
47
  export const createServer = async () => {
48
48
  const server = new McpServer({ name: 'my-service', version: '1.0.0' });
49
49
 
50
- server.tool('list_examples', 'List all example items', {}, async () => {
51
- const entity = await createExampleEntity();
52
- const result = await entity.scan.go();
53
- return {
54
- content: [{ type: 'text', text: JSON.stringify(result.data) }],
55
- };
56
- });
50
+ server.registerTool(
51
+ 'list_examples',
52
+ { description: 'List all example items', inputSchema: {} },
53
+ async () => {
54
+ const entity = await createExampleEntity();
55
+ const result = await entity.scan.go();
56
+ return {
57
+ content: [{ type: 'text' as const, text: JSON.stringify(result.data) }],
58
+ };
59
+ },
60
+ );
57
61
 
58
62
  return server;
59
63
  };
@@ -36,13 +36,13 @@ Select your MCP server project as the source and your relational database projec
36
36
 
37
37
  ## Generator Output
38
38
 
39
- The generator modifies two files in your MCP server's source directory:
39
+ The generator modifies the following files in your MCP server's source directory:
40
40
 
41
41
  <FileTree>
42
42
 
43
43
  - packages/my-service/src/my-mcp
44
44
  - server.ts Prisma client fetched and available to all tools registered inside `createServer`
45
- - Dockerfile RDS CA bundle installed for SSL connections to Aurora
45
+ - Dockerfile RDS CA bundle installed for SSL connections to Aurora (only when the MCP server's `infra` is `agentcore-ecr`)
46
46
 
47
47
  </FileTree>
48
48
 
@@ -52,11 +52,12 @@ Additionally, the `<mcp-server-name>-dev` target is updated to depend on the dat
52
52
 
53
53
  The Prisma client is fetched inside `createServer` and available to all tools and resources registered there:
54
54
 
55
- ```ts title="packages/my-service/src/my-mcp/server.ts" {1,4}
55
+ ```ts title="packages/my-service/src/my-mcp/server.ts" {1,4,5}
56
56
  import { getPrisma as getMyDb } from '@my-scope/my-db';
57
57
 
58
58
  export const createServer = async () => {
59
59
  const myDb = await getMyDb();
60
+ myDb.$on('error', console.error);
60
61
  const server = new McpServer({ name: 'my-service', version: '1.0.0' });
61
62
  // register tools/resources that use myDb
62
63
  return server;
@@ -133,11 +133,18 @@ Some npm packages cannot be bundled because they rely on dynamic `require`, nati
133
133
 
134
134
  ### Dockerfile
135
135
 
136
- Create a `Dockerfile` in your project source directory. The file does nothing more than `COPY` the bundle into a Node base image, plus `npm install` any `external` packages that could not be bundled. Place the `RUN npm install` step **before** the `COPY`, so Docker can cache the installed `node_modules` layer and only re-run it when the dependency list actually changes:
136
+ Create a `Dockerfile` in your project source directory. The file does nothing more than [apply the base image's security updates](#apply-the-distributions-security-updates), `COPY` the bundle into a Node base image, plus `npm install` any `external` packages that could not be bundled. Place the `RUN npm install` step **before** the `COPY`, so Docker can cache the installed `node_modules` layer and only re-run it when the dependency list actually changes:
137
137
 
138
138
  ```dockerfile
139
139
  FROM public.ecr.aws/docker/library/node:lts
140
140
 
141
+ # Apply the distribution's security updates: base image tags lag behind the
142
+ # security suite, so their OS packages carry vulnerabilities that already have a
143
+ # published fix.
144
+ RUN apt-get update && \
145
+ apt-get upgrade -y --no-install-recommends && \
146
+ rm -rf /var/lib/apt/lists/*
147
+
141
148
  WORKDIR /app
142
149
 
143
150
  # Install packages that cannot be bundled (declared as "external" in rolldown.config.ts).
@@ -236,11 +243,18 @@ Running `nx bundle my-project` produces `dist/packages/my-project/bundle-arm/` c
236
243
 
237
244
  ### Dockerfile
238
245
 
239
- The `Dockerfile` simply copies the bundle into a Python base image. Because `uv` already installed all dependencies into the bundle directory, you do not need to run `pip install` inside the image:
246
+ The `Dockerfile` [applies the base image's security updates](#apply-the-distributions-security-updates), then copies the bundle into a Python base image. Because `uv` already installed all dependencies into the bundle directory, you do not need to run `pip install` inside the image:
240
247
 
241
248
  ```dockerfile
242
249
  FROM public.ecr.aws/docker/library/python:3.14-slim
243
250
 
251
+ # Apply the distribution's security updates: base image tags lag behind the
252
+ # security suite, so their OS packages carry vulnerabilities that already have a
253
+ # published fix.
254
+ RUN apt-get update && \
255
+ apt-get upgrade -y --no-install-recommends && \
256
+ rm -rf /var/lib/apt/lists/*
257
+
244
258
  WORKDIR /app
245
259
 
246
260
  # Copy bundled package (source + installed dependencies)
@@ -288,7 +302,13 @@ This clears the output directory, then copies both the bundle contents and the `
288
302
 
289
303
  It's good practice to scan your images for known vulnerabilities. The generators that follow this pattern add a `trivy` target which scans the built image with [Trivy](https://trivy.dev/), running from the [ECR-hosted Trivy image](https://gallery.ecr.aws/aquasecurity/trivy), and exits non-zero on `HIGH` or `CRITICAL` findings.
290
304
 
291
- Add a `trivy` target which `dependsOn` your `docker` target. It saves the built image to a tarball and scans it via a workspace-relative bind mount, so the same command works under both `docker` and `finch`:
305
+ The target copies a `.trivyignore` from the root of your project into the scan directory and passes it to Trivy with `--ignorefile`, so create that file first — an empty one is fine, and it is where you [suppress findings](#suppressing-findings) later:
306
+
307
+ ```bash
308
+ touch packages/my-project/.trivyignore
309
+ ```
310
+
311
+ Then add a `trivy` target which `dependsOn` your `docker` target. It saves the built image to a tarball and scans it via a workspace-relative bind mount, so the same command works under both `docker` and `finch`:
292
312
 
293
313
  <Code lang="json" code={trivyTarget} />
294
314
 
@@ -17,6 +17,7 @@ import PackageManagerShortCommand from '@components/package-manager-short-comman
17
17
  import Infrastructure from '@components/infrastructure.astro';
18
18
  import Snippet from '@components/snippet.astro';
19
19
  import OptionFilter from '@components/option-filter.astro';
20
+ import { PY_VERSIONS } from '../../../../../../packages/nx-plugin/src/utils/versions';
20
21
 
21
22
  [FastAPI](https://fastapi.tiangolo.com/) is a framework for building APIs in Python.
22
23
 
@@ -86,12 +87,12 @@ class Item(BaseModel):
86
87
  @app.get("/items/{item_id}")
87
88
  @tracer.capture_method
88
89
  def get_item(item_id: int) -> Item:
89
- return Item(name=...)
90
+ return Item(name=f"Item {item_id}")
90
91
 
91
92
  @app.post("/items")
92
93
  @tracer.capture_method
93
- def create_item(item: Item):
94
- return ...
94
+ def create_item(item: Item) -> Item:
95
+ return item
95
96
  ```
96
97
 
97
98
  The generator sets up several features automatically:
@@ -191,7 +192,11 @@ When your API is protected by authentication, your route handlers often need to
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.
192
193
 
193
194
  <OptionFilter when={{ auth: 'iam' }} description="Identity extraction for IAM-authenticated APIs">
194
- 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`:
195
+ For `IAM` authentication, we look up the caller in Cognito using the sub extracted from the API Gateway request context, which requires `boto3`. Add it to your API project:
196
+
197
+ <NxCommands commands={[`run my-api:add boto3${PY_VERSIONS.boto3}`]} />
198
+
199
+ Create `identity.py` alongside `main.py`:
195
200
 
196
201
  <Tabs syncKey="http-rest">
197
202
  <TabItem label="REST API" _filter={{ infra: 'rest-lambda' }}>
@@ -652,6 +657,8 @@ If you are actively working on both your CDK infrastructure and FastAPI together
652
657
  'run @<scope>/common-constructs:"generate:<ApiName>-metadata"',
653
658
  ]}
654
659
  />
660
+
661
+ `nx watch` requires the [Nx daemon](https://nx.dev/concepts/nx-daemon), which is enabled by default but switched off inside CI, Docker containers and sandboxed environments. Where it is off, the command exits with `Daemon is not running` — set `NX_DAEMON=true` to enable it.
655
662
  :::
656
663
  </Fragment>
657
664
  <Fragment slot="terraform">
@@ -717,7 +724,7 @@ The key outputs from the API module that you can use for IAM policies are:
717
724
 
718
725
  The generator configures a local development server that you can run with:
719
726
 
720
- <NxCommands commands={['serve my-api']} />
727
+ <NxCommands commands={['serve <project-name>']} />
721
728
 
722
729
  This starts a local FastAPI development server with:
723
730
 
@@ -725,6 +732,10 @@ This starts a local FastAPI development server with:
725
732
  - Interactive API documentation at `/docs` or `/redoc`
726
733
  - OpenAPI schema at `/openapi.json`
727
734
 
735
+ :::note[Project Names]
736
+ Python project names use underscores, so an API generated with `--name=MyApi` is addressed as `my_api` (or by its fully qualified name, `<scope>.my_api`). The port the server listens on is assigned per project — read it from the `serve` target in your project's `project.json`.
737
+ :::
738
+
728
739
  ## Invoking your FastAPI
729
740
 
730
741
  To invoke your API from a React website, you can use the <Link path="guides/connection/react-fastapi">`connection` generator</Link>.