UNPKG

aareguru-mcp

Version:

MCP server for Aare.guru API - provides water temperature and swimming conditions for the Aare river

314 lines (287 loc) 9.79 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"; const API_BASE_URL = "https://aareguru.existenz.ch"; const DEFAULT_APP = "aareguru-mcp-server"; const DEFAULT_VERSION = "1.0.0"; class AareGuruServer { constructor() { this.server = new Server( { name: "aareguru-server", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); this.setupToolHandlers(); } setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "get_cities", description: "Get list of all available cities/locations with Aare data", inputSchema: { type: "object", properties: { app: { type: "string", description: "Optional app identifier", default: DEFAULT_APP }, version: { type: "string", description: "Optional version number", default: DEFAULT_VERSION }, values: { type: "string", description: "Optional comma-separated list of specific values to extract" } } } }, { name: "get_current_conditions", description: "Get comprehensive current Aare data for a specific location including temperature, flow, forecasts", inputSchema: { type: "object", properties: { city: { type: "string", description: "City identifier (e.g., 'bern', 'thun')", default: "bern" }, app: { type: "string", description: "Optional app identifier", default: DEFAULT_APP }, version: { type: "string", description: "Optional version number", default: DEFAULT_VERSION }, values: { type: "string", description: "Optional comma-separated list of specific values to extract" } } } }, { name: "get_today_summary", description: "Get minimal current Aare temperature and swimming recommendation for a location", inputSchema: { type: "object", properties: { city: { type: "string", description: "City identifier (e.g., 'bern', 'thun')", default: "bern" }, app: { type: "string", description: "Optional app identifier", default: DEFAULT_APP }, version: { type: "string", description: "Optional version number", default: DEFAULT_VERSION }, values: { type: "string", description: "Optional comma-separated list of specific values to extract" } } } }, { name: "get_widget_data", description: "Get current Aare data for all locations at once, suitable for widgets/dashboards", inputSchema: { type: "object", properties: { app: { type: "string", description: "Optional app identifier", default: DEFAULT_APP }, version: { type: "string", description: "Optional version number", default: DEFAULT_VERSION }, values: { type: "string", description: "Optional comma-separated list of specific values to extract" } } } }, { name: "get_historical_data", description: "Get historical time series data for water temperature, flow, and air temperature", inputSchema: { type: "object", properties: { city: { type: "string", description: "City identifier (required for historical data)", required: true }, start: { type: "string", description: "Start date/time in various formats (ISO, timestamp, 'yesterday', '-1 day')", required: true }, end: { type: "string", description: "End date/time in various formats (ISO, timestamp, 'now')", required: true }, app: { type: "string", description: "Optional app identifier", default: DEFAULT_APP }, version: { type: "string", description: "Optional version number", default: DEFAULT_VERSION }, values: { type: "string", description: "Optional comma-separated list of specific values to extract" } }, required: ["city", "start", "end"] } } ] }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "get_cities": return await this.getCities(args); case "get_current_conditions": return await this.getCurrentConditions(args); case "get_today_summary": return await this.getTodaySummary(args); case "get_widget_data": return await this.getWidgetData(args); case "get_historical_data": return await this.getHistoricalData(args); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: "text", text: `Error: ${error.message}` } ], isError: true }; } }); } async makeApiRequest(endpoint, params = {}) { const url = new URL(`${API_BASE_URL}${endpoint}`); // Add default app and version if not provided if (!params.app) params.app = DEFAULT_APP; if (!params.version) params.version = DEFAULT_VERSION; // Add all parameters to URL Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null) { url.searchParams.append(key, value); } }); const response = await fetch(url.toString()); if (!response.ok) { throw new Error(`API request failed: ${response.status} ${response.statusText}`); } const data = await response.json(); return data; } async getCities(args = {}) { const data = await this.makeApiRequest("/v2018/cities", args); return { content: [ { type: "text", text: `Available Aare monitoring locations:\n\n${JSON.stringify(data, null, 2)}` } ] }; } async getCurrentConditions(args = {}) { const data = await this.makeApiRequest("/v2018/current", args); return { content: [ { type: "text", text: `Current Aare conditions for ${args.city || 'Bern'}:\n\n${JSON.stringify(data, null, 2)}` } ] }; } async getTodaySummary(args = {}) { const data = await this.makeApiRequest("/v2018/today", args); return { content: [ { type: "text", text: `Today's Aare summary for ${args.city || 'Bern'}:\n\n${JSON.stringify(data, null, 2)}` } ] }; } async getWidgetData(args = {}) { const data = await this.makeApiRequest("/v2018/widget", args); return { content: [ { type: "text", text: `Aare widget data for all locations:\n\n${JSON.stringify(data, null, 2)}` } ] }; } async getHistoricalData(args = {}) { if (!args.city || !args.start || !args.end) { throw new Error("Historical data requires city, start, and end parameters"); } const data = await this.makeApiRequest("/v2018/history", args); return { content: [ { type: "text", text: `Historical Aare data for ${args.city} (${args.start} to ${args.end}):\n\n${JSON.stringify(data, null, 2)}` } ] }; } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error("Aare.guru MCP server running on stdio"); } } const server = new AareGuruServer(); server.run().catch(console.error);