fig. Bmcp
Build Your First MCP Server in Python (and Connect It to Claude Code)
A hands-on guide to the Model Context Protocol: build a small MCP server in Python with tools and resources, then wire it into an AI coding agent.
- Written by
- Mayank Panchal
- Published
- Reading time
- 3 min
- Filed under
- mcp
- mcp
- python
- ai-agents
On this page · 8
The Model Context Protocol (MCP) is an open protocol that lets AI applications discover and call tools you write, without a custom connector for each app. One server, many clients: a coding agent, a chat app, or your own script can all use it.
This is the shortest path from nothing to a working server in Python.
The three things a server offers#
| Concept | Who controls it | Think of it as |
|---|---|---|
| Tools | The model | Functions it can call to do something |
| Resources | The application | Read-only data it can load as context |
| Prompts | The user | Reusable templates the user picks explicitly |
Most servers start with tools. Add resources when there is data worth reading rather than computing.
Setup#
python -m venv .venv && source .venv/bin/activate
pip install "mcp[cli]"A small server#
This one manages a notes list in memory:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("notes")
NOTES: dict[int, str] = {}
@mcp.tool()
def add_note(text: str) -> str:
"""Save a note and return its id."""
note_id = len(NOTES) + 1
NOTES[note_id] = text
return f"Saved note {note_id}"
@mcp.tool()
def search_notes(query: str) -> list[str]:
"""Return every note that contains the query, case-insensitively."""
q = query.lower()
return [t for t in NOTES.values() if q in t.lower()]
@mcp.resource("notes://{note_id}")
def get_note(note_id: int) -> str:
"""Read one note by id."""
return NOTES.get(note_id, "No such note")
if __name__ == "__main__":
mcp.run()Three details carry the whole experience:
- Type hints become the input schema. The SDK builds the JSON schema the model sees from your annotations, so
query: strmeans the model is told to pass a string. - The docstring is the tool description. The model decides when to call your tool from this text. Write it for the model: what it does, what it returns, when not to use it.
mcp.run()defaults to stdio. The client launches your script as a subprocess and talks over standard input and output.
Try it without a client#
The mcp[cli] extra includes an inspector:
mcp dev server.pyIt opens a UI where you can list tools and call them by hand. Debug here first. It is much faster than guessing from a chat transcript.
Connect it to Claude Code#
Register the server by command:
claude mcp add notes -- python /absolute/path/to/server.pyThen ask it to "save a note that the deploy is on Friday" and watch it call add_note. Use an absolute path to the script, and make sure python resolves to the environment where you installed mcp.
Making tools the model uses well#
- Keep tools narrow.
search_notesbeatsdo_anything(command: str). Small, well-named tools get chosen correctly. - Return something readable. Errors should say what went wrong and what to try, not a bare stack trace.
- Cap the output. A tool that returns 50,000 lines wastes context and money. Paginate or summarise.
Security: treat the model as an untrusted caller#
An MCP server is an API whose caller is a language model that may have read hostile text. So:
- Validate every argument exactly as you would for a public endpoint. Never pass a model-supplied string to a shell, a SQL query, or a file path unchecked.
- Grant least privilege. A read-only database role for a reporting tool; a single directory for a file tool.
- Gate the dangerous tools. Anything that deletes, spends money, or sends messages should need explicit approval from the user in the client.
- Don't expose a server to the network by accident. Stdio is local by design. If you move to an HTTP transport, add authentication first.
Where to go next#
Wrap an API you already use, such as your own FastAPI backend, and expose three or four of its most useful operations as tools. That is a better learning project than any toy example, because you will immediately feel how much the tool descriptions matter.
fig. B.1keep reading
Related posts
· 4 min
From Web Developer to AI Engineer: The Skills That Transfer
You don't need a PhD to build AI features. A practical roadmap for Next.js and Python developers: tool calls, retrieval, evals, streaming and cost control.
Read →· 4 min
Make Your Website Readable by AI Agents: A Practical Checklist
AI assistants and agents now read websites alongside people. Learn what actually helps: semantic HTML, JSON-LD, llms.txt, crawler rules and fast pages.
Read →· 4 min
Is the AI Boom a Bubble? A Developer's Read of the Numbers
Hundreds of billions are going into AI infrastructure. Here is what the spending, the revenue and the skeptics say, and what it means for developers.
Read →