Building a Weather MCP Tool: Complete Walkthrough
Build a real, working weather MCP tool — from API key to mcpm publish.
What You'll Build
A weather MCP server with:
get_current_weather — current conditions for any city
get_forecast — 5-day forecast
- Proper error handling
- Unit conversion (celsius/fahrenheit)
Step 1: Get an API Key
Sign up for a free OpenWeatherMap API key at https://openweathermap.org/api.
Free tier: 60 calls/minute, plenty for personal use.
Step 2: Initialize
mkdir weather-mcp && cd weather-mcp
npm init -y
npm install @modelcontextprotocol/sdk
Step 3: Write the Server
Create index.js:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const API_KEY = process.env.OPENWEATHER_API_KEY;
if (!API_KEY) {
console.error("OPENWEATHER_API_KEY environment variable is required");
process.exit(1);
}
const server = new Server({
name: "weather-mcp",
version: "1.0.0",
}, {
capabilities: { tools: {} }
});
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "get_current_weather",
description: "Get current weather conditions for any city",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "City name (e.g., 'London', 'Tokyo', 'San Francisco')"
},
units: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "Temperature unit (default: celsius)"
}
},
required: ["city"]
}
},
{
name: "get_forecast",
description: "Get 5-day weather forecast for any city",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "City name"
},
days: {
type: "number",
description: "Number of days to forecast (1-5, default: 3)"
}
},
required: ["city"]
}
}
]
}));
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "get_current_weather": {
const { city, units = "celsius" } = args;
const unitParam = units === "fahrenheit" ? "imperial" : "metric";
const resp = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(city)}&units=${unitParam}&appid=${API_KEY}`
);
if (!resp.ok) {
const err = await resp.json();
return {
content: [{ type: "text", text: `❌ Weather not found: ${err.message || city}` }]
};
}
const data = await resp.json();
return {
content: [{
type: "text",
text: `🌤️ ${data.name}, ${data.sys.country}
` +
` Temperature: ${Math.round(data.main.temp)}°${units === "fahrenheit" ? "F" : "C"}
` +
` Feels like: ${Math.round(data.main.feels_like)}°
` +
` Condition: ${data.weather[0].description}
` +
` Humidity: ${data.main.humidity}%
` +
` Wind: ${data.wind.speed} m/s`
}]
};
}
case "get_forecast": {
const { city, days = 3 } = args;
const resp = await fetch(
`https://api.openweathermap.org/data/2.5/forecast?q=${encodeURIComponent(city)}&units=metric&appid=${API_KEY}`
);
if (!resp.ok) {
return {
content: [{ type: "text", text: `❌ Forecast not available for: ${city}` }]
};
}
const data = await resp.json();
const daily = {};
for (const entry of data.list) {
const date = entry.dt_txt.split(" ")[0];
if (!daily[date]) {
daily[date] = { temps: [], conditions: [] };
}
daily[date].temps.push(entry.main.temp);
daily[date].conditions.push(entry.weather[0].description);
}
const forecast = Object.entries(daily).slice(0, days).map(([date, d]) => {
const avg = Math.round(d.temps.reduce((a, b) => a + b, 0) / d.temps.length);
const mostCommon = d.conditions.sort((a, b) =>
d.conditions.filter(v => v === a).length - d.conditions.filter(v => v === b).length
).pop();
return ` ${date}: ${avg}°C, ${mostCommon}`;
}).join("\n");
return {
content: [{
type: "text",
text: `📅 ${days}-Day Forecast for ${data.city.name}:
${forecast}`
}]
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
Step 4: Test Locally
OPENWEATHER_API_KEY=your_key node index.js
Step 5: Write README.md
# Weather MCP
Get real-time weather and forecasts via MCP.
## Install
\`\`\`bash
mcpm-dev add weather-mcp
\`\`\`
## Setup
Get a free API key at https://openweathermap.org/api
## Tools
See full documentation at https://www.mcpm.dev/packages/weather-mcp
Step 6: Publish
mcpm-dev login
mcpm-dev publish
Key Takeaways
- API keys in env vars — never hardcode
- Handle errors gracefully — agents need clear messages
- Encode user input —
encodeURIComponent() is essential
- Format output for readability — use emoji and newlines
Your weather MCP tool is live! 🎉
#MCP #Tutorial #Weather #mcpm #NodeJS
Building a Weather MCP Tool: Complete Walkthrough
Build a real, working weather MCP tool — from API key to mcpm publish.
What You'll Build
A weather MCP server with:
get_current_weather— current conditions for any cityget_forecast— 5-day forecastStep 1: Get an API Key
Sign up for a free OpenWeatherMap API key at https://openweathermap.org/api.
Free tier: 60 calls/minute, plenty for personal use.
Step 2: Initialize
mkdir weather-mcp && cd weather-mcp npm init -y npm install @modelcontextprotocol/sdkStep 3: Write the Server
Create
index.js:import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; const API_KEY = process.env.OPENWEATHER_API_KEY; if (!API_KEY) { console.error("OPENWEATHER_API_KEY environment variable is required"); process.exit(1); } const server = new Server({ name: "weather-mcp", version: "1.0.0", }, { capabilities: { tools: {} } }); server.setRequestHandler("tools/list", async () => ({ tools: [ { name: "get_current_weather", description: "Get current weather conditions for any city", inputSchema: { type: "object", properties: { city: { type: "string", description: "City name (e.g., 'London', 'Tokyo', 'San Francisco')" }, units: { type: "string", enum: ["celsius", "fahrenheit"], description: "Temperature unit (default: celsius)" } }, required: ["city"] } }, { name: "get_forecast", description: "Get 5-day weather forecast for any city", inputSchema: { type: "object", properties: { city: { type: "string", description: "City name" }, days: { type: "number", description: "Number of days to forecast (1-5, default: 3)" } }, required: ["city"] } } ] })); server.setRequestHandler("tools/call", async (request) => { const { name, arguments: args } = request.params; switch (name) { case "get_current_weather": { const { city, units = "celsius" } = args; const unitParam = units === "fahrenheit" ? "imperial" : "metric"; const resp = await fetch( `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(city)}&units=${unitParam}&appid=${API_KEY}` ); if (!resp.ok) { const err = await resp.json(); return { content: [{ type: "text", text: `❌ Weather not found: ${err.message || city}` }] }; } const data = await resp.json(); return { content: [{ type: "text", text: `🌤️ ${data.name}, ${data.sys.country} ` + ` Temperature: ${Math.round(data.main.temp)}°${units === "fahrenheit" ? "F" : "C"} ` + ` Feels like: ${Math.round(data.main.feels_like)}° ` + ` Condition: ${data.weather[0].description} ` + ` Humidity: ${data.main.humidity}% ` + ` Wind: ${data.wind.speed} m/s` }] }; } case "get_forecast": { const { city, days = 3 } = args; const resp = await fetch( `https://api.openweathermap.org/data/2.5/forecast?q=${encodeURIComponent(city)}&units=metric&appid=${API_KEY}` ); if (!resp.ok) { return { content: [{ type: "text", text: `❌ Forecast not available for: ${city}` }] }; } const data = await resp.json(); const daily = {}; for (const entry of data.list) { const date = entry.dt_txt.split(" ")[0]; if (!daily[date]) { daily[date] = { temps: [], conditions: [] }; } daily[date].temps.push(entry.main.temp); daily[date].conditions.push(entry.weather[0].description); } const forecast = Object.entries(daily).slice(0, days).map(([date, d]) => { const avg = Math.round(d.temps.reduce((a, b) => a + b, 0) / d.temps.length); const mostCommon = d.conditions.sort((a, b) => d.conditions.filter(v => v === a).length - d.conditions.filter(v => v === b).length ).pop(); return ` ${date}: ${avg}°C, ${mostCommon}`; }).join("\n"); return { content: [{ type: "text", text: `📅 ${days}-Day Forecast for ${data.city.name}: ${forecast}` }] }; } default: throw new Error(`Unknown tool: ${name}`); } }); const transport = new StdioServerTransport(); await server.connect(transport);Step 4: Test Locally
Step 5: Write README.md
# Weather MCP Get real-time weather and forecasts via MCP. ## Install \`\`\`bash mcpm-dev add weather-mcp \`\`\` ## Setup Get a free API key at https://openweathermap.org/api ## Tools See full documentation at https://www.mcpm.dev/packages/weather-mcpStep 6: Publish
Key Takeaways
encodeURIComponent()is essentialYour weather MCP tool is live! 🎉
#MCP #Tutorial #Weather #mcpm #NodeJS