Skip to main content
Glama

Analytics MCP

by Ninoambaraa
weather-workflow.tsβ€’5.62 kB
import { createStep, createWorkflow } from '@mastra/core/workflows'; import { z } from 'zod'; const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); function getWeatherCondition(code: number): string { const conditions: Record<number, string> = { 0: 'Clear sky', 1: 'Mainly clear', 2: 'Partly cloudy', 3: 'Overcast', 45: 'Foggy', 48: 'Depositing rime fog', 51: 'Light drizzle', 53: 'Moderate drizzle', 55: 'Dense drizzle', 61: 'Slight rain', 63: 'Moderate rain', 65: 'Heavy rain', 71: 'Slight snow fall', 73: 'Moderate snow fall', 75: 'Heavy snow fall', 95: 'Thunderstorm', }; return conditions[code] || 'Unknown'; } const fetchWeather = createStep({ id: 'fetch-weather', description: 'Fetches weather forecast for a given city', inputSchema: z.object({ city: z.string().describe('The city to get the weather for'), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error('Input data not found'); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), location: name, }; return forecast; }, }); const planActivities = createStep({ id: 'plan-activities', description: 'Suggests activities based on weather conditions', inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error('Forecast data not found'); } const agent = mastra?.getAgent('weatherAgent'); if (!agent) { throw new Error('Weather agent not found'); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} For each day in the forecast, structure your response exactly as follows: πŸ“… [Day, Month Date, Year] ═══════════════════════════ 🌑️ WEATHER SUMMARY β€’ Conditions: [brief description] β€’ Temperature: [XΒ°C/YΒ°F to AΒ°C/BΒ°F] β€’ Precipitation: [X% chance] πŸŒ… MORNING ACTIVITIES Outdoor: β€’ [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: β€’ [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES β€’ [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS β€’ [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown.`; const response = await agent.stream([ { role: 'user', content: prompt, }, ]); let activitiesText = ''; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); const weatherWorkflow = createWorkflow({ id: 'weather-workflow', description: "Get current weather for a location", inputSchema: z.object({ city: z.string().describe('The city to get the weather for'), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .then(planActivities); weatherWorkflow.commit(); export { weatherWorkflow };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Ninoambaraa/superalink-mcp-analytics'

If you have feedback or need assistance with the MCP directory API, please join our Discord server