AgentCore Gateway to AgentCore Gateway
The connection generator can register an AgentCore Gateway as a target of another AgentCore Gateway. This lets you compose gateways hierarchically — for example a team-level gateway aggregating several domain gateways, each of which fronts its own MCP servers.
Once connected, the source Gateway aggregates the target Gateway’s tools into its single MCP endpoint. Since the target Gateway already prefixes its tools with its own target names, tools surface through the source Gateway as <gateway-target-name>___<target-name>___<tool-name> — each gateway in the chain adds one prefix. Both gateways evaluate their own Cedar policies: the source Gateway authorizes the caller for the prefixed action, then the target Gateway authorizes the source Gateway’s execution role for the inner action.
Prerequisites
Section titled “Prerequisites”Before using this generator, ensure you have:
- Two
agentcore-gatewayprojects
Both gateways must have protocol: mcp, and the target gateway must have auth: iam — the source gateway invokes the target signing with its own execution role, so only the target’s inbound auth needs to be IAM. The generator validates this, and also rejects connections that would create a cycle between gateways, which would otherwise recurse infinitely on tools/list.
Run the Generator
Section titled “Run the Generator”- Install the Nx Console VSCode Plugin if you haven't already
- Open the Nx Console in VSCode
- Click
Generate (UI)in the "Common Nx Commands" section - Search for
@aws/nx-plugin - connection - Fill in the required parameters
- Click
Generate
pnpm nx g @aws/nx-plugin:connectionyarn nx g @aws/nx-plugin:connectionnpx nx g @aws/nx-plugin:connectionbunx nx g @aws/nx-plugin:connectionYou can also perform a dry-run to see what files would be changed
pnpm nx g @aws/nx-plugin:connection --dry-runyarn nx g @aws/nx-plugin:connection --dry-runnpx nx g @aws/nx-plugin:connection --dry-runbunx nx g @aws/nx-plugin:connection --dry-runSelect the aggregating Gateway project as the source and the Gateway to be aggregated as the target.
Options
Section titled “Options”| Parameter | Type | Default | Description |
|---|---|---|---|
| sourceProject Required | string | - | The source project |
| targetProject Required | string | - | The target project to connect to |
| sourceComponent | string | - | The source component to connect from (component name, path relative to source project root, or generator id). Use '.' to explicitly select the project as the source. |
| targetComponent | string | - | The target component to connect to (component name, path relative to target project root, or generator id). Use '.' to explicitly select the project as the target. |
| preferInstallDependencies | boolean | true | Whether to prefer installing dependencies after the generator runs. Set to false to defer installing when batching multiple generators (an install still runs if needed so subsequent generators can compute the Nx project graph); install once at the end. |
Generator Output
Section titled “Generator Output”The generator wires existing projects together rather than emitting new source files. The following files are modified:
Directorypackages/<source-gateway>
- project.json the source Gateway’s
devtarget gains a dependency on the target gateway’sdevtarget - local-dev.ts
ATTACHED_MCP_SERVERSupdated so the local gateway aggregates the target gateway
- project.json the source Gateway’s
The source Gateway project’s dev target gains a dependency on the target Gateway’s dev target, so running the source Gateway locally also starts the target gateway (and, transitively, every MCP server attached to it). The target gateway is also registered in the source Gateway project’s local-dev.ts so the local gateway aggregates its tools.
Adding the gateway target to your stack
Section titled “Adding the gateway target to your stack”The generator cannot automatically wire the gateway target into your infrastructure because it doesn’t know which stack or module instantiates the Gateways. Add a single call to gateway.addGateway(targetGateway) yourself.
In the stack where you instantiate the Gateways, register the target gateway as a target of the source gateway:
const innerGateway = new InnerGateway(this, 'InnerGateway');const outerGateway = new OuterGateway(this, 'OuterGateway');
// Register the inner gateway as a target of the outer gateway. The target// name defaults to the inner gateway's `gatewayName` (its class name in// kebab-case, e.g. `InnerGateway` -> `inner-gateway`).outerGateway.addGateway(innerGateway);The Gateway target name (the target gateway’s gatewayName by default) prefixes Cedar action names on the source gateway — the action format is AgentCore::Action::"<gatewayTargetName>___<targetName>___<toolName>". See the Writing Policies section. Keep the target name short and stable; changing it later invalidates any Cedar policies that reference the old name.
To override the default target name, pass gatewayTargetName:
outerGateway.addGateway(innerGateway, { gatewayTargetName: 'inner' });The construct grants the source gateway’s execution role bedrock-agentcore:InvokeGateway access to the target gateway, and configures the target with iamCredentialProvider.service = 'bedrock-agentcore' so the source gateway signs outbound calls using its own execution role. The target is created after the target gateway and all of its own targets, since AgentCore fetches the target’s tools during creation.
In the Terraform file where you instantiate the Gateways, wire the gateway target in:
module "inner_gateway" { source = "../../common/terraform/src/app/gateways/inner-gateway"
# Target ids of the inner gateway's own targets (e.g. its MCP servers), so # its gateway_url is not consumed until it serves their tools. tool_dependencies = [aws_bedrockagentcore_gateway_target.my_mcp_server.target_id]}
module "outer_gateway" { source = "../../common/terraform/src/app/gateways/outer-gateway" policy_dependencies = [aws_bedrockagentcore_gateway_target.inner_gateway.target_id]
additional_iam_policy_statements = [ { Effect = "Allow" Action = ["bedrock-agentcore:InvokeGateway"] Resource = [module.inner_gateway.gateway_arn] } ]}
# Register the inner gateway as a target of the outer gatewayresource "aws_bedrockagentcore_gateway_target" "inner_gateway" { gateway_identifier = module.outer_gateway.gateway_id name = "inner-gateway"
target_configuration { mcp { mcp_server { endpoint = module.inner_gateway.gateway_url } } }
credential_provider_configuration { gateway_iam_role { service = "bedrock-agentcore" } }}The target name (inner-gateway above) prefixes Cedar action names on the outer gateway — see the Writing Policies section. The additional_iam_policy_statements entry grants the outer gateway’s execution role invoke access to the inner gateway, which is required both to fetch the inner gateway’s tools at target creation time and to route calls at runtime. policy_dependencies ensures Cedar policies referencing this target’s actions are created after the target has registered them.
Cedar policies across chained gateways
Section titled “Cedar policies across chained gateways”Each gateway in the chain evaluates its own policy set:
- The source gateway evaluates the original caller (e.g. an agent’s execution role) against the prefixed action, e.g.
AgentCore::Action::"inner-gateway___my-mcp___add". - The target gateway evaluates the source gateway’s execution role against the inner action, e.g.
AgentCore::Action::"my-mcp___add".
This means a tool call through a gateway chain must be permitted at every hop. The default permit-all.cedar permits any caller in the same AWS account, which includes the source gateway’s role; if you write narrower policies on the target gateway, remember that the principal it sees is the source gateway’s role, not the original caller.
Local Development
Section titled “Local Development”Running the source Gateway locally with:
pnpm nx dev <source-gateway-name>yarn nx dev <source-gateway-name>npx nx dev <source-gateway-name>bunx nx dev <source-gateway-name>starts the local source gateway, the local target gateway, and every MCP server attached to either, each on its assigned local port. Tool names are prefixed at each hop exactly as deployed (<gateway-target-name>___<target-name>___<tool-name>), so agent prompts and Cedar action names remain consistent across local and deployed runs.