@aws/nx-plugin-mcp 1.0.0-rc.98 → 1.0.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 (54) hide show
  1. package/bin/aws-nx-mcp.js +17 -9
  2. package/docs/get_started/building-with-ai.mdx +21 -14
  3. package/docs/get_started/concepts.mdx +1 -1
  4. package/docs/get_started/existing-project.mdx +7 -4
  5. package/docs/get_started/quick-start.mdx +153 -65
  6. package/docs/get_started/tutorials/contribute-generator.mdx +5 -5
  7. package/docs/get_started/tutorials/dungeon-game/1.mdx +17 -17
  8. package/docs/get_started/tutorials/dungeon-game/overview.mdx +5 -76
  9. package/docs/guides/agentcore-gateway.mdx +2 -26
  10. package/docs/guides/connection/agentcore-gateway-agent.mdx +1 -1
  11. package/docs/guides/connection/py-agent-a2a.mdx +2 -2
  12. package/docs/guides/connection/py-agent-gateway.mdx +1 -1
  13. package/docs/guides/connection/py-agent-mcp.mdx +1 -1
  14. package/docs/guides/connection/react-trpc.mdx +1 -1
  15. package/docs/guides/connection/react-ts-agent.mdx +1 -1
  16. package/docs/guides/open-api-py-client.mdx +270 -0
  17. package/docs/guides/py-dynamodb.mdx +7 -0
  18. package/docs/guides/react-website-auth.mdx +3 -33
  19. package/docs/guides/react-website.mdx +3 -28
  20. package/docs/guides/runtime-config.mdx +2 -34
  21. package/docs/guides/terraform-project.mdx +1 -1
  22. package/docs/guides/ts-dynamodb.mdx +7 -0
  23. package/docs/guides/ts-smithy-api.mdx +8 -47
  24. package/docs/guides/typescript-project.mdx +2 -2
  25. package/docs/guides/workspace.mdx +7 -10
  26. package/docs/snippets/agent/architecture.mdx +9 -52
  27. package/docs/snippets/agent/bedrock-deployment.mdx +1 -1
  28. package/docs/snippets/agent/runtime-arn.mdx +1 -1
  29. package/docs/snippets/api/access-logging.mdx +1 -1
  30. package/docs/snippets/api/api-architecture.mdx +4 -75
  31. package/docs/snippets/api/type-safe-api-integrations.mdx +2 -4
  32. package/docs/snippets/lambda-function/architecture.mdx +3 -29
  33. package/docs/snippets/mcp/architecture.mdx +9 -38
  34. package/docs/snippets/mcp/bedrock-deployment.mdx +1 -1
  35. package/docs/snippets/pdk-migration/example/01-migrate-api.mdx +8 -6
  36. package/docs/snippets/pdk-migration/example/02-migrate-website.mdx +7 -7
  37. package/docs/snippets/pdk-migration/example/03-migrate-infra.mdx +4 -3
  38. package/docs/snippets/pdk-migration/example/04-deploy.mdx +8 -7
  39. package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +4 -4
  40. package/docs/snippets/prerequisites.mdx +0 -5
  41. package/docs/snippets/rdb/architecture.mdx +2 -33
  42. package/docs/snippets/recommended-prerequisites.mdx +1 -1
  43. package/docs/snippets/workspace-prerequisite.mdx +8 -0
  44. package/generators.json +7 -0
  45. package/package.json +1 -1
  46. package/src/agentcore-gateway/schema.json +1 -0
  47. package/src/open-api/py-client/schema.json +28 -0
  48. package/src/py/agent/schema.json +2 -0
  49. package/src/py/mcp-server/schema.json +1 -0
  50. package/src/ts/agent/schema.json +1 -0
  51. package/src/ts/api/schema.json +2 -0
  52. package/src/ts/mcp-server/schema.json +1 -0
  53. package/src/ts/react-website/app/schema.json +1 -0
  54. package/src/ts/website/app/schema.json +1 -0
@@ -26,7 +26,7 @@ import gameConversationPng from '@assets/game-conversation.png'
26
26
 
27
27
  To create a new monorepo, from within your desired directory, run the following command:
28
28
 
29
- <CreateNxWorkspaceCommand workspace="dungeon-adventure" iac="cdk" />
29
+ <CreateNxWorkspaceCommand workspace="dungeon-adventure" iac="cdk" readonly />
30
30
 
31
31
  :::note[CDK as IaC Provider]
32
32
  We use `--iac=cdk` as we will use CDK for infrastructure as code in this tutorial. The Nx Plugin for AWS also supports `terraform`.
@@ -72,7 +72,7 @@ Rather than copying the commands all at once, you can run each generator individ
72
72
 
73
73
  First, let's create our Game API. To do this, create a tRPC API called `GameApi` using these steps:
74
74
 
75
- <RunGenerator generator="ts#api" requiredParameters={{ name: "GameApi", framework: "trpc" }} noInteractive />
75
+ <RunGenerator generator="ts#api" requiredParameters={{ name: "GameApi", framework: "trpc" }} noInteractive readonly />
76
76
 
77
77
  <br />
78
78
 
@@ -137,7 +137,7 @@ Below is a list of all files which have been generated by the `ts#api` generator
137
137
 
138
138
  Let us look at these key files:
139
139
 
140
- ```ts {7}
140
+ ```ts {8}
141
141
  // packages/game-api/src/router.ts
142
142
  import { echo } from './procedures/echo.js';
143
143
  import { t } from './init.js';
@@ -152,7 +152,7 @@ export type AppRouter = typeof appRouter;
152
152
  ```
153
153
  The router defines the tRPC router for your API and is the place where you will declare all of your API methods. As you can see above, we have a method called `echo` with it's implementation in the `./procedures/echo.ts` file. The Lambda handler entrypoint is in `handler.ts`, which is configured automatically by the generator.
154
154
 
155
- ```ts {4-6}
155
+ ```ts {5-7}
156
156
  // packages/game-api/src/procedures/echo.ts
157
157
  import { publicProcedure } from '../init.js';
158
158
  import { EchoInputSchema, EchoOutputSchema } from '../schema/index.js';
@@ -403,7 +403,7 @@ Now let's create our Story Agent.
403
403
 
404
404
  To create a Python project:
405
405
 
406
- <RunGenerator generator="py#project" requiredParameters={{name:"story"}} noInteractive />
406
+ <RunGenerator generator="py#project" requiredParameters={{name:"story"}} noInteractive readonly />
407
407
 
408
408
  You will see some new files appear in your file tree.
409
409
  <details>
@@ -433,7 +433,7 @@ This has configured a Python project and [UV Workspace](https://docs.astral.sh/u
433
433
 
434
434
  To add a Strands agent to the project with the `py#agent` generator:
435
435
 
436
- <RunGenerator generator="py#agent" requiredParameters={{project:"story", auth:"cognito", protocol:"ag-ui"}} noInteractive />
436
+ <RunGenerator generator="py#agent" requiredParameters={{project:"story", auth:"cognito", protocol:"ag-ui"}} noInteractive readonly />
437
437
 
438
438
  :::note[AG-UI protocol]
439
439
  We choose `--protocol=ag-ui` so the agent speaks the [Agent-User Interaction protocol](https://docs.copilotkit.ai/aws-strands/protocol) — this lets our React website talk to it directly via [CopilotKit](https://docs.copilotkit.ai/), with streaming, tool calls, and conversation history handled by the protocol instead of a hand-rolled HTTP client.
@@ -916,7 +916,7 @@ Let us create an MCP server to provide tools for our Story Agent to manage a pla
916
916
 
917
917
  First, we create a TypeScript project:
918
918
 
919
- <RunGenerator generator="ts#project" requiredParameters={{name:"inventory"}} noInteractive />
919
+ <RunGenerator generator="ts#project" requiredParameters={{name:"inventory"}} noInteractive readonly />
920
920
 
921
921
  This will create an empty TypeScript project.
922
922
 
@@ -944,7 +944,7 @@ The `ts#project` generator generates these files.
944
944
 
945
945
  Next, we'll add an MCP server to our TypeScript project:
946
946
 
947
- <RunGenerator generator="ts#mcp-server" requiredParameters={{project:"inventory"}} noInteractive />
947
+ <RunGenerator generator="ts#mcp-server" requiredParameters={{project:"inventory"}} noInteractive readonly />
948
948
 
949
949
  This will add an MCP server.
950
950
  <details>
@@ -977,7 +977,7 @@ The `ts#mcp-server` generator generates these files.
977
977
 
978
978
  Our game state — saved games and each player's inventory — lives in [Amazon DynamoDB](https://aws.amazon.com/dynamodb/). Create a DynamoDB project called `DungeonDb` with the `ts#dynamodb` generator:
979
979
 
980
- <RunGenerator generator="ts#dynamodb" requiredParameters={{name:"DungeonDb"}} noInteractive />
980
+ <RunGenerator generator="ts#dynamodb" requiredParameters={{name:"DungeonDb"}} noInteractive readonly />
981
981
 
982
982
  :::tip[Local-first development]
983
983
  The `ts#dynamodb` generator vends a `dev` target that runs [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) in a container. Combined with the `connection` generator (which we run below), this means **the entire game runs on your machine without a deployment** until the end of the tutorial.
@@ -1029,7 +1029,7 @@ Next, we will create the UI which will allow you to interact with the game.
1029
1029
 
1030
1030
  To create the UI, create a website called `GameUI` using these steps:
1031
1031
 
1032
- <RunGenerator generator="ts#website" requiredParameters={{name:"GameUI", ux:"shadcn"}} noInteractive />
1032
+ <RunGenerator generator="ts#website" requiredParameters={{name:"GameUI", ux:"shadcn"}} noInteractive readonly />
1033
1033
 
1034
1034
  :::note[Shadcn UI]
1035
1035
  We select `--ux=shadcn` so the generated website uses [shadcn/ui](https://ui.shadcn.com/) components styled with Tailwind — all our route code uses shadcn primitives like `Card`, `Button`, and `Input`, and the `connection` generator later wires a matching shadcn-themed [CopilotKit](https://docs.copilotkit.ai/) chat surface.
@@ -1166,7 +1166,7 @@ A component will be rendered when navigating to the `/` route. `@tanstack/react-
1166
1166
 
1167
1167
  Let us configure our Game UI to require authenticated access via Amazon Cognito using these steps:
1168
1168
 
1169
- <RunGenerator generator="ts#website#auth" requiredParameters={{cognitoDomain:"game-ui", project:"@dungeon-adventure/game-ui", allowSignup:true}} noInteractive />
1169
+ <RunGenerator generator="ts#website#auth" requiredParameters={{cognitoDomain:"game-ui", project:"@dungeon-adventure/game-ui", allowSignup:true}} noInteractive readonly />
1170
1170
 
1171
1171
  You will see some new files appear/change in your file tree.
1172
1172
 
@@ -1250,7 +1250,7 @@ The `RuntimeConfigProvider` and `CognitoAuth` components have been added to the
1250
1250
 
1251
1251
  Let us configure our Game UI to connect to our previously created Game API.
1252
1252
 
1253
- <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/game-ui", targetProject:"@dungeon-adventure/game-api"}} noInteractive />
1253
+ <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/game-ui", targetProject:"@dungeon-adventure/game-api"}} noInteractive readonly />
1254
1254
 
1255
1255
  You will see some new files have appear/change in your file tree.
1256
1256
 
@@ -1344,7 +1344,7 @@ The `main.tsx` file has been updated via an AST transform to inject the tRPC pro
1344
1344
 
1345
1345
  Let us connect our Story Agent to the Inventory MCP server so the agent can discover and invoke the MCP server's tools.
1346
1346
 
1347
- <RunGenerator generator="connection" requiredParameters={{sourceProject:"story", targetProject:"inventory"}} noInteractive />
1347
+ <RunGenerator generator="connection" requiredParameters={{sourceProject:"story", targetProject:"inventory"}} noInteractive readonly />
1348
1348
 
1349
1349
  <details>
1350
1350
  <summary>Examine the Story Agent → Inventory MCP connection files</summary>
@@ -1384,7 +1384,7 @@ For more details, refer to the <Link path="guides/connection/py-agent-mcp">Pytho
1384
1384
 
1385
1385
  Let us connect our Game UI to the Story Agent. Since the agent speaks AG-UI, the `connection` generator wires up [CopilotKit](https://docs.copilotkit.ai/): a themed chat component and an `@ag-ui/client` `HttpAgent` ready to render.
1386
1386
 
1387
- <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/game-ui", targetProject:"story"}} noInteractive />
1387
+ <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/game-ui", targetProject:"story"}} noInteractive readonly />
1388
1388
 
1389
1389
  <details>
1390
1390
  <summary>Examine the UI → Story Agent connection files</summary>
@@ -1419,9 +1419,9 @@ For more details, refer to the <Link path="guides/connection/react-agui">React t
1419
1419
 
1420
1420
  Both the Game API and the Inventory MCP server read and write our DynamoDB table, so let us connect them to the `DungeonDb` project. The `connection` generator detects that the target is a `ts#dynamodb` project and wires each source project's `dev` target to start DynamoDB Local automatically.
1421
1421
 
1422
- <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/game-api", targetProject:"@dungeon-adventure/dungeon-db"}} noInteractive />
1422
+ <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/game-api", targetProject:"@dungeon-adventure/dungeon-db"}} noInteractive readonly />
1423
1423
 
1424
- <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/inventory", targetProject:"@dungeon-adventure/dungeon-db"}} noInteractive />
1424
+ <RunGenerator generator="connection" requiredParameters={{sourceProject:"@dungeon-adventure/inventory", targetProject:"@dungeon-adventure/dungeon-db"}} noInteractive readonly />
1425
1425
 
1426
1426
  <Aside type="tip" title="One command boots the whole stack locally">
1427
1427
  Because the Story Agent's `agent-dev` already depends on the Inventory MCP server's `mcp-server-dev` (via the `story → inventory` connection above), and both the Game API and MCP server now depend on `dungeon-db:dev`, running any one project's `dev` target starts every dependency it needs in the right order.
@@ -1431,7 +1431,7 @@ Because the Story Agent's `agent-dev` already depends on the Inventory MCP serve
1431
1431
 
1432
1432
  Let us create the final sub-project for the CDK infrastructure.
1433
1433
 
1434
- <RunGenerator generator="ts#infra" requiredParameters={{name:"infra"}} noInteractive />
1434
+ <RunGenerator generator="ts#infra" requiredParameters={{name:"infra"}} noInteractive readonly />
1435
1435
 
1436
1436
  You will see some new files have appear/change in your file tree.
1437
1437
 
@@ -10,13 +10,13 @@ import Drawer from '@components/drawer.astro';
10
10
  import RunGenerator from '@components/run-generator.astro';
11
11
  import NxCommands from '@components/nx-commands.astro';
12
12
  import InstallCommand from '@components/install-command.astro';
13
- import Link from '@components/link.astro';
14
13
 
15
14
  import baselineWebsitePng from '@assets/baseline-website.png'
16
15
  import baselineGamePng from '@assets/baseline-game.png'
17
16
  import nxGraphPng from '@assets/nx-graph.png'
18
17
  import gameSelectPng from '@assets/game-select.png'
19
18
  import gameConversationPng from '@assets/game-conversation.png'
19
+ import EmbeddedGraph from '@components/embedded-graph.astro';
20
20
 
21
21
 
22
22
  Using this tutorial, you will build an Agentic AI-powered dungeon adventure game with `@aws/nx-plugin`. This tutorial does not assume any existing knowledge of the `@aws/nx-plugin` or related technologies.
@@ -52,76 +52,9 @@ The game interface will resemble something like this diagram:
52
52
 
53
53
  ### Application architecture
54
54
 
55
- The Agentic AI-powered dungeon adventure game is built using the following architecture:
56
-
57
- ```d2 inline=true
58
- direction: down
59
-
60
- browser: Web Browser {
61
- shape: image
62
- icon: /nx-plugin-for-aws/icons/aws/client.svg
63
- }
64
-
65
- cognito: Cognito / IAM {
66
- shape: image
67
- icon: /nx-plugin-for-aws/icons/aws/cognito.svg
68
- }
69
-
70
- cloudfront: CloudFront {
71
- shape: image
72
- icon: /nx-plugin-for-aws/icons/aws/cloudfront.svg
73
- }
74
-
75
- s3: Static Assets\n(S3) {
76
- shape: image
77
- icon: /nx-plugin-for-aws/icons/aws/s3.svg
78
- }
79
-
80
- apigw: API Gateway\n(Game API) {
81
- shape: image
82
- icon: /nx-plugin-for-aws/icons/aws/api-gateway.svg
83
- }
84
-
85
- lambda: tRPC API\n(Lambda) {
86
- shape: image
87
- icon: /nx-plugin-for-aws/icons/aws/lambda.svg
88
- }
89
-
90
- story: Story Agent\n(AgentCore) {
91
- shape: image
92
- icon: /nx-plugin-for-aws/icons/aws/bedrock-agentcore-runtime.svg
93
- }
94
-
95
- mcp: Inventory MCP\n(AgentCore) {
96
- shape: image
97
- icon: /nx-plugin-for-aws/icons/aws/bedrock-agentcore-runtime.svg
98
- }
99
-
100
- ddb: Game State\n(DynamoDB) {
101
- shape: image
102
- icon: /nx-plugin-for-aws/icons/aws/dynamodb.svg
103
- }
104
-
105
- sessions: Story Sessions\n(S3) {
106
- shape: image
107
- icon: /nx-plugin-for-aws/icons/aws/s3.svg
108
- }
109
-
110
- browser -> cognito: Sign in
111
- browser -> cloudfront
112
- cloudfront -> s3
113
- browser -> apigw
114
- apigw -> lambda
115
- lambda -> ddb
116
- lambda -> sessions: Read transcripts
117
- browser -> story: AG-UI stream
118
- story -> sessions: Persist turns
119
- story -> mcp: Tool calls
120
- mcp -> ddb
121
- ddb -> sessions: {
122
- style.opacity: 0
123
- }
124
- ```
55
+ The Agentic AI-powered dungeon adventure game is built using the following architecture — switch to **Projects** to see the workspace it is built from, which you scaffold in Module 1:
56
+
57
+ <EmbeddedGraph preset="dungeon-adventure" workspace="dungeon-adventure" iac="cdk" view="infrastructure" copyable={false} />
125
58
 
126
59
  - React/Vite frontend website utilising:
127
60
  - Amazon Cognito/Identity Pools for secure API calls.
@@ -138,8 +71,4 @@ Before you proceed, you will need the following global dependencies:
138
71
 
139
72
  <Snippet name="required-prerequisites" />
140
73
  - [AWS Credentials](https://docs.aws.amazon.com/sdkref/latest/guide/access.html) configured to your target AWS account, since this tutorial deploys the application and invokes Amazon Bedrock
141
- - [Docker](https://www.docker.com/) (or [Finch](https://github.com/runfinch/finch)) is required for local DynamoDB development
142
-
143
- :::tip[AI Assistant Setup]
144
- If you use an AI Assistant such as Kiro, Kiro CLI, Cursor, Claude Code or Cline, refer to the <Link path="/get_started/building-with-ai">install the Nx Plugin for AWS MCP server</Link> page.
145
- :::
74
+ - [Docker](https://www.docker.com/) (or [Finch](https://github.com/runfinch/finch)) is required for local DynamoDB development
@@ -14,6 +14,7 @@ import Snippet from '@components/snippet.astro';
14
14
  import Link from '@components/link.astro';
15
15
  import NxCommands from '@components/nx-commands.astro';
16
16
  import OptionFilter from '@components/option-filter.astro';
17
+ import ArchitectureDiagram from '@components/architecture-diagram.astro';
17
18
 
18
19
  Generate an [Amazon Bedrock AgentCore Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html) project. An AgentCore Gateway is a managed entry point in front of your MCP servers or agents, authenticating inbound requests (IAM or Cognito) and signing outbound traffic to its targets with IAM SigV4.
19
20
 
@@ -89,32 +90,7 @@ The Gateway URL is automatically registered in the `agentcore.gateways.<ClassNam
89
90
 
90
91
  The deployed Gateway has the following architecture, with an [AWS WAFv2](https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html) Web ACL in front of the Gateway, which routes on to its downstream MCP server targets:
91
92
 
92
- ```d2 inline=true
93
- direction: right
94
-
95
- client: Client {
96
- shape: image
97
- icon: /nx-plugin-for-aws/icons/aws/client.svg
98
- }
99
-
100
- waf: WAF {
101
- shape: image
102
- icon: /nx-plugin-for-aws/icons/aws/waf.svg
103
- }
104
-
105
- gateway: AgentCore Gateway\n(MCP, IAM or Cognito auth) {
106
- shape: image
107
- icon: /nx-plugin-for-aws/icons/aws/bedrock-agentcore-gateway.svg
108
- }
109
-
110
- targets: Downstream MCP Servers\n(Gateway targets) {
111
- shape: rectangle
112
- }
113
-
114
- client -> waf
115
- waf -> gateway
116
- gateway -> targets
117
- ```
93
+ <ArchitectureDiagram />
118
94
 
119
95
  ## Authentication
120
96
 
@@ -108,7 +108,7 @@ AgentCore Runtime VPC deployments are only supported in certain availability zon
108
108
  <Fragment slot="terraform">
109
109
  In the Terraform file where you instantiate the Gateway, wire the agent target in:
110
110
 
111
- ```hcl title="packages/infra/src/main.tf" {9-20,24-40}
111
+ ```hcl title="packages/infra/src/main.tf" {9-25,28-48}
112
112
  module "my_agent" {
113
113
  source = "../../common/terraform/src/app/agents/my-agent"
114
114
  # ...
@@ -72,7 +72,7 @@ The generator transforms your agent's `agent.py` to wrap the remote A2A agent as
72
72
 
73
73
  <Tabs syncKey="agent-framework">
74
74
  <TabItem label="Strands" _filter={{ framework: 'strands' }}>
75
- ```python title="packages/my-project/my_module/agent/agent.py" {4,8-13,15}
75
+ ```python title="packages/my-project/my_module/agent/agent.py" {4,8-13,15,17}
76
76
  from contextlib import contextmanager
77
77
  from strands import Agent, tool
78
78
 
@@ -94,7 +94,7 @@ def get_agent():
94
94
  ```
95
95
  </TabItem>
96
96
  <TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
97
- ```python title="packages/my-project/my_module/agent/agent.py" {5,8-13,15}
97
+ ```python title="packages/my-project/my_module/agent/agent.py" {5,8-13,15,18}
98
98
  from langchain.agents import create_agent
99
99
  from langchain_aws import ChatBedrockConverse
100
100
  from langchain_core.tools import tool
@@ -77,7 +77,7 @@ The generator transforms your agent's `agent.py` to use the Gateway client:
77
77
 
78
78
  <Tabs syncKey="agent-framework">
79
79
  <TabItem label="Strands" _filter={{ framework: 'strands' }}>
80
- ```python title="packages/example/example/my_agent/agent.py" {4,8,9-13}
80
+ ```python title="packages/example/example/my_agent/agent.py" {4,8-11,14}
81
81
  from contextlib import contextmanager
82
82
  from strands import Agent
83
83
 
@@ -74,7 +74,7 @@ The generator transforms your agent's `agent.py` to use the MCP server's tools:
74
74
 
75
75
  <Tabs syncKey="agent-framework">
76
76
  <TabItem label="Strands" _filter={{ framework: 'strands' }}>
77
- ```python title="packages/my-project/my_module/agent/agent.py" {4,8,9-13}
77
+ ```python title="packages/my-project/my_module/agent/agent.py" {4,8-11,14}
78
78
  from contextlib import contextmanager
79
79
  from strands import Agent
80
80
 
@@ -186,7 +186,7 @@ For information on how to define subscription procedures in your backend, see th
186
186
 
187
187
  You can consume subscriptions using the `useSubscription` hook with `subscriptionOptions` from the options proxy:
188
188
 
189
- ```tsx {1-2,7-22}
189
+ ```tsx {1-2,7-23}
190
190
  import { useSubscription } from '@trpc/tanstack-react-query';
191
191
  import { useMyApi } from './hooks/useMyApi';
192
192
 
@@ -84,7 +84,7 @@ The generated code handles authentication depending on your agent's configuratio
84
84
 
85
85
  The most common use case is streaming the agent's response using the `invoke` subscription with the `use<AgentName>Agent` hook, which returns a [tRPC options proxy](https://trpc.io/docs/client/tanstack-react-query) for use with TanStack Query:
86
86
 
87
- ```tsx {1-2,7-22}
87
+ ```tsx {1-2,7-23}
88
88
  import { useSubscription } from '@trpc/tanstack-react-query';
89
89
  import { useMyAgentAgent } from './hooks/useMyAgentAgent';
90
90
 
@@ -0,0 +1,270 @@
1
+ ---
2
+ title: OpenAPI Python Client
3
+ description: Reference documentation for the OpenAPI Python client generator
4
+ generator: open-api#py-client
5
+ sidebar:
6
+ # Hidden until a connection generator vends this client, matching the
7
+ # generator's own `hidden: true`.
8
+ hidden: true
9
+ ---
10
+ import { FileTree } from '@astrojs/starlight/components';
11
+ import GeneratorParameters from '@components/generator-parameters.astro';
12
+ import RunGenerator from '@components/run-generator.astro';
13
+ import Drawer from '@components/drawer.astro';
14
+
15
+ Generate a type-safe Python client for any OpenAPI specification, built on [httpx](https://www.python-httpx.org/) and [pydantic](https://docs.pydantic.dev/).
16
+
17
+ The client is the Python counterpart of the `open-api#ts-client` generator: one class per API, keyword-only methods, typed errors you can narrow, and a single extension point — your own `httpx` client — for authentication and anything else you need on the wire.
18
+
19
+ ## Usage
20
+
21
+ <RunGenerator generator="open-api#py-client" />
22
+
23
+ ### Options
24
+
25
+ <GeneratorParameters generator="open-api#py-client" />
26
+
27
+ ## Generator Output
28
+
29
+ <FileTree>
30
+
31
+ - \<outputPath>
32
+ - \_\_init\_\_.py Exports the clients, `ApiError` and the `types` module
33
+ - types.py pydantic models for every schema in the specification
34
+ - errors.py `ApiError` and a subclass per operation
35
+ - client.py Synchronous client, using `httpx.Client`
36
+ - async_client.py Asynchronous client, using `httpx.AsyncClient`
37
+
38
+ </FileTree>
39
+
40
+ Pass `--clientType=sync` or `--clientType=async` to emit just one of the two clients.
41
+
42
+ :::tip[Generated Client in Git]
43
+ The client is ignored from version control by default, since it is regenerated from the specification. Remove the entry from your `.gitignore` to check it in instead — but note that any manual edits will be overwritten the next time it is generated.
44
+ :::
45
+
46
+ ### Dependencies
47
+
48
+ The generated code imports `httpx` and `pydantic`, so add both to the project you generate into:
49
+
50
+ ```toml
51
+ # pyproject.toml
52
+ dependencies = [
53
+ "httpx>=0.28.1",
54
+ "pydantic>=2.13.4",
55
+ ]
56
+ ```
57
+
58
+ Nothing else is required — no runtime of its own, and no framework to adopt.
59
+
60
+ ## Using the Generated Client
61
+
62
+ Instantiate the client with the API's base URL:
63
+
64
+ ```python
65
+ from my_api import MyApi, MyApiConfig
66
+
67
+ api = MyApi(MyApiConfig(url="https://api.example.com"))
68
+
69
+ pet = api.pet.add_pet(name="rex", status="available")
70
+ print(pet.id, pet.name)
71
+ ```
72
+
73
+ Methods are **keyword-only**, so a call reads as the specification does, and required parameters come first:
74
+
75
+ ```python
76
+ pets = api.pet.list_pets(status=["available"], limit=10)
77
+ pet = api.pet.get_pet_by_id(pet_id=42)
78
+ api.pet.delete_pet(pet_id=42)
79
+ ```
80
+
81
+ Operations tagged in the specification are grouped into namespaces — `api.pet.add_pet(...)` above comes from the `pet` tag. Untagged operations sit directly on the client, as `api.health()`.
82
+
83
+ An operation whose body is an object has its fields flattened into the call, so there is no wrapper to construct. Where the body is a list or a dictionary it is passed positionally instead:
84
+
85
+ ```python
86
+ created = api.pet.batch_create([types.Pet(name="a"), types.Pet(name="b")])
87
+ ```
88
+
89
+ ### Types
90
+
91
+ Every schema becomes a pydantic model in `types`, so results are validated and your editor knows their shape:
92
+
93
+ ```python
94
+ from my_api import types
95
+
96
+ pet = api.pet.add_pet(name="rex", owner=types.Owner(name="ann"))
97
+
98
+ reveal_type(pet) # types.Pet
99
+ reveal_type(pet.owner) # types.Owner | None
100
+ ```
101
+
102
+ Enums become `Literal` types, so an invalid value is a type error rather than a failed request:
103
+
104
+ ```python
105
+ api.pet.list_pets(status=["available"]) # ok
106
+ api.pet.list_pets(status=["on-mars"]) # rejected before it is sent
107
+ ```
108
+
109
+ Dates and date-times are `datetime.date` / `datetime.datetime` on the way in and out — the client handles the ISO-8601 conversion:
110
+
111
+ ```python
112
+ event = api.create_event(day=datetime.date(2026, 4, 18))
113
+ reveal_type(event.day) # datetime.date
114
+ ```
115
+
116
+ ### Errors
117
+
118
+ A non-success response raises an exception. Catch `ApiError` to handle any failure from either client:
119
+
120
+ ```python
121
+ from my_api import ApiError
122
+
123
+ try:
124
+ pet = api.pet.get_pet_by_id(pet_id=42)
125
+ except ApiError as e:
126
+ print(e.status, e.error)
127
+ ```
128
+
129
+ Each operation also has its own subclass, whose `.error` narrows to the responses that operation declares. `isinstance` picks out one status:
130
+
131
+ ```python {8,10}
132
+ from my_api import types
133
+ from my_api.errors import GetPetByIdApiError
134
+
135
+ try:
136
+ pet = api.pet.get_pet_by_id(pet_id=42)
137
+ except GetPetByIdApiError as e:
138
+ if isinstance(e.error, types.GetPetById404Error):
139
+ print("no such pet:", e.error.error.detail)
140
+ else:
141
+ print("failed with", e.status)
142
+ ```
143
+
144
+ There is one class per response the operation declares, named after its status code — a declared `4XX` range becomes `GetPetById4XXError`.
145
+
146
+ A body that doesn't match the schema the specification declares still raises the typed exception, carrying whatever the server actually sent — so a proxy's HTML error page surfaces as an error rather than a validation failure inside your error handler.
147
+
148
+ ### Streaming
149
+
150
+ An operation that streams returns an iterator of parsed items, so you can consume the response as it arrives:
151
+
152
+ ```python
153
+ for chunk in api.stream_chunks(count=4):
154
+ print(chunk.index, chunk.message)
155
+ ```
156
+
157
+ ### Async
158
+
159
+ The async client mirrors the sync one, method for method:
160
+
161
+ ```python
162
+ from my_api import AsyncMyApi, AsyncMyApiConfig
163
+
164
+ async with AsyncMyApi(AsyncMyApiConfig(url="https://api.example.com")) as api:
165
+ pet = await api.pet.add_pet(name="rex")
166
+
167
+ async for chunk in api.stream_chunks(count=4):
168
+ print(chunk.message)
169
+ ```
170
+
171
+ Both clients raise from the same hierarchy, so `except ApiError` catches either.
172
+
173
+ ## Authentication
174
+
175
+ Authentication is the one thing every API does differently, so the client doesn't invent an abstraction for it. Supply your own `httpx` client and whatever you configure on it applies to every request:
176
+
177
+ ```python {6,13}
178
+ import httpx
179
+ from my_api import MyApi, MyApiConfig
180
+
181
+
182
+ class BearerAuth(httpx.Auth):
183
+ def __init__(self, token: str) -> None:
184
+ self.token = token
185
+
186
+ def auth_flow(self, request):
187
+ request.headers["Authorization"] = f"Bearer {self.token}"
188
+ yield request
189
+
190
+
191
+ with httpx.Client(auth=BearerAuth("my-token")) as http:
192
+ api = MyApi(MyApiConfig(url="https://api.example.com", httpx_client=http))
193
+ pet = api.pet.add_pet(name="rex")
194
+ ```
195
+
196
+ This is the Python equivalent of passing a custom `fetch` to the TypeScript client. An [`httpx.Auth`](https://www.python-httpx.org/advanced/authentication/), event hooks, a custom transport, timeouts, retries, proxies, HTTP/2, and the client's own headers and query parameters all apply — including on multipart uploads and streaming responses.
197
+
198
+ A client you supply is never closed by the generated one, so it is safe to share across several clients.
199
+
200
+ <Drawer title="Signing requests with AWS SigV4" trigger="Click here for an example which signs requests with AWS IAM credentials.">
201
+
202
+ `httpx.Auth` is all a signer needs to be. For an API behind IAM authentication:
203
+
204
+ ```python
205
+ import hashlib
206
+ from collections.abc import Generator
207
+
208
+ import boto3
209
+ import httpx
210
+ from botocore.auth import SigV4Auth
211
+ from botocore.awsrequest import AWSRequest
212
+
213
+ from my_api import MyApi, MyApiConfig
214
+
215
+
216
+ class SigV4HTTPXAuth(httpx.Auth):
217
+ requires_request_body = True
218
+
219
+ def __init__(self, credentials, service: str, region: str):
220
+ self.signer = SigV4Auth(credentials, service, region)
221
+
222
+ def auth_flow(
223
+ self, request: httpx.Request
224
+ ) -> Generator[httpx.Request, httpx.Response]:
225
+ headers = dict(request.headers)
226
+ headers.pop("connection", None)
227
+ headers["x-amz-content-sha256"] = hashlib.sha256(
228
+ request.content or b""
229
+ ).hexdigest()
230
+
231
+ aws_request = AWSRequest(
232
+ method=request.method,
233
+ url=str(request.url),
234
+ data=request.content,
235
+ headers=headers,
236
+ )
237
+ self.signer.add_auth(aws_request)
238
+
239
+ request.headers.clear()
240
+ request.headers.update(dict(aws_request.headers))
241
+ yield request
242
+
243
+
244
+ session = boto3.Session()
245
+ auth = SigV4HTTPXAuth(session.get_credentials(), "execute-api", session.region_name)
246
+
247
+ with httpx.Client(auth=auth) as http:
248
+ api = MyApi(MyApiConfig(url="https://api.example.com", httpx_client=http))
249
+ pet = api.pet.add_pet(name="rex")
250
+ ```
251
+
252
+ </Drawer>
253
+
254
+ ### Other configuration
255
+
256
+ `Config` carries a small number of options beyond the URL and the client:
257
+
258
+ ```python
259
+ api = MyApi(
260
+ MyApiConfig(
261
+ url="https://api.example.com",
262
+ # Sent with every request, where the operation sets no header of its own
263
+ headers={"x-tenant-id": "acme"},
264
+ # Omit the Content-Type the specification declares for each request
265
+ omit_content_type_header=False,
266
+ )
267
+ )
268
+ ```
269
+
270
+ A header an operation sets always wins over the same header here, so a per-call value is never merged into the configured one.
@@ -11,6 +11,7 @@ import Link from '@components/link.astro';
11
11
  import RunGenerator from '@components/run-generator.astro';
12
12
  import GeneratorParameters from '@components/generator-parameters.astro';
13
13
  import Snippet from '@components/snippet.astro';
14
+ import ArchitectureDiagram from '@components/architecture-diagram.astro';
14
15
 
15
16
  This generator creates a new Python project backed by [Amazon DynamoDB](https://aws.amazon.com/dynamodb/), using [PynamoDB](https://pynamodb.readthedocs.io/) for entity modelling. It generates the application code and infrastructure needed to provision and manage a DynamoDB table using AWS CDK or Terraform, with single-table design support and built-in local development via DynamoDB Local.
16
17
 
@@ -53,6 +54,12 @@ The local development scripts are shared across all DynamoDB projects (both Type
53
54
 
54
55
  <Snippet name="dynamodb/infrastructure" />
55
56
 
57
+ #### Architecture
58
+
59
+ The deployed project provisions the table itself, which any project it is connected to reads and writes:
60
+
61
+ <ArchitectureDiagram />
62
+
56
63
  ## Local Development
57
64
 
58
65
  ### Starting Local DynamoDB