AWS Agent built with Strand Agent framework and deployed to Bedrock Agentcore


In this post, I will show you how I created my AWS Agent built with Strand Agent framework and deployed to Bedrock Agentcore.

First you need to create an execution role for AgentCore Runtime.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ECRImageAccess",
            "Effect": "Allow",
            "Action": [
                "ecr:BatchGetImage",
                "ecr:GetDownloadUrlForLayer"
            ],
            "Resource": [
                "arn:aws:ecr:us-east-1:123456789012:repository/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogStreams",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:123456789012:log-group:/aws/bedrock-agentcore/runtimes/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogGroups"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:123456789012:log-group:*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:123456789012:log-group:/aws/bedrock-agentcore/runtimes/*:log-stream:*"
            ]
        },
        {
            "Sid": "ECRTokenAccess",
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords",
                "xray:GetSamplingRules",
                "xray:GetSamplingTargets"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": "cloudwatch:PutMetricData",
            "Condition": {
                "StringEquals": {
                    "cloudwatch:namespace": "bedrock-agentcore"
                }
            }
        },
        {
            "Sid": "GetAgentAccessToken",
            "Effect": "Allow",
            "Action": [
                "bedrock-agentcore:GetWorkloadAccessToken",
                "bedrock-agentcore:GetWorkloadAccessTokenForJWT",
                "bedrock-agentcore:GetWorkloadAccessTokenForUserId"
            ],
            "Resource": [
                "arn:aws:bedrock-agentcore:us-east-1:123456789012:workload-identity-directory/default",
                "arn:aws:bedrock-agentcore:us-east-1:123456789012:workload-identity-directory/default/workload-identity/agent*"
            ]
        },
        {
            "Sid": "BedrockModelInvocation",
            "Effect": "Allow",
            "Action": [
                "bedrock:InvokeModel",
                "bedrock:InvokeModelWithResponseStream"
            ],
            "Resource": [
                "arn:aws:bedrock:*::foundation-model/*",
                "arn:aws:bedrock:us-east-1:123456789012:*"
            ]
        }
    ]
}
Enter fullscreen mode

Exit fullscreen mode

The import part is in “arn:aws:bedrock-agentcore:us-east-1:123456789012:workload-identity-directory/default/workload-identity/agent*”, agent* is set here so that you can create agent starts with agent and then just atttach this policy, you don’t need to create a new policy or role for new agent.

Also you need some more policy so that the tools from AWS MCP server can have access to your resource and do the task.

For this project, I want to create a supervisor agent that control other AWS MCP agents using Strands Agents framework and deploy Bedrock AgentCore.

The only LLM is use is us.anthropic.claude-3-7-sonnet-20250219-v1:0.

bedrock_model = BedrockModel(
        model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
        region_name="us-east-1",
    )
Enter fullscreen mode

Exit fullscreen mode

Here is the prompt I use for my orchestrator agent, it works pretty well:

SUPERVISOR_AGENT_PROMPT = """
You are Orchestrator Agent, a sophisticated orchestrator designed to coordinate support across AWS services.
Your role is to analyze incoming queries and route them to the most appropriate specialized agent.

Available Specialized Agents:

SPECIALIZED SERVICES:
- AWS CloudTrail Assistant: Security auditing, compliance monitoring, API call tracking, and forensic analysis
- AWS CloudWatch Assistant: Monitoring, logging, observability, alarm management, and performance analysis
- AWS Cost Assistant: Cost analysis, spend reports, billing optimization, and usage tracking
- AWS Diagram Assistant: Architecture visualization, AWS diagram generation, and infrastructure mapping
- AWS Documentation Researcher: Search AWS documentation for technical information and best practices
- AWS DynamoDB Assistant: NoSQL database operations, data modeling, and performance optimization
- AWS IAM Assistant: Identity and access management, policy analysis, and security audits
- AWS Nova Canvas: AI image generation and creative visual content
- AWS Terraform Assistant: Infrastructure as code, Terraform best practices, and security compliance

Key Responsibilities:
- Accurately classify and route queries to appropriate specialized agents
- Maintain conversation context using memory for personalized responses
- Coordinate multi-step problems requiring multiple agents
- Provide cohesive responses when multiple agents are needed

Decision Protocol:
- Security audits/compliance/API tracking → AWS CloudTrail Assistant
- Monitoring/logging/observability/alarms → AWS CloudWatch Assistant
- Cost/billing/usage analysis → AWS Cost Assistant
- Architecture diagrams/visualization → AWS Diagram Assistant
- Documentation/research/best practices → AWS Documentation Researcher
- NoSQL/DynamoDB/data modeling → AWS DynamoDB Assistant
- IAM/security/permissions/policies → AWS IAM Assistant
- Image creation/AI art → AWS Nova Canvas
- Infrastructure/Terraform/IaC → AWS Terraform Assistant


Always leverage user context from memory to provide personalized assistance. Just give me enough answer, do not overthinking.
"""
Enter fullscreen mode

Exit fullscreen mode

I have created 9 agents for 9 diferrent AWS MCP servers:

Here is the list of all AWS MCP servers: https://github.com/awslabs/mcp/tree/main

Here is an example of an agent:

import os

from mcp import StdioServerParameters, stdio_client
from strands import Agent, tool
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient
from strands_tools import file_write, think


@tool
def aws_cost_assistant(query: str) -> str:
    bedrock_model = BedrockModel(
        model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
        region_name="us-east-1",
    )

    response = str()

    try:
        env = {}
        cost_mcp_server = MCPClient(
            lambda: stdio_client(
                StdioServerParameters(
                    command="uvx",
                    args=["awslabs.cost-explorer-mcp-server@latest"],
                    env=env,
                )
            )
        )

        with cost_mcp_server:

            tools = cost_mcp_server.list_tools_sync() + [think]

            cost_agent = Agent(
                model=bedrock_model,
                system_prompt="""You are a AWS account cost analyst. You can do the following tasks:
                - Amazon EC2 Spend Analysis: View detailed breakdowns of EC2 spending for the last day
                - Amazon Bedrock Spend Analysis: View breakdown by region, users and models over the last 30 days
                - Service Spend Reports: Analyze spending across all AWS services for the last 30 days
                - Detailed Cost Breakdown: Get granular cost data by day, region, service, and instance type
                - Interactive Interface: Use Claude to query your cost data through natural language
                """,
                tools=tools,
            )
            response = str(cost_agent(query))
            print("\n\n")

        if len(response) > 0:
            return response

        return "I apologize, but I couldn't properly analyze your question. Could you please rephrase or provide more context?"

    except Exception as e:
        return f"Error processing your query: {str(e)}"


if __name__ == "__main__":
    aws_cost_assistant("Get my cost usage of this month. I just the number of money.")

Enter fullscreen mode

Exit fullscreen mode

For every agent, I use think tool from Strand Agent so that the agent can brainstorm better.

At the end of every agent file, I added:

if __name__ == "__main__":
    aws_cost_assistant("Get my usage of last 7 days per service")
Enter fullscreen mode

Exit fullscreen mode

I added this code so that I can test the agent independently just by running the file, check that my agent is working or not:

py .\aws_cost_assistant.py
Enter fullscreen mode

Exit fullscreen mode

You don’t have to invoke the agent through orchestrator agent.

I’ve also created the memory hook using AgentCore memory. The memory hook provides:



OrchestratorMemoryHooks

  1. User Context Retrieval: Automatically retrieves relevant context before processing queries
  2. Interaction Storage: Saves user-agent interactions for personalized responses
  3. Multi-Strategy Memory: Supports user preferences and semantic memory storage
  4. Session Management: Maintains context across conversation sessions



MemoryManager

  1. Resource Management: Creates and manages AgentCore Memory resources
  2. Strategy Configuration: Configures user preference and semantic memory strategies
  3. Actor-Specific Memory: Isolated memory namespaces for different users
  4. Automatic Expiry: 90-day event expiry for data management

Start Docker and run commands to launch your agent AgentCore Runtime:

agentcore configure -e agent.py --execution-role arn:aws:iam::123456789012:role/agentcore_role

agentcore launch
Enter fullscreen mode

Exit fullscreen mode

I’ve prepared a simple chat app to visualize the agent. You can find it in chat_app folder and run:

streamlit run agent_chat_app.py --server.headless true
Enter fullscreen mode

Exit fullscreen mode

Go to View invocation code on your agent console, get agentRuntimeArn and runtimeSessionId. Paste them in the settings:

Now you can start working with the agent. Try asking this:

Get my cost usage of this month. I just the number of money. 
Enter fullscreen mode

Exit fullscreen mode

The response you get from the agent also have token usage, tool used and I also visualize that:

All of the above is created based on the formatted response from the agent. I’ve included everything I could.

Here is an example I told my agent to create a DynamoDB table

You can test the agent in agent sandbox on console:
Here is an example with aws_diagram_assistant:

Here I was asking about my chat history. As you can see that the agent can access the memory, everything is working as expected:

That is all for my AWS Agent built with Strand Agent framework and deployed to Bedrock Agentcore.
Have fun coding your agent!

Reference:

  1. https://github.com/Hung-00/aws-strand-agent-core
  2. https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html
  3. https://strandsagents.com/latest/documentation/docs/
  4. https://github.com/strands-agents/tools
  5. https://awslabs.github.io/mcp/



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *