How to Create a Simple MCP Server

If you've wondered how to create an MCP server, the good news is that a simple one takes about 20 lines of Python. In this guide I'll build an MCP server with two tiny tools, test it, and connect it to Claude Desktop. Every command below comes from the official docs, and I ran each one myself before writing it down.

New to the idea? Start with What is an MCP server? first. Short version: an MCP server exposes tools and data, and an AI app like Claude (the client) connects to it using the Model Context Protocol [1].

Step 1: Prerequisites to build an MCP server

You need:

  • Python 3.10 or newer (the official quickstart's minimum) [2]
  • uv, the Python package manager the docs use [2][3]
  • Node.js, only for running MCP Inspector in Step 4 [4]
  • Claude Desktop, if you want to try it with Claude [2]

Install uv on macOS or Linux:

curl -LsSf https://astral.sh/uv/install.sh | sh

On Windows, see the uv install page [3]. Restart your terminal afterward so the uv command is found.

Step 2: Create the project and install the MCP SDK

uv init hello-mcp
cd hello-mcp
uv add "mcp[cli]"

This installs the official MCP Python SDK [5]. One heads-up: older tutorials use from mcp.server.fastmcp import FastMCP. In version 2 of the SDK, FastMCP was renamed to MCPServer, so the old import now fails [6]. The code below uses the current name.

Step 3: Write a minimal MCP server with one tool

Create server.py:

from mcp.server import MCPServer

mcp = MCPServer("hello")


@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


@mcp.tool()
def say_hello(name: str) -> str:
    """Say hello to someone."""
    return f"Hello, {name}!"


if __name__ == "__main__":
    mcp.run(transport="stdio")

That's the whole MCP server. The @mcp.tool() decorator turns a normal function into a tool. The SDK reads the type hints and docstring to tell the AI what the tool does and what inputs it takes [5]. transport="stdio" means the server talks over standard input and output, which is how Claude Desktop runs local servers [2].

You can run it with:

uv run server.py

It will look like it's doing nothing. That's normal: it's waiting for a client to talk to it. Press Ctrl+C to stop it.

Step 4: Test your MCP server with MCP Inspector

MCP Inspector is the official testing tool [4]. To open its web UI:

npx @modelcontextprotocol/inspector uv run server.py

Click Connect, open the Tools tab, and try add with 2 and 3.

Prefer the terminal? The Inspector also has a CLI mode [7]:

npx @modelcontextprotocol/inspector --cli uv run server.py --method tools/list

npx @modelcontextprotocol/inspector --cli uv run server.py \
  --method tools/call --tool-name add --tool-arg a=2 --tool-arg b=3

The first command lists both tools. The second returns a result containing "text": "5". If you see that, your server works.

Step 5: Connect your MCP server to Claude Desktop (Claude MCP setup)

Open the Claude Desktop config file (create it if it doesn't exist) [2]:

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

Add your server under mcpServers:

{
  "mcpServers": {
    "hello": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/TO/hello-mcp",
        "run",
        "server.py"
      ]
    }
  }
}

Use the full path to your project folder. On Windows that looks like C:\\Users\\you\\hello-mcp, with doubled backslashes. If Claude can't find uv, put the full path to it in command (run which uv on macOS, or where uv on Windows) [2].

Fully quit and reopen Claude Desktop. Then ask, "Use the hello tool to say hello to Sam." Claude should ask permission to run say_hello and reply with "Hello, Sam!"

If it doesn't show up, the official guide has a troubleshooting section, and Claude's logs are in ~/Library/Logs/Claude on macOS [2].

Common mistakes when you create an MCP server

A few things tripped me up, or trip up most people the first time:

  • Printing to stdout. With stdio, stdout carries the protocol messages, so a stray print() can break the connection. Log to stderr instead [2].
  • Relative paths in the config. Claude Desktop doesn't start in your project folder, so always use the absolute path.
  • Not fully restarting Claude. Closing the window isn't enough. Quit the app completely, then reopen it.
  • Old FastMCP imports. If you copy code from an older tutorial, change the import to from mcp.server import MCPServer [6].

Step 6: Next steps for your MCP server

Once the basics work, here's where to go:

  • Do something real. Swap add for a tool that calls an API you use, the way the official quickstart builds a weather server [2].
  • Go remote with HTTP. Stdio only works on your own machine. To let other people or hosted agents connect, run over Streamable HTTP instead [5][8]: ``python mcp.run(transport="streamable-http") ` That serves your MCP server at http://localhost:8000/mcp`. You'd still need hosting, HTTPS and authentication before putting it on the public internet.
  • Read the SDK docs. The Python SDK README covers resources, prompts and more [5].

Step 7: List your server free

Built something useful? List your server free on MCP Lantern so other people (and their agents) can find it. I'd love to see what you make.

References

  1. Model Context Protocol, "What is the Model Context Protocol (MCP)?" https://modelcontextprotocol.io/docs/getting-started/intro
  2. Model Context Protocol, "Build an MCP server." https://modelcontextprotocol.io/docs/develop/build-server
  3. Astral, "Installing uv." https://docs.astral.sh/uv/getting-started/installation/
  4. Model Context Protocol, "MCP Inspector." https://modelcontextprotocol.io/docs/tools/inspector
  5. MCP Python SDK (GitHub). https://github.com/modelcontextprotocol/python-sdk
  6. MCP Python SDK, "Migration guide: FastMCP renamed to MCPServer." https://py.sdk.modelcontextprotocol.io/v2/migration/#fastmcp-renamed-to-mcpserver
  7. MCP Inspector (GitHub). https://github.com/modelcontextprotocol/inspector
  8. Model Context Protocol, "Transports" specification. https://modelcontextprotocol.io/specification/2025-06-18/basic/transports

Published · More posts