Give your AI real tools with an MCP client
An MCP server is only half the story. The other half is the client: the code that connects to a server, reads what tools it has, and calls them. Write one in Python, point it at a running server, then put those tools in front of a local model so it can work out a sum, read a file and query a live API on its own.
- Level 0 done: Install anything from GitHub, safely and The terminal survival kit.
- uv, the fast Python runner:
winget install --id astral-sh.uv -eon Windows, orcurl -LsSf https://astral.sh/uv/install.sh | shon a Mac or Linux. It downloads the MCP Python SDK and a suitable Python for you. - A server and a client are two halves of the same standard. This mission builds the client; Build your own MCP server so Claude can use your tools builds a server you own. Either order works, and the tiny server here means you do not need that lesson first.
- Ollama for the model loop in step 5 only: install it from ollama.com ↗, then
ollama pull qwen3.5:4b(about 3GB). Steps 1 to 4 and the tests need no model. Any tool-capable model works; a small one runs on a CPU, slowly. - An internet connection for the live API tool and for the first package download. You can read a little Python. Every file is complete and in the kit.
What MCP is, and why you'd write a client
The words client, server and host sound alike until you see which one you're building. Two minutes here makes the rest obvious.
MCP (Model Context Protocol) is an open standard for connecting AI apps to other software: tools to call, data to read, prompts to reuse. The official introduction ↗ likens it to a USB-C port, one shape of plug that fits everything. Three roles use that plug, and it is worth being exact about them:
- The host is the AI app a person uses: Claude Desktop, an editor, or a script you write. It holds the model and decides what to do.
- The server offers capabilities: a function to run, a file to read. Build your own MCP server builds one of these.
- The client is the piece inside the host that actually speaks MCP to one server: it opens the connection, asks what the server offers, and makes the calls. One host runs one client per server it connects to.
This mission builds the client and the small host loop around it. When you understand this side, you understand what Claude Desktop is doing every time it uses a server, and you can put any MCP server's tools in front of any model, including one running on your own machine.
The three things a server can offer, split by who decides to use them, from the SDK's guide ↗:
- Tools are chosen by the model: functions it can call to do something. The tiny server here offers
calculate,read_fileandnext_bank_holiday. - Resources are chosen by the app or the user: read-only data attached to a conversation, addressed by a URI like
todo://list. - Prompts are chosen by the user: saved message templates, often shown as slash commands.
- Tools are chosen by the model: functions it can call to do something. The tiny server here offers
A client can list and use all three. This mission spends its time on tools, because tools are what let a model *act*: read a file, query an API, run a calculation.
The transport is how the two ends actually swap bytes. There are two. stdio: the host starts the server as a child process and talks to it through standard input and output, with nothing on the network. HTTP (with server-sent events, SSE, for streaming): the server runs somewhere and the client reaches it over a URL. This mission uses stdio, the common case for a local tool, and step 7 covers the HTTP case.
Check your tools. Both should print a version:
Terminaluv --version ollama --versionTipOlder tutorials and the version-1 SDK start a server withfrom mcp.server.fastmcp import FastMCP. Version 2 renamed that class toMCPServer. The client side is steadier:from mcp import ClientSessionand the high-levelfrom mcp import Clientboth work in version 2. This mission pins the SDK to the 2.3 series so the imports in the kit match the package that installs.
uv --version prints a version, and you can say in one sentence what the client does that the server and host do not (it speaks MCP to one server: connects, lists, calls).If it breaks'uv' is not recognised + 1 more
'uv' is not recognised
winget install --id astral-sh.uv -e (Windows) or curl -LsSf https://astral.sh/uv/install.sh | sh (Mac or Linux), then close the terminal and open a new one.