Building MCP Servers
Ship your own Model Context Protocol servers. Expose tools, resources, and prompts to any MCP-compatible client such as Claude Desktop, Claude Code, or your own app. Cover stdio and HTTP transports, packaging and distribution, and testing patterns in Python.
About This Course
Ship your own Model Context Protocol servers. Use the official Python mcp SDK to build servers that expose tools, resources, and prompts to any MCP-compatible client (Claude Desktop, Claude Code, custom apps). Cover stdio and HTTP transports, packaging + distribution, and testing patterns. Course pairs with CLD-AI-105 (client side) to complete the MCP story.
Course Curriculum
10 Lessons
Introduction to building MCP servers
By the end of this lesson you will know the two API surfaces of the official mcp Python SDK — FastMCP (high-level, decorator-driven, what you'll use ~95% of the time) vs the low-level protocol API (used when you need direct JSON-RPC control) — and the shape of a minimal working MCP server: a FastMCP instance, one @mcp.tool() decorated function, and stdio transport. Sets up the L2 hands-on where you build your first three-tool server end-to-end.
Your first FastMCP server - Lab Exercises
By the end of this hands-on lab you will have shipped your first FastMCP server — three Python functions (greet, add, lookup_customer_tier) exposed as MCP tools via @mcp.tool() decorators with type-hinted parameters, verified all three registered on the FastMCP instance via a smoke test, and seen the sentinel-return vs raise-KeyError design tradeoff for the 'customer not found' case. Uses the PythonAI container + Claude API proxy — no external MCP client needed, the smoke test imports each tool directly.
Tool schemas + Pydantic validation
By the end of this lesson you will know how to shape FastMCP tool schemas beyond simple primitives — Literal enums for constrained categorical inputs, Optional fields and defaults for graceful degradation, complex nested Pydantic model inputs, cross-field validators for business rules (e.g., 'refund_amount ≤ original_amount'), and how dict returns get auto-serialized to JSON. This is what separates a demo MCP server from one that survives real user input. Sets up the L4 hands-on where you build hardened tools.
Typed FastMCP tools with Pydantic - Lab Exercises
By the end of this hands-on lab you will have built three FastMCP tools using advanced typing: set_priority constrained by a Literal enum, process_refund accepting a Pydantic BaseModel with a cross-field validator that enforces refund SLA rules, and inspected the JSON schemas FastMCP auto-inferred from your type hints. Verify each validator rejects invalid inputs at the SDK layer before the tool body ever runs. Uses the PythonAI container + Claude API proxy.
MCP resources: static + dynamic + templated
By the end of this lesson you will know when to reach for MCP resources instead of tools — resources are client-attached read-only data (the client decides when to fetch), tools are Claude-invoked side-effecting actions — and how to expose them via FastMCP's @mcp.resource() decorator: static URIs (orion://config), templated URIs with path parameters (orion://customer/{id}), dynamic content generation on read, and mime types. Sets up the L6 hands-on where you build a resource-only MCP server.
Resource-focused MCP server - Lab Exercises
By the end of this hands-on lab you will have built an MCP server exposing three FastMCP resources — one static (orion://config/current) and two templated (orion://customer/{id} for profile lookup and orion://runbook/{name} for escalation runbooks) — running the smoke test that verifies each resource's URI, mime type, and read result. Reinforces when resources beat tools: read-only reference data the client controls when to fetch. Uses the PythonAI container.
MCP prompts: reusable templates
By the end of this lesson you will know what MCP prompts actually are — server-defined reusable message templates parametrized by user arguments that clients inject on demand (slash commands in Claude Desktop, custom UIs in your own app) — how they differ from tools/resources, and how to build them with FastMCP: string-return single-message templates, Literal-argument-constrained templates, and multi-message templates that pre-seed a conversation. Sets up the L8 hands-on where you build a three-prompt server.
Prompts-focused MCP server - Lab Exercises
By the end of this hands-on lab you will have built three FastMCP prompt templates: review_ticket (string-returning, one argument), escalate_alert (with a Literal enum for severity level, string returning), and weekly_digest (multi-message return that pre-seeds a system+user+assistant sequence). Run the smoke test to confirm each prompt's arguments, message shape, and return value match expectations. Uses the PythonAI container + Claude API proxy.
Packaging + deploying MCP servers
By the end of this lesson you will know how to package an MCP server for real distribution: a pyproject.toml with the console-script entry point that clients like Claude Desktop can spawn, publish to PyPI or a private index, containerize with Docker for isolated execution, or expose over HTTP+SSE for a hosted deployment. Covers version pinning for reproducibility, semantic-version compatibility rules across MCP-SDK bumps, and the manifest fields registries scrape. Prepares you for the L10 capstone package.
Complete packaged Orion MCP server capstone - Lab Exercises
By the end of this hands-on capstone you will have shipped a proper pip-installable MCP package for Orion Analytics — pyproject.toml with a console-script entry point, three FastMCP tools + two resources + one prompt combining every pattern from L2 through L9 — and run the end-to-end smoke test that pip-installs your package into a fresh venv, spawns the entry point, and exercises every primitive. Uses the PythonAI container + Claude API proxy — proves the package is ready for a real MCP client to consume.