A reference implementation of a Model Context Protocol server
MCP Server Example
A simple MCP (Model Context Protocol) server for learning the core primitives: Tools, Resources, and Prompts.
Setup
Prerequisites
- Python 3.10+
- uv
Install
uv sync
Test
Option 1 — MCP Inspector (recommended)
uv run mcp dev server.py
Opens a browser UI at http://localhost:6274. From there you can:
- Tools tab: call
add,multiply,save_note,delete_notewith custom inputs - Resources tab: read
notes://listornotes://{name} - Prompts tab: run
summarize_notesorbrainstormwith arguments
Option 2 — CLI with `mcp` client
List all available tools:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | uv run python server.py
Call a tool (e.g. add 3 + 4):
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"add","arguments":{"a":3,"b":4}}}' | uv run python server.py
Connect to Claude Code (CLI)
Add the server to your Claude Code session:
claude mcp add learning-mcp -- uv run --directory /Users/binod/projects/mcp-example python server.py
Verify it's connected:
claude mcp list
Once added, Claude Code can call your tools directly in the chat — just ask it to, e.g. "save a note called 'ideas'" or "what is 3 + 5?".
Connect to Claude Desktop
Add this to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"learning-mcp": {
"command": "uv",
"args": [
"run",
"--directory", "/Users/binod/projects/mcp-example",
"python", "server.py"
]
}
}
}
Then restart Claude Desktop.
Use programmatically (Python)
Use the mcp library to call tools, read resources, and fetch prompts from your own code:
from mcp import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
import asyncio
async def main():
server = StdioServerParameters(
command="uv", args=["run", "python", "server.py"]
)
async with stdio_client(server) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Call a tool
result = await session.call_tool("add", {"a": 3, "b": 4})
print(result) # 7.0
# Read a resource
notes = await session.read_resource("notes://list")
print(notes)
# Get a prompt
prompt = await session.get_prompt("brainstorm", {"topic": "side projects"})
print(prompt)
asyncio.run(main())
To let Claude (via Anthropic API) call your tools, add anthropic[mcp] to your dependencies and convert the tools:
from anthropic.lib.tools.mcp import async_mcp_tool
import anthropic
client = anthropic.AsyncAnthropic()
tools = [async_mcp_tool(t, session) for t in (await session.list_tools()).tools]
runner = client.beta.messages.tool_runner(
model="claude-opus-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Save a note called ideas"}],
tools=tools,
)
async for message in runner:
for block in message.content:
if hasattr(block, "text"):
print(block.text)
What's inside
| File | Description |
|---|---|
server.py |
MCP server with tools, resources, and prompts |
pyproject.toml |
Project dependencies |
Tools (Claude can call these)
| Tool | Description |
|---|---|
add(a, b) |
Add two numbers |
multiply(a, b) |
Multiply two numbers |
save_note(name, content) |
Save a note |
delete_note(name) |
Delete a note |
Resources (Claude can read these)
| URI | Description |
|---|---|
notes://list |
List all saved notes |
notes://{name} |
Read a specific note |
Prompts (reusable templates)
| Prompt | Description |
|---|---|
summarize_notes |
Summarize all saved notes |
brainstorm(topic) |
Brainstorm ideas on a topic |
Tools (4)
addAdd two numbersmultiplyMultiply two numberssave_noteSave a notedelete_noteDelete a noteConfiguration
{"mcpServers": {"learning-mcp": {"command": "uv", "args": ["run", "--directory", "/path/to/mcp-example", "python", "server.py"]}}}