build ai agent claude-agent-sdk mcp personal-ai-assistant

🎯 The Grand Finale! Ready to Build Your Own AI Assistant?
Thank you so much for sticking with us through all 9 episodes! Today is the series finale. We’re going to take every puzzle piece we’ve collected since EP1 and put them all together to build a real, working personal AI assistant.
For real? We can actually build something useful using everything we learned over 9 episodes?
Absolutely! Remember the Agentic AI we first met in EP1? Now we can build one ourselves. And don’t worry — we won’t try to do everything at once. We’ll evolve it in 5 stages, like stacking LEGO blocks!
One of the hottest trends of 2026 is personal AI assistants. Building an AI agent has never been easier, thanks to the Claude Agent SDK and FastMCP. We can build one ourselves — and today, we’ll walk through the entire process together.

The diagram above is today’s complete roadmap. We’ll go through 5 stages of building an AI agent — from Stage 1 to Stage 5, adding features step by step to evolve our assistant.
🔧 Stage 1 — Creating MCP Tools (EP7 Review)
Since our assistant needs abilities, we start by building tools first, right?
Exactly! Remember MCP from EP7? We’ll use FastMCP’s @mcp.tool() decorator to create 6 tools — 3 for memos, 2 for scheduling, and 1 for weather!
The first step is building the tools as an MCP server. The key to building an AI agent is starting with the tools. With FastMCP, all you need is a decorator on a Python function and you’re done.
# tools_server.py (Stage 1)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("personal-assistant")
@mcp.tool()
def save_memo(
title: str, content: str
) -> str:
"""Save a memo with title/content."""
memos = _load_json(MEMOS_FILE)
memo = {
"title": title,
"content": content,
"created":
datetime.now().isoformat(),
}
memos.append(memo)
_save_json(MEMOS_FILE, memos)
return f"Memo saved: '{title}'"
@mcp.tool()
def get_schedule(date: str) -> str:
"""Get all events for a date."""
schedule = _load_json(SCHEDULE_FILE)
events = [
e for e in schedule
if e["date"] == date
]
if not events:
return f"No events on {date}"
lines = []
for e in events:
lines.append(
f"- {e['time']}: {e['event']}"
)
return (
f"Schedule for {date}:\n"
+ "\n".join(lines)
)
save_memo saves a memo to a JSON file, and get_schedule retrieves events for a specific date. Along with these, we’ll also create search_memos, list_memos, add_schedule, and get_weather — 6 tools total. You can find the complete code on GitHub.
One function = one tool. Clean and simple. But how do we connect these to an agent?
🔌 Stage 2 — Connecting a Basic Assistant (EP5+EP8 Review)
Remember in EP5 when we wrote the agent loop from scratch — over 50 lines? With the SDK, it’s just one call to query()! The SDK from EP8 handles all the loop logic automatically.
# simple_assistant.py (Stage 2)
import asyncio
from claude_agent_sdk import (
query,
ClaudeAgentOptions,
MCPServerStdio,
ResultMessage,
)
async def main():
options = ClaudeAgentOptions(
allowed_tools=[
# Built-in tools
"WebSearch", "Read", "Write",
# MCP tools
"mcp__assistant__save_memo",
"mcp__assistant__search_memos",
"mcp__assistant__list_memos",
"mcp__assistant__add_schedule",
"mcp__assistant__get_schedule",
"mcp__assistant__get_weather",
],
mcp_servers={
"assistant": MCPServerStdio(
command="python",
args=["tools_server.py"],
)
},
max_turns=10,
)
async for msg in query(
prompt="Save a memo titled "
"'Meeting' with content "
"'Team sync at 3pm'.",
options=options,
):
if isinstance(msg, ResultMessage):
if msg.subtype == "success":
print(msg.result)
asyncio.run(main())
The key here is MCPServerStdio. The SDK automatically launches tools_server.py as a child process, so you don’t need to open two terminals. With 6 MCP tools + 3 built-in tools, we now have an assistant with 9 tools total! Building an AI agent — simpler than you thought, right?
It works, but… it has no personality, and it could write to dangerous files. That’s a bit concerning, isn’t it?
🛡️ Stage 3 — A Smarter Assistant: Hooks and System Prompts
That’s why in Stage 3, we add two things. First, we give it a personality using system prompts from EP6. Second, we introduce a brand new concept you haven’t seen before — Hooks!
Hooks are callback functions that intercept events when an agent uses tools. PreToolUse (before execution) can block dangerous actions, while PostToolUse (after execution) can log all activity. Think of them as the agent’s security system.
Intercept? You mean catching tool calls in the middle?
Exactly! Here’s a good analogy: PreToolUse is like a door lock — it checks before anyone enters and either allows or blocks access. PostToolUse is like a security camera — it records what happened so you can review it later.

The diagram above makes the flow clear. When the agent tries to use a tool, the PreToolUse Hook runs first. If allowed, the tool executes and then the PostToolUse Hook logs the activity.
# smart_assistant.py (Stage 3)
# Hook 1: Safety guard (PreToolUse)
async def safety_guard(
input_data, tool_use_id, context
):
"""Block writes to system paths."""
tool = input_data["tool_name"]
tool_input = input_data["tool_input"]
if tool in ("Write", "Edit"):
path = tool_input.get(
"file_path", ""
)
blocked = [
"/etc/", "/usr/",
"C:\\Windows",
"C:\\Program",
]
if any(
p in path for p in blocked
):
return {
"hookSpecificOutput": {
"hookEventName":
input_data[
"hook_event_name"
],
"permissionDecision":
"deny",
"permissionDecisionReason":
"System path blocked",
}
}
return {} # Allow
# Hook 2: Activity logger (PostToolUse)
async def activity_logger(
input_data, tool_use_id, context
):
"""Log all tool usage."""
tool = input_data["tool_name"]
print(f" [LOG] Tool used: {tool}")
return {}
safety_guard returns "deny" to block Write or Edit tools from accessing system paths. activity_logger logs all tool usage to the console.
Registering these Hooks is just as straightforward.
# Hooks registration in options
options = ClaudeAgentOptions(
system_prompt=(
"You are a friendly, helpful "
"personal AI assistant. "
"Your name is 'Buddy'."
),
hooks={
"PreToolUse": [
HookMatcher(
matcher="Write|Edit",
hooks=[safety_guard],
),
],
"PostToolUse": [
HookMatcher(
hooks=[activity_logger],
),
],
},
# ... tools and mcp_servers
)
By providing a regex pattern to HookMatcher‘s matcher, the Hook only applies to matching tools. If you omit matcher like in PostToolUse, the Hook applies to all tools. We’ve also given our assistant a friendly “Buddy” personality through the system prompt!

👥 Stage 4 — Team Assistant: Multi-Agent (EP9 Review)
A solo assistant is fine, but building a team of specialists makes it way more powerful! We’ll apply the orchestrator pattern from EP9.
EP9’s blog team had Researcher, Writer, and Reviewer, so this time we’re building an assistant team?
Same pattern, different specialists! This time, we’ll build a team of 3: Scheduler (calendar), Researcher (search), and Assistant (memos/files).
# team_assistant.py (Stage 4)
agents = {
"scheduler": AgentDefinition(
description=(
"Manages calendar and "
"schedules."
),
prompt=(
"You are a precise "
"scheduling assistant."
),
tools=[
"mcp__assistant__"
"add_schedule",
"mcp__assistant__"
"get_schedule",
],
),
"researcher": AgentDefinition(
description=(
"Searches the web for "
"information."
),
prompt=(
"You are a thorough "
"research assistant."
),
tools=[
"WebSearch", "WebFetch",
],
),
"assistant": AgentDefinition(
description=(
"Handles memos, files, "
"and general tasks."
),
prompt=(
"You are a helpful "
"personal assistant."
),
tools=[
"Read", "Write",
"mcp__assistant__save_memo",
"mcp__assistant__"
"search_memos",
],
),
}
# Orchestrator
options = ClaudeAgentOptions(
system_prompt=(
"You are a team manager "
"coordinating 3 specialists."
),
allowed_tools=["Agent"],
agents=agents,
max_turns=15,
)
The manager agent analyzes the user’s request and delegates to the right specialist. If you say “Book a dentist appointment, search for Seoul cafes, and save the results as a memo,” it chains Scheduler, Researcher, and then Assistant! Building an AI agent with this kind of team structure makes it far more capable.

The architecture diagram above shows the full structure through Stage 4. The MCP server provides the tools, the SDK runs the agent loop, and the orchestrator coordinates 3 specialists.
💾 Stage 5 — An Assistant That Remembers: Sessions (EP4 Review + New)
This is pretty good so far, but there’s one problem. Once the conversation ends, it forgets everything, right?
Remember learning about context and memory in EP4? Today I’ll show you how to implement that with the SDK — meet Sessions!
Sessions let you connect multiple query() calls into a single continuous conversation. Capture the session_id and pass it via the resume parameter, and the full context from the previous conversation is restored. Think of it like a bookmark — it remembers “where you left off.”
# persistent_assistant.py (Stage 5)
async def main():
# Turn 1: Save something
session_id = None
async for msg in query(
prompt=(
"Save a memo titled "
"'Project Ideas' with "
"content 'Build a recipe "
"recommender using "
"MCP tools'."
),
options=build_options(),
):
if isinstance(
msg, ResultMessage
):
# Capture session_id!
session_id = msg.session_id
if msg.subtype == "success":
print(msg.result)
print(f"Session: {session_id}")
# Turn 2: Ask WITH memory
async for msg in query(
prompt=(
"What memo did I just save?"
),
options=ClaudeAgentOptions(
**{
**build_options()
.__dict__,
"resume": session_id,
}
),
):
if isinstance(
msg, ResultMessage
):
if msg.subtype == "success":
print(msg.result)
It all comes down to just two lines. Capture session_id from ResultMessage, then pass resume=session_id to the next query() call — that’s it! The last puzzle piece for building an AI agent is now in place.
WITH vs WITHOUT Comparison
Let’s see the power of Sessions in action.
| Scenario | Question | Response |
|---|---|---|
| WITHOUT session | “What did I just save?” | “I don’t have any previous conversation history to check.” |
| WITH session | “What did I just save?” | “You saved a memo titled ‘Project Ideas’!” |
Without a session, every call starts a completely fresh conversation with no memory of what came before. With a session, it remembers everything perfectly, as if the conversation never stopped.
If managing session_id manually feels tedious, try ClaudeSDKClient. Inside an async with ClaudeSDKClient() as c: block, just call await c.query() multiple times and the session is maintained automatically!
📋 EP1–EP10 Complete Recap
Every concept from all 10 episodes came together today! Let me give you a quick overview.

| Episode | Key Concept | Used in EP10 |
|---|---|---|
| EP1 | First Look at Agentic AI | We built it! The reality behind “AI that acts on its own” |
| EP2 | LLM (The Brain) | Every decision our assistant makes is powered by the LLM |
| EP3 | Tool Use (The Hands) | 6 MCP tools + 3 built-in tools |
| EP4 | Context & Memory | Conversation memory via Sessions |
| EP5 | Agent Loop | Handled automatically by the SDK (one query() call) |
| EP6 | System Prompts | Gave “Buddy” its personality |
| EP7 | MCP Protocol | Built a custom tool server with FastMCP |
| EP8 | Claude Agent SDK | Used query(), Options, MCPServerStdio |
| EP9 | Multi-Agent | 3-agent orchestrator team |
| EP10 | Capstone Project | Personal AI assistant completed in 5 stages! |
A customized AI agent tailored to an individual user. It leverages various tools — memo management, scheduling, web search, and more — to act like a personal secretary. As of 2026, platforms like OpenClaw (over 250k GitHub stars) and many others are implementing this very pattern.
📚 References
- Claude Agent SDK Documentation — Complete SDK guide
- SDK Hooks Documentation — Detailed PreToolUse, PostToolUse specs
- SDK Sessions Documentation — Session management guide
- FastMCP GitHub — v3.1.0, 23.6k stars, 1M+ daily downloads
- EP10 Full Code (GitHub) — All 5 Python files
- Building Effective Agents — Anthropic’s official agent design guide
The 5-stage assistant we built today is for learning purposes. For production use, it’s best to pick only the features you need. Multi-agent setups increase API calls, so keep that in mind!
◀ Previous: EP9 — AI Teamwork: Multi-Agent Systems

✅ Wrapping Up — This Isn’t the End, It’s Just the Beginning!
Our 10-episode journey has come to a close! We started with “What even is Agentic AI?” and now you can build your own personal AI assistant in 5 stages. That’s incredible — you should be proud!
We built tools with MCP, connected them with the SDK, added safety with Hooks, scaled up with a team, and topped it off with memory via Sessions. We really used everything.
And this is just the beginning! There are endless ways to extend this assistant. Add email tools, integrate a calendar API, or deploy it as a Discord bot. Go ahead and build your own AI assistant!
The complete code for all 5 files we built today is available on the GitHub repository. Our journey of building an AI agent may be over, but your AI assistant development is just getting started! Thank you for joining Claudie’s Agentic AI Classroom!