DEV Community

Cover image for Building Your First MCP Server: A Complete Beginner's Guide
Increase Akinwole
Increase Akinwole

Posted on

Building Your First MCP Server: A Complete Beginner's Guide

If you've been exploring AI development, you've probably heard about the Model Context Protocol (MCP). But what exactly is it, and how do you build your own MCP server? In this guide, we'll walk through creating your first MCP server from scratch, no prior experience required.

What is MCP?

The Model Context Protocol is an open standard that enables AI assistants like Claude to securely connect with external data sources and tools. Think of it as a universal adapter that lets AI models interact with your applications, databases, and services in a standardized way.

Before MCP, integrating AI with different tools meant building custom solutions for each integration. MCP provides a unified protocol that makes these connections simpler and more maintainable.

What We're Building

We'll create a simple weather MCP server that provides current weather information. This server will expose a tool that Claude can use to fetch weather data for any city. It's a perfect first project because it's practical, straightforward, and demonstrates all the core MCP concepts.

Prerequisites

Before we start, make sure you have:

  • Node.js installed (version 18 or higher)
  • Basic knowledge of JavaScript/TypeScript
  • A code editor (VS Code recommended)
  • An API key from OpenWeatherMap (free tier works fine)

Step 1: Set Up Your Project

First, create a new directory and initialize a Node.js project:

mkdir weather-mcp-server
cd weather-mcp-server
npm init -y
Enter fullscreen mode Exit fullscreen mode

Install the required dependencies:

npm install @modelcontextprotocol/sdk
npm install --save-dev typescript @types/node
Enter fullscreen mode Exit fullscreen mode

Create a tsconfig.json file:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Understanding MCP Server Structure

An MCP server has three main components:

  1. Resources: Read-only data that the AI can access (like files or database records)
  2. Tools: Functions that the AI can execute (like searching, creating, or updating data)
  3. Prompts: Pre-built prompt templates the AI can use

For our weather server, we'll focus on creating a tool since we want Claude to actively fetch weather data.

Step 3: Create the Server

Create a src directory and add an index.ts file:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const WEATHER_API_KEY = process.env.OPENWEATHER_API_KEY;

if (!WEATHER_API_KEY) {
  throw new Error("OPENWEATHER_API_KEY environment variable is required");
}

// Create the MCP server
const server = new Server(
  {
    name: "weather-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "get_weather",
        description: "Get current weather information for a city",
        inputSchema: {
          type: "object",
          properties: {
            city: {
              type: "string",
              description: "The city name (e.g., 'London', 'New York')",
            },
          },
          required: ["city"],
        },
      },
    ],
  };
});

// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "get_weather") {
    const city = request.params.arguments?.city as string;

    if (!city) {
      throw new Error("City parameter is required");
    }

    try {
      // Fetch weather data from OpenWeatherMap API
      const response = await fetch(
        `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(
          city
        )}&appid=${WEATHER_API_KEY}&units=metric`
      );

      if (!response.ok) {
        throw new Error(`Weather API error: ${response.statusText}`);
      }

      const data = await response.json();

      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(
              {
                city: data.name,
                temperature: data.main.temp,
                feels_like: data.main.feels_like,
                humidity: data.main.humidity,
                description: data.weather[0].description,
                wind_speed: data.wind.speed,
              },
              null,
              2
            ),
          },
        ],
      };
    } catch (error) {
      throw new Error(
        `Failed to fetch weather data: ${
          error instanceof Error ? error.message : String(error)
        }`
      );
    }
  }

  throw new Error(`Unknown tool: ${request.params.name}`);
});

// Start the server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Weather MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});
Enter fullscreen mode Exit fullscreen mode

Step 4: Understanding the Code

Let's break down what's happening:

Server Initialization: We create a new MCP server with a name and version, specifying that it has tool capabilities.

ListToolsRequestSchema Handler: This tells Claude what tools are available. We define a get_weather tool with a clear description and input schema that specifies it needs a city name.

CallToolRequestSchema Handler: This is where the actual work happens. When Claude calls our tool, we fetch data from the OpenWeatherMap API and return formatted results.

Transport: We use StdioServerTransport which allows the server to communicate via standard input/output, making it easy to integrate with Claude.

Step 5: Build and Configure

Add build scripts to your package.json:

{
  "scripts": {
    "build": "tsc",
    "start": "node build/index.js"
  },
  "type": "module"
}
Enter fullscreen mode Exit fullscreen mode

Build your server:

npm run build
Enter fullscreen mode Exit fullscreen mode

Step 6: Get Your API Key

  1. Go to OpenWeatherMap
  2. Sign up for a free account
  3. Navigate to your API keys section
  4. Copy your API key

Step 7: Connect to Claude Desktop

To use your MCP server with Claude Desktop, you need to configure it. Create or edit the Claude Desktop configuration file:

On macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

On Windows: %APPDATA%\Claude\claude_desktop_config.json

Add your server configuration:

{
  "mcpServers": {
    "weather": {
      "command": "node",
      "args": ["/absolute/path/to/your/weather-mcp-server/build/index.js"],
      "env": {
        "OPENWEATHER_API_KEY": "your_api_key_here"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Replace /absolute/path/to/your/weather-mcp-server with the actual path to your project and your_api_key_here with your OpenWeatherMap API key.

Step 8: Test Your Server

Restart Claude Desktop. You should now be able to ask Claude questions like:

  • "What's the weather in Tokyo?"
  • "Can you check the current temperature in Paris?"
  • "Tell me about the weather conditions in Lagos"

Claude will automatically use your MCP server to fetch real-time weather data!

Understanding What Just Happened

When you ask Claude about the weather:

  1. Claude recognizes it needs weather information
  2. It discovers your get_weather tool through the MCP protocol
  3. It calls the tool with the appropriate city parameter
  4. Your server fetches data from OpenWeatherMap
  5. The results are returned to Claude
  6. Claude presents the information in a natural, conversational way

Common Issues and Solutions

Server not appearing in Claude: Make sure you've restarted Claude Desktop after editing the config file, and check that the path to your server is absolute, not relative.

API errors: Verify your OpenWeatherMap API key is correct and that you've activated it (it can take a few minutes after signing up).

TypeScript errors: Ensure you're using Node.js 18 or higher and that all dependencies are installed correctly.

Next Steps

Congratulations! You've built your first MCP server. Here are some ways to extend it:

  • Add more weather endpoints (forecast, air quality, historical data)
  • Implement caching to reduce API calls
  • Add error handling for invalid city names
  • Create additional tools for related functionality
  • Add resources to provide weather data access patterns

Where to Go From Here

The MCP ecosystem is growing rapidly. Here are some resources to continue your journey:

Building MCP servers opens up endless possibilities for enhancing AI capabilities. Whether you're connecting to databases, APIs or custom business logic, the pattern you've learned here applies universally.

Top comments (1)

Collapse
 
oluwatitofunmi_adesuyan_9 profile image
Oluwatitofunmi Adesuyan

One question; are there any specific troubleshooting tips for common issues that might arise during the setup process?