DEV Community

πŸš€ Building Your First MCP Server: A Step-by-Step Guide

🧐 link to the practice repository:
PRESS ME


In the rapidly evolving landscape of AI, the ability to connect Large Language Models (LLMs) to your own data and tools is a game-changer. The Model Context Protocol (MCP) has emerged as a standard for this connection, allowing developers to build servers that expose data and functionality to MCP clients like Claude Desktop, VS Code, and others.

In this article, we will explore what an MCP server is and build a simple "Weather Server" from scratch using Python. By the end, you'll have a working server that you can connect to Claude to ask for weather updates!

What is an MCP Server?

An MCP Server is a lightweight application that implements the Model Context Protocol. It acts as a bridge between your data sources (databases, APIs, files) and an AI client. Instead of building custom integrations for every AI tool, you build one MCP server that any MCP-compliant client can use.

Key concepts:

  • Resources: Data that the server can read (like files or database rows).
  • Tools: Functions that the server can execute (like "get_weather" or "query_database").
  • Prompts: Pre-defined templates for interacting with the server.

Prerequisites

To follow this tutorial, you will need:

  • Python 3.10+ installed on your machine.
  • A code editor (like VS Code).
  • Claude Desktop (optional, for testing the client connection).

Step 1: Setting Up the Project

First, let's create a directory for our project and set up a virtual environment.

mkdir weather-mcp-server
cd weather-mcp-server
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
Enter fullscreen mode Exit fullscreen mode

Next, install the official MCP SDK for Python:

pip install mcp
Enter fullscreen mode Exit fullscreen mode

Step 2: Writing the Server Code

We will create a simple server that exposes a single tool: get_weather. This tool will take a city name as input and return a mock weather report.

Create a file named server.py and add the following code:

from typing import Any
import asyncio
from mcp.server.models import InitializationOptions
import mcp.types as types
from mcp.server import NotificationOptions, Server
from mcp.server.stdio import stdio_server

# Initialize the server
server = Server("weather-demo")

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    """
    List available tools.
    This server provides a single tool to get weather information.
    """
    return [
        types.Tool(
            name="get_weather",
            description="Get the current weather for a specific city",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "The name of the city (e.g., London, Lima, New York)"
                    }
                },
                "required": ["city"]
            },
        )
    ]

@server.call_tool()
async def handle_call_tool(
    name: str, arguments: dict[str, Any] | None
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    """
    Handle tool execution requests.
    """
    if name != "get_weather":
        raise ValueError(f"Unknown tool: {name}")

    if not arguments:
        raise ValueError("Missing arguments")

    city = arguments.get("city")

    # Mock data for demonstration purposes
    weather_data = {
        "London": "Cloudy, 15Β°C",
        "New York": "Sunny, 22Β°C",
        "Tokyo": "Rainy, 18Β°C",
        "Lima": "Sunny, 24Β°C",
        "Paris": "Windy, 12Β°C"
    }

    result = weather_data.get(city, f"Weather data not available for {city}")

    return [types.TextContent(type="text", text=result)]

async def main():
    # Run the server using stdin/stdout streams
    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="weather-demo",
                server_version="0.1.0",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                ),
            ),
        )

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

Step 3: Connecting to an MCP Client (Claude Desktop)

Now that our server is ready, let's connect it to Claude Desktop.

  1. Open your Claude Desktop configuration file.

    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows: %APPDATA%\Claude\claude_desktop_config.json
  2. Add your server to the mcpServers object. You need to provide the full path to your python executable and the server.py file.

{
  "mcpServers": {
    "weather-demo": {
      "command": "absolute/path/to/venv/bin/python",
      "args": ["absolute/path/to/weather-mcp-server/server.py"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Restart Claude Desktop.

Step 4: Testing the Server

Once Claude restarts, you should see a plug icon indicating that the MCP server is connected.

Try asking Claude:

"What is the weather in Lima?"

Claude will recognize the get_weather tool, call your local Python server, retrieve the data ("Sunny, 24Β°C"), and present it to you in the chat!

Conclusion

Congratulations! You've just built and connected your first MCP server. This simple example demonstrates the power of the Model Context Protocol: standardizing how AI models interact with external tools.

From here, you can expand your server to:

  • Query a real SQL database.
  • Fetch data from a live REST API.
  • Read and write files on your local system.

The possibilities are endless. Happy coding!


Resources:

Top comments (1)

Collapse
 
victor_williamscruzmama profile image
VICTOR WILLIAMS CRUZ MAMANI

Unvaliabable, you are insane! , this information is worth its weight in gold.