index.js•5.19 kB
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
const API_KEY = "538138d58dd24af548ec18f74f84f73f";
class WeatherServer {
constructor() {
this.server = new Server(
{
name: "weather-server",
version: "0.1.0",
},
{
capabilities: {
tools: {},
},
}
);
this.setupToolHandlers();
}
setupToolHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_weather",
description: "Get current weather for a city",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "Name of the city to get weather for",
},
},
required: ["city"],
},
},
{
name: "send_notification",
description: "Send a macOS notification with provided weather data",
inputSchema: {
type: "object",
properties: {
title: {
type: "string",
description: "Notification title",
},
message: {
type: "string",
description: "Notification message",
},
},
required: ["title", "message"],
},
},
],
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_weather") {
return await this.getWeather(args.city);
}
if (name === "send_notification") {
return await this.sendNotification(args.title, args.message);
}
throw new Error(`Unknown tool: ${name}`);
});
}
async getWeather(city) {
if (!API_KEY) {
throw new Error("OpenWeatherMap API key not found. Set OPENWEATHER_API_KEY environment variable.");
}
try {
const response = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric`
);
const weather = response.data;
return {
content: [
{
type: "text",
text: `Weather in ${weather.name}, ${weather.sys.country}:
Temperature: ${weather.main.temp}°C (feels like ${weather.main.feels_like}°C)
Condition: ${weather.weather[0].description}
Humidity: ${weather.main.humidity}%
Wind: ${weather.wind.speed} m/s
Pressure: ${weather.main.pressure} hPa`,
},
],
};
} catch (error) {
throw new Error(`Failed to get weather for ${city}: ${error.message}`);
}
}
async sendNotification(title, message) {
try {
const { exec } = await import('child_process');
const { promisify } = await import('util');
const execAsync = promisify(exec);
const combinedMessage = `${title}\\n\\n${message}`;
const script = `osascript -e 'tell application "System Events" to display dialog "${combinedMessage}" with title "Weather Update" buttons {"OK"} default button "OK" giving up after 10'`;
console.error("Executing:", script);
await execAsync(script);
return {
content: [
{
type: "text",
text: `✅ Weather dialog displayed!\nTitle: ${title}\nMessage: ${message}`,
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `❌ Failed: ${error.message}`,
},
],
};
}
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error("Weather MCP server running on stdio");
}
}
const server = new WeatherServer();
server.run().catch(console.error);