Model Context ProtocolMCP Python SDK 2.2 · LangChain 1.4 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
27 small wins to finish your pathNext lesson →

MCPServer quickstart

MCPServer is the SDK's server class: decorate a function with it and the SDK builds the name, description and schema you wrote by hand in the previous lesson.

Last updated: 29 Sep, 2026 · MCP 2.2

In Tools without MCP you wrote a JSON Schema next to your function. Here an MCPServer reads your function's type hints and docstring and builds that schema for you.

Writing the math server · from the Complete Agentic AI Course In 10 Hours · 278:46 to 282:20

Porting the math server from the video

The video writes mathserver.py. FastMCP("Math") names the server, and each function under @mcp.tool() becomes a tool: add and multiple, the video's name for multiply. The docstring is what the LLM reads to decide which tool to call. At the bottom, mcp.run(transport="stdio") starts the server; stdio transport explains that transport.

The video imports FastMCP from mcp.server.fastmcp, the class's name in mcp 1.x. In mcp 2.2 that import raises ModuleNotFoundError: the class is MCPServer, imported from mcp.server, and the decorator and run() work as before. The video's file with only those two lines changed:

python
from mcp.server import MCPServer

mcp=MCPServer("Math")

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

@mcp.tool()
def multiple(a:int,b:int)-> int:
    """Multiply two numbers"""
    return a*b

#The transport="stdio" argument tells the server to:

#Use standard input/output (stdin and stdout) to receive and respond to tool function calls.

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

Ask the server what it offers. Save this in a second file next to mathserver.py, such as list_tools.py, and run it. The client code is the next lesson's subject; for now, read what it prints.

Example
import asyncio

from mcp import Client
from mathserver import mcp


async def main():
    async with Client(mcp) as client:
        tools = await client.list_tools()
        for tool in tools.tools:
            print(tool.name, repr(tool.description))


asyncio.run(main())

multiple is described by its docstring, Multiply two numbers. add carries the video's leftover docstring template, _summary_, and that text is what a model is told about add. In your own servers, write a docstring that says what the tool does.

The shop server is built the same way, with a tool the support team needs.

The MCPServer and tool API

python
from mcp.server import MCPServer

mcp = MCPServer("Shop support")   # create and name the server

@mcp.tool()                       # register the function below as a tool
def lookup_order(order_id: str) -> str:
    """Docstring becomes the tool description."""
    ...

The server object

Create the server and give it a name. The order data is a dictionary for now.

python
from mcp.server import MCPServer

mcp = MCPServer("Shop support")

ORDERS = {
    "A17": {"item": "blue mug", "status": "shipped", "total": 12.50},
    "B42": {"item": "desk lamp", "status": "processing", "total": 48.00},
}

The lookup_order tool

@mcp.tool() registers lookup_order as a tool, a function a model can call. The SDK reads three things from it: the name from the function name, the description from the docstring, and the arguments from the type hints.

python
@mcp.tool()
def lookup_order(order_id: str) -> str:
    """Look up an order by its id and say where it is."""
    order = ORDERS[order_id]
    return f"Order {order_id}: {order['item']}, {order['status']}."

Listing the tool a client is told about

The same listing, pointed at shop.py, prints what the SDK built from order_id: str and the docstring.

Example
import asyncio

from mcp import Client
from shop import mcp


async def main():
    async with Client(mcp) as client:
        tools = await client.list_tools()
        for tool in tools.tools:
            print(tool.name)
            print(tool.description)
            print(tool.input_schema)


asyncio.run(main())

What the SDK built for you

  • The name lookup_order came from the function name.
  • The description came from the docstring, word for word.
  • The schema lists order_id as a required string, built from the type hint. Change the function and the schema changes with it.
  • The title keys come from Pydantic, which builds the schema; a model reads properties, the types and required.

By hand vs @mcp.tool()

By hand@mcp.tool()
NameYou type it into the schemaThe function name
DescriptionA string in the schemaThe docstring
ArgumentsYou write the JSON SchemaRead from the type hints
Stays in stepOnly if you rememberRebuilt from the function

When to reach for MCPServer

  • Any time more than one application, or a host you do not control, will call your function.
  • As the single place your tools, resources and prompts live, which the rest of the course fills in.
Watch out. The SDK has two halves. The server is from mcp.server import MCPServer; the client is from mcp import Client. There is no from mcp import MCPServer, and reaching for it is the first mistake most people make.
Try it yourself
  • Give lookup_order a second parameter, include_total: bool = False, and list the tools again. What changed in required?
  • Delete the docstring and look at tool.description.
  • Add a second tool, count_orders() -> int, and list the tools.

Slow is fine. Stopping is the only problem.