DEV Community

Nebula
Nebula

Posted on

How to Build an MCP Server with Python in 5 Min

You want to give Claude (or any MCP client) access to your own custom tools. Every Python tutorial you find is 2,000+ words and 15 steps. Here's a working MCP server with two tools in under 30 lines.

The Code

Create a file called notes_server.py:

from fastmcp import FastMCP

mcp = FastMCP("Notes")

# In-memory storage
notes: dict[str, str] = {}


@mcp.tool
def add_note(name: str, content: str) -> str:
    """Save a note with a given name and content."""
    notes[name] = content
    return f"Saved note '{name}'."


@mcp.tool
def search_notes(query: str) -> list[dict]:
    """Search notes by keyword. Returns all notes containing the query string."""
    results = [
        {"name": name, "content": content}
        for name, content in notes.items()
        if query.lower() in name.lower() or query.lower() in content.lower()
    ]
    return results if results else [{"message": f"No notes found for '{query}'"}]


if __name__ == "__main__":
    mcp.run()
Enter fullscreen mode Exit fullscreen mode

That's the entire server. Two tools, fully typed, ready to connect.

Install and Run

Install FastMCP:

pip install fastmcp
Enter fullscreen mode Exit fullscreen mode

Test it locally with the built-in inspector:

fastmcp dev notes_server.py:mcp
Enter fullscreen mode Exit fullscreen mode

This opens a browser-based inspector where you can call add_note and search_notes directly. Try adding a note, then searching for it.

Connect to Claude Desktop

To use your server inside Claude Desktop, edit the config file.

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

Add your server:

{
  "mcpServers": {
    "notes": {
      "command": "python",
      "args": ["/full/path/to/notes_server.py"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Restart Claude Desktop. You'll see a hammer icon in the chat input indicating your tools are connected. Ask Claude to "save a note about today's meeting" and it will call add_note on your server.

How It Works

FastMCP handles all the MCP protocol details. Here's what each piece does:

FastMCP("Notes") creates a server instance. The string is the server name that MCP clients display.

@mcp.tool registers a function as an MCP tool. FastMCP reads the function's type hints and docstring to generate the tool's schema automatically. The docstring becomes the tool description that the LLM reads when deciding which tool to call.

mcp.run() starts the server using the stdio transport (the default). Claude Desktop launches your script as a subprocess and communicates over stdin/stdout.

The notes dictionary is intentionally simple. In production, you'd swap this for a database or file storage. The pattern stays the same -- FastMCP doesn't care what your function does internally, only that it has type hints and returns a value.

Add More Tools

Extending the server is just adding more decorated functions:

@mcp.tool
def delete_note(name: str) -> str:
    """Delete a note by name."""
    if name in notes:
        del notes[name]
        return f"Deleted note '{name}'."
    return f"Note '{name}' not found."
Enter fullscreen mode Exit fullscreen mode

No configuration, no registration steps. Decorate, restart, done.

Quick Reference

What Command
Install pip install fastmcp
Test locally fastmcp dev server.py:mcp
Run with stdio python server.py
Run with HTTP mcp.run(transport="http", port=8000)
Client connect Client("http://localhost:8000/mcp")

What's Next

This server loses notes when you restart it. For persistence, swap the dictionary for SQLite or a JSON file. If you're building agents that need to orchestrate multiple MCP servers across services, Nebula handles that coordination layer so you can focus on the tools themselves.

The full FastMCP docs are at gofastmcp.com. The Tools guide covers advanced patterns like async tools, Pydantic validation, and custom error handling.

Top comments (0)