Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions strands-agentcore-smithy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*-deps/
*-package/
*.zip
.aws-sam/
samconfig.toml
.kiro/
.venv/
venv/
__pycache__/
*.pyc
*.so
*.egg-info/
.pytest_cache/
.hypothesis/
.DS_Store
31 changes: 31 additions & 0 deletions strands-agentcore-smithy/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ============================================================
# AgentCore Smithy Bedrock - SAM Makefile build target
# ============================================================
# Used by `sam build` via the AgentLambdaFunction resource's
# `Metadata: BuildMethod: makefile`. This replaces the previous
# manual packaging in deploy.sh and requires NO Docker.
#
# SAM invokes `make build-AgentLambdaFunction` with ARTIFACTS_DIR
# set to the directory SAM expects the built artifacts in.
#
# Two-step install reproduces the original packaging behaviour:
# 1. Install all dependencies as manylinux2014 x86_64 wheels
# 2. Re-install pure-Python packages with --no-deps so nothing
# is skipped by the binary-only constraint
# ============================================================

build-AgentLambdaFunction:
pip3 install \
--target "$(ARTIFACTS_DIR)" \
--platform manylinux2014_x86_64 \
--python-version 3.12 \
--only-binary=:all: \
-r requirements.txt
pip3 install \
--target "$(ARTIFACTS_DIR)" \
--platform manylinux2014_x86_64 \
--python-version 3.12 \
--only-binary=:all: \
--no-deps \
requests urllib3 charset-normalizer idna certifi PyJWT cryptography cffi
cp -r src "$(ARTIFACTS_DIR)/"
184 changes: 184 additions & 0 deletions strands-agentcore-smithy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Strands Agent on Lambda with AgentCore Smithy Bedrock Target

A serverless AI agent that uses AWS Bedrock AgentCore Gateway with a Smithy model target to call Bedrock Runtime. The agent (Claude Sonnet 4.6) calls another model (Claude Haiku 4.5) as a tool via the gateway's Converse API.

## Architecture

![Architecture Diagram](architecture/target-smithy.png)

```
User → test.sh → Agent Lambda ──────────────→ AgentCore Gateway (MCP) ──────────→ Bedrock Runtime
│ │ │
Strands Agent CUSTOM_JWT Auth GATEWAY_IAM_ROLE
+ BedrockModel (Cognito JWKS) (IAM role signs
(Sonnet 4.6) + MCP Protocol requests — no
+ MCPClient + Tool Discovery API key needed)
│ + SmithyModel target │
Cognito JWT (loaded from S3) Converse API call
validated → Claude Haiku 4.5
```

## How It Works

1. User authenticates with Cognito and invokes the Lambda with a natural language prompt
2. The Lambda runs a Strands SDK agent with Claude Sonnet 4.6 as the LLM
3. The agent connects to AgentCore Gateway via MCP and discovers available tools
4. The gateway reads the official Bedrock Runtime Smithy model (from S3) and exposes operations as MCP tools
5. Sonnet decides to call the Converse tool, passing the user's prompt to Claude Haiku 4.5
6. The gateway assumes its IAM execution role, signs the request, and calls Bedrock Runtime
7. Haiku's response flows back through the gateway → MCP → agent → user

## Deploy

### Step 1: Prerequisites

- AWS CLI v2
- AWS SAM CLI
- Python 3.12+
- pip3
- `make` (used by the SAM Makefile build — no Docker required)
- AWS account with Bedrock and AgentCore enabled in `us-east-1`
- Bedrock model access enabled for Claude Sonnet 4.6 and Claude Haiku 4.5

### Step 2: Open a Terminal

Open a terminal on your machine and navigate to where you want to clone the project.

### Step 3: Clone the Repository

```bash
git clone https://github.com/aws-samples/serverless-patterns
cd serverless-patterns/strands-agentcore-smithy
```

### Step 4: Deploy

One command deploys everything:

```bash
bash scripts/deploy.sh
```

This will:
1. Validate the SAM template (`sam validate`)
2. Download the official Bedrock Runtime Smithy model and upload to S3
3. Build the Lambda with `sam build` (Makefile build — two-step pip3 install, no Docker)
4. Deploy the stack with `sam deploy` (Gateway, Cognito, Lambda, IAM roles)
5. Create a Cognito test user
6. Generate `scripts/test.sh` with baked-in config values

## Test

After deployment, test with:

```bash
./scripts/test.sh "Ask Haiku to write a short poem about the Beatles"
```

Or use the default prompt:

```bash
./scripts/test.sh
```

## Project Structure

```
├── infrastructure/
│ ├── template.yaml # SAM template (all AWS resources)
│ └── bedrock-runtime-2023-09-30.json # Official Smithy model (for tests)
├── Makefile # SAM Makefile build (no Docker)
├── scripts/
│ ├── deploy.sh # Full deployment script (SAM)
│ └── test.sh # Generated by deploy.sh
├── src/
│ ├── agent/
│ │ ├── handler.py # Lambda entry point
│ │ ├── agent_processor.py # Strands Agent + MCP lifecycle
│ │ └── strands_client.py # MCP client + Bedrock model factories
│ └── shared/
│ ├── models.py # UserContext, AgentRequest, AgentResponse
│ ├── jwt_utils.py # JWT validation (Cognito ID tokens)
│ ├── error_utils.py # Error response formatting
│ └── logging_utils.py # Structured logging
├── tests/
│ ├── unit/ # Unit tests
│ └── property/ # Property-based tests (Hypothesis)
├── requirements.txt # Lambda runtime dependencies
└── README.md
```

## Changing the Outer Agent Model

The outer agent model is set in `src/agent/strands_client.py`:

```python
# Default Bedrock model ID for Claude Sonnet 4.6
DEFAULT_MODEL_ID = "us.anthropic.claude-sonnet-4-6"
```

To use a different model, update `DEFAULT_MODEL_ID` to any Bedrock cross-region inference profile ID you have access to. For example:

```python
DEFAULT_MODEL_ID = "us.anthropic.claude-3-5-sonnet-20241022-v2:0"
```

Make sure the model is enabled in your AWS account under **Bedrock → Model access** before deploying.

> **Note:** The inner model (the one the agent calls as a tool) is separate — it's configured in the `SYSTEM_PROMPT` string in `src/agent/agent_processor.py`. See [Changing the Inner Model](#changing-the-inner-model) and [Key Design Decisions](#key-design-decisions) for more detail.

## Changing the Inner Model

The inner model is the one the outer agent calls *as a tool* via the AgentCore Gateway. It's configured inside the `SYSTEM_PROMPT` string in `src/agent/agent_processor.py`:

```python
SYSTEM_PROMPT = """You have access to Bedrock Runtime tools via MCP. Use the Converse tool (not InvokeModel) to call another model.

When using bedrock-runtime-target___Converse:
- Set modelId to: anthropic.claude-haiku-4-5-20251001-v1:0
...
```

To use a different model, replace the `modelId` value in that instruction:

```python
- Set modelId to: anthropic.claude-haiku-4-5-20251001-v1:0
```

A few things to keep in mind:

- The model ID here is passed as a parameter in the MCP tool call, not used directly by the Lambda — so it must be a valid Bedrock `modelId` (not a cross-region inference profile).
- Make sure the model supports the **Converse API** (most Claude models do, but check the [Bedrock docs](https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference-supported-models-features.html)).
- Enable the model in your AWS account under **Bedrock → Model access** before deploying.

## Key Design Decisions

### Official Smithy Model (not custom)
Custom Smithy models don't work for AWS service targets — the gateway needs the full endpoint resolution metadata (`aws.api#service` trait, partition data, FIPS/DualStack logic) that only official models have. The deploy script downloads the official model from the [AWS API Models repo](https://github.com/aws/api-models-aws).

### Converse API (not InvokeModel)
The `InvokeModel` operation uses a `Blob` with `httpPayload` trait for the request body, which doesn't map to MCP tool input parameters. `Converse` has structured `messages` and `modelId` fields that map cleanly.

### GATEWAY_IAM_ROLE (not API_KEY)
Since the target is an AWS service (Bedrock Runtime), the gateway uses its IAM execution role to sign requests. No API keys, no Secrets Manager secrets, no credential provider CLI commands.

### Agent code is target-agnostic
All code in `src/agent/` and `src/shared/` connects to the gateway via MCP and doesn't reference Bedrock, DynamoDB, or any specific target. The same code works with any gateway target type.

## Teardown

```bash
aws cloudformation delete-stack --stack-name agentcore-smithy-bedrock --region us-east-1
aws s3 rb s3://agentcore-smithy-bedrock-smithy-models --force --region us-east-1
```

## Run Tests

```bash
python -m pytest tests/ -v
```

---

Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 86 additions & 0 deletions strands-agentcore-smithy/example-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"title": "Strands Agent on Lambda with AgentCore Smithy Bedrock Target",
"description": "Strands SDK agent on Lambda calls Bedrock Runtime via AgentCore Gateway using a Smithy model target, with Cognito JWT auth and IAM role signing.",
"language": "Python",
"level": "300",
"framework": "SAM",
"introBox": {
"headline": "How it works",
"text": [
"The user authenticates with Amazon Cognito and receives a JWT token.",
"The JWT is passed to an Agent Lambda which uses the Strands Agents SDK to create an AI agent backed by Amazon Bedrock (Claude Sonnet 4.6 cross-region inference profile).",
"The Strands Agent connects to an AgentCore Gateway MCP endpoint, dynamically discovering available Bedrock Runtime operations via the MCP tools/list protocol.",
"The AgentCore Gateway validates the JWT token using a CUSTOM_JWT authorizer backed by Cognito, then routes MCP tool calls to the Smithy model target.",
"The gateway target uses the official Bedrock Runtime Smithy model (loaded from S3) to expose Bedrock Runtime operations as MCP tools.",
"The gateway uses its IAM execution role (GATEWAY_IAM_ROLE) to sign requests to Bedrock Runtime — no API keys or Secrets Manager secrets are required.",
"The outer agent (Claude Sonnet 4.6) calls the Converse tool, which invokes Claude Haiku 4.5 as the inner model to generate the response.",
"The Strands SDK handles the full agentic loop: tool discovery, Claude tool selection, MCP tool execution, and response formatting — all in a single agent() call."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/strands-agentcore-smithy",
"templateURL": "serverless-patterns/strands-agentcore-smithy",
"projectFolder": "strands-agentcore-smithy",
"templateFile": "infrastructure/template.yaml"
}
},
"resources": {
"bullets": [
{
"text": "Strands Agents SDK",
"link": "https://github.com/strands-agents/sdk-python"
},
{
"text": "Amazon Bedrock AgentCore Gateway",
"link": "https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway.html"
},
{
"text": "AgentCore Gateway Smithy Model Target",
"link": "https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-building-smithy-targets.html"
},
{
"text": "Model Context Protocol (MCP)",
"link": "https://modelcontextprotocol.io/"
},
{
"text": "Amazon Cognito JWT Authentication",
"link": "https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html"
},
{
"text": "Amazon Bedrock Converse API",
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html"
},
{
"text": "Amazon Bedrock Cross-Region Inference",
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html"
}
]
},
"deploy": {
"text": [
"bash scripts/deploy.sh"
]
},
"testing": {
"text": [
"./scripts/test.sh",
"./scripts/test.sh 'Ask Haiku to write a short poem about the Beatles'"
]
},
"cleanup": {
"text": [
"aws cloudformation delete-stack --stack-name agentcore-smithy-bedrock --region us-east-1",
"aws s3 rb s3://agentcore-smithy-bedrock-smithy-models --force --region us-east-1"
]
},
"authors": [
{
"name": "Mike Hume",
"image": "https://serverlessland.com/assets/images/contributors/mike-hume.jpg",
"bio": "AWS Senior Solutions Architect & UKPS Serverless Lead.",
"linkedin": "michael-hume-4663bb64",
"twitter": ""
}
]
}
Loading