Skip to main content
Glama
WeatherDailyTool.test.ts5.61 kB
// tests/WeatherDailyTool.test.ts import { inputSchema, handler } from "../src/tools/WeatherDailyTool"; import axios from "axios"; import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js"; jest.mock("axios"); const mockedAxios = axios as jest.Mocked<typeof axios>; beforeAll(() => { // Make axios.isAxiosError always return true for our error‐tests jest.spyOn(axios, "isAxiosError").mockReturnValue(true); }); describe("WeatherDailyTool handler", () => { const validArgs = { location: "Paris", days: 5, units: "metric" }; const extra: RequestHandlerExtra<any, any> = { signal: new AbortController().signal, requestId: "req-1", sendNotification: jest.fn(), sendRequest: jest.fn(), }; const originalApiKey = process.env.ACCUWEATHER_API_KEY; beforeEach(() => { process.env.ACCUWEATHER_API_KEY = "dummy-key"; mockedAxios.get.mockReset(); }); afterAll(() => { // restore env if (originalApiKey) process.env.ACCUWEATHER_API_KEY = originalApiKey; else delete process.env.ACCUWEATHER_API_KEY; }); it("passes zod validation for well-formed input", () => { expect(() => inputSchema.parse(validArgs)).not.toThrow(); }); it("accepts requests with minimal required parameters", () => { const result = inputSchema.parse({ location: validArgs.location }); // Just verify parsing doesn't throw an error expect(result.location).toBe(validArgs.location); // The handler will use default values for days (5) and units ("metric") }); it("rejects when location is empty", () => { expect(() => inputSchema.parse({ location: "", days: 5, units: "metric" }) ).toThrow(/Location must be at least 1 character/); }); it("fetches location key and daily forecast and formats text", async () => { // location-search API mockedAxios.get .mockResolvedValueOnce({ data: [{ Key: "LOC123" }] }) // forecast API .mockResolvedValueOnce({ data: { DailyForecasts: [ { Date: "2025-05-04T07:00:00+02:00", Temperature: { Minimum: { Value: 15, Unit: "C" }, Maximum: { Value: 25, Unit: "C" } }, Day: { IconPhrase: "Partly sunny", HasPrecipitation: false }, Night: { IconPhrase: "Mostly clear", HasPrecipitation: false } } ] } }); const result = await handler(validArgs, extra); // two calls: one for cities/search, one for daily forecast expect(mockedAxios.get).toHaveBeenCalledTimes(2); expect(mockedAxios.get).toHaveBeenCalledWith( expect.stringContaining("locations/v1/cities/search") ); expect(mockedAxios.get).toHaveBeenCalledWith( expect.stringContaining("forecasts/v1/daily/5day/LOC123") ); expect(mockedAxios.get).toHaveBeenCalledWith( expect.stringContaining("metric=true") ); // one text item in content array expect(result.content).toHaveLength(1); expect(result.content[0].text).toContain("15°C to 25°C"); expect(result.content[0].text).toContain("Day: Partly sunny"); expect(result.content[0].text).toContain("Night: Mostly clear"); }); it("handles unit preferences correctly", async () => { // location-search API mockedAxios.get .mockResolvedValueOnce({ data: [{ Key: "LOC123" }] }) // forecast API .mockResolvedValueOnce({ data: { DailyForecasts: [ { Date: "2025-05-04T07:00:00+02:00", Temperature: { Minimum: { Value: 59, Unit: "F" }, Maximum: { Value: 77, Unit: "F" } }, Day: { IconPhrase: "Partly sunny", HasPrecipitation: false }, Night: { IconPhrase: "Mostly clear", HasPrecipitation: false } } ] } }); const result = await handler({ ...validArgs, units: "imperial" }, extra); expect(mockedAxios.get).toHaveBeenCalledTimes(2); expect(mockedAxios.get).toHaveBeenCalledWith( expect.stringContaining("metric=false") ); expect(result.content[0].text).toContain("59°F to 77°F"); }); it("adjusts the forecast days correctly", async () => { mockedAxios.get .mockResolvedValueOnce({ data: [{ Key: "LOC123" }] }) .mockResolvedValueOnce({ data: { DailyForecasts: [] } }); // Test with days=1 await handler({ ...validArgs, days: 1 }, extra); expect(mockedAxios.get).toHaveBeenCalledWith( expect.stringContaining("forecasts/v1/daily/1day/LOC123") ); mockedAxios.get.mockReset(); mockedAxios.get .mockResolvedValueOnce({ data: [{ Key: "LOC123" }] }) .mockResolvedValueOnce({ data: { DailyForecasts: [] } }); // Test with days=10 await handler({ ...validArgs, days: 10 }, extra); expect(mockedAxios.get).toHaveBeenCalledWith( expect.stringContaining("forecasts/v1/daily/10day/LOC123") ); }); it("handles no-location-found", async () => { mockedAxios.get.mockResolvedValueOnce({ data: [] }); const resp = await handler(validArgs, extra); expect(mockedAxios.get).toHaveBeenCalledTimes(1); expect(resp.content[0].text).toBe("No location found for: Paris"); }); });

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/TimLukaHorstmann/mcp-weather'

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