@aws/agentcore 1.0.0-preview.13 → 1.0.0-preview.15

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 (91) hide show
  1. package/README.md +31 -17
  2. package/dist/agent-inspector/index.css +1 -1
  3. package/dist/agent-inspector/index.js +90 -85
  4. package/dist/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +966 -106
  5. package/dist/assets/agents/AGENTS.md +14 -0
  6. package/dist/assets/cdk/bin/cdk.ts +42 -20
  7. package/dist/assets/cdk/lib/cdk-stack.ts +19 -14
  8. package/dist/assets/cdk/test/cdk.test.ts +2 -1
  9. package/dist/assets/container/python/Dockerfile +4 -0
  10. package/dist/assets/python/a2a/strands/capabilities/memory/session.py +4 -1
  11. package/dist/assets/python/agui/strands/capabilities/memory/session.py +4 -1
  12. package/dist/assets/python/http/googleadk/base/mcp_client/client.py +7 -7
  13. package/dist/assets/python/http/googleadk/base/pyproject.toml +1 -1
  14. package/dist/assets/python/http/langchain_langgraph/base/mcp_client/client.py +10 -8
  15. package/dist/assets/python/http/langchain_langgraph/base/pyproject.toml +1 -1
  16. package/dist/assets/python/http/openaiagents/base/main.py +19 -9
  17. package/dist/assets/python/http/openaiagents/base/mcp_client/client.py +4 -4
  18. package/dist/assets/python/http/openaiagents/base/pyproject.toml +1 -1
  19. package/dist/assets/python/http/strands/base/main.py +438 -27
  20. package/dist/assets/python/http/strands/base/mcp_client/client.py +45 -5
  21. package/dist/assets/python/http/strands/base/model/load.py +3 -3
  22. package/dist/assets/python/http/strands/base/pyproject.toml +5 -2
  23. package/dist/assets/python/http/strands/base/skills/fetcher.py +279 -0
  24. package/dist/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
  25. package/dist/assets/python/http/strands/capabilities/memory/session.py +4 -1
  26. package/dist/cli/index.mjs +1274 -1088
  27. package/dist/lib/errors/types.d.ts +18 -0
  28. package/dist/lib/errors/types.d.ts.map +1 -1
  29. package/dist/lib/errors/types.js +28 -1
  30. package/dist/lib/errors/types.js.map +1 -1
  31. package/dist/lib/schemas/io/config-io.d.ts.map +1 -1
  32. package/dist/lib/schemas/io/config-io.js +0 -2
  33. package/dist/lib/schemas/io/config-io.js.map +1 -1
  34. package/dist/schema/constants.d.ts +20 -0
  35. package/dist/schema/constants.d.ts.map +1 -1
  36. package/dist/schema/constants.js +25 -1
  37. package/dist/schema/constants.js.map +1 -1
  38. package/dist/schema/schemas/agent-env.d.ts +35 -0
  39. package/dist/schema/schemas/agent-env.d.ts.map +1 -1
  40. package/dist/schema/schemas/agentcore-project.d.ts +184 -25
  41. package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
  42. package/dist/schema/schemas/agentcore-project.js +81 -31
  43. package/dist/schema/schemas/agentcore-project.js.map +1 -1
  44. package/dist/schema/schemas/auth.d.ts +175 -0
  45. package/dist/schema/schemas/auth.d.ts.map +1 -1
  46. package/dist/schema/schemas/auth.js +126 -3
  47. package/dist/schema/schemas/auth.js.map +1 -1
  48. package/dist/schema/schemas/deployed-state.d.ts +140 -46
  49. package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
  50. package/dist/schema/schemas/deployed-state.js +39 -14
  51. package/dist/schema/schemas/deployed-state.js.map +1 -1
  52. package/dist/schema/schemas/mcp-defs.d.ts +2 -1
  53. package/dist/schema/schemas/mcp-defs.d.ts.map +1 -1
  54. package/dist/schema/schemas/mcp-defs.js +3 -2
  55. package/dist/schema/schemas/mcp-defs.js.map +1 -1
  56. package/dist/schema/schemas/mcp.d.ts +186 -0
  57. package/dist/schema/schemas/mcp.d.ts.map +1 -1
  58. package/dist/schema/schemas/mcp.js +479 -4
  59. package/dist/schema/schemas/mcp.js.map +1 -1
  60. package/dist/schema/schemas/primitives/ab-test.d.ts +0 -6
  61. package/dist/schema/schemas/primitives/ab-test.d.ts.map +1 -1
  62. package/dist/schema/schemas/primitives/ab-test.js +0 -2
  63. package/dist/schema/schemas/primitives/ab-test.js.map +1 -1
  64. package/dist/schema/schemas/primitives/harness.d.ts +209 -11
  65. package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
  66. package/dist/schema/schemas/primitives/harness.js +268 -21
  67. package/dist/schema/schemas/primitives/harness.js.map +1 -1
  68. package/dist/schema/schemas/primitives/index.d.ts +6 -8
  69. package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
  70. package/dist/schema/schemas/primitives/index.js +6 -5
  71. package/dist/schema/schemas/primitives/index.js.map +1 -1
  72. package/dist/schema/schemas/primitives/knowledge-base.d.ts +104 -0
  73. package/dist/schema/schemas/primitives/knowledge-base.d.ts.map +1 -0
  74. package/dist/schema/schemas/primitives/knowledge-base.js +99 -0
  75. package/dist/schema/schemas/primitives/knowledge-base.js.map +1 -0
  76. package/dist/schema/schemas/primitives/online-eval-config.d.ts +20 -2
  77. package/dist/schema/schemas/primitives/online-eval-config.d.ts.map +1 -1
  78. package/dist/schema/schemas/primitives/online-eval-config.js +43 -5
  79. package/dist/schema/schemas/primitives/online-eval-config.js.map +1 -1
  80. package/dist/schema/schemas/primitives/policy.d.ts +26 -0
  81. package/dist/schema/schemas/primitives/policy.d.ts.map +1 -1
  82. package/dist/schema/schemas/primitives/policy.js +5 -1
  83. package/dist/schema/schemas/primitives/policy.js.map +1 -1
  84. package/npm-shrinkwrap.json +195 -330
  85. package/package.json +10 -8
  86. package/scripts/bundle.mjs +51 -0
  87. package/scripts/run-e2e-local.sh +40 -8
  88. package/dist/schema/schemas/primitives/http-gateway.d.ts +0 -21
  89. package/dist/schema/schemas/primitives/http-gateway.d.ts.map +0 -1
  90. package/dist/schema/schemas/primitives/http-gateway.js +0 -34
  91. package/dist/schema/schemas/primitives/http-gateway.js.map +0 -1
@@ -122,6 +122,19 @@ When modifying JSON config files:
122
122
  4. Use CloudFormation-safe names (alphanumeric, start with letter)
123
123
  5. Run `agentcore validate` to verify changes
124
124
 
125
+ ## Harness Export
126
+
127
+ `agentcore export harness` converts a harness configuration into a deployable Strands Python agent under `app/<agentName>/`.
128
+
129
+ **After every export, you MUST read `app/<agentName>/EXPORT_NOTES.md` before proceeding.**
130
+
131
+ This file lists any manual follow-up items required before the agent will deploy or run correctly — missing files to create, IAM policies to add, or configuration steps the exporter could not automate. A clean export produces "No manual steps required." Complete every item in the file before running `agentcore deploy`.
132
+
133
+ ```bash
134
+ agentcore export harness --name <harnessName> # generates app/<agentName>/EXPORT_NOTES.md
135
+ cat app/<agentName>/EXPORT_NOTES.md # read this before touching anything else
136
+ ```
137
+
125
138
  ## CLI Commands
126
139
 
127
140
  | Command | Description |
@@ -129,6 +142,7 @@ When modifying JSON config files:
129
142
  | `agentcore create` | Create a new project |
130
143
  | `agentcore add <resource>` | Add agent, memory, credential, gateway, evaluator, policy |
131
144
  | `agentcore remove <resource>` | Remove a resource |
145
+ | `agentcore export harness` | Export a harness to a Strands runtime agent |
132
146
  | `agentcore dev` | Run agent locally with hot-reload |
133
147
  | `agentcore deploy` | Deploy to AWS |
134
148
  | `agentcore status` | Show deployment status |
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { AgentCoreStack } from '../lib/cdk-stack';
3
- import { ConfigIO, type AwsDeploymentTarget } from '@aws/agentcore-cdk';
2
+ import { AgentCoreStack, type HarnessConfig } from '../lib/cdk-stack';
3
+ import { ConfigIO, HarnessSpecSchema, type AwsDeploymentTarget } from '@aws/agentcore-cdk';
4
4
  import { App, type Environment } from 'aws-cdk-lib';
5
5
  import * as path from 'path';
6
6
  import * as fs from 'fs';
@@ -56,40 +56,61 @@ async function main() {
56
56
  throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
57
57
  }
58
58
 
59
- // Read harness configs for role creation.
59
+ // Read harness configs: the full validated spec drives the CFN resource; the
60
+ // role-scoped fields drive the IAM role + container build.
60
61
  const projectRoot = path.resolve(configRoot, '..');
61
- const harnessConfigs: {
62
- name: string;
63
- executionRoleArn?: string;
64
- memoryName?: string;
65
- containerUri?: string;
66
- hasDockerfile?: boolean;
67
- dockerfile?: string;
68
- codeLocation?: string;
69
- tools?: { type: string; name: string }[];
70
- apiKeyArn?: string;
71
- efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
72
- s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
73
- apiFormat?: 'converse_stream' | 'responses' | 'chat_completions';
74
- }[] = [];
75
- for (const entry of specAny.harnesses ?? []) {
62
+
63
+ // Read non-S3 KB connector-config files and pass their parsed contents to the
64
+ // L3 verbatim. The L3 does not read files; it expects the parsed
65
+ // connectorParameters keyed by the data source's connectorConfigFile path.
66
+ const connectorParametersByFile: Record<string, Record<string, unknown>> = {};
67
+ for (const kb of specAny.knowledgeBases ?? []) {
68
+ for (const ds of kb.dataSources ?? []) {
69
+ if (ds.type !== 'S3' && ds.connectorConfigFile) {
70
+ const abs = path.resolve(projectRoot, ds.connectorConfigFile);
71
+ try {
72
+ connectorParametersByFile[ds.connectorConfigFile] = JSON.parse(fs.readFileSync(abs, 'utf-8'));
73
+ } catch (err) {
74
+ throw new Error(
75
+ `Could not read connector config '${ds.connectorConfigFile}' for knowledge base '${kb.name}' at ${abs}: ${err instanceof Error ? err.message : err}`
76
+ );
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ // Harness is preview-gated. The CLI bundle bakes the preview flag at build time and
83
+ // forwards it to this child process via AGENTCORE_PREVIEW (see toolkit-lib/wrapper.ts).
84
+ // This app is built separately and cannot see that build-time define, so it gates on the
85
+ // env var. Absent/anything-but-'1' defaults to off so a stale harnesses[] entry in a
86
+ // non-preview build never synthesizes an AWS::BedrockAgentCore::Harness resource.
87
+ const previewEnabled = process.env.AGENTCORE_PREVIEW === '1';
88
+
89
+ const harnessConfigs: HarnessConfig[] = [];
90
+ for (const entry of previewEnabled ? (specAny.harnesses ?? []) : []) {
76
91
  const harnessDir = path.resolve(projectRoot, entry.path);
77
92
  const harnessPath = path.resolve(harnessDir, 'harness.json');
78
93
  try {
79
- const harnessSpec = JSON.parse(fs.readFileSync(harnessPath, 'utf-8'));
94
+ const harnessSpec = HarnessSpecSchema.parse(JSON.parse(fs.readFileSync(harnessPath, 'utf-8')));
80
95
  harnessConfigs.push({
81
96
  name: entry.name,
82
97
  executionRoleArn: harnessSpec.executionRoleArn,
83
- memoryName: harnessSpec.memory?.name,
98
+ // Only an `existing` memory ref carries a name to wire IAM against; managed memory is
99
+ // owned by the harness (no sibling) and disabled has none — both resolve to undefined.
100
+ memoryName: harnessSpec.memory?.mode === 'existing' ? harnessSpec.memory.name : undefined,
84
101
  containerUri: harnessSpec.containerUri,
85
102
  hasDockerfile: !!harnessSpec.dockerfile,
86
103
  dockerfile: harnessSpec.dockerfile,
87
104
  codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
88
105
  tools: harnessSpec.tools,
106
+ skills: harnessSpec.skills,
89
107
  apiKeyArn: harnessSpec.model?.apiKeyArn,
90
108
  efsAccessPoints: harnessSpec.efsAccessPoints,
91
109
  s3AccessPoints: harnessSpec.s3AccessPoints,
92
110
  apiFormat: harnessSpec.model?.apiFormat,
111
+ // Full spec + dir drive the AWS::BedrockAgentCore::Harness CFN resource.
112
+ spec: harnessSpec,
113
+ harnessDir,
93
114
  });
94
115
  } catch (err) {
95
116
  throw new Error(
@@ -156,6 +177,7 @@ async function main() {
156
177
  spec,
157
178
  mcpSpec,
158
179
  credentials,
180
+ connectorParametersByFile,
159
181
  harnesses: harnessConfigs.length > 0 ? harnessConfigs : undefined,
160
182
  paymentSpec,
161
183
  env,
@@ -6,24 +6,18 @@ import {
6
6
  type AgentCoreProjectSpec,
7
7
  type AgentCoreMcpSpec,
8
8
  type CustomJWTAuthorizerConfig,
9
+ type HarnessDeploymentConfig,
9
10
  } from '@aws/agentcore-cdk';
10
11
  import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
11
12
  import * as iam from 'aws-cdk-lib/aws-iam';
12
13
  import { Construct } from 'constructs';
13
14
 
14
- export interface HarnessConfig {
15
- name: string;
16
- executionRoleArn?: string;
17
- memoryName?: string;
18
- containerUri?: string;
19
- hasDockerfile?: boolean;
20
- dockerfile?: string;
21
- codeLocation?: string;
22
- tools?: { type: string; name: string }[];
23
- apiKeyArn?: string;
24
- efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
25
- s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
26
- }
15
+ /**
16
+ * Harness deployment config: role-scoped fields (for IAM role + container build)
17
+ * plus the full validated spec + its config directory so the L3 construct can
18
+ * synthesize the AWS::BedrockAgentCore::Harness resource.
19
+ */
20
+ export type HarnessConfig = HarnessDeploymentConfig;
27
21
 
28
22
  export interface PaymentConnectorSpec {
29
23
  name: string;
@@ -59,6 +53,11 @@ export interface AgentCoreStackProps extends StackProps {
59
53
  * Harness role configurations.
60
54
  */
61
55
  harnesses?: HarnessConfig[];
56
+ /**
57
+ * Parsed connectorParameters for non-S3 KB data sources, keyed by
58
+ * connectorConfigFile path. Forwarded to AgentCoreApplication.
59
+ */
60
+ connectorParametersByFile?: Record<string, Record<string, unknown>>;
62
61
  /**
63
62
  * Payment specifications with resolved credential provider ARNs.
64
63
  */
@@ -98,7 +97,7 @@ export class AgentCoreStack extends Stack {
98
97
  constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
99
98
  super(scope, id, props);
100
99
 
101
- const { spec, mcpSpec, credentials, harnesses, paymentSpec } = props;
100
+ const { spec, mcpSpec, credentials, harnesses, connectorParametersByFile, paymentSpec } = props;
102
101
 
103
102
  // Create AgentCoreApplication with all agents and harness roles
104
103
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -106,6 +105,12 @@ export class AgentCoreStack extends Stack {
106
105
  if (harnesses?.length) {
107
106
  appProps.harnesses = harnesses;
108
107
  }
108
+ if (connectorParametersByFile && Object.keys(connectorParametersByFile).length > 0) {
109
+ appProps.connectorParametersByFile = connectorParametersByFile;
110
+ }
111
+ if (credentials) {
112
+ appProps.credentials = credentials;
113
+ }
109
114
  this.application = new AgentCoreApplication(this, 'Application', appProps as any);
110
115
 
111
116
  // Create AgentCoreMcp if there are gateways configured
@@ -14,13 +14,14 @@ test('AgentCoreStack synthesizes with empty spec', () => {
14
14
  credentials: [],
15
15
  evaluators: [],
16
16
  onlineEvalConfigs: [],
17
+ configBundles: [],
17
18
  policyEngines: [],
18
19
  payments: [],
19
- configBundles: [],
20
20
  agentCoreGateways: [],
21
21
  mcpRuntimeTools: [],
22
22
  unassignedTargets: [],
23
23
  datasets: [],
24
+ knowledgeBases: [],
24
25
  },
25
26
  });
26
27
  const template = Template.fromStack(stack);
@@ -1,5 +1,9 @@
1
1
  FROM public.ecr.aws/docker/library/python:3.12-slim-trixie
2
2
 
3
+ {{#if gitSkills}}
4
+ RUN apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/*
5
+
6
+ {{/if}}
3
7
  RUN pip install --no-cache-dir uv
4
8
 
5
9
  ARG UV_DEFAULT_INDEX
@@ -24,8 +24,11 @@ def get_memory_session_manager(session_id: Optional[str], actor_id: str) -> Opti
24
24
  {{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}}
25
25
  f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5),
26
26
  {{/if}}
27
+ {{#if (includes memoryProviders.[0].strategies "EPISODIC")}}
28
+ f"/episodes/{actor_id}/{session_id}": RetrievalConfig(top_k=5, relevance_score=0.5),
29
+ {{/if}}
27
30
  {{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}}
28
- f"/summaries/{actor_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
31
+ f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
29
32
  {{/if}}
30
33
  }
31
34
  {{/if}}
@@ -24,8 +24,11 @@ def get_memory_session_manager(session_id: Optional[str], actor_id: str) -> Opti
24
24
  {{#if (includes memoryProviders.[0].strategies "USER_PREFERENCE")}}
25
25
  f"/users/{actor_id}/preferences": RetrievalConfig(top_k=3, relevance_score=0.5),
26
26
  {{/if}}
27
+ {{#if (includes memoryProviders.[0].strategies "EPISODIC")}}
28
+ f"/episodes/{actor_id}/{session_id}": RetrievalConfig(top_k=5, relevance_score=0.5),
29
+ {{/if}}
27
30
  {{#if (includes memoryProviders.[0].strategies "SUMMARIZATION")}}
28
- f"/summaries/{actor_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
31
+ f"/summaries/{actor_id}/{session_id}": RetrievalConfig(top_k=3, relevance_score=0.5),
29
32
  {{/if}}
30
33
  }
31
34
  {{/if}}
@@ -34,20 +34,20 @@ def get_all_gateway_mcp_toolsets() -> list[MCPToolset]:
34
34
  {{#each gatewayProviders}}
35
35
  url = os.environ.get("{{envVarName}}")
36
36
  if url:
37
- {{#if (eq authType "AWS_IAM")}}
37
+ {{#if (eq authType "AWS_IAM")}}
38
38
  session = create_aws_session()
39
39
  auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
40
- toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(
40
+ toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(
41
41
  url=url,
42
42
  httpx_client_factory=lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)
43
43
  )))
44
- {{else if (eq authType "CUSTOM_JWT")}}
44
+ {{else if (eq authType "CUSTOM_JWT")}}
45
45
  token = _get_bearer_token_{{snakeCase name}}()
46
46
  headers = {"Authorization": f"Bearer {token}"} if token else None
47
- toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url, headers=headers)))
48
- {{else}}
49
- toolsets.append(MCPToolset(connection_params=StreamableHTTPConnectionParams(url=url)))
50
- {{/if}}
47
+ toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(url=url, headers=headers)))
48
+ {{else}}
49
+ toolsets.append(MCPToolset(tool_name_prefix="{{snakeCase name}}", connection_params=StreamableHTTPConnectionParams(url=url)))
50
+ {{/if}}
51
51
  else:
52
52
  logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
53
53
  {{/each}}
@@ -11,7 +11,7 @@ requires-python = ">=3.10"
11
11
  dependencies = [
12
12
  "opentelemetry-distro",
13
13
  "opentelemetry-exporter-otlp",
14
- "google-adk >= 1.17.0, < 2.0.0",
14
+ "google-adk >= 1.35.0, < 2.0.0",
15
15
  "google-genai >= 1.0.0, < 2.0.0",
16
16
  "bedrock-agentcore >= 1.0.3",
17
17
  "botocore[crt] >= 1.35.0",
@@ -32,23 +32,25 @@ def get_all_gateway_mcp_client() -> MultiServerMCPClient | None:
32
32
  {{#each gatewayProviders}}
33
33
  url = os.environ.get("{{envVarName}}")
34
34
  if url:
35
- {{#if (eq authType "AWS_IAM")}}
35
+ {{#if (eq authType "AWS_IAM")}}
36
36
  session = create_aws_session()
37
37
  auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
38
- servers["{{name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
39
- {{else if (eq authType "CUSTOM_JWT")}}
38
+ servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url, "auth": auth}
39
+ {{else if (eq authType "CUSTOM_JWT")}}
40
40
  token = _get_bearer_token_{{snakeCase name}}()
41
41
  headers = {"Authorization": f"Bearer {token}"} if token else None
42
- servers["{{name}}"] = {"transport": "streamable_http", "url": url, "headers": headers}
43
- {{else}}
44
- servers["{{name}}"] = {"transport": "streamable_http", "url": url}
45
- {{/if}}
42
+ servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url, "headers": headers}
43
+ {{else}}
44
+ servers["{{snakeCase name}}"] = {"transport": "streamable_http", "url": url}
45
+ {{/if}}
46
46
  else:
47
47
  logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
48
48
  {{/each}}
49
49
  if not servers:
50
50
  return None
51
- return MultiServerMCPClient(servers)
51
+ # tool_name_prefix namespaces each gateway's tools by server key so multiple
52
+ # gateways exposing the same tool (e.g. x_amz_bedrock_agentcore_search) don't collide.
53
+ return MultiServerMCPClient(servers, tool_name_prefix=True)
52
54
  {{else}}
53
55
  {{#if isVpc}}
54
56
  # VPC mode: external MCP endpoints are not reachable without a NAT gateway.
@@ -13,7 +13,7 @@ dependencies = [
13
13
  "opentelemetry-instrumentation-langchain >= 0.59.0",
14
14
  "langgraph >= 1.0.2",
15
15
  "mcp >= 1.19.0",
16
- "langchain-mcp-adapters >= 0.1.11",
16
+ "langchain-mcp-adapters >= 0.2.0",
17
17
  "langchain >= 1.0.3",
18
18
  "bedrock-agentcore >= 1.8.0",
19
19
  "botocore[crt] >= 1.35.0",
@@ -1,6 +1,9 @@
1
1
  {{#if needsOs}}
2
2
  import os
3
3
  {{/if}}
4
+ {{#if hasGateway}}
5
+ from contextlib import AsyncExitStack
6
+ {{/if}}
4
7
  from agents import Agent, Runner, function_tool
5
8
  from bedrock_agentcore.runtime import BedrockAgentCoreApp
6
9
  from model.load import load_model
@@ -111,15 +114,22 @@ async def main(query):
111
114
  try:
112
115
  {{#if hasGateway}}
113
116
  if mcp_servers:
114
- agent = Agent(
115
- name="{{ name }}",
116
- model="gpt-4.1",
117
- instructions=INSTRUCTIONS,
118
- mcp_servers=mcp_servers,
119
- tools=tools
120
- )
121
- result = await Runner.run(agent, query)
122
- return result
117
+ # Connect every gateway server before the run; include_server_in_tool_names
118
+ # namespaces each server's tools so multiple gateways exposing the same tool
119
+ # (e.g. x_amz_bedrock_agentcore_search) don't collide.
120
+ async with AsyncExitStack() as stack:
121
+ for server in mcp_servers:
122
+ await stack.enter_async_context(server)
123
+ agent = Agent(
124
+ name="{{ name }}",
125
+ model="gpt-4.1",
126
+ instructions=INSTRUCTIONS,
127
+ mcp_servers=mcp_servers,
128
+ tools=tools,
129
+ mcp_config={"include_server_in_tool_names": True},
130
+ )
131
+ result = await Runner.run(agent, query)
132
+ return result
123
133
  else:
124
134
  agent = Agent(
125
135
  name="{{ name }}",
@@ -33,20 +33,20 @@ def get_all_gateway_mcp_servers() -> list[MCPServerStreamableHttp]:
33
33
  {{#each gatewayProviders}}
34
34
  url = os.environ.get("{{envVarName}}")
35
35
  if url:
36
- {{#if (eq authType "AWS_IAM")}}
36
+ {{#if (eq authType "AWS_IAM")}}
37
37
  session = create_aws_session()
38
38
  auth = SigV4HTTPXAuth(session.get_credentials(), "bedrock-agentcore", session.region_name)
39
39
  servers.append(MCPServerStreamableHttp(
40
40
  name="{{name}}",
41
41
  params={"url": url, "httpx_client_factory": lambda **kwargs: httpx.AsyncClient(auth=auth, **kwargs)}
42
42
  ))
43
- {{else if (eq authType "CUSTOM_JWT")}}
43
+ {{else if (eq authType "CUSTOM_JWT")}}
44
44
  token = _get_bearer_token_{{snakeCase name}}()
45
45
  headers = {"Authorization": f"Bearer {token}"} if token else {}
46
46
  servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url, "headers": headers}))
47
- {{else}}
47
+ {{else}}
48
48
  servers.append(MCPServerStreamableHttp(name="{{name}}", params={"url": url}))
49
- {{/if}}
49
+ {{/if}}
50
50
  else:
51
51
  logger.warning("{{envVarName}} not set — {{name}} gateway tools unavailable")
52
52
  {{/each}}
@@ -10,7 +10,7 @@ readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  dependencies = [
12
12
  "aws-opentelemetry-distro",
13
- "openai-agents >= 0.4.2",
13
+ "openai-agents >= 0.16.0",
14
14
  "bedrock-agentcore >= 1.8.0",
15
15
  "botocore[crt] >= 1.35.0",
16
16
  {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0",