@aws/nx-plugin 1.0.0-rc.17 → 1.0.0-rc.19

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 (110) hide show
  1. package/generators.json +9 -1
  2. package/package.json +1 -1
  3. package/src/agentcore-gateway/attach-upstream.d.ts +33 -0
  4. package/src/agentcore-gateway/attach-upstream.js +41 -0
  5. package/src/agentcore-gateway/attach-upstream.js.map +1 -0
  6. package/src/agentcore-gateway/files/project/serve-local.ts.template +3 -2
  7. package/src/agentcore-gateway/gateway-connection/generator.d.ts +21 -0
  8. package/src/agentcore-gateway/gateway-connection/generator.js +102 -0
  9. package/src/agentcore-gateway/gateway-connection/generator.js.map +1 -0
  10. package/src/agentcore-gateway/gateway-connection/schema.d.ts +12 -0
  11. package/src/agentcore-gateway/gateway-connection/schema.json +26 -0
  12. package/src/agentcore-gateway/mcp-connection/generator.js +8 -24
  13. package/src/agentcore-gateway/mcp-connection/generator.js.map +1 -1
  14. package/src/connection/generator.js +66 -63
  15. package/src/connection/generator.js.map +1 -1
  16. package/src/license/generator.js +8 -19
  17. package/src/license/generator.js.map +1 -1
  18. package/src/license/known-exceptions.d.ts +0 -1
  19. package/src/license/known-exceptions.js +1 -8
  20. package/src/license/known-exceptions.js.map +1 -1
  21. package/src/py/agent/__snapshots__/generator.spec.ts.snap +15 -6
  22. package/src/py/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +201 -0
  23. package/src/py/agent/a2a-connection/files/agent-connection/app/{__targetAgentSnakeCase___client.py.template → __targetAgentSnakeCase___client_strands.py.template} +7 -5
  24. package/src/py/agent/a2a-connection/generator.js +6 -5
  25. package/src/py/agent/a2a-connection/generator.js.map +1 -1
  26. package/src/py/agent/files/http/main.py.template +2 -2
  27. package/src/py/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +197 -0
  28. package/src/py/agent/gateway-connection/files/agent-connection/app/{__gatewaySnakeCase___client.py.template → __gatewaySnakeCase___client_strands.py.template} +6 -6
  29. package/src/py/agent/gateway-connection/generator.js +5 -5
  30. package/src/py/agent/gateway-connection/generator.js.map +1 -1
  31. package/src/py/agent/generator.js +3 -5
  32. package/src/py/agent/generator.js.map +1 -1
  33. package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +157 -79
  34. package/src/py/agent/mcp-connection/files/agent-connection/app/{__mcpServerSnakeCase___client.py.template → __mcpServerSnakeCase___client_strands.py.template} +7 -5
  35. package/src/py/agent/mcp-connection/generator.js +5 -5
  36. package/src/py/agent/mcp-connection/generator.js.map +1 -1
  37. package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +37 -3
  38. package/src/py/fast-api/files/app/__name__/main.py.template +4 -1
  39. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +13 -4
  40. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +1 -0
  41. package/src/smithy/project/files/src/operations/echo.smithy.template +1 -0
  42. package/src/terraform/project/files/application/src/main.tf.template +6 -1
  43. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +35 -4
  44. package/src/trpc/backend/files/src/procedures/echo.ts.template +1 -1
  45. package/src/trpc/backend/files/src/schema/echo.ts.template +2 -2
  46. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +14 -5
  47. package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +256 -0
  48. package/src/ts/agent/a2a-connection/files/agent-connection/app/{__targetAgentKebabCase__-client.ts.template → __targetAgentKebabCase__-client-strands.ts.template} +5 -5
  49. package/src/ts/agent/a2a-connection/generator.js +3 -3
  50. package/src/ts/agent/a2a-connection/generator.js.map +1 -1
  51. package/src/ts/agent/files/http/router.ts.template +1 -1
  52. package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +220 -0
  53. package/src/ts/agent/gateway-connection/files/agent-connection/app/{__gatewayKebabCase__-client.ts.template → __gatewayKebabCase__-client-strands.ts.template} +5 -5
  54. package/src/ts/agent/gateway-connection/generator.js +3 -3
  55. package/src/ts/agent/gateway-connection/generator.js.map +1 -1
  56. package/src/ts/agent/generator.js +3 -0
  57. package/src/ts/agent/generator.js.map +1 -1
  58. package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +183 -110
  59. package/src/ts/agent/mcp-connection/files/agent-connection/app/{__mcpServerKebabCase__-client.ts.template → __mcpServerKebabCase__-client-strands.ts.template} +5 -5
  60. package/src/ts/agent/mcp-connection/generator.js +3 -3
  61. package/src/ts/agent/mcp-connection/generator.js.map +1 -1
  62. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +13 -4
  63. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +64 -24
  64. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +13 -4
  65. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +9 -3
  66. package/src/utils/agent-connection/agent-connection.d.ts +50 -24
  67. package/src/utils/agent-connection/agent-connection.js +137 -45
  68. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  69. package/src/utils/agent-connection/files/core-a2a/agentcore-a2a-client-config.ts.template +93 -0
  70. package/src/utils/agent-connection/files/core-auth/agentcore-endpoints.ts.template +37 -0
  71. package/src/utils/agent-connection/files/core-auth/agentcore-fetch.ts.template +54 -0
  72. package/src/utils/agent-connection/files/core-gateway/agentcore-gateway-mcp-transport.ts.template +41 -0
  73. package/src/utils/agent-connection/files/core-mcp/agentcore-mcp-transport.ts.template +70 -0
  74. package/src/utils/agent-connection/files/core-shared/agentcore-transport.ts.template +39 -0
  75. package/src/utils/agent-connection/files/core-strands/a2a/agentcore-a2a-client-strands.ts.template +61 -0
  76. package/src/utils/agent-connection/files/core-strands/gateway/agentcore-gateway-mcp-client-strands.ts.template +26 -0
  77. package/src/utils/agent-connection/files/core-strands/mcp/agentcore-mcp-client-strands.ts.template +27 -0
  78. package/src/utils/agent-connection/files/py-core-a2a/agentcore_a2a_client_config.py.template +43 -0
  79. package/src/utils/agent-connection/files/py-core-auth/agentcore_endpoints.py.template +47 -0
  80. package/src/utils/agent-connection/files/py-core-auth/auth/session.py.template +51 -0
  81. package/src/utils/agent-connection/files/py-core-gateway/agentcore_gateway_mcp_transport.py.template +28 -0
  82. package/src/utils/agent-connection/files/py-core-mcp/agentcore_mcp_transport.py.template +34 -0
  83. package/src/utils/agent-connection/files/py-core-shared/agentcore_transport.py.template +40 -0
  84. package/src/utils/agent-connection/files/py-core-strands/a2a/agentcore_a2a_client_strands.py.template +66 -0
  85. package/src/utils/agent-connection/files/py-core-strands/gateway/agentcore_gateway_mcp_client_strands.py.template +22 -0
  86. package/src/utils/agent-connection/files/py-core-strands/mcp/agentcore_mcp_client_strands.py.template +30 -0
  87. package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +3 -0
  88. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +110 -28
  89. package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +95 -2
  90. package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +13 -4
  91. package/src/utils/api-constructs/files/cdk/core/api/http/http-api.ts.template +9 -0
  92. package/src/utils/api-constructs/files/cdk/core/api/rest/rest-api.ts.template +23 -1
  93. package/src/utils/files/terraform/src/core/runtime-config/appconfig-deployment/appconfig-deployment.tf.template +9 -3
  94. package/src/utils/files/terraform/src/core/runtime-config/read/read.tf.template +7 -2
  95. package/src/utils/identity-constructs/files/terraform/core/user-identity/add-callback-url/add-callback-url.tf.template +9 -3
  96. package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +22 -8
  97. package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +10 -4
  98. package/src/utils/versions.d.ts +1 -1
  99. package/src/utils/versions.js +1 -1
  100. package/src/utils/website-constructs/files/terraform/core/static-website/static-website.tf.template +13 -4
  101. package/src/utils/agent-connection/files/core-a2a/agentcore-a2a-client.ts.template +0 -123
  102. package/src/utils/agent-connection/files/core-gateway/agentcore-gateway-mcp-client.ts.template +0 -78
  103. package/src/utils/agent-connection/files/core-mcp/agentcore-mcp-client.ts.template +0 -128
  104. package/src/utils/agent-connection/files/py-core-a2a/agentcore_a2a_client.py.template +0 -120
  105. package/src/utils/agent-connection/files/py-core-gateway/agentcore_gateway_mcp_client.py.template +0 -78
  106. package/src/utils/agent-connection/files/py-core-mcp/agentcore_mcp_client.py.template +0 -89
  107. /package/src/utils/agent-connection/files/{core-runtime-config/model-errors.ts.template → core-strands/base/model-errors-strands.ts.template} +0 -0
  108. /package/src/utils/agent-connection/files/{core-runtime-config/with-session-id.ts.template → core-strands/base/with-session-id-strands.ts.template} +0 -0
  109. /package/src/utils/agent-connection/files/{py-core-runtime-config/model_errors.py.template → py-core-strands/base/model_errors_strands.py.template} +0 -0
  110. /package/src/utils/agent-connection/files/{py-core-runtime-config/with_session_id.py.template → py-core-strands/base/with_session_id_strands.py.template} +0 -0
@@ -61,12 +61,13 @@ resource "null_resource" "add_callback_url" {
61
61
  command = <<-EOT
62
62
  uv run --with boto3 python -c "
63
63
  import boto3
64
+ import os
64
65
  import sys
65
66
 
66
67
  # Configuration
67
- user_pool_id = '${local.user_pool_id}'
68
- client_id = '${local.user_pool_client_id}'
69
- new_callback_url = '${var.callback_url}'
68
+ user_pool_id = os.environ['USER_POOL_ID']
69
+ client_id = os.environ['CLIENT_ID']
70
+ new_callback_url = os.environ['NEW_CALLBACK_URL']
70
71
 
71
72
  # Initialize Cognito client
72
73
  cognito = boto3.client('cognito-idp')
@@ -118,6 +119,11 @@ except Exception as e:
118
119
  sys.exit(1)
119
120
  "
120
121
  EOT
122
+ environment = {
123
+ USER_POOL_ID = local.user_pool_id
124
+ CLIENT_ID = local.user_pool_client_id
125
+ NEW_CALLBACK_URL = var.callback_url
126
+ }
121
127
  }
122
128
 
123
129
  depends_on = [terraform_data.validate_cognito_props]
@@ -287,10 +287,15 @@ resource "null_resource" "docker_publish" {
287
287
 
288
288
  provisioner "local-exec" {
289
289
  command = <<-EOT
290
- aws ecr get-login-password --region ${data.aws_region.current.region} | <%= containerEngine %> login --username AWS --password-stdin ${self.triggers.repository_url}
291
- <%= containerEngine %> tag ${self.triggers.docker_image_tag} ${self.triggers.repository_url}:latest
292
- <%= containerEngine %> push ${self.triggers.repository_url}:latest
290
+ aws ecr get-login-password --region "$AWS_REGION" | <%= containerEngine %> login --username AWS --password-stdin "$REPOSITORY_URL"
291
+ <%= containerEngine %> tag "$DOCKER_IMAGE_TAG" "$REPOSITORY_URL:latest"
292
+ <%= containerEngine %> push "$REPOSITORY_URL:latest"
293
293
  EOT
294
+ environment = {
295
+ AWS_REGION = data.aws_region.current.region
296
+ REPOSITORY_URL = self.triggers.repository_url
297
+ DOCKER_IMAGE_TAG = self.triggers.docker_image_tag
298
+ }
294
299
  }
295
300
 
296
301
  depends_on = [aws_ecr_repository_policy.migration_handler]
@@ -574,10 +579,10 @@ resource "null_resource" "create_db_user_trigger" {
574
579
  command = <<-EOT
575
580
  output_file=$(mktemp)
576
581
  response=$(aws lambda invoke \
577
- --region ${data.aws_region.current.region} \
578
- --function-name ${self.triggers.function_name} \
582
+ --region "$AWS_REGION" \
583
+ --function-name "$FUNCTION_NAME" \
579
584
  --cli-binary-format raw-in-base64-out \
580
- --payload '{"RequestType":"Create","PhysicalResourceId":"db-user:${self.triggers.db_user}"}' \
585
+ --payload "{\"RequestType\":\"Create\",\"PhysicalResourceId\":\"db-user:$DB_USER\"}" \
581
586
  "$output_file")
582
587
  cat "$output_file"
583
588
  echo "$response"
@@ -587,6 +592,11 @@ resource "null_resource" "create_db_user_trigger" {
587
592
  fi
588
593
  rm -f "$output_file"
589
594
  EOT
595
+ environment = {
596
+ AWS_REGION = data.aws_region.current.region
597
+ FUNCTION_NAME = self.triggers.function_name
598
+ DB_USER = self.triggers.db_user
599
+ }
590
600
  }
591
601
 
592
602
  depends_on = [aws_lambda_function.create_db_user, module.aurora]
@@ -655,8 +665,8 @@ resource "null_resource" "migration_trigger" {
655
665
  command = <<-EOT
656
666
  output_file=$(mktemp)
657
667
  response=$(aws lambda invoke \
658
- --region ${data.aws_region.current.region} \
659
- --function-name ${self.triggers.function_name} \
668
+ --region "$AWS_REGION" \
669
+ --function-name "$FUNCTION_NAME" \
660
670
  --cli-binary-format raw-in-base64-out \
661
671
  "$output_file")
662
672
  cat "$output_file"
@@ -667,6 +677,10 @@ resource "null_resource" "migration_trigger" {
667
677
  fi
668
678
  rm -f "$output_file"
669
679
  EOT
680
+ environment = {
681
+ AWS_REGION = data.aws_region.current.region
682
+ FUNCTION_NAME = self.triggers.function_name
683
+ }
670
684
  }
671
685
 
672
686
  depends_on = [
@@ -540,9 +540,9 @@ resource "null_resource" "proxy_target_ready" {
540
540
  deadline=$((start_time + 600))
541
541
  while true; do
542
542
  target_state=$(aws rds describe-db-proxy-targets \
543
- --region ${data.aws_region.current.region} \
544
- --db-proxy-name ${self.triggers.db_proxy_name} \
545
- --target-group-name ${self.triggers.target_group_name} \
543
+ --region "$AWS_REGION" \
544
+ --db-proxy-name "$DB_PROXY_NAME" \
545
+ --target-group-name "$TARGET_GROUP_NAME" \
546
546
  --query "Targets[?Type=='RDS_INSTANCE'] | [0].TargetHealth.State" \
547
547
  --output text)
548
548
 
@@ -552,13 +552,19 @@ resource "null_resource" "proxy_target_ready" {
552
552
 
553
553
  current_time=$(date +%s)
554
554
  if [ "$current_time" -ge "$deadline" ]; then
555
- echo "RDS Proxy target ${self.triggers.db_cluster_identifier} did not become AVAILABLE within 10 minutes. Last state: $target_state"
555
+ echo "RDS Proxy target $DB_CLUSTER_IDENTIFIER did not become AVAILABLE within 10 minutes. Last state: $target_state"
556
556
  exit 1
557
557
  fi
558
558
 
559
559
  sleep 10
560
560
  done
561
561
  EOT
562
+ environment = {
563
+ AWS_REGION = data.aws_region.current.region
564
+ DB_PROXY_NAME = self.triggers.db_proxy_name
565
+ TARGET_GROUP_NAME = self.triggers.target_group_name
566
+ DB_CLUSTER_IDENTIFIER = self.triggers.db_cluster_identifier
567
+ }
562
568
  }
563
569
 
564
570
  depends_on = [
@@ -135,7 +135,7 @@ export declare const withVersions: (deps: ITsDepVersion[]) => {
135
135
  */
136
136
  export declare const PY_VERSIONS: {
137
137
  readonly 'ag-ui-protocol': "==0.1.19";
138
- readonly 'ag-ui-strands': "==0.1.9";
138
+ readonly 'ag-ui-strands': "==0.2.1";
139
139
  readonly 'aws-lambda-powertools': "==3.29.0";
140
140
  readonly 'aws-lambda-powertools[tracer]': "==3.29.0";
141
141
  readonly 'aws-lambda-powertools[parser]': "==3.29.0";
@@ -136,7 +136,7 @@ exports.withVersions = withVersions;
136
136
  */
137
137
  exports.PY_VERSIONS = {
138
138
  'ag-ui-protocol': '==0.1.19',
139
- 'ag-ui-strands': '==0.1.9',
139
+ 'ag-ui-strands': '==0.2.1',
140
140
  'aws-lambda-powertools': '==3.29.0',
141
141
  'aws-lambda-powertools[tracer]': '==3.29.0',
142
142
  'aws-lambda-powertools[parser]': '==3.29.0',
@@ -553,7 +553,7 @@ resource "null_resource" "upload_website_files" {
553
553
 
554
554
  provisioner "local-exec" {
555
555
  command = <<-EOT
556
- cd "${path.root}"
556
+ cd "$ROOT_PATH"
557
557
  uv run --with boto3 python3 -c "
558
558
  import os
559
559
  import sys
@@ -642,9 +642,14 @@ def sync_to_s3(local_path, bucket_name):
642
642
  sys.exit(1)
643
643
 
644
644
  # Execute sync
645
- sync_to_s3('${var.website_file_path}', '${aws_s3_bucket.website.bucket}')
645
+ sync_to_s3(os.environ['WEBSITE_FILE_PATH'], os.environ['BUCKET_NAME'])
646
646
  "
647
647
  EOT
648
+ environment = {
649
+ ROOT_PATH = path.root
650
+ WEBSITE_FILE_PATH = var.website_file_path
651
+ BUCKET_NAME = aws_s3_bucket.website.bucket
652
+ }
648
653
  }
649
654
 
650
655
  depends_on = [aws_s3_bucket_policy.website_cloudfront_policy]
@@ -674,6 +679,7 @@ resource "null_resource" "cloudfront_invalidation" {
674
679
  command = <<-EOT
675
680
  uv run --with boto3 python3 -c "
676
681
  import boto3
682
+ import os
677
683
  import sys
678
684
  from botocore.exceptions import ClientError, NoCredentialsError
679
685
 
@@ -695,7 +701,7 @@ def create_invalidation(distribution_id):
695
701
 
696
702
  invalidation_id = response['Invalidation']['Id']
697
703
  print(f'CloudFront cache invalidation created: {invalidation_id}')
698
- print(f'Distribution: ${aws_cloudfront_distribution.website.id}')
704
+ print(f'Distribution: {distribution_id}')
699
705
  print(f'Status: {response[\"Invalidation\"][\"Status\"]}')
700
706
 
701
707
  except NoCredentialsError:
@@ -709,9 +715,12 @@ def create_invalidation(distribution_id):
709
715
  sys.exit(1)
710
716
 
711
717
  # Execute invalidation
712
- create_invalidation('${aws_cloudfront_distribution.website.id}')
718
+ create_invalidation(os.environ['DISTRIBUTION_ID'])
713
719
  "
714
720
  EOT
721
+ environment = {
722
+ DISTRIBUTION_ID = aws_cloudfront_distribution.website.id
723
+ }
715
724
  }
716
725
 
717
726
  depends_on = [
@@ -1,123 +0,0 @@
1
- import {
2
- ClientFactory,
3
- ClientFactoryOptions,
4
- DefaultAgentCardResolver,
5
- JsonRpcTransportFactory,
6
- } from '@a2a-js/sdk/client';
7
- import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
8
- import { A2AAgent } from '@strands-agents/sdk/a2a';
9
- import { AwsClient } from 'aws4fetch';
10
- import { getCurrentSessionId } from './session-context.js';
11
-
12
- const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
13
-
14
- /**
15
- * Common options for creating an AgentCore A2A client.
16
- */
17
- export interface AgentCoreA2aClientOptions {
18
- /** The ARN of the Bedrock AgentCore Runtime to connect to. */
19
- agentRuntimeArn: string;
20
- /** Optional description for the remote agent. */
21
- description?: string;
22
- /** Optional friendly name for the remote agent. */
23
- name?: string;
24
- }
25
-
26
- /** Options for an IAM-authenticated A2A client. */
27
- export interface AgentCoreA2aClientIamOptions
28
- extends AgentCoreA2aClientOptions {
29
- credentialProvider?: ReturnType<typeof fromNodeProviderChain>;
30
- }
31
-
32
- /** Options for a JWT-authenticated A2A client. */
33
- export interface AgentCoreA2aClientJwtOptions
34
- extends AgentCoreA2aClientOptions {
35
- accessTokenProvider: () => Promise<string>;
36
- }
37
-
38
- /** Options for a no-auth A2A client (local dev). */
39
- export interface AgentCoreA2aClientNoAuthOptions {
40
- /** Full URL of the local A2A endpoint. */
41
- url: string;
42
- name?: string;
43
- description?: string;
44
- }
45
-
46
- interface BuildOptions {
47
- name?: string;
48
- description?: string;
49
- }
50
-
51
- /** Factory for A2A clients that forward the current async-context session. */
52
- export class AgentCoreA2aClient {
53
- /**
54
- * Construct the A2A invocations URL for an AgentCore runtime ARN and
55
- * extract the region. A2A on AgentCore is mounted at `/invocations/`
56
- * (trailing slash matters).
57
- */
58
- private static buildUrl(agentRuntimeArn: string): {
59
- region: string;
60
- url: string;
61
- } {
62
- const region = agentRuntimeArn.split(':')[3];
63
- const url = `https://bedrock-agentcore.${region}.amazonaws.com/runtimes/${encodeURIComponent(agentRuntimeArn)}/invocations/`;
64
- return { region, url };
65
- }
66
-
67
- private static build(
68
- url: string,
69
- authFetch: typeof fetch,
70
- options: BuildOptions,
71
- ): A2AAgent {
72
- const sessionFetch: typeof fetch = (input, init) => {
73
- const headers = new Headers(init?.headers);
74
- const sessionId = getCurrentSessionId();
75
- if (sessionId) headers.set(SESSION_HEADER, sessionId);
76
- return authFetch(input, { ...init, headers });
77
- };
78
- const clientFactory = new ClientFactory({
79
- ...ClientFactoryOptions.default,
80
- transports: [new JsonRpcTransportFactory({ fetchImpl: sessionFetch })],
81
- cardResolver: new DefaultAgentCardResolver({ fetchImpl: sessionFetch }),
82
- });
83
- return new A2AAgent({
84
- url,
85
- clientFactory,
86
- ...(options.name ? { name: options.name } : {}),
87
- ...(options.description ? { description: options.description } : {}),
88
- });
89
- }
90
-
91
- static withIamAuth(options: AgentCoreA2aClientIamOptions): A2AAgent {
92
- const { region, url } = AgentCoreA2aClient.buildUrl(options.agentRuntimeArn);
93
- const credentialProvider =
94
- options.credentialProvider ?? fromNodeProviderChain();
95
- const sigv4Fetch: typeof fetch = async (...args) => {
96
- const client = new AwsClient({
97
- ...(await credentialProvider()),
98
- service: 'bedrock-agentcore',
99
- region,
100
- });
101
- return client.fetch(...args);
102
- };
103
- return AgentCoreA2aClient.build(url, sigv4Fetch, options);
104
- }
105
-
106
- static withJwtAuth(options: AgentCoreA2aClientJwtOptions): A2AAgent {
107
- const { url } = AgentCoreA2aClient.buildUrl(options.agentRuntimeArn);
108
- const bearerFetch: typeof fetch = async (input, init) => {
109
- const headers = new Headers(init?.headers);
110
- headers.set(
111
- 'Authorization',
112
- `Bearer ${await options.accessTokenProvider()}`,
113
- );
114
- return fetch(input, { ...init, headers });
115
- };
116
- return AgentCoreA2aClient.build(url, bearerFetch, options);
117
- }
118
-
119
- /** For local dev — plain HTTP, no auth. */
120
- static withoutAuth(options: AgentCoreA2aClientNoAuthOptions): A2AAgent {
121
- return AgentCoreA2aClient.build(options.url, fetch, options);
122
- }
123
- }
@@ -1,78 +0,0 @@
1
- import { McpClient } from '@strands-agents/sdk';
2
- import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
- import { AwsClient } from 'aws4fetch';
4
- import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
5
- import { getCurrentSessionId } from './session-context.js';
6
-
7
- const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
8
-
9
- export interface AgentCoreGatewayMcpClientIamOptions {
10
- /**
11
- * The MCP URL of the AgentCore Gateway, of the form
12
- * https://<gatewayId>.gateway.bedrock-agentcore.<region>.amazonaws.com/mcp
13
- */
14
- gatewayUrl: string;
15
- /** AWS region override; by default parsed from `gatewayUrl`. */
16
- region?: string;
17
- /** AWS credential provider; defaults to the standard provider chain. */
18
- credentialProvider?: ReturnType<typeof fromNodeProviderChain>;
19
- }
20
-
21
- /**
22
- * Factory for MCP clients that connect to an AgentCore Gateway. Forwards the
23
- * current async-context session via the AgentCore session header, which the
24
- * gateway propagates to downstream MCP server targets.
25
- */
26
- export class AgentCoreGatewayMcpClient {
27
- /** Create a gateway MCP client authenticated with IAM SigV4. */
28
- static withIamAuth(options: AgentCoreGatewayMcpClientIamOptions): McpClient {
29
- const credentialProvider =
30
- options.credentialProvider ?? fromNodeProviderChain();
31
- const region =
32
- options.region ?? parseRegionFromGatewayUrl(options.gatewayUrl);
33
-
34
- const sigv4Fetch: typeof fetch = async (input, init) => {
35
- const client = new AwsClient({
36
- ...(await credentialProvider()),
37
- service: 'bedrock-agentcore',
38
- region,
39
- });
40
- return client.fetch(input, {
41
- ...init,
42
- headers: withSessionHeader(init?.headers),
43
- });
44
- };
45
- return AgentCoreGatewayMcpClient.create(options.gatewayUrl, sigv4Fetch);
46
- }
47
-
48
- /** Plain-HTTP gateway client, for the local gateway started by serve-local. */
49
- static withoutAuth(options: { gatewayUrl: string }): McpClient {
50
- const plainFetch: typeof fetch = async (input, init) =>
51
- fetch(input, { ...init, headers: withSessionHeader(init?.headers) });
52
- return AgentCoreGatewayMcpClient.create(options.gatewayUrl, plainFetch);
53
- }
54
-
55
- private static create(gatewayUrl: string, fetchFn: typeof fetch): McpClient {
56
- const transport = new StreamableHTTPClientTransport(new URL(gatewayUrl), {
57
- fetch: fetchFn,
58
- });
59
- return new McpClient({ transport });
60
- }
61
- }
62
-
63
- const withSessionHeader = (init?: RequestInit['headers']): Headers => {
64
- const headers = new Headers(init);
65
- const sessionId = getCurrentSessionId();
66
- if (sessionId) headers.set(SESSION_HEADER, sessionId);
67
- return headers;
68
- };
69
-
70
- const parseRegionFromGatewayUrl = (gatewayUrl: string): string => {
71
- const match = /\.bedrock-agentcore\.([^.]+)\.amazonaws\.com/.exec(gatewayUrl);
72
- if (!match) {
73
- throw new Error(
74
- `Cannot determine region from gateway URL '${gatewayUrl}'. Pass region explicitly.`,
75
- );
76
- }
77
- return match[1];
78
- };
@@ -1,128 +0,0 @@
1
- import { McpClient } from '@strands-agents/sdk';
2
- import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
- import { AwsClient } from 'aws4fetch';
4
- import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
5
- import { getCurrentSessionId } from './session-context.js';
6
-
7
- const SESSION_HEADER = 'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id';
8
-
9
- /**
10
- * Common options for creating an AgentCore MCP client.
11
- */
12
- export interface AgentCoreMcpClientOptions {
13
- /**
14
- * The ARN of the Bedrock AgentCore Runtime to connect to.
15
- */
16
- agentRuntimeArn: string;
17
- }
18
-
19
- /**
20
- * Options for creating an AgentCore MCP client with IAM authentication.
21
- */
22
- export interface AgentCoreMcpClientIamOptions
23
- extends AgentCoreMcpClientOptions {
24
- /**
25
- * Optional AWS credential provider. If not provided, uses the default
26
- * credential provider chain from the AWS SDK.
27
- */
28
- credentialProvider?: ReturnType<typeof fromNodeProviderChain>;
29
- }
30
-
31
- /**
32
- * Options for creating an AgentCore MCP client with JWT authentication.
33
- */
34
- export interface AgentCoreMcpClientJwtOptions
35
- extends AgentCoreMcpClientOptions {
36
- /**
37
- * A function which returns the JWT access token used to authenticate.
38
- */
39
- accessTokenProvider: () => Promise<string>;
40
- }
41
-
42
- /**
43
- * Options for creating an MCP client with no auth (local dev).
44
- */
45
- export interface AgentCoreMcpClientNoAuthOptions {
46
- /** Full URL of the local MCP endpoint. */
47
- url: string;
48
- }
49
-
50
- interface CreateOptions {
51
- url: string;
52
- buildHeaders?: () => Promise<Record<string, string>>;
53
- fetch?: typeof fetch;
54
- }
55
-
56
- /** Factory for MCP clients that forward the current async-context session. */
57
- export class AgentCoreMcpClient {
58
- /**
59
- * Construct the invocation URL for an AgentCore runtime ARN and extract
60
- * the region. ARN format: arn:partition:service:region:account-id:resource
61
- */
62
- private static buildUrl(agentRuntimeArn: string): {
63
- region: string;
64
- url: string;
65
- } {
66
- const region = agentRuntimeArn.split(':')[3];
67
- const url = `https://bedrock-agentcore.${region}.amazonaws.com/runtimes/${encodeURIComponent(agentRuntimeArn)}/invocations?qualifier=DEFAULT`;
68
- return { region, url };
69
- }
70
-
71
- private static create(options: CreateOptions): McpClient {
72
- const {
73
- url,
74
- buildHeaders = async (): Promise<Record<string, string>> => ({}),
75
- fetch: customFetch,
76
- } = options;
77
- const fetchWithHeaders: typeof fetch = async (input, init) => {
78
- const headers = new Headers(init?.headers);
79
- const sessionId = getCurrentSessionId();
80
- if (sessionId) headers.set(SESSION_HEADER, sessionId);
81
- const extra = await buildHeaders();
82
- for (const k of Object.keys(extra)) {
83
- headers.set(k, extra[k]);
84
- }
85
- return (customFetch ?? fetch)(input, { ...init, headers });
86
- };
87
- const transport = new StreamableHTTPClientTransport(new URL(url), {
88
- fetch: fetchWithHeaders,
89
- });
90
- return new McpClient({ transport });
91
- }
92
-
93
- /**
94
- * SigV4-authenticated client for a Bedrock AgentCore runtime.
95
- */
96
- static withIamAuth(options: AgentCoreMcpClientIamOptions): McpClient {
97
- const { region, url } = AgentCoreMcpClient.buildUrl(options.agentRuntimeArn);
98
- const credentialProvider =
99
- options.credentialProvider ?? fromNodeProviderChain();
100
- const sigv4Fetch: typeof fetch = async (...args) => {
101
- const client = new AwsClient({
102
- ...(await credentialProvider()),
103
- service: 'bedrock-agentcore',
104
- region,
105
- });
106
- return client.fetch(...args);
107
- };
108
- return AgentCoreMcpClient.create({ url, fetch: sigv4Fetch });
109
- }
110
-
111
- /**
112
- * Bearer-authenticated client for a Bedrock AgentCore runtime.
113
- */
114
- static withJwtAuth(options: AgentCoreMcpClientJwtOptions): McpClient {
115
- const { url } = AgentCoreMcpClient.buildUrl(options.agentRuntimeArn);
116
- return AgentCoreMcpClient.create({
117
- url,
118
- buildHeaders: async () => ({
119
- Authorization: `Bearer ${await options.accessTokenProvider()}`,
120
- }),
121
- });
122
- }
123
-
124
- /** For local dev — plain HTTP, no auth. */
125
- static withoutAuth(options: AgentCoreMcpClientNoAuthOptions): McpClient {
126
- return AgentCoreMcpClient.create({ url: options.url });
127
- }
128
- }
@@ -1,120 +0,0 @@
1
- from collections.abc import Callable
2
- from urllib.parse import quote
3
-
4
- import boto3
5
- import httpx
6
- from a2a.client import ClientConfig
7
- from strands.agent.a2a_agent import A2AAgent
8
-
9
- from .auth import SigV4HTTPXAuth
10
- from .session_context import get_current_session_id
11
-
12
- SESSION_HEADER = "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id"
13
-
14
-
15
- class _SessionHeaderAuth(httpx.Auth):
16
- """Stamps the AgentCore session header from the current async context."""
17
-
18
- requires_request_body = True
19
- requires_response_body = True
20
-
21
- def __init__(self, inner: httpx.Auth | None = None):
22
- self._inner = inner
23
-
24
- def auth_flow(self, request: httpx.Request): # type: ignore[override]
25
- sid = get_current_session_id()
26
- if sid:
27
- request.headers[SESSION_HEADER] = sid
28
- if self._inner is None:
29
- yield request
30
- return
31
- yield from self._inner.auth_flow(request)
32
-
33
-
34
- class AgentCoreA2aClient:
35
- """Factory for A2A clients that forward the current async-context session."""
36
-
37
- @staticmethod
38
- def _build_url(agent_runtime_arn: str) -> tuple[str, str]:
39
- """Extract region from ARN and construct the A2A invocations URL.
40
-
41
- ARN format: arn:partition:service:region:account-id:resource
42
- A2A on AgentCore is mounted at `/invocations/` (trailing slash matters).
43
- """
44
- region = agent_runtime_arn.split(":")[3]
45
- encoded_arn = quote(agent_runtime_arn, safe="")
46
- url = (
47
- f"https://bedrock-agentcore.{region}.amazonaws.com/runtimes/"
48
- f"{encoded_arn}/invocations/"
49
- )
50
- return region, url
51
-
52
- @staticmethod
53
- def _build(
54
- url: str,
55
- auth: httpx.Auth | None,
56
- headers: dict | None,
57
- *,
58
- name: str | None,
59
- description: str | None,
60
- ) -> A2AAgent:
61
- httpx_client = httpx.AsyncClient(
62
- auth=_SessionHeaderAuth(auth),
63
- headers=headers or {},
64
- timeout=120,
65
- )
66
- client_config = ClientConfig(httpx_client=httpx_client, streaming=False)
67
- kwargs: dict = {"endpoint": url, "client_config": client_config}
68
- if name:
69
- kwargs["name"] = name
70
- if description:
71
- kwargs["description"] = description
72
- return A2AAgent(**kwargs)
73
-
74
- @staticmethod
75
- def with_iam_auth(
76
- agent_runtime_arn: str,
77
- *,
78
- name: str | None = None,
79
- description: str | None = None,
80
- ) -> A2AAgent:
81
- """SigV4-authenticated client for a Bedrock AgentCore runtime."""
82
- region, url = AgentCoreA2aClient._build_url(agent_runtime_arn)
83
- credentials = boto3.Session(region_name=region).get_credentials()
84
- return AgentCoreA2aClient._build(
85
- url,
86
- SigV4HTTPXAuth(credentials, "bedrock-agentcore", region),
87
- None,
88
- name=name,
89
- description=description,
90
- )
91
-
92
- @staticmethod
93
- def with_jwt_auth(
94
- agent_runtime_arn: str,
95
- access_token_provider: Callable[[], str],
96
- *,
97
- name: str | None = None,
98
- description: str | None = None,
99
- ) -> A2AAgent:
100
- """Bearer-authenticated client for a Bedrock AgentCore runtime."""
101
- _, url = AgentCoreA2aClient._build_url(agent_runtime_arn)
102
- return AgentCoreA2aClient._build(
103
- url,
104
- None,
105
- {"Authorization": f"Bearer {access_token_provider()}"},
106
- name=name,
107
- description=description,
108
- )
109
-
110
- @staticmethod
111
- def without_auth(
112
- url: str,
113
- *,
114
- name: str | None = None,
115
- description: str | None = None,
116
- ) -> A2AAgent:
117
- """Plain-HTTP client — for local dev."""
118
- return AgentCoreA2aClient._build(
119
- url, None, None, name=name, description=description
120
- )