intermediate20 minentree

Entree: Weather API Server

An MCP server that fetches real weather data from Open-Meteo. Learn to integrate external APIs, handle errors, and return structured data to AI assistants.


title: "Entree: Weather API Server" description: "An MCP server that fetches real weather data from Open-Meteo. Learn to integrate external APIs, handle errors, and return structured data to AI assistants." order: 3 category: "entree" level: "intermediate" duration: "20 min" date: "2026-04-01" tags:

  • tools
  • api
  • weather keywords:
  • mcp weather server
  • mcp-framework api integration
  • weather api mcp
  • open-meteo mcp

What You Get

A production-quality MCP server that lets Claude check the weather for any city. It uses the free Open-Meteo API — no API key required.

Tools included:

  • get_weather — fetch current weather for a city (temperature, humidity, wind speed, conditions)
  • get_forecast — get a multi-day weather forecast

Quick Start

npx mcp-framework create weather-server
cd weather-server

The Weather Tool

Create src/tools/GetWeatherTool.ts:

import { MCPTool } from "mcp-framework";
import { z } from "zod";

const WeatherInput = z.object({
  city: z.string().describe("City name (e.g. 'London', 'New York')"),
});

class GetWeatherTool extends MCPTool<typeof WeatherInput> {
  name = "get_weather";
  description = "Get current weather for a city using Open-Meteo";
  schema = { input: WeatherInput };

  async execute(input: z.infer<typeof WeatherInput>) {
    // Step 1: Geocode the city
    const geoRes = await fetch(
      `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(input.city)}&count=1`
    );
    const geoData = await geoRes.json();

    if (!geoData.results?.length) {
      throw new Error(`City not found: ${input.city}`);
    }

    const { latitude, longitude, name, country } = geoData.results[0];

    // Step 2: Fetch weather
    const weatherRes = await fetch(
      `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code`
    );
    const weatherData = await weatherRes.json();
    const current = weatherData.current;

    return {
      location: `${name}, ${country}`,
      temperature: `${current.temperature_2m}°C`,
      humidity: `${current.relative_humidity_2m}%`,
      windSpeed: `${current.wind_speed_10m} km/h`,
      conditionCode: current.weather_code,
    };
  }
}

export default GetWeatherTool;

The Forecast Tool

Create src/tools/GetForecastTool.ts:

import { MCPTool } from "mcp-framework";
import { z } from "zod";

const ForecastInput = z.object({
  city: z.string().describe("City name"),
  days: z.number().min(1).max(7).default(3).describe("Number of forecast days"),
});

class GetForecastTool extends MCPTool<typeof ForecastInput> {
  name = "get_forecast";
  description = "Get a multi-day weather forecast";
  schema = { input: ForecastInput };

  async execute(input: z.infer<typeof ForecastInput>) {
    const geoRes = await fetch(
      `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(input.city)}&count=1`
    );
    const geoData = await geoRes.json();

    if (!geoData.results?.length) {
      throw new Error(`City not found: ${input.city}`);
    }

    const { latitude, longitude, name, country } = geoData.results[0];

    const weatherRes = await fetch(
      `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=temperature_2m_max,temperature_2m_min,weather_code&forecast_days=${input.days}`
    );
    const data = await weatherRes.json();

    return {
      location: `${name}, ${country}`,
      forecast: data.daily.time.map((date: string, i: number) => ({
        date,
        high: `${data.daily.temperature_2m_max[i]}°C`,
        low: `${data.daily.temperature_2m_min[i]}°C`,
        conditionCode: data.daily.weather_code[i],
      })),
    };
  }
}

export default GetForecastTool;

Error Handling

Notice how both tools throw descriptive errors when a city is not found. mcp-framework will automatically catch these and return them as structured error responses to the AI assistant.

Build & Connect

npm run build
{
  "mcpServers": {
    "weather": {
      "command": "node",
      "args": ["./dist/index.js"]
    }
  }
}

What You Learn

  • Integrating external REST APIs in MCP tools
  • Chaining API calls (geocoding then weather)
  • Returning structured data that AI can reason about
  • Input validation with defaults (days defaults to 3)
  • Error handling patterns for MCP servers

Next Up

Try the Database Query Server or the GitHub Integration Server for more real-world patterns.


Built with mcp-framework (3.3M+ downloads) by @QuantGeekDev. Validated by Anthropic.