AI Engineering · 75 min

Build an MCP Server and Client

Use the official `mcp` Python SDK to build a minimal MCP server exposing two real tools, then write a client that connects over stdio, lists the tool catalog, and invokes both tools end to end.

Premium

Problem

The Model Context Protocol (MCP) standardizes how an AI application discovers and calls tools exposed by a separate process — instead of every agent framework inventing its own bespoke way to wire up tools, an MCP **server** exposes a catalog of tools over a well-defined protocol, and any MCP-compatible **client** (a chat app, an IDE, an agent) can connect, list what's available, and invoke it, regardless of what language or framework either side is written in. Most people first encounter MCP as a consumer — installing someone else's server into Claude Desktop or an IDE. This lab has you build both halves yourself using the official `mcp` Python SDK: a server exposing two genuinely simple tools (`get_time` and `echo`), and a client that connects to it over the **stdio transport** — the same mechanism most local MCP integrations use, where the client launches the server as a subprocess and the two communicate over its stdin/stdout. By the end you'll have watched a full MCP round trip happen — tool discovery, then tool invocation — with nothing hidden inside a larger application, which is the fastest way to actually understand what an MCP client is doing when it "connects to a server" in any real tool you use later.

Objectives

By the end of this lab you will be able to:

Prerequisites

To complete this lab you'll need:

The two halves you're building

┌─────────────┐   stdio (stdin/stdout)   ┌─────────────┐
│  client.py  │ ───────────────────────► │  server.py  │
│             │ ◄─────────────────────── │             │
│ launches    │                          │  exposes:   │
│ server.py   │                          │  - get_time │
│ as a        │                          │  - echo     │
│ subprocess  │                          │             │
└─────────────┘                          └─────────────┘

The server doesn't know or care what kind of client connects to it — it
just exposes tools over the protocol. The client doesn't need to know
the server is written in Python, or how get_time is implemented — it
just needs to speak MCP. That decoupling is the entire point.

Why stdio, specifically

MCP supports multiple transports (stdio, SSE/HTTP, and others), but
stdio is the simplest and most common for local tools: the client
process spawns the server process directly and talks to it over
ordinary pipes, with no network port, no auth handshake, and no
separate process to keep running. This is exactly how tools like Claude
Desktop or an MCP-aware IDE typically run a locally installed MCP
server.

How to work through this lab

Build the server first and sanity-check it standalone, then build the
client against it. The real proof this all works is Step 4: the client
programmatically discovering and calling tools it never had hardcoded
knowledge of beyond their names.

Steps

Content exclusive to subscribers. See plans