Quick Start

This chapter builds a tiny add tool (plus an echo tool) with the official SDK and calls it from Inspector. You do not need Cursor or Claude Code to prove the protocol works.


Minimal server.py

Create server.py in an activated virtual environment:

from mcp.server import MCPServer

mcp = MCPServer("demo")

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

@mcp.tool()
def echo(text: str) -> str:
    """Echo the given text back unchanged."""
    return text

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

That is a complete stdio server. The MCPServer name shows up in client identity. @mcp.tool() builds the schema from the function name, docstring, and type hints. mcp.run() with no arguments speaks stdio. Keep the if __name__ == "__main__" guard so mcp dev does not start a second server on import.

Many posts still show from mcp.server.fastmcp import FastMCP. That is official SDK v1. Use the import above on v2. Decorators and run() behave the same.


Open it in Inspector

Option A: SDK CLI (preferred)

mcp dev .\server.py
mcp dev ./server.py

Option B: hand the launch command to Inspector

npx @modelcontextprotocol/inspector python .\server.py
npx @modelcontextprotocol/inspector python ./server.py

Open the printed URL. The Tools tab should list add and echo. Call add with a=1, b=2 and expect 3. Call echo with any string and expect the same text back.

Inspector does what a real host does: spawn server.py and speak tools/list / tools/call over stdio.


Optional: one-shot CLI

Without a browser:

npx @modelcontextprotocol/inspector --cli python .\server.py --method tools/list
npx @modelcontextprotocol/inspector --cli python ./server.py --method tools/list

Then call a tool (confirm flags with Inspector --help):

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

Optional: in-memory client

No subprocess, no port—useful later in pytest:

import asyncio
from mcp import Client
from server import mcp

async def main() -> None:
    async with Client(mcp) as client:
        result = await client.call_tool("add", {"a": 1, "b": 2})
        print(result.structured_content)

asyncio.run(main())

from mcp import Client and from mcp.server import MCPServer are the two import paths. There is no from mcp import MCPServer.


Optional: Streamable HTTP

Change the entry point to:

if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="127.0.0.1", port=8000)

Then:

python .\server.py

In another terminal, point Inspector at HTTP (flags follow current Inspector help; --server-url plus --transport http is common):

npx @modelcontextprotocol/inspector --server-url http://127.0.0.1:8000/mcp --transport http

While you learn the protocol, stay on stdio and mcp dev.


Checklist

  1. pip install "mcp[cli]" in a venv
  2. Save the server.py above
  3. mcp dev .\server.py (Unix: mcp dev ./server.py)
  4. Call add and echo in Inspector
  5. (Optional) Client(mcp) or Streamable HTTP

On failure, read stderr and Inspector’s connection panel, not a chat window. Stdio stdout is the wire—do not print from tools for debugging.


Next

评论