Skip to content

feat(mcp): MCP server discovery + auto-connect from AWS Agent Registry - #159

Open
harshitkgupta wants to merge 1 commit into
mainfrom
feat/dynamic-mcp-servers-registry
Open

feat(mcp): MCP server discovery + auto-connect from AWS Agent Registry#159
harshitkgupta wants to merge 1 commit into
mainfrom
feat/dynamic-mcp-servers-registry

Conversation

@harshitkgupta

Copy link
Copy Markdown

Summary

Adds a lightweight, opt-in capability for the FAST agent to discover MCP servers from an AWS Agent Registry at runtime and auto-connect to each approved public streamable-HTTP server as a live Strands MCPClient, so their tools become directly callable by the agent.

Deliberately lightweight and independent of the existing config-catalog Dynamic MCP Servers feature: no DynamoDB, no UI, no per-user preferences. Default off; enabled per-deploy via config.

How it works

When backend.mcp_registry.enabled is set, on each request the agent:

  1. Lists the registry's Approved recordType=MCP records (list_discoverable_registry_records, paginated).
  2. Batch-fetches their descriptors (batch_get_discoverable_registry_record) and reads the streamable-HTTP endpoint from the mcpServer definition (remotes[0].url).
  3. Builds a live MCPClient per public streamable-HTTP server and adds it to the agent's tools (prefix registry_<slug>).

Changes

  • patterns/strands-single-agent/tools/mcp_registry.py (new) — discovery + client construction. Fail-loud on misconfig, fail-soft on runtime/registry errors. Prefix length-cap + de-duplication to respect Bedrock's 64-char tool-name limit.
  • basic_agent.py — wire discovered clients into the agent's tools, flag-gated and wrapped fail-soft.
  • CDK (config-manager.ts, backend-construct.ts, config.yaml) — typed mcp_registry config + validation, env vars, and two IAM statements.
  • Terraform (variables.tf, main.tf, modules/backend/{variables,runtime}.tf, terraform.tfvars.example) — full parity.
  • requirements.txt — pin boto3/botocore >= 1.43.66 (versions that ship the agent-registry client).
  • docs/MCP_REGISTRY_DISCOVERY.md (new) — config, IAM, namespace note, limits, troubleshooting.
  • tests/unit/test_mcp_registry.py (new) — 13 unit tests.

IAM note (subtle)

The BatchGetDiscoverableRegistryRecord API is authorized by the permission-only action agent-registry:GetDiscoverableRegistryRecord on the record resource (.../registry/<id>/record/*), while List/Search authorize on the registry resource. Granting the API name as an action is a silent no-op leading to AccessDenied. Both statements are emitted correctly.

Testing

  • ruff check + ruff format --check clean; 13 unit tests pass.
  • CDK tsc + cdk synth clean (flag off = inert; flag on = 2 IAM statements + 2 env vars, zero cdk-nag errors).
  • Terraform fmt -check + validate clean.
  • End-to-end against a live AWS Agent Registry: deployed the stack, created a registry, synced and approved the AWS Knowledge MCP record, invoked the runtime, and confirmed the runtime logs [MCP-REGISTRY] Discovered 1 connectable MCP server(s) and Connected MCP server 'AWSKnowledgeMCP'.

Limits / follow-ups

  • v1 connects public streamable-HTTP servers only; per-server OAuth is a documented follow-up.
  • Requires the registry's discovery authorizerType: AWS_IAM and the runtime role's discovery permissions (both handled by this PR's IAM).

…istry

Add a lightweight, opt-in capability for the FAST agent to discover MCP
servers from an AWS Agent Registry at runtime and auto-connect to each
approved public streamable-HTTP server as a live Strands MCP client, so
their tools become directly callable. No DynamoDB, no UI, no per-user
preferences.

- patterns/strands-single-agent/tools/mcp_registry.py: discovery
  (list + batch-get) and MCPClient construction; parses the real
  descriptors.mcpServer.data JSON shape; fail-loud on misconfig,
  fail-soft on runtime errors; prefix length-cap + de-duplication to
  respect Bedrock's 64-char tool-name limit.
- basic_agent.py: wire discovered clients into the agent's tools list,
  flag-gated and wrapped fail-soft.
- CDK (config-manager, backend-construct, config.yaml) and Terraform
  (variables, main, runtime, tfvars example): typed config + validation,
  env vars, and two IAM statements — List/Search on the registry ARN and
  the permission-only GetDiscoverableRegistryRecord on the record ARN
  (the IAM action name differs from the BatchGet API name).
- requirements.txt: pin boto3/botocore >=1.43.66 (ships agent-registry).
- docs/MCP_REGISTRY_DISCOVERY.md and unit tests (13 cases).

Verified end-to-end against a live AWS Agent Registry: the deployed agent
logs "Discovered 1 connectable MCP server(s)" and connects the AWS
Knowledge MCP server.
@harshitkgupta
harshitkgupta requested a review from a team August 27, 2026 22:27
@github-actions github-actions Bot added documentation Improvements or additions to documentation backend infrastructure tests labels Aug 27, 2026
@harshitkgupta

Copy link
Copy Markdown
Author

Tested this by creating registry by

REG=$(aws agent-registry-control create-registry \
  --name fast-aws-mcp-registry \
  --region us-east-1 --query registryArn --output text)

# wait until READY
aws agent-registry-control get-registry --registry-id "$REG" --region us-east-1 --query status

REC=$(aws agent-registry-control create-registry-record \
  --registry-id "$REG" --name aws-knowledge --descriptor-type MCP \
  --descriptors '{"mcpServer":{"source":{"fromUrl":{"url":"https://knowledge-mcp.global.api.aws"}}}}' \
  --region us-east-1 --query recordArn --output text)

# wait until record status is DRAFT, then approve (two hops)
aws agent-registry-control submit-registry-record-for-approval --registry-id "$REG" --record-id "$REC" --region us-east-1
aws agent-registry-control update-registry-record-status --registry-id "$REG" --record-id "$REC" \
  --status APPROVED --status-reason "Approved for testing" --region us-east-1

# verify discoverable
aws agent-registry list-discoverable-registry-records \
  --registry-id "$REG" --filters '[{"name":"recordType","values":["MCP"]}]' --region us-east-1

Then asked question in agent UI and listed tools from AWS Documentation MCP below-

what tools do you have?

I have access to the following tools:
Text Analysis Tool

Analyzes a block of text to count the number of words and return the top N most frequent characters.
Python Code Execution

Executes Python code in a secure sandbox environment, useful for calculations, data processing, and general programming tasks.
AWS Documentation Tools

A comprehensive set of tools for working with AWS documentation and resources:
Search Documentation

Searches AWS documentation across various topics including:

API/SDK/CLI references
Troubleshooting guides
AWS CDK documentation and constructs
CloudFormation templates
AWS Amplify docs
General architecture, best practices, and tutorials
Strands Agents SDK documentation

Read Documentation

Fetches full AWS documentation pages as markdown from allowed sources (AWS docs, GitHub repositories, etc.)
Regional Availability

Checks the availability of AWS products, service APIs, and CloudFormation resources across different AWS regions.
List Regions

Retrieves a list of all AWS regions.
Retrieve Skill

Retrieves AWS skills, workflows, and reference materials from the knowledge base.

These tools allow me to help you with text analysis, programming tasks, and comprehensive AWS-related questions including documentation lookup, service availability, and best practices.

@github-actions

Copy link
Copy Markdown

Latest scan for commit: 9b3dada | Updated: 2026-08-27 22:47:16 UTC

Security Scan Results

Scan Metadata

  • Project: ASH
  • Scan executed: 2026-08-27T22:40:17+00:00
  • ASH version: 3.2.2

Summary

Scanner Results

The table below shows findings by scanner, with status based on severity thresholds and dependencies:

Column Explanations:

Severity Levels (S/C/H/M/L/I):

  • Suppressed (S): Security findings that have been explicitly suppressed/ignored and don't affect the scanner's pass/fail status
  • Critical (C): The most severe security vulnerabilities requiring immediate remediation (e.g., SQL injection, remote code execution)
  • High (H): Serious security vulnerabilities that should be addressed promptly (e.g., authentication bypasses, privilege escalation)
  • Medium (M): Moderate security risks that should be addressed in normal development cycles (e.g., weak encryption, input validation issues)
  • Low (L): Minor security concerns with limited impact (e.g., information disclosure, weak recommendations)
  • Info (I): Informational findings for awareness with minimal security risk (e.g., code quality suggestions, best practice recommendations)

Other Columns:

  • Time: Duration taken by each scanner to complete its analysis
  • Action: Total number of actionable findings at or above the configured severity threshold that require attention

Scanner Results:

  • PASSED: Scanner found no security issues at or above the configured severity threshold - code is clean for this scanner
  • FAILED: Scanner found security vulnerabilities at or above the threshold that require attention and remediation
  • MISSING: Scanner could not run because required dependencies/tools are not installed or available
  • SKIPPED: Scanner was intentionally disabled or excluded from this scan
  • ERROR: Scanner encountered an execution error and could not complete successfully

Severity Thresholds (Thresh Column):

  • CRITICAL: Only Critical severity findings cause scanner to fail
  • HIGH: High and Critical severity findings cause scanner to fail
  • MEDIUM (MED): Medium, High, and Critical severity findings cause scanner to fail
  • LOW: Low, Medium, High, and Critical severity findings cause scanner to fail
  • ALL: Any finding of any severity level causes scanner to fail

Threshold Source: Values in parentheses indicate where the threshold is configured:

  • (g) = global: Set in the global_settings section of ASH configuration
  • (c) = config: Set in the individual scanner configuration section
  • (s) = scanner: Default threshold built into the scanner itself

Statistics calculation:

  • All statistics are calculated from the final aggregated SARIF report
  • Suppressed findings are counted separately and do not contribute to actionable findings
  • Scanner status is determined by comparing actionable findings to the threshold
Scanner S C H M L I Time Action Result Thresh
bandit 0 0 0 0 26 0 680ms 0 PASSED MED (g)
cdk-nag 0 0 0 0 0 0 7.4s 0 PASSED MED (g)
cfn-nag 0 0 0 0 0 0 17ms 0 PASSED MED (g)
checkov 0 1 0 0 0 0 8.6s 1 FAILED MED (g)
detect-secre… 0 0 0 0 0 0 888ms 0 PASSED MED (g)
grype 0 2 0 0 0 0 1m 2s 2 FAILED MED (g)
npm-audit 0 0 0 0 0 0 200ms 0 PASSED MED (g)
opengrep 12 1 0 0 0 0 20.1s 1 FAILED MED (g)
semgrep 0 0 0 0 0 0 <1ms 0 MISSING MED (g)
syft 0 0 0 0 0 0 2.1s 0 PASSED MED (g)

Detailed Findings

Show 4 actionable findings

Finding 1: CKV2_AWS_5

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV2_AWS_5
  • Location: infra-terraform/modules/backend/runtime.tf:408-418

Description:
Ensure that Security Groups are attached to another resource

Code Snippet:

resource "aws_security_group" "runtime_default" {
  count = var.backend_network_mode == "VPC" && length(var.backend_vpc_security_group_ids) == 0 ? 1 : 0

  name        = "${var.stack_name_base}-agentcore-runtime-sg"
  description = "Default security group for AgentCore Runtime VPC deployment"
  vpc_id      = var.backend_vpc_id

  tags = {
    Name = "${var.stack_name_base}-agentcore-runtime-sg"
  }
}

Finding 2: terraform.aws.security.aws-ecr-mutable-image-tags.aws-ecr-mutable-image-tags

  • Severity: HIGH
  • Scanner: opengrep
  • Rule ID: terraform.aws.security.aws-ecr-mutable-image-tags.aws-ecr-mutable-image-tags
  • Location: infra-terraform/modules/backend/runtime.tf:14-28

Description:
The ECR repository allows tag mutability. Image tags could be overwritten with compromised images. ECR images should be set to IMMUTABLE to prevent code injection through image mutation. This can be done by setting image_tag_mutability to IMMUTABLE.

Code Snippet:

resource "aws_ecr_repository" "agent" {
  count = local.is_docker && var.container_uri == null ? 1 : 0

  name                 = "${var.stack_name_base}-agent-runtime"
  image_tag_mutability = "MUTABLE"
  force_delete         = true

  image_scanning_configuration {
    scan_on_push = true
  }

  encryption_configuration {
    encryption_type = "AES256"
  }
}

Finding 3: GHSA-j6g5-3hh3-pgw8-bedrock-agentcore

  • Severity: HIGH
  • Scanner: grype
  • Rule ID: GHSA-j6g5-3hh3-pgw8-bedrock-agentcore
  • Location: patterns/strands-single-agent/requirements.txt:1

Description:
A high vulnerability in python package: bedrock-agentcore, version 1.4.7 was found at: /patterns/strands-single-agent/requirements.txt


Finding 4: GHSA-6rfw-mq36-jm8h-bedrock-agentcore

  • Severity: HIGH
  • Scanner: grype
  • Rule ID: GHSA-6rfw-mq36-jm8h-bedrock-agentcore
  • Location: patterns/strands-single-agent/requirements.txt:1

Description:
A high vulnerability in python package: bedrock-agentcore, version 1.4.7 was found at: /patterns/strands-single-agent/requirements.txt


Report generated by Automated Security Helper (ASH) at 2026-08-27T22:40:13+00:00

@kaleko

kaleko commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

At a high level this looks good to me but I don't have bandwidth to more deeply test it while I am out on leave. If @razkenari reviews this and approves, I approve as well

@razkenari

Copy link
Copy Markdown
Contributor

Reviewed and validated end-to-end. The feature behaves as designed across both states.
LGTM — approving. Good to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend documentation Improvements or additions to documentation infrastructure tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants