
Building AI Agents from Zero to Hero
Built AI agents with Strands SDK, Bedrock, and MCP from simple chatbots to an AWS Study Buddy with memory and tools.
š Introduction
I participated in the AWSUG MDU April Skill Sprint, a 5-challenge journey to build AI agents from scratch using the Strands Agents SDK and Amazon Bedrock. Each challenge builds on the previous one, going from a simple chatbot to a full MCP-powered study assistant.
Here's my complete journey through all 5 challenges, including the code, architecture, errors I hit, and how I solved them.
šŗļø The Journey at a Glance

Challenge 1: My First Agent ā
Goal
Create a basic conversational agent using Strands SDK with a local LLM (Ollama).
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from strands import Agent
from strands.models.ollama import OllamaModel
model = OllamaModel(
host="http://localhost:11434",
model_id="llama3.2:3b"
)
agent = Agent(
model=model,
system_prompt="You are a helpful AI assistant.",
tools=[]
)
response = agent("What is Python?")
print(f"š¤ Agent: {response}")What I Learned
- Strands SDK makes agent creation dead simple ā 3 lines of config
OllamaModelconnects to a local LLM (no cloud needed for testing)- The
system_promptshapes the agent's personality tools=[]means no tools ā just pure conversation
Output

1
2
š¤ Agent: Python is a high-level, interpreted programming language known for
its simplicity and readability...Challenge 2: Adding Tools āā
Goal
Give the agent superpowers with custom tools using Amazon Nova Pro via Bedrock.
Architecture

Key Code ā The @tool Decorator
1
2
3
4
5
6
7
8
9
10
11
12
13
from strands.tools import tool
def weather(city: str) -\> str:
"""Get the current weather for a given city.
Args:
city: The name of the city to get weather for.
"""
response = requests.get(f"https://wttr.in/{city}?format=j1")
data = response.json()
current = data["current_condition"][0]
return f"Weather in {city}: {current['weatherDesc'][0]['value']}, {current['temp_C']}°C"How Tool Selection Works
The agent reads the docstring and type annotations to understand:
- When to use the tool (docstring describes purpose)
- What to pass (type annotations define parameters)
- What to expect back (return type)
You can see the agent's reasoning in
\<thinking\> tags:1
2
3
\<thinking\> I need to use the 'weather' tool to get the current weather
conditions in Chennai. \</thinking\>
Tool #1: weatherOutput

1
2
3
4
5
š§® Math: 42 * 17 = 714
š¤ļø Weather: Chennai is thundery, 35°C, humidity 51%
š Age: Someone born Jan 15, 2000 is 26 years old
š Conversion: 100 km = 62.14 miles
š”ļø Multi-tool: Delhi is 44°C (111.2°F) ā used weather + unit_converter!Key Insight
The agent chains multiple tools automatically. When asked "weather in Delhi in Fahrenheit", it calls
weather first, then unit_converter without being told to.Challenge 3: Persistent Memory āā
Goal
Give the agent memory that survives program restarts using FAISS vector store.
Architecture

The Two Types of Memory
| Type | Persists? | How |
|---|---|---|
| Conversation History | ā | Messages sent to model each turn |
| mem0_memory + FAISS | ā | Vectors stored on disk |
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os
os.environ["MEM0_LLM_MODEL"] = "amazon.nova-pro-v1:0"
os.environ["MEM0_EMBEDDER_MODEL"] = "amazon.titan-embed-text-v2:0"
os.environ["BYPASS_TOOL_CONSENT"] = "true"
from strands_tools import mem0_memory
agent = Agent(model=model, tools=[mem0_memory])
# Store
agent.tool.mem0_memory(action="store", content="My name is DD", user_id="dd_user")
# Retrieve
agent.tool.mem0_memory(action="retrieve", query="name", user_id="dd_user")š„ Errors I Hit (and Fixes)
| Error | Root Cause | Fix |
|---|---|---|
No module named 'strands_tools' | Wrong package name | pip install strands-agents-tools |
No module named 'mem0' | Missing dependency | pip install "strands-agents-tools[mem0-memory]" |
No module named 'opensearchpy' | Missing dependency | pip install opensearch-py |
Unsupported vector store provider: faiss | mem0ai too new (1.x) | pip install "mem0ai\>=0.1.99,\<1.0.0" |
Unsupported embedding provider: aws_bedrock | Same version issue | Same fix as above |
| Authorization error | mem0 defaults to Claude Haiku internally | Set MEM0_LLM_MODEL env var |
output :

Critical Lesson
>
mem0ai must be \<1.0.0. Version 1.x removed FAISS and aws_bedrock support. Always install with: pip install "strands-agents-tools[mem0-memory]"Challenge 4: The Full Agent āāā
Goal
Combine everything ā tools, memory and streaming ā in an interactive chat.
Architecture

Key Innovation: Simple File-Based Memory
After fighting
mem0ai version issues, I replaced it with a dead-simple JSON approach:1
2
3
4
5
6
7
8
9
10
11
12
13
def remember(key: str, value: str) -\> str:
"""Store info to persistent memory."""
memory = json.load(open("memory.json"))
memory[key] = value
json.dump(memory, open("memory.json", "w"))
return f"ā
Stored: {key} = {value}"
def recall(key: str) -\> str:
"""Retrieve from memory. Use key='all' for everything."""
memory = json.load(open("memory.json"))
return memory.get(key, "Not found")Why this works better:
- Zero dependencies
- No version conflicts
- No auth errors
- Always works
- Persists across restarts
Streaming Callback
1
2
3
4
5
def streaming_callback(**kwargs):
if "data" in kwargs:
print(kwargs["data"], end="", flush=True)
if "current_tool_use" in kwargs and kwargs["current_tool_use"].get("name"):
print(f"\nš§ Using tool: {kwargs['current_tool_use']['name']}")> Important: Use
**kwargs, NOT positional arguments. The SDK passes everything as keyword args.output

Demo Conversation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
š§ You: Remember my name is DD and I'm from Tanjore
š¤ Buddy: š§ Using tool: remember
š§ Using tool: remember
ā
Stored! Your name is DD and you're from Tanjore! šļø
š§ You: What's the weather in my city?
š¤ Buddy: š§ Using tool: recall
š§ Using tool: weather
Weather in Tanjore: Sunny, 38°C āļø
š§ You: How old is someone born 2002-03-15? Also 365 * 24?
š¤ Buddy: š§ Using tool: age_calculator
š§ Using tool: calculator
24 years old! And 365 Ć 24 = 8,760 hours in a year! š§®Challenge 5: MCP-Powered Innovation
Goal
Build a creative agent using MCP (Model Context Protocol) that solves a real problem.
My Project: AWS Study Buddy š
An interactive AWS tutor that:
- š Searches real AWS documentation via MCP
- š§ Remembers what you've studied
- š Quizzes you on learned topics
- š§® Calculates AWS costs
- ā” Streams responses in real time
more details about MCP project: Building an AWS Study Buddy with MCP + Strands Agents SDK | AWS Builder CenterĀ
Architecture

MCP Connection Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from strands.tools.mcp import MCPClient
from mcp import StdioServerParameters, stdio_client
aws_docs_mcp = MCPClient(
lambda: stdio_client(
StdioServerParameters(
command="uvx",
args=["awslabs.aws-documentation-mcp-server@latest"],
env={**os.environ, "FASTMCP_LOG_LEVEL": "ERROR"}
)
)
)
with aws_docs_mcp:
mcp_tools = aws_docs_mcp.list_tools_sync()
all_tools = mcp_tools + [save_note, get_notes, record_quiz_score, calculator]
agent = Agent(model=model, tools=all_tools)Learning Flow

output :

Demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
š AWS Study Buddy ā Learn AWS with Official Docs + Memory
š§ You: Explain Lambda in simple terms
š¤ Study Buddy:
š§ Using tool: search_documentation
š§ Using tool: read_documentation
AWS Lambda is serverless compute! ā”
⢠Run code without managing servers
⢠Pay only for compute time used
⢠Triggers: API Gateway, S3, DynamoDB, etc.
⢠Max execution: 15 minutes
⢠Supports Python, Node.js, Java, Go, .NET
š§ Using tool: save_note
š Note saved for 'Lambda'! You've now studied 1 topic.
š§ You: How much for 1 million Lambda requests?
š¤ Study Buddy:
š§ Using tool: calculator
Lambda pricing: $0.20 per 1M requests
1,000,000 Ć $0.0000002 = $0.20/month š°
Plus compute time based on memory and duration.
š§ You: Quiz me!
š¤ Study Buddy:
š§ Using tool: get_notes
Q1: What's the max execution time for Lambda?
Q2: Name 3 Lambda triggers.
Q3: Do you manage servers with Lambda?š Summary: Skills Progression
| Challenge | New Skill | Model | Key Feature |
|---|---|---|---|
| 1 | Agent basics | Ollama (local) | System prompt, simple Q&A |
| 2 | @tool decorator | Nova Pro (Bedrock) | Weather, age calc, unit converter |
| 3 | Persistent memory | Nova Pro + Titan Embed | FAISS/JSON storage across sessions |
| 4 | Streaming + multi-tool | Nova Pro | Callback handler, interactive chat |
| 5 | MCP protocol | Nova Pro + MCP Server | AWS docs search, quiz system |
š„ Top Errors & Lessons
| # | Error | Lesson |
|---|---|---|
| 1 | pip install strands-tools fails | Package is strands-agents-tools |
| 2 | mem0ai 1.x breaks everything | Pin to \<1.0.0 or use [mem0-memory] extra |
| 3 | streaming_callback(event) fails | Use **kwargs not positional args |
| 4 | mem0 authorization errors | Set MEM0_LLM_MODEL env var or use simple JSON memory |
| 5 | MCP server not found | Install uv for uvx command |
š ļø Full Tech Stack
| Component | Technology |
|---|---|
| Agent Framework | Strands Agents SDK |
| LLM | Amazon Nova Pro v1 (Bedrock) |
| Embeddings | Amazon Titan Embed Text V2 |
| MCP Server | awslabs.aws-documentation-mcp-server |
| Memory | JSON file (simple) / FAISS (advanced) |
| Weather API | wttr.in |
| Language | Python 3.12 |
| Region | us-east-1 |
šļø Project Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
may-skill-sprint/
āāā challenge-1-first-agent/
ā āāā starter.py # Basic agent with Ollama
āāā challenge-2-tools/
ā āāā starter.py # Custom tools + Bedrock
āāā challenge-3-memory/
ā āāā starter.py # mem0_memory + FAISS
ā āāā verify_memory.py # Persistence test
ā āāā debug_mem0.py # Debug script
āāā challenge-4-full-agent/
ā āāā starter.py # Full interactive agent
ā āāā memory.json # Persistent memory store
āāā challenge-5-mcp-agent/
āāā starter.py # MCP-powered study buddy
āāā study_notes.json # Study progress
š Final Thoughts
Building AI agents is easier than you think but getting the dependencies right is harder than you'd expect. The Strands SDK itself is elegant and simple. The pain points are all in the ecosystem (version conflicts, auth issues, package naming).
My biggest takeaway: start simple, add complexity gradually. Challenge 1 ā 5 is the perfect progression. And when something complex breaks (like mem0), don't be afraid to replace it with something simpler that just works.
The future of AI development is agents + tools + memory + MCP. This sprint gave me hands-on experience with all four.
Built with ā¤ļø by DD for the AWSUG MDU April Skill Sprint 2026
Thank you for taking the time to read my article! If you found it helpful, feel free to like, share, and drop your thoughts in the comments; Iād love to hear from you.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article