For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://modelgates.ai/docs/_mcp/server.

Weather Tool

Prerequisites

bash
pnpm add @modelgates/sdk zod

You'll need a weather API key. This example uses WeatherAPI (free tier available).

bash
export WEATHER_API_KEY=your_api_key_hereexport MODELGATES_API_KEY=your_modelgates_key

Basic Implementation

typescript
import { ModelGates, tool } from '@modelgates/agent';import { z } from 'zod'; const modelgates = new ModelGates({  apiKey: process.env.MODELGATES_API_KEY,}); const weatherTool = tool({  name: 'get_weather',  description: 'Get current weather conditions for any city worldwide',  inputSchema: z.object({    city: z.string().describe('City name, e.g., "San Francisco" or "London, UK"'),    units: z      .enum(['celsius', 'fahrenheit'])      .default('celsius')      .describe('Temperature units'),  }),  outputSchema: z.object({    temperature: z.number(),    feelsLike: z.number(),    conditions: z.string(),    humidity: z.number(),    windSpeed: z.number(),    windDirection: z.string(),    location: z.object({      name: z.string(),      region: z.string(),      country: z.string(),    }),  }),  execute: async ({ city, units }) => {    const apiKey = process.env.WEATHER_API_KEY;    if (!apiKey) {      throw new Error('WEATHER_API_KEY environment variable not set');    }     const response = await fetch(      `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${encodeURIComponent(city)}`    );     if (!response.ok) {      if (response.status === 400) {        throw new Error(`City not found: ${city}`);      }      throw new Error(`Weather API error: ${response.status}`);    }     const data = await response.json();     return {      temperature: units === 'celsius' ? data.current.temp_c : data.current.temp_f,      feelsLike: units === 'celsius' ? data.current.feelslike_c : data.current.feelslike_f,      conditions: data.current.condition.text,      humidity: data.current.humidity,      windSpeed: data.current.wind_kph,      windDirection: data.current.wind_dir,      location: {        name: data.location.name,        region: data.location.region,        country: data.location.country,      },    };  },});

Usage

typescript
const result = modelgates.callModel({  model: 'openai/gpt-5-nano',  input: 'What is the weather like in Tokyo?',  tools: [weatherTool],}); const text = await result.getText();console.log(text);// "The current weather in Tokyo, Japan is partly cloudy with a temperature// of 22°C (feels like 24°C). Humidity is at 65% with winds from the SW// at 15 km/h."

With Multiple Cities

typescript
const result = modelgates.callModel({  model: 'openai/gpt-5-nano',  input: 'Compare the weather in New York and Los Angeles',  tools: [weatherTool],}); // The model will call the tool twice, once for each cityconst text = await result.getText();

Extended Version with Forecast

typescript
const forecastTool = tool({  name: 'get_forecast',  description: 'Get weather forecast for the next few days',  inputSchema: z.object({    city: z.string().describe('City name'),    days: z.number().min(1).max(7).default(3).describe('Number of forecast days'),    units: z.enum(['celsius', 'fahrenheit']).default('celsius'),  }),  outputSchema: z.object({    location: z.string(),    forecast: z.array(      z.object({        date: z.string(),        maxTemp: z.number(),        minTemp: z.number(),        conditions: z.string(),        chanceOfRain: z.number(),      })    ),  }),  execute: async ({ city, days, units }) => {    const apiKey = process.env.WEATHER_API_KEY;    if (!apiKey) {      throw new Error('WEATHER_API_KEY environment variable not set');    }     const response = await fetch(      `https://api.weatherapi.com/v1/forecast.json?key=${apiKey}&q=${encodeURIComponent(city)}&days=${days}`    );     if (!response.ok) {      throw new Error(`Weather API error: ${response.status}`);    }     const data = await response.json();     return {      location: `${data.location.name}, ${data.location.country}`,      forecast: data.forecast.forecastday.map((day: any) => ({        date: day.date,        maxTemp: units === 'celsius' ? day.day.maxtemp_c : day.day.maxtemp_f,        minTemp: units === 'celsius' ? day.day.mintemp_c : day.day.mintemp_f,        conditions: day.day.condition.text,        chanceOfRain: day.day.daily_chance_of_rain,      })),    };  },}); // Use both tools togetherconst result = modelgates.callModel({  model: 'openai/gpt-5-nano',  input: 'What is the weather in Paris today and for the next 3 days?',  tools: [weatherTool, forecastTool],});

Error Handling

The tool includes proper error handling:

typescript
const weatherToolWithRetry = tool({  name: 'get_weather',  description: 'Get current weather with retry logic',  inputSchema: z.object({    city: z.string(),    units: z.enum(['celsius', 'fahrenheit']).default('celsius'),  }),  outputSchema: z.object({    temperature: z.number(),    conditions: z.string(),    error: z.string().optional(),  }),  execute: async ({ city, units }) => {    const maxRetries = 3;    let lastError: Error | null = null;     for (let attempt = 1; attempt <= maxRetries; attempt++) {      try {        const response = await fetch(          `https://api.weatherapi.com/v1/current.json?key=${process.env.WEATHER_API_KEY}&q=${encodeURIComponent(city)}`        );         if (response.status === 429) {          // Rate limited, wait and retry          await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));          continue;        }         if (!response.ok) {          throw new Error(`API error: ${response.status}`);        }         const data = await response.json();        return {          temperature: units === 'celsius' ? data.current.temp_c : data.current.temp_f,          conditions: data.current.condition.text,        };      } catch (error) {        lastError = error as Error;      }    }     // Return error in output rather than throwing    return {      temperature: 0,      conditions: 'Unknown',      error: `Failed after ${maxRetries} attempts: ${lastError?.message}`,    };  },});

Testing

typescript
import { describe, it, expect, mock } from 'bun:test'; describe('weatherTool', () => {  it('returns weather data for valid city', async () => {    // Mock the fetch response    global.fetch = mock(() =>      Promise.resolve({        ok: true,        json: () =>          Promise.resolve({            current: {              temp_c: 22,              temp_f: 72,              feelslike_c: 24,              feelslike_f: 75,              condition: { text: 'Sunny' },              humidity: 45,              wind_kph: 10,              wind_dir: 'NW',            },            location: {              name: 'London',              region: 'City of London',              country: 'UK',            },          }),      })    );     const result = await weatherTool.function.execute(      { city: 'London', units: 'celsius' },      { numberOfTurns: 1 }    );     expect(result.temperature).toBe(22);    expect(result.conditions).toBe('Sunny');    expect(result.location.name).toBe('London');  });   it('handles city not found', async () => {    global.fetch = mock(() =>      Promise.resolve({        ok: false,        status: 400,      })    );     await expect(      weatherTool.function.execute(        { city: 'InvalidCity123', units: 'celsius' },        { numberOfTurns: 1 }      )    ).rejects.toThrow('City not found');  });});

See Also