mcp-test
mcp-test — learning the Model Context Protocol
A minimal MCP server in Python: one tool that returns the current temperature for a city. Plus a client that calls it, so you can see both halves of the protocol as plain Python.
No API key required — it uses Open-Meteo, which is free and needs no signup.
server.py the MCP server — one tool, get_temperature
test_client.py a real MCP client that launches the server over stdioRun it
Requires uv and Python 3.12+.
uv run test_client.pyThat launches server.py as a subprocess, connects over stdio, and walks through
four things: tool discovery, a successful call, a recoverable error, and schema
validation rejecting a bad argument.
⚠️ This uses SDK v2, not v1
The MCP Python SDK is at v2.x, a major rework. Most tutorials online are v1 and will not run against it:
v1 (most tutorials) | v2 (this repo) |
|
|
|
|
|
|
What the code demonstrates
The three primitives, split by who decides to use them: tools (the model decides), resources (the application decides), prompts (the user decides). This server exposes a tool, because "get the temperature" is a model-driven action.
Your function is the contract. From
async def get_temperature(city: str) -> Temperature, the SDK derives the tool name,
the description (from the docstring), the input schema (from the type hints), and the
output schema (from the return annotation). No JSON Schema is written by hand — and
the type hints are enforced, so a client sending city=42 is rejected before the
function runs.
Two results, two audiences. Every call returns content (text the model reads)
and structured_content (typed data the application reads). Returning a Pydantic
model rather than a string is what makes the second one useful.
Errors: raise, never return. A ToolError comes back with is_error=True and
your message where the model can read it, so the model can retry. A returned error
string has is_error=False — the model would read it as the answer.
stdio means stdout is the wire. The client launches the server as a subprocess and
speaks JSON-RPC over its stdin/stdout, so a stray print() in a server corrupts the
protocol stream. Use logging, which writes to stderr.
Try it in the MCP Inspector
A browser UI over your server, showing the raw protocol messages (needs npx):
uv run mcp dev server.pyConnect it to Claude Code
claude mcp add weather -- uv run --directory "$PWD" server.pyLatest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jonathan-daidai/mcp-test'
If you have feedback or need assistance with the MCP directory API, please join our Discord server