Repository navigation
fix(export): export agentcore_gateway tools from harnesses - #2768
Conversation
Harness export dropped every agentcore_gateway tool with a manual follow-up note, while 0.31.x generated an MCP client for it. Each gateway tool now becomes an MCP client in mcp_client/client.py that reads GATEWAY_<TOOL>_URL, signs requests with SigV4 for awsIam, sends a bearer token for OAuth client credentials, and honors @tool/* allowedTools selectors. The exported runtime gets a gateway connection per tool, so deploy grants access and sets the URL, and agentcore/.env.local carries the URL for agentcore dev. Closes #2766
Package TarballHow to installgh release download pr-2768-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-1.0.1.tgz |
|
Claude Security Review: no high-confidence findings. (run) |
There was a problem hiding this comment.
AgentCore Harness Review
Verdict: Changes requested
I verified the deploy-side contract against the pinned @aws/agentcore-cdk@1.0.0 tarball and it lines up:
bindConnection → importedDiscoveryPrefix('GATEWAY', connectionTokenFor(connection)) produces exactly
GATEWAY_<TOKEN>_URL with the same connectionEnvToken derivation, gatewayUrlFromArn builds the same
https://<id>.gateway.bedrock-agentcore.<region>.<urlSuffix>/mcp, and ImportedGateway maps
unset/awsIam → AWS_IAM + InvokeGateway, none → NONE, oauth → CUSTOM_JWT + the OAuth token grants —
which is what each rendered client branch needs. mcp_proxy_for_aws.client.aws_iam_streamablehttp_client(endpoint, aws_service, aws_region) exists at the 1.1.0 floor, and its Python lower bound (3.10) matches the exported project's
requires-python, so uv resolution is fine. requires_access_token's sync wrapper handles being called from a
running loop, so fetching the bearer token inside transport() works. Two things to fix.
1. The gateway path can now abort an otherwise-exportable harness (src/core/project/templates/export.ts)
Before this PR, nothing about a gateway tool could fail an export — it degraded to an EXPORT_NOTES.md entry. Now
three paths throw InputValidationError and kill the whole command:
- L694-699:
CONNECTION_ID_PATTERNrejects any tool name that doesn't start with a letter.HarnessToolNameSchemais
^[a-zA-Z0-9_-]+$, so3p-toolsor_toolsis a perfectly valid harness tool name. - L762-772: two tool names that tokenize to the same env token (
my-tools+my_tools), or a tool name that collides
with an existing harness connection id. - L786-793 (
gatewayUrl): agatewayArnthat isn't an ARN. The harness schema only requiresz.string().min(1).
The message tells the user to "Rename the tool in the harness, then export again", but on the --arn path the spec
comes from the service (serviceHarness.ts L75: name: tool.name ?? tool.type), so there is nothing local to rename —
a single oddly-named gateway tool makes agentcore export harness --arn ... unusable with no workaround. Options:
- Degrade to
GATEWAY_TOOL_NOTE_CATEGORYand skip that one tool, exactly as theUSER_FEDERATIONbranch already does
(L686-699) — the rest of the harness still exports. - Derive a schema-valid connection id instead of requiring the tool name to be one (e.g. prefix/sanitize, and
disambiguate on collision), keepingnameonly for the Python docstrings/log text. - Keep the throw only for the in-project
--namepath, where the user can actually editharness.yaml.
Related, non-blocking: the collision check (L762-764) skips spec.connections entries without an id, but the CDK
still tokenizes those via connectionTokenFor → connectionIdForTarget, so an id-less connection can still shadow a
gateway tool's variable silently.
2. pyproject.toml loses its indentation for every export
src/assets/templates/export-harness-python/pyproject.toml L16-17:
{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0, < 2.0.0",
{{/if}} {{#if bedrockMantle}}"aws-bedrock-token-generator >= 1.1.0, < 2.0.0",
Neither {{#if}} nor {{/if}} is standalone on its line, so the four spaces after {{/if}} are emitted literally and
concatenate with the four before the next block. Every exported pyproject.toml — gateway tools or not — now renders
"strands-agents ... " with eight spaces. Dropping the stray four spaces after {{/if}} restores the existing
pattern. pythonSecurity.test.ts only parses the TOML, so nothing catches this.
Minor
connectionEnvToken and CONNECTION_ID_PATTERN (L778-783) are a third copy of a contract that
src/projectSchemas/v0/schemas/connections.ts explicitly marks as the single source of truth ("do not re-implement the
token derivation") and whose regex also lives in ConnectionSchema in src/projectSchemas/connections.ts. Exporting
the helper (and reusing the schema's regex) from the v1 connections.ts would keep the CLI↔CDK handshake in one place.
|
Thanks for picking this up so quickly. While waiting, we wired a SigV4 gateway client into a 1.0.1 export by hand, and the approach here matches what worked for us. A few things I noticed reading the diff:
Also, the |
- A gateway tool whose name is not a valid connection id, whose gatewayArn is not a gateway ARN, or whose env var prefix collides with another connection is now skipped with an EXPORT_NOTES entry instead of failing the whole export. Collisions include id-less harness connections. - Connection validation reuses ConnectionSchema, and the env var token comes from connectionTokenFor in projectSchemas/connections.ts. - SigV4 signing is a botocore httpx.Auth in the template, so exports no longer pull in mcp-proxy-for-aws and its fastmcp dependency tree. This also removes the pyproject.toml line that broke indentation. - OAuth gateways cache the bearer token per client and fetch a new one when the gateway answers 401.
|
Thanks for the review. Addressed in 38870b0. 1. Gateway tools no longer abort the export. An invalid connection id (such as 2. pyproject.toml indentation. The Minor. The connection is validated with |
|
@nyousef7 thanks, all three were worth changing. Fixed in 38870b0.
The |
|
Claude Security Review: no high-confidence findings. (run) |
What
agentcore export harnessnow exportsagentcore_gatewaytools instead of replacing them with an EXPORT_NOTES entry. Each gateway tool becomes an MCP client inmcp_client/client.pyand is added to the agent's tools inmain.py. This applies to both--nameand--arnexports.GATEWAY_<TOOL>_URL, named after the tool rather than the gateway id.awsIam(also the default whenoutboundAuthis unset) signs requests with SigV4 forbedrock-agentcorethrough a botocorehttpx.Auth, so no new Python dependency is added.noneconnects without auth. OAuth withCLIENT_CREDENTIALSsends a bearer token from@requires_access_token, cached per client and fetched again when the gateway answers 401.allowedToolsselectors such as@tools/*filter the gateway's tools the same way they filter remote MCP tools.connectionper tool, withidset to the tool name. Deploy then grants access and sets the URL through the existing@aws/agentcore-cdk1.0.0 connection binding. The URL is also written toagentcore/.env.localforagentcore dev.USER_FEDERATION, a name that is not a valid connection id, a gatewayArn that is not a gateway ARN, and an env var prefix that collides with another connection.Why
Fixes #2766. 0.31.x exported gateway tools, and 1.x dropped them.
How tested
bun test, typecheck, lint, and format all pass.awsIamandnone).agentcore devloaded both gateways' tools and made a SigV4 tool call. The deployed runtime hadGATEWAY_TOOLS_URLset by deploy, and invoking it made a successful SigV4 gateway tool call. The stacks were torn down afterwards.<target>___<tool>with no harness tool-name prefix, and the exported agent uses the same names.