@aws/nx-plugin-mcp 1.0.0-rc.57 → 1.0.0-rc.59
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 +149 -156
- package/docs/get_started/graph-builder.mdx +37 -0
- package/docs/get_started/tutorials/contribute-generator.mdx +2 -2
- package/docs/get_started/tutorials/dungeon-game/1.mdx +2 -2
- package/docs/guides/agentcore-gateway.mdx +37 -10
- package/docs/guides/connection/agentcore-gateway-agent.mdx +282 -0
- package/docs/guides/connection/agentcore-gateway-gateway.mdx +2 -2
- package/docs/guides/connection/agentcore-gateway-mcp.mdx +2 -2
- package/docs/guides/connection/py-agent-a2a.mdx +1 -1
- package/docs/guides/connection/py-agent-gateway.mdx +2 -2
- package/docs/guides/connection/py-agent-mcp.mdx +3 -3
- package/docs/guides/connection/react-agentcore-gateway.mdx +112 -0
- package/docs/guides/connection/smithy-rdb.mdx +1 -1
- package/docs/guides/connection/trpc-rdb.mdx +1 -1
- package/docs/guides/connection/ts-agent-a2a.mdx +1 -1
- package/docs/guides/connection/ts-agent-gateway.mdx +1 -1
- package/docs/guides/connection/ts-agent-mcp.mdx +1 -1
- package/docs/guides/connection.mdx +18 -0
- package/docs/guides/fastapi.mdx +1 -1
- package/docs/guides/py-agent.mdx +7 -0
- package/docs/guides/react-website.mdx +9 -2
- package/docs/guides/terraform-project.mdx +1 -1
- package/docs/guides/trpc.mdx +2 -2
- package/docs/guides/ts-agent.mdx +7 -0
- package/docs/guides/ts-smithy-api.mdx +8 -8
- package/docs/snippets/agent/bedrock-deployment.mdx +1 -1
- package/docs/snippets/agent/runtime-arn.mdx +1 -1
- package/docs/snippets/api/cors-configuration-terraform-note.mdx +1 -1
- package/docs/snippets/api/type-safe-api-integrations.mdx +2 -2
- package/docs/snippets/api/waf-configuration.mdx +2 -2
- package/docs/snippets/connection/a2a-infrastructure.mdx +1 -1
- package/docs/snippets/mcp/bedrock-deployment.mdx +1 -1
- package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +1 -1
- package/generators.json +17 -1
- package/package.json +1 -1
- package/src/agentcore-gateway/agent-connection/schema.json +31 -0
- package/src/agentcore-gateway/react-connection/schema.json +31 -0
- package/src/agentcore-gateway/schema.json +3 -2
- package/src/py/agent/schema.json +1 -0
- package/src/py/dynamodb/schema.json +1 -0
- package/src/py/fast-api/schema.json +1 -0
- package/src/py/mcp-server/schema.json +1 -0
- package/src/py/rdb/schema.json +1 -0
- package/src/smithy/ts/api/schema.json +1 -0
- package/src/trpc/backend/schema.json +1 -0
- package/src/ts/agent/schema.json +1 -0
- package/src/ts/dynamodb/schema.json +1 -0
- package/src/ts/mcp-server/schema.json +1 -0
- package/src/ts/rdb/schema.json +1 -0
- package/src/ts/react-website/app/schema.json +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Graph Builder
|
|
3
|
+
description: Design your workspace visually, then copy the commands that scaffold it.
|
|
4
|
+
# The builder needs the full content width, which the table of contents column
|
|
5
|
+
# would otherwise take.
|
|
6
|
+
tableOfContents: false
|
|
7
|
+
---
|
|
8
|
+
import Link from '@components/link.astro';
|
|
9
|
+
import GraphBuilder from '@components/graph-builder.astro';
|
|
10
|
+
|
|
11
|
+
Sketch the projects your workspace needs and the connections between them, and the builder generates the commands that scaffold exactly what you drew. Copy them, run them, and you have a working workspace.
|
|
12
|
+
|
|
13
|
+
Drag components from the palette onto the canvas, drag from a component's right edge to another to connect them, and edit each component's properties on the right. The generated commands at the bottom update with every change — hit **Copy** to take the whole script.
|
|
14
|
+
|
|
15
|
+
<GraphBuilder />
|
|
16
|
+
|
|
17
|
+
## How it works
|
|
18
|
+
|
|
19
|
+
Each component on the canvas maps to a generator, and each connection to the <Link path="guides/connection">connection generator</Link>. The commands are emitted in dependency order: the workspace first, then the projects, then the components they host, then the connections wiring them together.
|
|
20
|
+
|
|
21
|
+
A website always gets <Link path="guides/react-website-auth">Cognito authentication</Link> added straight after it, since `ts#website` leaves that to a follow-up generator.
|
|
22
|
+
|
|
23
|
+
An `infra` project is added at the end — <Link path="guides/typescript-infrastructure">`ts#infra`</Link> or <Link path="guides/terraform-project">`terraform#project`</Link>, matching your IaC choice. Every generated project vends constructs for it to instantiate, so this is what you deploy. Because it owns that name, no component on the canvas can be called `infra`.
|
|
24
|
+
|
|
25
|
+
Drag the canvas background to pan around, and drag a component to reposition it. Shift-click to select several components and move them as a group. Click a connection to select it, then press <kbd>Delete</kbd> to remove it (or use the ✕ on the connection itself).
|
|
26
|
+
|
|
27
|
+
The palette lists every project and component type that can take part in a connection, and you can only draw the connections the plugin supports — so a graph that validates is a graph that scaffolds.
|
|
28
|
+
|
|
29
|
+
Three rules are worth knowing:
|
|
30
|
+
|
|
31
|
+
- **Components share a host project.** An agent and an MCP server are added _to_ a project rather than being projects of their own. Give them the same host project name to put them in one project, or different names for one project each.
|
|
32
|
+
- **Some connections constrain their endpoints.** Connecting an agent to another agent requires the target to use the `a2a` protocol, for instance. Where a property setting would break a connection you have drawn, the builder says so against the component and the connection.
|
|
33
|
+
- **Drawing a connection can adjust the target.** Connecting a website to an agent switches that agent to the `ag-ui` protocol, and connecting an agent to another agent switches the target to `a2a` — the protocols those connections are built on. A property you have set yourself is never changed.
|
|
34
|
+
|
|
35
|
+
:::tip[Prefer to build with AI?]
|
|
36
|
+
The plugin ships an MCP server, so your coding agent can scaffold and connect projects for you. See <Link path="get_started/building-with-ai">Building with AI</Link>.
|
|
37
|
+
:::
|
|
@@ -182,7 +182,7 @@ So we'll need to make sure we pass those to `generateFiles`, as well as the dire
|
|
|
182
182
|
|
|
183
183
|
Let's update the generator to do that:
|
|
184
184
|
|
|
185
|
-
```ts title="procedure/generator.ts" {
|
|
185
|
+
```ts title="procedure/generator.ts" {16-30}
|
|
186
186
|
import {
|
|
187
187
|
generateFiles,
|
|
188
188
|
joinPathFragments,
|
|
@@ -230,7 +230,7 @@ Next, we want the generator to hook up the new procedure to the router. This mea
|
|
|
230
230
|
|
|
231
231
|
We use [GritQL](https://docs.grit.io/) to declaratively search and transform source code. The `addDestructuredImport` helper adds named imports, and `applyGritQL` applies a GritQL pattern to add the procedure to the router's object literal.
|
|
232
232
|
|
|
233
|
-
```ts title="procedure/generator.ts" {
|
|
233
|
+
```ts title="procedure/generator.ts" {11, 33-46}
|
|
234
234
|
import {
|
|
235
235
|
generateFiles,
|
|
236
236
|
joinPathFragments,
|
|
@@ -120,7 +120,7 @@ Below is a list of all files which have been generated by the `ts#api` generator
|
|
|
120
120
|
|
|
121
121
|
Let us look at these key files:
|
|
122
122
|
|
|
123
|
-
```ts {
|
|
123
|
+
```ts {7}
|
|
124
124
|
// packages/game-api/src/router.ts
|
|
125
125
|
import { echo } from './procedures/echo.js';
|
|
126
126
|
import { t } from './init.js';
|
|
@@ -135,7 +135,7 @@ export type AppRouter = typeof appRouter;
|
|
|
135
135
|
```
|
|
136
136
|
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.
|
|
137
137
|
|
|
138
|
-
```ts {
|
|
138
|
+
```ts {7-10}
|
|
139
139
|
// packages/game-api/src/procedures/echo.ts
|
|
140
140
|
import { publicProcedure } from '../init.js';
|
|
141
141
|
import {
|
|
@@ -15,7 +15,12 @@ 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
17
|
|
|
18
|
-
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
|
|
18
|
+
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
|
+
The `protocol` option selects what the Gateway fronts:
|
|
21
|
+
|
|
22
|
+
- **`mcp`** (default) — aggregates one or more MCP server targets behind a single MCP endpoint, and evaluates every tool call against a [Cedar policy engine](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/policy.html).
|
|
23
|
+
- **`http`** — proxies requests directly to [AgentCore Runtime targets](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-http-runtime.html) (your agents) via path-based routing (`/<targetName>/invocations`), without aggregation or protocol translation. Use this to front agents with a single governed endpoint — for example so a website can reach agents that are deployed inside a VPC through the Gateway.
|
|
19
24
|
|
|
20
25
|
## Usage
|
|
21
26
|
|
|
@@ -33,10 +38,10 @@ The generator creates a new project at `packages/<name>/`, plus a CDK construct
|
|
|
33
38
|
|
|
34
39
|
<FileTree>
|
|
35
40
|
- packages/\<name>/
|
|
36
|
-
- policies/ Cedar policy source files (omitted when `cedarPolicy: false`)
|
|
41
|
+
- policies/ Cedar policy source files (`mcp` protocol only; omitted when `cedarPolicy: false`)
|
|
37
42
|
- permit-all.cedar Default Cedar policy that permits authenticated callers
|
|
38
43
|
- README.md Reference for writing Cedar policies
|
|
39
|
-
- local-dev.ts Local gateway
|
|
44
|
+
- local-dev.ts Local gateway for local development — aggregates attached MCP servers (`mcp`) or proxies attached agents (`http`)
|
|
40
45
|
- project.json Adds the `serve` and `dev` targets
|
|
41
46
|
</FileTree>
|
|
42
47
|
|
|
@@ -71,9 +76,9 @@ Infrastructure is generated when `infra` is `agentcore` (the default). With `inf
|
|
|
71
76
|
|
|
72
77
|
The generated construct creates the following AWS resources:
|
|
73
78
|
|
|
74
|
-
- An `AgentCore::Gateway`
|
|
75
|
-
- An `AgentCore::PolicyEngine` running in `ENFORCE` mode, attached to the Gateway (omitted when `cedarPolicy: false`)
|
|
76
|
-
- One `AgentCore::Policy` per `.cedar` file in `policies/`
|
|
79
|
+
- An `AgentCore::Gateway` with inbound IAM authentication (default) or Cognito JWT authentication (see <a href="#authentication">Authentication</a>). An `mcp` gateway is configured for the MCP protocol; an `http` gateway has no protocol type, which AgentCore requires for its runtime targets
|
|
80
|
+
- An `AgentCore::PolicyEngine` running in `ENFORCE` mode, attached to the Gateway (`mcp` gateways only; omitted when `cedarPolicy: false`)
|
|
81
|
+
- One `AgentCore::Policy` per `.cedar` file in `policies/` (`mcp` gateways only)
|
|
77
82
|
- An AWS WAFv2 Web ACL associated with the Gateway, with request logging to CloudWatch (enabled by default — see <a href="#aws-waf">AWS WAF</a>)
|
|
78
83
|
|
|
79
84
|
The Gateway URL is automatically registered in the `agentcore.gateways.<ClassName>` namespace of <Link path="guides/runtime-config">Runtime Configuration</Link> so agents can discover it at runtime.
|
|
@@ -146,7 +151,7 @@ export class ApplicationStack extends Stack {
|
|
|
146
151
|
<Fragment slot="terraform">
|
|
147
152
|
The generated module requires `user_pool_id` and `user_pool_client_ids` variables:
|
|
148
153
|
|
|
149
|
-
```hcl {
|
|
154
|
+
```hcl {7-8} title="packages/infra/src/main.tf"
|
|
150
155
|
module "user_identity" {
|
|
151
156
|
source = "../../common/terraform/src/core/user-identity"
|
|
152
157
|
}
|
|
@@ -207,7 +212,7 @@ Add new variables where the policies are rendered, for example to pass an agent'
|
|
|
207
212
|
<Fragment slot="cdk">
|
|
208
213
|
In `packages/common/constructs/src/app/gateways/<name>/<name>.ts`, pass `cedarPolicyVariables` through to the shared construct:
|
|
209
214
|
|
|
210
|
-
```ts {
|
|
215
|
+
```ts {5-6}
|
|
211
216
|
super(scope, id, {
|
|
212
217
|
cedarPolicyPath: path.join(
|
|
213
218
|
...
|
|
@@ -347,11 +352,19 @@ This denies the Python agent role from calling `ts-mcp___divide` while leaving t
|
|
|
347
352
|
|
|
348
353
|
## Local Development
|
|
349
354
|
|
|
350
|
-
The generator adds a `dev` target to the Gateway project, which runs `local-dev.ts
|
|
355
|
+
The generator adds a `dev` target to the Gateway project, which runs `local-dev.ts`. Running it starts the local gateway and every attached target together:
|
|
351
356
|
|
|
352
357
|
<NxCommands commands={["dev <name>"]} />
|
|
353
358
|
|
|
354
|
-
|
|
359
|
+
<OptionFilter when={{ protocol: 'mcp' }} description="MCP aggregator local gateway">
|
|
360
|
+
The local gateway exposes a single MCP endpoint that aggregates every attached MCP server (connected via the <Link path="guides/connection/agentcore-gateway-mcp">`agentcore-gateway#mcp-connection` generator</Link>), with tools prefixed `<target>___<tool>` to match the deployed Gateway.
|
|
361
|
+
</OptionFilter>
|
|
362
|
+
|
|
363
|
+
<OptionFilter when={{ protocol: 'http' }} description="Path-routing proxy local gateway">
|
|
364
|
+
The local gateway proxies `/<targetName>/...` paths to each attached agent's local server (connected via the <Link path="guides/connection/agentcore-gateway-agent">`agentcore-gateway#agent-connection` generator</Link>), matching the deployed Gateway's path-based routing.
|
|
365
|
+
</OptionFilter>
|
|
366
|
+
|
|
367
|
+
See the connection guides for the full local development story.
|
|
355
368
|
|
|
356
369
|
## Deploying your AgentCore Gateway
|
|
357
370
|
|
|
@@ -460,4 +473,18 @@ Use the <Link path="guides/connection">`connection`</Link> generator to integrat
|
|
|
460
473
|
sourceBadge="python"
|
|
461
474
|
target="agentcore"
|
|
462
475
|
/>
|
|
476
|
+
<ConnectionCard
|
|
477
|
+
title="AgentCore Gateway to Agent"
|
|
478
|
+
description="Front an agent with an AgentCore Gateway as a runtime target"
|
|
479
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/agentcore-gateway-agent`}
|
|
480
|
+
source="agentcore"
|
|
481
|
+
target="strands"
|
|
482
|
+
/>
|
|
483
|
+
<ConnectionCard
|
|
484
|
+
title="React Website to AgentCore Gateway"
|
|
485
|
+
description="Connect a React website to agents through an AgentCore Gateway"
|
|
486
|
+
href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-agentcore-gateway`}
|
|
487
|
+
source="react"
|
|
488
|
+
target="agentcore"
|
|
489
|
+
/>
|
|
463
490
|
</CardGrid>
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AgentCore Gateway to Agent
|
|
3
|
+
description: Front an agent with an AgentCore Gateway as a runtime target
|
|
4
|
+
when:
|
|
5
|
+
sourceType: agentcore-gateway
|
|
6
|
+
targetType:
|
|
7
|
+
- ts#agent
|
|
8
|
+
- py#agent
|
|
9
|
+
---
|
|
10
|
+
import { FileTree } from '@astrojs/starlight/components';
|
|
11
|
+
import Link from '@components/link.astro';
|
|
12
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
13
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
14
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
15
|
+
import Infrastructure from '@components/infrastructure.astro';
|
|
16
|
+
|
|
17
|
+
The `connection` generator can register an agent (either <Link path="guides/ts-agent">TypeScript</Link> or <Link path="guides/py-agent">Python</Link>) as an [AgentCore Runtime target](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-target-http-runtime.html) of an <Link path="guides/agentcore-gateway">AgentCore Gateway</Link> generated with `protocol: http`.
|
|
18
|
+
|
|
19
|
+
Once connected, the Gateway proxies requests for the agent under `<gatewayUrl>/<targetName>/invocations`, signing outbound traffic to the runtime with IAM SigV4. This gives your agents a single governed entry point — and since callers only need to reach the Gateway, the agent runtimes themselves can be deployed inside a VPC behind it.
|
|
20
|
+
|
|
21
|
+
## Prerequisites
|
|
22
|
+
|
|
23
|
+
Before using this generator, ensure you have:
|
|
24
|
+
|
|
25
|
+
1. An <Link path="guides/agentcore-gateway">`agentcore-gateway`</Link> project generated with `protocol: http`
|
|
26
|
+
2. An agent component (<Link path="guides/ts-agent">`ts#agent`</Link> or <Link path="guides/py-agent">`py#agent`</Link>) created with `infra: agentcore` and `auth: iam`
|
|
27
|
+
|
|
28
|
+
:::caution[TypeScript HTTP agents]
|
|
29
|
+
A TypeScript `http` agent serves tRPC over WebSocket, and AgentCore Gateway does not support WebSocket or bidirectional streaming — the generator rejects this combination. Generate the agent with the `ag-ui` protocol instead.
|
|
30
|
+
:::
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Run the Generator
|
|
35
|
+
|
|
36
|
+
<RunGenerator generator="connection" />
|
|
37
|
+
|
|
38
|
+
Select the Gateway project as the source and the agent project as the target. If the agent project contains multiple components, specify `targetComponent` to disambiguate.
|
|
39
|
+
|
|
40
|
+
### Options
|
|
41
|
+
|
|
42
|
+
<GeneratorParameters generator="connection" />
|
|
43
|
+
|
|
44
|
+
## Generator Output
|
|
45
|
+
|
|
46
|
+
The generator wires existing projects together rather than emitting new source files. The following files are modified:
|
|
47
|
+
|
|
48
|
+
<FileTree>
|
|
49
|
+
|
|
50
|
+
- packages/\<gateway>
|
|
51
|
+
- project.json the Gateway's `dev` target gains a dependency on the agent's `<agent>-dev`
|
|
52
|
+
- local-dev.ts `ATTACHED_AGENTS` updated so the local gateway proxies to the agent
|
|
53
|
+
|
|
54
|
+
</FileTree>
|
|
55
|
+
|
|
56
|
+
## Adding the agent target to your stack
|
|
57
|
+
|
|
58
|
+
The generator **cannot** automatically wire the agent target into your infrastructure because it doesn't know which stack or module instantiates the Gateway. Add a single call to `gateway.addAgent(agent)` yourself.
|
|
59
|
+
|
|
60
|
+
<Infrastructure>
|
|
61
|
+
<Fragment slot="cdk">
|
|
62
|
+
In the stack where you instantiate the Gateway, register the agent as a target:
|
|
63
|
+
|
|
64
|
+
```ts title="packages/infra/src/stacks/application-stack.ts" {5-8}
|
|
65
|
+
const myAgent = new MyAgent(this, 'MyAgent');
|
|
66
|
+
const myGateway = new MyGateway(this, 'MyGateway');
|
|
67
|
+
|
|
68
|
+
// Register the agent as a runtime target of the Gateway. The target name
|
|
69
|
+
// defaults to the agent's `agentName` (its class name in kebab-case,
|
|
70
|
+
// e.g. `MyAgent` -> `my-agent`), and forms the target's invocation path:
|
|
71
|
+
// <gatewayUrl>/my-agent/invocations
|
|
72
|
+
myGateway.addAgent(myAgent);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
To override the default target name, pass `gatewayTargetName`:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
myGateway.addAgent(myAgent, { gatewayTargetName: 'my-target' });
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The construct grants the Gateway's execution role invoke access to the agent runtime and configures the target with the `GATEWAY_IAM_ROLE` credential provider, so the Gateway signs outbound calls with its own role.
|
|
82
|
+
|
|
83
|
+
:::tip[Deploying agents into a VPC]
|
|
84
|
+
Fronting an agent with a Gateway is what makes a VPC-deployed agent reachable: callers talk to the Gateway's public endpoint, and the Gateway reaches the runtime internally. Pass a VPC network configuration to the agent construct:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { RuntimeNetworkConfiguration } from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
88
|
+
|
|
89
|
+
const myAgent = new MyAgent(this, 'MyAgent', {
|
|
90
|
+
networkConfiguration: RuntimeNetworkConfiguration.usingVpc(this, {
|
|
91
|
+
vpc,
|
|
92
|
+
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Use a **private subnet with egress**, not a private isolated subnet: the runtime needs outbound internet access to reach Bedrock and read its configuration from AWS AppConfig.
|
|
98
|
+
:::
|
|
99
|
+
</Fragment>
|
|
100
|
+
<Fragment slot="terraform">
|
|
101
|
+
In the Terraform file where you instantiate the Gateway, wire the agent target in:
|
|
102
|
+
|
|
103
|
+
```hcl title="packages/infra/src/main.tf" {9-20,24-40}
|
|
104
|
+
module "my_agent" {
|
|
105
|
+
source = "../../common/terraform/src/app/agents/my-agent"
|
|
106
|
+
# ...
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module "my_gateway" {
|
|
110
|
+
source = "../../common/terraform/src/app/gateways/my-gateway"
|
|
111
|
+
|
|
112
|
+
# The Gateway signs outbound calls to the runtime with its own role and
|
|
113
|
+
# validates access at target creation, so it needs invoke access first.
|
|
114
|
+
additional_iam_policy_statements = [
|
|
115
|
+
{
|
|
116
|
+
Effect = "Allow"
|
|
117
|
+
Action = [
|
|
118
|
+
"bedrock-agentcore:InvokeAgentRuntime",
|
|
119
|
+
"bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream",
|
|
120
|
+
# A2A targets additionally serve their agent card via the gateway
|
|
121
|
+
"bedrock-agentcore:GetAgentCard",
|
|
122
|
+
]
|
|
123
|
+
Resource = [
|
|
124
|
+
module.my_agent.agent_core_runtime_arn,
|
|
125
|
+
"${module.my_agent.agent_core_runtime_arn}/*",
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Register the agent as a runtime target of the Gateway. The target name
|
|
132
|
+
# forms the invocation path: <gatewayUrl>/my-agent/invocations
|
|
133
|
+
resource "aws_bedrockagentcore_gateway_target" "my_agent" {
|
|
134
|
+
gateway_identifier = module.my_gateway.gateway_id
|
|
135
|
+
name = "my-agent"
|
|
136
|
+
# AgentCore fills in a description when none is set, which the provider
|
|
137
|
+
# reports as an inconsistent result after apply — so always set one.
|
|
138
|
+
description = "Agent runtime target my-agent"
|
|
139
|
+
|
|
140
|
+
target_configuration {
|
|
141
|
+
http {
|
|
142
|
+
agentcore_runtime {
|
|
143
|
+
arn = module.my_agent.agent_core_runtime_arn
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
credential_provider_configuration {
|
|
149
|
+
gateway_iam_role {}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
:::tip[Deploying agents into a VPC]
|
|
155
|
+
Fronting an agent with a Gateway is what makes a VPC-deployed agent reachable: callers talk to the Gateway's public endpoint, and the Gateway reaches the runtime internally. Set the agent module's VPC variables:
|
|
156
|
+
|
|
157
|
+
```hcl
|
|
158
|
+
module "my_agent" {
|
|
159
|
+
source = "../../common/terraform/src/app/agents/my-agent"
|
|
160
|
+
|
|
161
|
+
enable_vpc = true
|
|
162
|
+
vpc_id = aws_vpc.my_vpc.id
|
|
163
|
+
subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Use private subnets with egress (a route to a NAT gateway), not private isolated subnets: the runtime needs outbound internet access to reach Bedrock and read its configuration from AWS AppConfig.
|
|
168
|
+
:::
|
|
169
|
+
</Fragment>
|
|
170
|
+
</Infrastructure>
|
|
171
|
+
|
|
172
|
+
## Invoking the agent through the Gateway
|
|
173
|
+
|
|
174
|
+
Requests to `<gatewayUrl origin>/<targetName>/invocations` are forwarded to the agent runtime without protocol translation, so callers use the same request shape they'd use against the runtime directly — SSE streams (AG-UI), JSON streaming (Python HTTP) and A2A JSON-RPC all proxy through. Callers authenticate with the Gateway (IAM SigV4 or Cognito JWT depending on the Gateway's `auth`) rather than with the agent.
|
|
175
|
+
|
|
176
|
+
To connect a website to the Gateway's agents, use the <Link path="guides/connection/react-agentcore-gateway">`connection` generator</Link>.
|
|
177
|
+
|
|
178
|
+
## Forwarding caller identity to the runtime
|
|
179
|
+
|
|
180
|
+
By default the Gateway signs outbound calls with its own IAM role (the `GATEWAY_IAM_ROLE` credential provider), so the runtime sees the _Gateway's_ identity, not the caller's. If you want the agent to authorize on the caller — for example to read the user's `sub` or `scope` claims — the Gateway can instead forward the caller's JWT to the runtime unchanged. This requires three changes:
|
|
181
|
+
|
|
182
|
+
1. **The Gateway accepts JWTs.** Generate the Gateway with `auth: cognito` so its inbound authorizer validates a Cognito (or other OIDC) bearer token.
|
|
183
|
+
2. **The runtime accepts the same JWTs.** Generate the agent with `auth: cognito` (same user pool) so the runtime revalidates the forwarded token.
|
|
184
|
+
3. **The target uses the `JWT_PASSTHROUGH` credential provider** instead of `GATEWAY_IAM_ROLE`, and the **runtime allowlists the `Authorization` header** so it reaches your agent code. Without the allowlist, AgentCore validates the token but strips the header before your container.
|
|
185
|
+
|
|
186
|
+
Callers then invoke the Gateway with `Authorization: Bearer <jwt>` (no SigV4), and the agent reads the claims from the `Authorization` header — skipping signature validation, since the runtime's inbound authorizer has already verified the token:
|
|
187
|
+
|
|
188
|
+
```python title="packages/py_project/.../my_agent/main.py"
|
|
189
|
+
import jwt # PyJWT
|
|
190
|
+
|
|
191
|
+
@app.post('/invocations')
|
|
192
|
+
async def invoke(input: InvokeInput, request: Request):
|
|
193
|
+
token = request.headers['authorization'].removeprefix('Bearer ')
|
|
194
|
+
claims = jwt.decode(token, options={'verify_signature': False})
|
|
195
|
+
# authorize on claims['sub'], claims['scope'], ...
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
<Infrastructure>
|
|
199
|
+
<Fragment slot="cdk">
|
|
200
|
+
Pass `requestHeaderConfiguration` to the agent so the runtime receives the header, and create the target yourself (instead of `gateway.addAgent(agent)`) with the `JWT_PASSTHROUGH` credential provider:
|
|
201
|
+
|
|
202
|
+
```ts title="packages/infra/src/stacks/application-stack.ts" {5-7,17-19}
|
|
203
|
+
import { CfnGatewayTarget } from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
204
|
+
import { PolicyStatement } from 'aws-cdk-lib/aws-iam';
|
|
205
|
+
|
|
206
|
+
const myAgent = new MyAgent(this, 'MyAgent', {
|
|
207
|
+
identity,
|
|
208
|
+
// Let the runtime receive the forwarded Authorization header.
|
|
209
|
+
requestHeaderConfiguration: { allowlistedHeaders: ['Authorization'] },
|
|
210
|
+
});
|
|
211
|
+
const myGateway = new MyGateway(this, 'MyGateway', { identity });
|
|
212
|
+
|
|
213
|
+
const target = new CfnGatewayTarget(this, 'Target-my-agent', {
|
|
214
|
+
gatewayIdentifier: myGateway.gateway.gatewayId,
|
|
215
|
+
name: myAgent.agentName,
|
|
216
|
+
targetConfiguration: {
|
|
217
|
+
http: { agentcoreRuntime: { arn: myAgent.agentCoreRuntime.agentRuntimeArn } },
|
|
218
|
+
},
|
|
219
|
+
// Forward the caller's validated JWT to the runtime unchanged.
|
|
220
|
+
credentialProviderConfigurations: [
|
|
221
|
+
{ credentialProviderType: 'JWT_PASSTHROUGH' },
|
|
222
|
+
],
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// The Gateway role still needs invoke access to the runtime.
|
|
226
|
+
myGateway.gateway.role.addToPrincipalPolicy(
|
|
227
|
+
new PolicyStatement({
|
|
228
|
+
actions: ['bedrock-agentcore:InvokeAgentRuntime'],
|
|
229
|
+
resources: [
|
|
230
|
+
myAgent.agentCoreRuntime.agentRuntimeArn,
|
|
231
|
+
`${myAgent.agentCoreRuntime.agentRuntimeArn}/*`,
|
|
232
|
+
],
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
```
|
|
236
|
+
</Fragment>
|
|
237
|
+
<Fragment slot="terraform">
|
|
238
|
+
Add a `request_header_configuration` block to the runtime so it receives the header, and configure the target with the `JWT_PASSTHROUGH` credential provider (instead of `gateway_iam_role {}`):
|
|
239
|
+
|
|
240
|
+
```hcl title="packages/infra/src/main.tf" {5-7,20-22}
|
|
241
|
+
# Let the runtime receive the forwarded Authorization header. Add this block
|
|
242
|
+
# to the runtime resource in the agent module (packages/common/terraform/...).
|
|
243
|
+
resource "aws_bedrockagentcore_agent_runtime" "agent_runtime" {
|
|
244
|
+
# ...
|
|
245
|
+
request_header_configuration {
|
|
246
|
+
request_header_allowlist = ["Authorization"]
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
resource "aws_bedrockagentcore_gateway_target" "my_agent" {
|
|
251
|
+
gateway_identifier = module.my_gateway.gateway_id
|
|
252
|
+
name = "my-agent"
|
|
253
|
+
description = "Agent runtime target my-agent"
|
|
254
|
+
|
|
255
|
+
target_configuration {
|
|
256
|
+
http {
|
|
257
|
+
agentcore_runtime {
|
|
258
|
+
arn = module.my_agent.agent_core_runtime_arn
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
# Forward the caller's validated JWT to the runtime unchanged.
|
|
264
|
+
credential_provider_configuration {
|
|
265
|
+
credential_provider_type = "JWT_PASSTHROUGH"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
</Fragment>
|
|
270
|
+
</Infrastructure>
|
|
271
|
+
|
|
272
|
+
:::note
|
|
273
|
+
`JWT_PASSTHROUGH` suits a single identity provider whose token audience already covers the runtime. If one Gateway fronts agents across multiple tenants or audiences, use OAuth [on-behalf-of token exchange](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-building-adding-targets-authorization.html) instead.
|
|
274
|
+
:::
|
|
275
|
+
|
|
276
|
+
## Local Development
|
|
277
|
+
|
|
278
|
+
Running the Gateway locally with:
|
|
279
|
+
|
|
280
|
+
<NxCommands commands={["dev <gateway-name>"]} />
|
|
281
|
+
|
|
282
|
+
starts a local gateway plus every attached agent on its assigned local port. The local gateway proxies `/<targetName>/...` paths to each agent's local server, matching the deployed Gateway's path-based routing.
|
|
@@ -58,7 +58,7 @@ The generator **cannot** automatically wire the gateway target into your infrast
|
|
|
58
58
|
<Fragment slot="cdk">
|
|
59
59
|
In the stack where you instantiate the Gateways, register the target gateway as a target of the source gateway:
|
|
60
60
|
|
|
61
|
-
```ts title="packages/infra/src/stacks/application-stack.ts" {
|
|
61
|
+
```ts title="packages/infra/src/stacks/application-stack.ts" {4-7}
|
|
62
62
|
const innerGateway = new InnerGateway(this, 'InnerGateway');
|
|
63
63
|
const outerGateway = new OuterGateway(this, 'OuterGateway');
|
|
64
64
|
|
|
@@ -81,7 +81,7 @@ The construct grants the source gateway's execution role `bedrock-agentcore:Invo
|
|
|
81
81
|
<Fragment slot="terraform">
|
|
82
82
|
In the Terraform file where you instantiate the Gateways, wire the gateway target in:
|
|
83
83
|
|
|
84
|
-
```hcl title="packages/infra/src/main.tf" {
|
|
84
|
+
```hcl title="packages/infra/src/main.tf" {4-6,11,13-19,22-40}
|
|
85
85
|
module "inner_gateway" {
|
|
86
86
|
source = "../../common/terraform/src/app/gateways/inner-gateway"
|
|
87
87
|
|
|
@@ -61,7 +61,7 @@ The generator **cannot** automatically wire the MCP server target into your infr
|
|
|
61
61
|
<Fragment slot="cdk">
|
|
62
62
|
In the stack where you instantiate the Gateway, register the MCP server as a target:
|
|
63
63
|
|
|
64
|
-
```ts title="packages/infra/src/stacks/application-stack.ts" {
|
|
64
|
+
```ts title="packages/infra/src/stacks/application-stack.ts" {4-7}
|
|
65
65
|
const myMcpServer = new MyMcpServer(this, 'MyMcpServer');
|
|
66
66
|
const myGateway = new MyGateway(this, 'MyGateway');
|
|
67
67
|
|
|
@@ -84,7 +84,7 @@ The construct configures the target with `iamCredentialProvider.service = 'bedro
|
|
|
84
84
|
<Fragment slot="terraform">
|
|
85
85
|
In the Terraform file where you instantiate the Gateway, wire the MCP server target in:
|
|
86
86
|
|
|
87
|
-
```hcl title="packages/infra/src/main.tf" {7,
|
|
87
|
+
```hcl title="packages/infra/src/main.tf" {7,10-28}
|
|
88
88
|
module "my_mcp_server" {
|
|
89
89
|
source = "../../common/terraform/src/app/mcp-servers/my-mcp-server"
|
|
90
90
|
}
|
|
@@ -92,7 +92,7 @@ def get_agent():
|
|
|
92
92
|
```
|
|
93
93
|
</TabItem>
|
|
94
94
|
<TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
|
|
95
|
-
```python title="packages/my-project/my_module/agent/agent.py" {
|
|
95
|
+
```python title="packages/my-project/my_module/agent/agent.py" {5,8-13,15}
|
|
96
96
|
from langchain.agents import create_agent
|
|
97
97
|
from langchain_aws import ChatBedrockConverse
|
|
98
98
|
from langchain_core.tools import tool
|
|
@@ -91,7 +91,7 @@ def get_agent():
|
|
|
91
91
|
`MyGatewayClientStrands.create()` returns a single context-manageable `MCPClient` whose `list_tools_sync()` yields every tool available through the Gateway.
|
|
92
92
|
</TabItem>
|
|
93
93
|
<TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
|
|
94
|
-
```python title="packages/example/example/my_agent/agent.py" {4,
|
|
94
|
+
```python title="packages/example/example/my_agent/agent.py" {4,7,11}
|
|
95
95
|
from langchain.agents import create_agent
|
|
96
96
|
from langchain_aws import ChatBedrockConverse
|
|
97
97
|
|
|
@@ -134,7 +134,7 @@ gateway.grantInvokeAccess(myAgent);
|
|
|
134
134
|
The Gateway URL is automatically registered in the `agentcore.gateways.<ClassName>` namespace of <Link path="guides/runtime-config">Runtime Configuration</Link> by the generated CDK construct, so the agent can discover it at runtime.
|
|
135
135
|
</Fragment>
|
|
136
136
|
<Fragment slot="terraform">
|
|
137
|
-
```hcl title="packages/infra/src/main.tf" {
|
|
137
|
+
```hcl title="packages/infra/src/main.tf" {8-13}
|
|
138
138
|
module "my_gateway" {
|
|
139
139
|
source = "../../common/terraform/src/app/gateways/my-gateway"
|
|
140
140
|
}
|
|
@@ -70,7 +70,7 @@ The generator transforms your agent's `agent.py` to use the MCP server's tools:
|
|
|
70
70
|
|
|
71
71
|
<Tabs syncKey="agent-framework">
|
|
72
72
|
<TabItem label="Strands" _filter={{ framework: 'strands' }}>
|
|
73
|
-
```python title="packages/my-project/my_module/agent/agent.py" {4,9-13}
|
|
73
|
+
```python title="packages/my-project/my_module/agent/agent.py" {4,8,9-13}
|
|
74
74
|
from contextlib import contextmanager
|
|
75
75
|
from strands import Agent
|
|
76
76
|
|
|
@@ -91,7 +91,7 @@ def get_agent():
|
|
|
91
91
|
The Strands client is a context manager, entered in a `with` block around the agent.
|
|
92
92
|
</TabItem>
|
|
93
93
|
<TabItem label="LangChain" _filter={{ framework: 'langchain' }}>
|
|
94
|
-
```python title="packages/my-project/my_module/agent/agent.py" {4,
|
|
94
|
+
```python title="packages/my-project/my_module/agent/agent.py" {4,7,11}
|
|
95
95
|
from langchain.agents import create_agent
|
|
96
96
|
from langchain_aws import ChatBedrockConverse
|
|
97
97
|
|
|
@@ -131,7 +131,7 @@ The MCP server's AgentCore runtime ARN is automatically registered in the `agent
|
|
|
131
131
|
<Fragment slot="terraform">
|
|
132
132
|
After running the connection generator, you need to grant the agent permission to invoke the MCP server in your Terraform configuration:
|
|
133
133
|
|
|
134
|
-
```hcl title="packages/infra/src/main.tf" {
|
|
134
|
+
```hcl title="packages/infra/src/main.tf" {9-25}
|
|
135
135
|
module "inventory_mcp_server" {
|
|
136
136
|
source = "../../common/terraform/src/app/mcp-servers/inventory-mcp"
|
|
137
137
|
}
|