@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.
- package/bin/aws-nx-mcp.js +17 -9
- package/docs/get_started/building-with-ai.mdx +21 -14
- package/docs/get_started/concepts.mdx +1 -1
- package/docs/get_started/existing-project.mdx +7 -4
- package/docs/get_started/quick-start.mdx +153 -65
- package/docs/get_started/tutorials/contribute-generator.mdx +5 -5
- package/docs/get_started/tutorials/dungeon-game/1.mdx +17 -17
- package/docs/get_started/tutorials/dungeon-game/overview.mdx +5 -76
- package/docs/guides/agentcore-gateway.mdx +2 -26
- package/docs/guides/connection/agentcore-gateway-agent.mdx +1 -1
- package/docs/guides/connection/py-agent-a2a.mdx +2 -2
- package/docs/guides/connection/py-agent-gateway.mdx +1 -1
- package/docs/guides/connection/py-agent-mcp.mdx +1 -1
- package/docs/guides/connection/react-trpc.mdx +1 -1
- package/docs/guides/connection/react-ts-agent.mdx +1 -1
- package/docs/guides/open-api-py-client.mdx +270 -0
- package/docs/guides/py-dynamodb.mdx +7 -0
- package/docs/guides/react-website-auth.mdx +3 -33
- package/docs/guides/react-website.mdx +3 -28
- package/docs/guides/runtime-config.mdx +2 -34
- package/docs/guides/terraform-project.mdx +1 -1
- package/docs/guides/ts-dynamodb.mdx +7 -0
- package/docs/guides/ts-smithy-api.mdx +8 -47
- package/docs/guides/typescript-project.mdx +2 -2
- package/docs/guides/workspace.mdx +7 -10
- package/docs/snippets/agent/architecture.mdx +9 -52
- package/docs/snippets/agent/bedrock-deployment.mdx +1 -1
- package/docs/snippets/agent/runtime-arn.mdx +1 -1
- package/docs/snippets/api/access-logging.mdx +1 -1
- package/docs/snippets/api/api-architecture.mdx +4 -75
- package/docs/snippets/api/type-safe-api-integrations.mdx +2 -4
- package/docs/snippets/lambda-function/architecture.mdx +3 -29
- package/docs/snippets/mcp/architecture.mdx +9 -38
- package/docs/snippets/mcp/bedrock-deployment.mdx +1 -1
- package/docs/snippets/pdk-migration/example/01-migrate-api.mdx +8 -6
- package/docs/snippets/pdk-migration/example/02-migrate-website.mdx +7 -7
- package/docs/snippets/pdk-migration/example/03-migrate-infra.mdx +4 -3
- package/docs/snippets/pdk-migration/example/04-deploy.mdx +8 -7
- package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +4 -4
- package/docs/snippets/prerequisites.mdx +0 -5
- package/docs/snippets/rdb/architecture.mdx +2 -33
- package/docs/snippets/recommended-prerequisites.mdx +1 -1
- package/docs/snippets/workspace-prerequisite.mdx +8 -0
- package/generators.json +7 -0
- package/package.json +1 -1
- package/src/agentcore-gateway/schema.json +1 -0
- package/src/open-api/py-client/schema.json +28 -0
- package/src/py/agent/schema.json +2 -0
- package/src/py/mcp-server/schema.json +1 -0
- package/src/ts/agent/schema.json +1 -0
- package/src/ts/api/schema.json +2 -0
- package/src/ts/mcp-server/schema.json +1 -0
- package/src/ts/react-website/app/schema.json +1 -0
- 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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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,
|
|
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,
|
|
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-
|
|
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-
|
|
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
|