@aws/agentcore 1.0.0-preview.12 → 1.0.0-preview.14

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 (112) 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 +1373 -113
  5. package/dist/assets/agents/AGENTS.md +14 -0
  6. package/dist/assets/cdk/bin/cdk.ts +90 -24
  7. package/dist/assets/cdk/lib/cdk-stack.ts +178 -12
  8. package/dist/assets/cdk/test/cdk.test.ts +3 -0
  9. package/dist/assets/container/python/Dockerfile +4 -0
  10. package/dist/assets/python/a2a/langchain_langgraph/base/pyproject.toml +1 -1
  11. package/dist/assets/python/a2a/strands/capabilities/memory/session.py +4 -1
  12. package/dist/assets/python/agui/googleadk/base/pyproject.toml +1 -1
  13. package/dist/assets/python/agui/langchain_langgraph/base/pyproject.toml +1 -1
  14. package/dist/assets/python/agui/strands/capabilities/memory/session.py +4 -1
  15. package/dist/assets/python/http/autogen/base/pyproject.toml +1 -1
  16. package/dist/assets/python/http/googleadk/base/mcp_client/client.py +7 -7
  17. package/dist/assets/python/http/googleadk/base/pyproject.toml +1 -1
  18. package/dist/assets/python/http/langchain_langgraph/base/mcp_client/client.py +10 -8
  19. package/dist/assets/python/http/langchain_langgraph/base/pyproject.toml +2 -2
  20. package/dist/assets/python/http/openaiagents/base/main.py +19 -9
  21. package/dist/assets/python/http/openaiagents/base/mcp_client/client.py +4 -4
  22. package/dist/assets/python/http/openaiagents/base/pyproject.toml +2 -2
  23. package/dist/assets/python/http/strands/base/main.py +475 -27
  24. package/dist/assets/python/http/strands/base/mcp_client/client.py +45 -5
  25. package/dist/assets/python/http/strands/base/model/load.py +3 -3
  26. package/dist/assets/python/http/strands/base/pyproject.toml +5 -2
  27. package/dist/assets/python/http/strands/base/skills/fetcher.py +279 -0
  28. package/dist/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
  29. package/dist/assets/python/http/strands/capabilities/memory/session.py +4 -1
  30. package/dist/assets/python/http/strands/capabilities/payments/__init__.py +4 -0
  31. package/dist/assets/python/http/strands/capabilities/payments/payments.py +142 -0
  32. package/dist/cli/index.mjs +1235 -983
  33. package/dist/lib/errors/types.d.ts +18 -0
  34. package/dist/lib/errors/types.d.ts.map +1 -1
  35. package/dist/lib/errors/types.js +28 -1
  36. package/dist/lib/errors/types.js.map +1 -1
  37. package/dist/lib/packaging/helpers.d.ts.map +1 -1
  38. package/dist/lib/packaging/helpers.js +50 -10
  39. package/dist/lib/packaging/helpers.js.map +1 -1
  40. package/dist/lib/schemas/io/config-io.d.ts.map +1 -1
  41. package/dist/lib/schemas/io/config-io.js +0 -2
  42. package/dist/lib/schemas/io/config-io.js.map +1 -1
  43. package/dist/lib/utils/env.d.ts +4 -0
  44. package/dist/lib/utils/env.d.ts.map +1 -1
  45. package/dist/lib/utils/env.js +18 -0
  46. package/dist/lib/utils/env.js.map +1 -1
  47. package/dist/lib/utils/index.d.ts +1 -1
  48. package/dist/lib/utils/index.d.ts.map +1 -1
  49. package/dist/lib/utils/index.js +2 -1
  50. package/dist/lib/utils/index.js.map +1 -1
  51. package/dist/schema/constants.d.ts +20 -0
  52. package/dist/schema/constants.d.ts.map +1 -1
  53. package/dist/schema/constants.js +25 -1
  54. package/dist/schema/constants.js.map +1 -1
  55. package/dist/schema/schemas/agent-env.d.ts +35 -0
  56. package/dist/schema/schemas/agent-env.d.ts.map +1 -1
  57. package/dist/schema/schemas/agentcore-project.d.ts +239 -25
  58. package/dist/schema/schemas/agentcore-project.d.ts.map +1 -1
  59. package/dist/schema/schemas/agentcore-project.js +140 -34
  60. package/dist/schema/schemas/agentcore-project.js.map +1 -1
  61. package/dist/schema/schemas/auth.d.ts +175 -0
  62. package/dist/schema/schemas/auth.d.ts.map +1 -1
  63. package/dist/schema/schemas/auth.js +126 -3
  64. package/dist/schema/schemas/auth.js.map +1 -1
  65. package/dist/schema/schemas/deployed-state.d.ts +237 -46
  66. package/dist/schema/schemas/deployed-state.d.ts.map +1 -1
  67. package/dist/schema/schemas/deployed-state.js +62 -17
  68. package/dist/schema/schemas/deployed-state.js.map +1 -1
  69. package/dist/schema/schemas/mcp-defs.d.ts +2 -1
  70. package/dist/schema/schemas/mcp-defs.d.ts.map +1 -1
  71. package/dist/schema/schemas/mcp-defs.js +3 -2
  72. package/dist/schema/schemas/mcp-defs.js.map +1 -1
  73. package/dist/schema/schemas/mcp.d.ts +186 -0
  74. package/dist/schema/schemas/mcp.d.ts.map +1 -1
  75. package/dist/schema/schemas/mcp.js +479 -4
  76. package/dist/schema/schemas/mcp.js.map +1 -1
  77. package/dist/schema/schemas/primitives/ab-test.d.ts +0 -6
  78. package/dist/schema/schemas/primitives/ab-test.d.ts.map +1 -1
  79. package/dist/schema/schemas/primitives/ab-test.js +0 -2
  80. package/dist/schema/schemas/primitives/ab-test.js.map +1 -1
  81. package/dist/schema/schemas/primitives/harness.d.ts +242 -11
  82. package/dist/schema/schemas/primitives/harness.d.ts.map +1 -1
  83. package/dist/schema/schemas/primitives/harness.js +309 -21
  84. package/dist/schema/schemas/primitives/harness.js.map +1 -1
  85. package/dist/schema/schemas/primitives/index.d.ts +8 -8
  86. package/dist/schema/schemas/primitives/index.d.ts.map +1 -1
  87. package/dist/schema/schemas/primitives/index.js +18 -5
  88. package/dist/schema/schemas/primitives/index.js.map +1 -1
  89. package/dist/schema/schemas/primitives/knowledge-base.d.ts +104 -0
  90. package/dist/schema/schemas/primitives/knowledge-base.d.ts.map +1 -0
  91. package/dist/schema/schemas/primitives/knowledge-base.js +99 -0
  92. package/dist/schema/schemas/primitives/knowledge-base.js.map +1 -0
  93. package/dist/schema/schemas/primitives/online-eval-config.d.ts +20 -2
  94. package/dist/schema/schemas/primitives/online-eval-config.d.ts.map +1 -1
  95. package/dist/schema/schemas/primitives/online-eval-config.js +43 -5
  96. package/dist/schema/schemas/primitives/online-eval-config.js.map +1 -1
  97. package/dist/schema/schemas/primitives/payment.d.ts +54 -0
  98. package/dist/schema/schemas/primitives/payment.d.ts.map +1 -0
  99. package/dist/schema/schemas/primitives/payment.js +79 -0
  100. package/dist/schema/schemas/primitives/payment.js.map +1 -0
  101. package/dist/schema/schemas/primitives/policy.d.ts +26 -0
  102. package/dist/schema/schemas/primitives/policy.d.ts.map +1 -1
  103. package/dist/schema/schemas/primitives/policy.js +5 -1
  104. package/dist/schema/schemas/primitives/policy.js.map +1 -1
  105. package/npm-shrinkwrap.json +941 -670
  106. package/package.json +11 -8
  107. package/scripts/bundle.mjs +51 -0
  108. package/scripts/run-e2e-local.sh +48 -10
  109. package/dist/schema/schemas/primitives/http-gateway.d.ts +0 -21
  110. package/dist/schema/schemas/primitives/http-gateway.d.ts.map +0 -1
  111. package/dist/schema/schemas/primitives/http-gateway.js +0 -34
  112. 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';
@@ -28,12 +28,14 @@ async function main() {
28
28
  const spec = await configIO.readProjectSpec();
29
29
  const targets = await configIO.readAWSDeploymentTargets();
30
30
 
31
- // Extract MCP configuration from project spec.
32
- // Gateway fields are stored in agentcore.json but may not yet be on the
33
- // AgentCoreProjectSpec type from @aws/agentcore-cdk, so we read them
34
- // dynamically and cast the resulting object.
31
+ // The vended CDK project compiles against the published @aws/agentcore-cdk
32
+ // schema type, which may lag the CLI's own AgentCoreProjectSpec (e.g. payments,
33
+ // harnesses, gateway fields). Cast once so those fields are reachable.
35
34
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
35
  const specAny = spec as any;
36
+
37
+ // Extract MCP configuration from project spec.
38
+ // Gateway fields are stored in agentcore.json but may not yet be on the
37
39
  const mcpSpec = specAny.agentCoreGateways?.length
38
40
  ? {
39
41
  agentCoreGateways: specAny.agentCoreGateways,
@@ -54,38 +56,61 @@ async function main() {
54
56
  throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
55
57
  }
56
58
 
57
- // 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.
58
61
  const projectRoot = path.resolve(configRoot, '..');
59
- const harnessConfigs: {
60
- name: string;
61
- executionRoleArn?: string;
62
- memoryName?: string;
63
- containerUri?: string;
64
- hasDockerfile?: boolean;
65
- dockerfile?: string;
66
- codeLocation?: string;
67
- tools?: { type: string; name: string }[];
68
- apiKeyArn?: string;
69
- efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
70
- s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
71
- }[] = [];
72
- 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 ?? []) : []) {
73
91
  const harnessDir = path.resolve(projectRoot, entry.path);
74
92
  const harnessPath = path.resolve(harnessDir, 'harness.json');
75
93
  try {
76
- const harnessSpec = JSON.parse(fs.readFileSync(harnessPath, 'utf-8'));
94
+ const harnessSpec = HarnessSpecSchema.parse(JSON.parse(fs.readFileSync(harnessPath, 'utf-8')));
77
95
  harnessConfigs.push({
78
96
  name: entry.name,
79
97
  executionRoleArn: harnessSpec.executionRoleArn,
80
- 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,
81
101
  containerUri: harnessSpec.containerUri,
82
102
  hasDockerfile: !!harnessSpec.dockerfile,
83
103
  dockerfile: harnessSpec.dockerfile,
84
104
  codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
85
105
  tools: harnessSpec.tools,
106
+ skills: harnessSpec.skills,
86
107
  apiKeyArn: harnessSpec.model?.apiKeyArn,
87
108
  efsAccessPoints: harnessSpec.efsAccessPoints,
88
109
  s3AccessPoints: harnessSpec.s3AccessPoints,
110
+ apiFormat: harnessSpec.model?.apiFormat,
111
+ // Full spec + dir drive the AWS::BedrockAgentCore::Harness CFN resource.
112
+ spec: harnessSpec,
113
+ harnessDir,
89
114
  });
90
115
  } catch (err) {
91
116
  throw new Error(
@@ -109,11 +134,52 @@ async function main() {
109
134
  | Record<string, { credentialProviderArn: string; clientSecretArn?: string }>
110
135
  | undefined;
111
136
 
137
+ // Payment credential provider ARNs live in the same credentials map as identity credentials
138
+ const paymentCredentials = credentials;
139
+
140
+ const paymentSpec = specAny.payments?.length
141
+ ? specAny.payments.map(
142
+ (p: {
143
+ name: string;
144
+ description?: string;
145
+ authorizerType: 'AWS_IAM' | 'CUSTOM_JWT';
146
+ authorizerConfiguration?: unknown;
147
+ autoPayment?: boolean;
148
+ paymentToolAllowlist?: string[];
149
+ networkPreferences?: string[];
150
+ connectors: { name: string; provider?: string; credentialName: string }[];
151
+ }) => ({
152
+ name: p.name,
153
+ description: p.description,
154
+ authorizerType: p.authorizerType,
155
+ authorizerConfiguration: p.authorizerConfiguration,
156
+ autoPayment: p.autoPayment,
157
+ paymentToolAllowlist: p.paymentToolAllowlist,
158
+ networkPreferences: p.networkPreferences,
159
+ connectors: p.connectors.map(c => {
160
+ const credentialProviderArn = paymentCredentials?.[c.credentialName]?.credentialProviderArn;
161
+ if (!credentialProviderArn) {
162
+ // Fail fast with an actionable message rather than passing an empty
163
+ // ARN that fails opaquely server-side at CreatePaymentConnector.
164
+ throw new Error(
165
+ `Payment connector "${c.name}" on manager "${p.name}" references credential ` +
166
+ `"${c.credentialName}", but no deployed credential provider was found for it. ` +
167
+ `Run \`agentcore deploy\` so the credential provider is created first.`
168
+ );
169
+ }
170
+ return { name: c.name, provider: c.provider, credentialProviderArn };
171
+ }),
172
+ })
173
+ )
174
+ : undefined;
175
+
112
176
  new AgentCoreStack(app, stackName, {
113
177
  spec,
114
178
  mcpSpec,
115
179
  credentials,
180
+ connectorParametersByFile,
116
181
  harnesses: harnessConfigs.length > 0 ? harnessConfigs : undefined,
182
+ paymentSpec,
117
183
  env,
118
184
  description: `AgentCore stack for ${spec.name} deployed to ${target.name} (${target.region})`,
119
185
  tags: {
@@ -128,5 +194,5 @@ async function main() {
128
194
 
129
195
  main().catch((error: unknown) => {
130
196
  console.error('AgentCore CDK synthesis failed:', error instanceof Error ? error.message : error);
131
- process.exitCode = 1;
197
+ process.exit(1);
132
198
  });
@@ -1,24 +1,39 @@
1
1
  import {
2
2
  AgentCoreApplication,
3
3
  AgentCoreMcp,
4
+ AgentCorePaymentManager,
5
+ AgentCorePaymentConnector,
4
6
  type AgentCoreProjectSpec,
5
7
  type AgentCoreMcpSpec,
8
+ type CustomJWTAuthorizerConfig,
9
+ type HarnessDeploymentConfig,
6
10
  } from '@aws/agentcore-cdk';
7
11
  import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
12
+ import * as iam from 'aws-cdk-lib/aws-iam';
8
13
  import { Construct } from 'constructs';
9
14
 
10
- export interface HarnessConfig {
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;
21
+
22
+ export interface PaymentConnectorSpec {
23
+ name: string;
24
+ provider: 'CoinbaseCDP' | 'StripePrivy';
25
+ credentialProviderArn: string;
26
+ }
27
+
28
+ export interface PaymentSpec {
11
29
  name: string;
12
- executionRoleArn?: string;
13
- memoryName?: string;
14
- containerUri?: string;
15
- hasDockerfile?: boolean;
16
- dockerfile?: string;
17
- codeLocation?: string;
18
- tools?: { type: string; name: string }[];
19
- apiKeyArn?: string;
20
- efsAccessPoints?: { accessPointArn: string; mountPath: string }[];
21
- s3AccessPoints?: { accessPointArn: string; mountPath: string }[];
30
+ description?: string;
31
+ authorizerType: 'AWS_IAM' | 'CUSTOM_JWT';
32
+ authorizerConfiguration?: { customJWTAuthorizer: CustomJWTAuthorizerConfig };
33
+ autoPayment?: boolean;
34
+ paymentToolAllowlist?: string[];
35
+ networkPreferences?: string[];
36
+ connectors: PaymentConnectorSpec[];
22
37
  }
23
38
 
24
39
  export interface AgentCoreStackProps extends StackProps {
@@ -38,6 +53,35 @@ export interface AgentCoreStackProps extends StackProps {
38
53
  * Harness role configurations.
39
54
  */
40
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>>;
61
+ /**
62
+ * Payment specifications with resolved credential provider ARNs.
63
+ */
64
+ paymentSpec?: PaymentSpec[];
65
+ }
66
+
67
+ function toCdkId(name: string): string {
68
+ return name.replace(/_/g, '');
69
+ }
70
+
71
+ /**
72
+ * Decide whether a deployed runtime should receive payment env vars + IAM grants.
73
+ * Payments today only ships a runtime shim for Python HTTP runtimes; injecting
74
+ * AGENTCORE_PAYMENT_* env vars into TypeScript / MCP / A2A / AGUI runtimes
75
+ * would surface env vars they cannot consume and would dilute least-privilege
76
+ * IAM grants for runtimes that never call ProcessPayment.
77
+ */
78
+ function isPaymentEligibleAgent(agent: { entrypoint?: string; protocol?: string }): boolean {
79
+ if (agent.protocol && agent.protocol !== 'HTTP') {
80
+ return false;
81
+ }
82
+ const entrypoint = typeof agent.entrypoint === 'string' ? agent.entrypoint : '';
83
+ const entrypointFile = entrypoint.split(':')[0] ?? '';
84
+ return entrypointFile.endsWith('.py');
41
85
  }
42
86
 
43
87
  /**
@@ -53,7 +97,7 @@ export class AgentCoreStack extends Stack {
53
97
  constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
54
98
  super(scope, id, props);
55
99
 
56
- const { spec, mcpSpec, credentials, harnesses } = props;
100
+ const { spec, mcpSpec, credentials, harnesses, connectorParametersByFile, paymentSpec } = props;
57
101
 
58
102
  // Create AgentCoreApplication with all agents and harness roles
59
103
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -61,6 +105,12 @@ export class AgentCoreStack extends Stack {
61
105
  if (harnesses?.length) {
62
106
  appProps.harnesses = harnesses;
63
107
  }
108
+ if (connectorParametersByFile && Object.keys(connectorParametersByFile).length > 0) {
109
+ appProps.connectorParametersByFile = connectorParametersByFile;
110
+ }
111
+ if (credentials) {
112
+ appProps.credentials = credentials;
113
+ }
64
114
  this.application = new AgentCoreApplication(this, 'Application', appProps as any);
65
115
 
66
116
  // Create AgentCoreMcp if there are gateways configured
@@ -74,6 +124,122 @@ export class AgentCoreStack extends Stack {
74
124
  });
75
125
  }
76
126
 
127
+ // Create payment infrastructure via CFN constructs
128
+ if (paymentSpec && paymentSpec.length > 0) {
129
+ for (const payment of paymentSpec) {
130
+ const mgrId = toCdkId(payment.name);
131
+ const manager = new AgentCorePaymentManager(this, `Payment${mgrId}`, {
132
+ projectName: spec.name,
133
+ name: payment.name,
134
+ authorizerType: payment.authorizerType,
135
+ description: payment.description,
136
+ authorizerConfiguration: payment.authorizerConfiguration,
137
+ tags: spec.tags,
138
+ });
139
+
140
+ const prefix = `AGENTCORE_PAYMENT_${payment.name.toUpperCase().replace(/-/g, '_')}`;
141
+
142
+ // Wire env vars from construct output tokens into eligible agent environments only.
143
+ // See isPaymentEligibleAgent — non-Python or non-HTTP runtimes have no shim that
144
+ // can consume these env vars, and giving them sts:AssumeRole on the
145
+ // ProcessPaymentRole would broaden the privilege surface unnecessarily.
146
+ for (const env of this.application.environments.values()) {
147
+ if (!isPaymentEligibleAgent(env.agent)) {
148
+ continue;
149
+ }
150
+ env.runtime.addEnvironmentVariable(`${prefix}_MANAGER_ARN`, manager.paymentManagerArn);
151
+ env.runtime.addEnvironmentVariable(`${prefix}_PROCESS_PAYMENT_ROLE_ARN`, manager.processPaymentRoleArn);
152
+
153
+ // Grant runtime execution role permission to assume the ProcessPaymentRole.
154
+ // The ProcessPaymentRole's trust policy allows AccountRootPrincipal, but the
155
+ // caller still needs sts:AssumeRole on its own role to perform the assumption.
156
+ env.runtime.role.addToPrincipalPolicy(
157
+ new iam.PolicyStatement({
158
+ actions: ['sts:AssumeRole'],
159
+ resources: [manager.processPaymentRoleArn],
160
+ })
161
+ );
162
+
163
+ // Grant payment data-plane actions directly to the runtime role.
164
+ //
165
+ // NOTE: This deviates from the canonical role model in the AgentCore Payments
166
+ // beta guide, which assigns Get/List/Create instrument+session actions to a
167
+ // separate ManagementRole and limits the agent's role to ProcessPayment only.
168
+ // The current SDK plugin (AgentCorePaymentsPlugin.generate_payment_header)
169
+ // calls GetPaymentInstrument internally during the 402 auto-pay path, so the
170
+ // runtime role needs read access. CreatePaymentSession is included so
171
+ // `agentcore invoke --auto-session` works without a separate ManagementRole
172
+ // call. Tighten this if the SDK is updated to accept pre-fetched instrument
173
+ // details and split create-session into a backend-only flow.
174
+ env.runtime.role.addToPrincipalPolicy(
175
+ new iam.PolicyStatement({
176
+ actions: [
177
+ 'bedrock-agentcore:GetPaymentInstrument',
178
+ 'bedrock-agentcore:ListPaymentInstruments',
179
+ 'bedrock-agentcore:GetPaymentInstrumentBalance',
180
+ 'bedrock-agentcore:GetPaymentSession',
181
+ 'bedrock-agentcore:ListPaymentSessions',
182
+ 'bedrock-agentcore:CreatePaymentSession',
183
+ 'bedrock-agentcore:ProcessPayment',
184
+ ],
185
+ resources: [manager.paymentManagerArn, `${manager.paymentManagerArn}/*`],
186
+ })
187
+ );
188
+
189
+ if (payment.autoPayment !== undefined) {
190
+ env.runtime.addEnvironmentVariable(`${prefix}_AUTO_PAYMENT`, String(payment.autoPayment));
191
+ }
192
+ if (payment.paymentToolAllowlist) {
193
+ env.runtime.addEnvironmentVariable(`${prefix}_TOOL_ALLOWLIST`, payment.paymentToolAllowlist.join(','));
194
+ }
195
+ if (payment.networkPreferences) {
196
+ env.runtime.addEnvironmentVariable(`${prefix}_NETWORK_PREFERENCES`, payment.networkPreferences.join(','));
197
+ }
198
+ if (payment.authorizerType === 'CUSTOM_JWT') {
199
+ env.runtime.addEnvironmentVariable(`${prefix}_AUTH_MODE`, 'bearer');
200
+ }
201
+ }
202
+
203
+ // Create connectors for this manager
204
+ for (const connector of payment.connectors) {
205
+ const connId = toCdkId(connector.name);
206
+ const conn = new AgentCorePaymentConnector(this, `Payment${mgrId}${connId}`, {
207
+ projectName: spec.name,
208
+ paymentManager: manager,
209
+ connectorName: connector.name,
210
+ connectorType: connector.provider,
211
+ credentialProviderArn: connector.credentialProviderArn,
212
+ });
213
+
214
+ // Wire first connector's ID as env var (eligible agents only)
215
+ if (connector === payment.connectors[0]) {
216
+ for (const env of this.application.environments.values()) {
217
+ if (!isPaymentEligibleAgent(env.agent)) continue;
218
+ env.runtime.addEnvironmentVariable(`${prefix}_CONNECTOR_ID`, conn.paymentConnectorId);
219
+ }
220
+ }
221
+
222
+ new CfnOutput(this, `Payment${mgrId}${connId}ConnectorId`, {
223
+ value: conn.paymentConnectorId,
224
+ });
225
+ }
226
+
227
+ // CFN Outputs for post-deploy state parsing
228
+ new CfnOutput(this, `Payment${mgrId}ManagerArn`, {
229
+ value: manager.paymentManagerArn,
230
+ });
231
+ new CfnOutput(this, `Payment${mgrId}ManagerId`, {
232
+ value: manager.paymentManagerId,
233
+ });
234
+ new CfnOutput(this, `Payment${mgrId}ProcessPaymentRoleArn`, {
235
+ value: manager.processPaymentRoleArn,
236
+ });
237
+ new CfnOutput(this, `Payment${mgrId}ResourceRetrievalRoleArn`, {
238
+ value: manager.resourceRetrievalRoleArn,
239
+ });
240
+ }
241
+ }
242
+
77
243
  // Stack-level output
78
244
  new CfnOutput(this, 'StackNameOutput', {
79
245
  description: 'Name of the CloudFormation Stack',
@@ -14,11 +14,14 @@ test('AgentCoreStack synthesizes with empty spec', () => {
14
14
  credentials: [],
15
15
  evaluators: [],
16
16
  onlineEvalConfigs: [],
17
+ configBundles: [],
17
18
  policyEngines: [],
19
+ payments: [],
18
20
  agentCoreGateways: [],
19
21
  mcpRuntimeTools: [],
20
22
  unassignedTargets: [],
21
23
  datasets: [],
24
+ knowledgeBases: [],
22
25
  },
23
26
  });
24
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
@@ -17,7 +17,7 @@ dependencies = [
17
17
  {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
18
18
  {{/if}}"aws-opentelemetry-distro",
19
19
  "opentelemetry-instrumentation-langchain >= 0.59.0",
20
- "bedrock-agentcore[a2a] >= 1.0.3",
20
+ "bedrock-agentcore[a2a] >= 1.8.0",
21
21
  "botocore[crt] >= 1.35.0",
22
22
  "langgraph >= 0.2.0",
23
23
  ]
@@ -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}}
@@ -11,7 +11,7 @@ requires-python = ">=3.10"
11
11
  dependencies = [
12
12
  "ag-ui-adk >= 0.6.0",
13
13
  "ag-ui-protocol >= 0.1.10",
14
- "bedrock-agentcore >= 1.0.3",
14
+ "bedrock-agentcore >= 1.8.0",
15
15
  "fastapi >= 0.115.12",
16
16
  "google-adk >= 1.16.0, < 2.0.0",
17
17
  "google-genai >= 1.0.0, < 2.0.0",
@@ -18,7 +18,7 @@ dependencies = [
18
18
  {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0",
19
19
  {{/if}}"aws-opentelemetry-distro",
20
20
  "opentelemetry-instrumentation-langchain >= 0.59.0",
21
- "bedrock-agentcore >= 1.0.3",
21
+ "bedrock-agentcore >= 1.8.0",
22
22
  "botocore[crt] >= 1.35.0",
23
23
  "langgraph >= 0.3.25",
24
24
  "langchain >= 0.3.0",
@@ -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}}
@@ -13,7 +13,7 @@ dependencies = [
13
13
  "autogen-ext[mcp] >= 0.7.5",
14
14
  "opentelemetry-distro",
15
15
  "opentelemetry-exporter-otlp",
16
- "bedrock-agentcore >= 1.0.3",
16
+ "bedrock-agentcore >= 1.8.0",
17
17
  "botocore[crt] >= 1.35.0",
18
18
  "tiktoken",
19
19
  {{#if (eq modelProvider "Bedrock")}}
@@ -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,9 +13,9 @@ 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
- "bedrock-agentcore >= 1.0.3",
18
+ "bedrock-agentcore >= 1.8.0",
19
19
  "botocore[crt] >= 1.35.0",
20
20
  {{#if (eq modelProvider "Bedrock")}}
21
21
  "langchain-aws >= 1.0.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 }}",