Skip to content

Commit da3a2b4

Browse files
authored
fix: CDK template types and credential ARN passthrough for gateway deploy (#432)
* fix: correct CDK template type names and prop names The CDK stack template used McpSpec (doesn't exist) instead of AgentCoreMcpSpec, and passed wrong prop names to AgentCoreMcp: - spec → mcpSpec - application → agentCoreApplication - Added missing projectName prop * fix: collect API key credential ARNs and write to deployed state before CDK synth API key credential providers were created during deploy but their ARNs were not stored in deployed state, causing CDK to fail with 'Credential not found in deployed state' for gateway targets with API key auth. - Return credentialProviderArn from create/update API key providers - Unify API key and OAuth credential ARNs into single deployed state map - Move credential setup before CDK synth so template can read ARNs - Write partial deployed state with credentials before synth * fix: pass credential ARNs from deployed state to CDK gateway construct CDK template now reads deployed-state.json and extracts credential provider ARNs per target, passing them to AgentCoreMcp so gateway targets can reference outbound auth credentials. * fix: reorder TUI preflight to create credentials before CDK synth * fix: fetch OAuth credential ARN via Get after create/update * fix: handle Mcp prefix in gateway output key parsing * fix: bump CDK version to 2.239.0 in project template * fix: lint errors in deploy actions and preflight hook
1 parent 571b528 commit da3a2b4

11 files changed

Lines changed: 243 additions & 125 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aws/agentcore",
3-
"version": "0.3.0-preview.2.1",
3+
"version": "0.3.0-preview.3",
44
"description": "CLI for Amazon Bedrock AgentCore",
55
"license": "Apache-2.0",
66
"repository": {

src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,20 @@ async function main() {
5959
6060
// Read MCP configuration if it exists
6161
let mcpSpec;
62-
let mcpDeployedState;
6362
try {
6463
mcpSpec = await configIO.readMcpSpec();
65-
const deployedState = JSON.parse(fs.readFileSync(path.join(configRoot, '.cli', 'deployed-state.json'), 'utf8'));
66-
mcpDeployedState = deployedState?.mcp;
6764
} catch {
6865
// MCP config is optional
6966
}
7067
68+
// Read deployed state for credential ARNs (populated by pre-deploy identity setup)
69+
let deployedState: Record<string, unknown> | undefined;
70+
try {
71+
deployedState = JSON.parse(fs.readFileSync(path.join(configRoot, '.cli', 'deployed-state.json'), 'utf8'));
72+
} catch {
73+
// Deployed state may not exist on first deploy
74+
}
75+
7176
if (targets.length === 0) {
7277
throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
7378
}
@@ -78,10 +83,15 @@ async function main() {
7883
const env = toEnvironment(target);
7984
const stackName = toStackName(spec.name, target.name);
8085
86+
// Extract credentials from deployed state for this target
87+
const targetState = (deployedState as Record<string, unknown>)?.targets as Record<string, Record<string, unknown>> | undefined;
88+
const targetResources = targetState?.[target.name]?.resources as Record<string, unknown> | undefined;
89+
const credentials = targetResources?.credentials as Record<string, { credentialProviderArn: string; clientSecretArn?: string }> | undefined;
90+
8191
new AgentCoreStack(app, stackName, {
8292
spec,
8393
mcpSpec,
84-
mcpDeployedState,
94+
credentials,
8595
env,
8696
description: \`AgentCore stack for \${spec.name} deployed to \${target.name} (\${target.region})\`,
8797
tags: {
@@ -221,8 +231,7 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/lib/cdk-stack.ts shou
221231
AgentCoreApplication,
222232
AgentCoreMcp,
223233
type AgentCoreProjectSpec,
224-
type McpSpec,
225-
type McpDeployedState,
234+
type AgentCoreMcpSpec,
226235
} from '@aws/agentcore-cdk';
227236
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
228237
import { Construct } from 'constructs';
@@ -235,11 +244,11 @@ export interface AgentCoreStackProps extends StackProps {
235244
/**
236245
* The MCP specification containing gateways and servers.
237246
*/
238-
mcpSpec?: McpSpec;
247+
mcpSpec?: AgentCoreMcpSpec;
239248
/**
240-
* The MCP deployed state.
249+
* Credential provider ARNs from deployed state, keyed by credential name.
241250
*/
242-
mcpDeployedState?: McpDeployedState;
251+
credentials?: Record<string, { credentialProviderArn: string; clientSecretArn?: string }>;
243252
}
244253
245254
/**
@@ -255,7 +264,7 @@ export class AgentCoreStack extends Stack {
255264
constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
256265
super(scope, id, props);
257266
258-
const { spec, mcpSpec, mcpDeployedState } = props;
267+
const { spec, mcpSpec, credentials } = props;
259268
260269
// Create AgentCoreApplication with all agents
261270
this.application = new AgentCoreApplication(this, 'Application', {
@@ -265,9 +274,10 @@ export class AgentCoreStack extends Stack {
265274
// Create AgentCoreMcp if there are gateways configured
266275
if (mcpSpec?.agentCoreGateways && mcpSpec.agentCoreGateways.length > 0) {
267276
new AgentCoreMcp(this, 'Mcp', {
268-
spec: mcpSpec,
269-
deployedState: mcpDeployedState,
270-
application: this.application,
277+
projectName: spec.name,
278+
mcpSpec,
279+
agentCoreApplication: this.application,
280+
credentials,
271281
});
272282
}
273283
@@ -318,7 +328,7 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/package.json should m
318328
},
319329
"dependencies": {
320330
"@aws/agentcore-cdk": "^0.1.0-alpha.1",
321-
"aws-cdk-lib": "2.234.1",
331+
"aws-cdk-lib": "2.239.0",
322332
"constructs": "^10.0.0"
323333
}
324334
}

src/assets/cdk/bin/cdk.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,20 @@ async function main() {
2626

2727
// Read MCP configuration if it exists
2828
let mcpSpec;
29-
let mcpDeployedState;
3029
try {
3130
mcpSpec = await configIO.readMcpSpec();
32-
const deployedState = JSON.parse(fs.readFileSync(path.join(configRoot, '.cli', 'deployed-state.json'), 'utf8'));
33-
mcpDeployedState = deployedState?.mcp;
3431
} catch {
3532
// MCP config is optional
3633
}
3734

35+
// Read deployed state for credential ARNs (populated by pre-deploy identity setup)
36+
let deployedState: Record<string, unknown> | undefined;
37+
try {
38+
deployedState = JSON.parse(fs.readFileSync(path.join(configRoot, '.cli', 'deployed-state.json'), 'utf8'));
39+
} catch {
40+
// Deployed state may not exist on first deploy
41+
}
42+
3843
if (targets.length === 0) {
3944
throw new Error('No deployment targets configured. Please define targets in agentcore/aws-targets.json');
4045
}
@@ -45,10 +50,15 @@ async function main() {
4550
const env = toEnvironment(target);
4651
const stackName = toStackName(spec.name, target.name);
4752

53+
// Extract credentials from deployed state for this target
54+
const targetState = (deployedState as Record<string, unknown>)?.targets as Record<string, Record<string, unknown>> | undefined;
55+
const targetResources = targetState?.[target.name]?.resources as Record<string, unknown> | undefined;
56+
const credentials = targetResources?.credentials as Record<string, { credentialProviderArn: string; clientSecretArn?: string }> | undefined;
57+
4858
new AgentCoreStack(app, stackName, {
4959
spec,
5060
mcpSpec,
51-
mcpDeployedState,
61+
credentials,
5262
env,
5363
description: `AgentCore stack for ${spec.name} deployed to ${target.name} (${target.region})`,
5464
tags: {

src/assets/cdk/lib/cdk-stack.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import {
22
AgentCoreApplication,
33
AgentCoreMcp,
44
type AgentCoreProjectSpec,
5-
type McpSpec,
6-
type McpDeployedState,
5+
type AgentCoreMcpSpec,
76
} from '@aws/agentcore-cdk';
87
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
98
import { Construct } from 'constructs';
@@ -16,11 +15,11 @@ export interface AgentCoreStackProps extends StackProps {
1615
/**
1716
* The MCP specification containing gateways and servers.
1817
*/
19-
mcpSpec?: McpSpec;
18+
mcpSpec?: AgentCoreMcpSpec;
2019
/**
21-
* The MCP deployed state.
20+
* Credential provider ARNs from deployed state, keyed by credential name.
2221
*/
23-
mcpDeployedState?: McpDeployedState;
22+
credentials?: Record<string, { credentialProviderArn: string; clientSecretArn?: string }>;
2423
}
2524

2625
/**
@@ -36,7 +35,7 @@ export class AgentCoreStack extends Stack {
3635
constructor(scope: Construct, id: string, props: AgentCoreStackProps) {
3736
super(scope, id, props);
3837

39-
const { spec, mcpSpec, mcpDeployedState } = props;
38+
const { spec, mcpSpec, credentials } = props;
4039

4140
// Create AgentCoreApplication with all agents
4241
this.application = new AgentCoreApplication(this, 'Application', {
@@ -46,9 +45,10 @@ export class AgentCoreStack extends Stack {
4645
// Create AgentCoreMcp if there are gateways configured
4746
if (mcpSpec?.agentCoreGateways && mcpSpec.agentCoreGateways.length > 0) {
4847
new AgentCoreMcp(this, 'Mcp', {
49-
spec: mcpSpec,
50-
deployedState: mcpDeployedState,
51-
application: this.application,
48+
projectName: spec.name,
49+
mcpSpec,
50+
agentCoreApplication: this.application,
51+
credentials,
5252
});
5353
}
5454

src/assets/cdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
},
2525
"dependencies": {
2626
"@aws/agentcore-cdk": "^0.1.0-alpha.1",
27-
"aws-cdk-lib": "2.234.1",
27+
"aws-cdk-lib": "2.239.0",
2828
"constructs": "^10.0.0"
2929
}
3030
}

src/cli/cloudformation/outputs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ export function parseGatewayOutputs(
4545
const gatewayNames = Object.keys(gatewaySpecs);
4646
const gatewayIdMap = new Map(gatewayNames.map(name => [toPascalId(name), name]));
4747

48-
// Match pattern: Gateway{GatewayName}UrlOutput
49-
const outputPattern = /^Gateway(.+?)UrlOutput/;
48+
// Match patterns: Gateway{Name}{Type}Output or McpGateway{Name}{Type}Output
49+
const outputPattern = /^(?:Mcp)?Gateway(.+?)(Id|Arn|Url)Output/;
5050

5151
for (const [key, value] of Object.entries(outputs)) {
5252
const match = outputPattern.exec(key);

0 commit comments

Comments
 (0)