Building MCP Servers

MCP Server Basics

5 min read

Now that you understand MCP's architecture, let's build a complete MCP server that exposes useful tools.

Server Lifecycle

Every MCP server follows this lifecycle:

  1. Initialization: Server starts and registers capabilities
  2. Connection: Client connects via stdio or SSE
  3. Capability Exchange: Server announces available tools/resources
  4. Operation: Server handles requests
  5. Shutdown: Clean disconnection

Creating a Server Instance

from mcp.server import Server
from mcp.types import Tool, TextContent

# Create server with a unique name
server = Server(name="my-awesome-server")

The server name appears in logs and helps identify your server when multiple MCP servers are configured.

Registering Tools

Tools are the primary way AI interacts with your server. Each tool needs:

Component Purpose
name Unique identifier (snake_case)
description What the tool does (AI reads this!)
inputSchema JSON Schema for parameters
@server.list_tools()
async def list_tools():
    return [
        Tool(
            name="get_weather",
            description="Get current weather for a city",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "City name (e.g., 'London', 'Tokyo')"
                    },
                    "units": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "default": "celsius"
                    }
                },
                "required": ["city"]
            }
        )
    ]

Handling Tool Calls

When the AI invokes a tool, your handler receives the name and arguments:

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "get_weather":
        city = arguments["city"]
        units = arguments.get("units", "celsius")

        # Your logic here (e.g., call weather API)
        weather = fetch_weather(city, units)

        return [TextContent(
            type="text",
            text=f"Weather in {city}: {weather}"
        )]

    raise ValueError(f"Unknown tool: {name}")

Tool Descriptions Matter

Pro Tip: Write tool descriptions as if explaining to a human. The AI uses these descriptions to decide when and how to use your tool.

Good description:

"Search the company knowledge base for relevant documents.
Returns top 5 matches with titles and snippets."

Bad description:

"Search KB"

Next, we'll add resources to expose data that the AI can read. :::

Quiz

Module 2 Quiz: Building MCP Servers

Take Quiz