Phase 5: Model Context Protocol (MCP) · 75 min · Python · MCP SDK · Anthropic SDK
Building MCP Servers
Tool descriptions are system prompts for your tool — the model uses them to decide when and how to call each one.
Hiring signal: Build us an MCP server for our internal tools is a concrete take-home assignment that appears in AI engineer hiring. Companies want to see correct tool schemas, good descriptions, proper error handling, and working client connectivity — all demo-able from this lesson.
What you will learn
- Build a production-ready MCP server using the Python MCP SDK with @server.list_tools() and @server.call_tool()
- Write tool descriptions that tell the model when to call, what to pass, what it returns, and when to use a different tool
- Return structured error responses that give the model enough information to self-correct
The Problem
Your company has a customer database, a ticket system, and a deployment API. Today, every AI feature that needs any of these tools requires a custom integration written by an engineer. When you add a new tool, every agent needs to be updated. When the underlying API changes, you fix it in five places.
With MCP, you build each integration once as an MCP server. The customer database server exposes search_customers, get_customer, get_orders. The ticket system exposes list_tickets, create_ticket, update_ticket. Deploy them, and every agent in the company gets access to all three — without touching the agent code.
This lesson is how you build those servers correctly. The protocol is straightforward. The quality trap is in the details: tool descriptions that don't tell the model enough, error messages that don't help recovery, and schemas that don't validate inputs.
@server.list_tools() and @server.call_tool()
The MCP Python SDK uses two decorators to build a server: @server.list_tools() handles the discovery request (returns tool definitions), and @server.call_tool() handles invocations (receives name + arguments, returns content). Every MCP server you build will follow this pattern.
MCP Server Structure
Import and instantiate: from mcp.server import Server; server = Server("my-server-name").
Register tool definitions with @server.list_tools() — this decorator marks the async function that returns your list of Tool objects when a client sends tools/list.
Register the call handler with @server.call_tool() — this decorator marks the async function that the server calls when a client sends tools/call. It receives the name and arguments and returns a list of TextContent (or ImageContent for images).
Run the server:
from mcp.server.stdio import stdio_server
async def main():
async with stdio_server() as streams:
await server.run(*streams, server.create_initialization_options())
asyncio.run(main())
For web deployment (Streamable HTTP), use create_mcp_app() from mcp.server.fastapi and mount it on a FastAPI app.
Unlock the full lesson
You've read the first 2 sections. The rest of this lesson covers Writing Great Tool Descriptions, Error Handling in MCP Tools, Exposing Resources, Build It, What to Practice — plus a hands-on lab, quiz, and project artifact.
Create a free account to unlock Phase 0 and Phase 1 of every course — no credit card.
Browse all courses · View pricing · DeVenture Academy