Skip to main content
Glama
hevy-mcp.integration.test.ts4.37 kB
import { config } from "dotenv"; config(); import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, } from "vitest"; import { z } from "zod"; import { registerWorkoutTools } from "../../src/tools/workouts.js"; import { createClient } from "../../src/utils/hevyClient.js"; const HEVY_API_BASEURL = "https://api.hevyapp.com"; // Zod schema for a formatted workout set const FormattedWorkoutSetSchema = z.object({ type: z.string().optional(), weight: z.number().nullable().optional(), reps: z.number().nullable().optional(), distance: z.number().nullable().optional(), duration: z.number().nullable().optional(), rpe: z.number().nullable().optional(), customMetric: z.number().nullable().optional(), }); // Zod schema for a formatted workout exercise const FormattedWorkoutExerciseSchema = z.object({ name: z.string().optional(), notes: z.string().nullable().optional(), sets: z.array(FormattedWorkoutSetSchema).optional(), }); // Zod schema for a formatted workout const FormattedWorkoutSchema = z.object({ id: z.string().optional(), date: z.string().optional(), name: z.string().optional(), description: z.string().nullable().optional(), duration: z.string(), exercises: z.array(FormattedWorkoutExerciseSchema).optional(), }); // Zod schema for the get-workouts response (array of formatted workouts) const GetWorkoutsResponseSchema = z.array(FormattedWorkoutSchema); describe("Hevy MCP Server Integration Tests", () => { let server: McpServer | null = null; let client: Client | null = null; let hevyApiKey: string; let hasApiKey = false; beforeAll(() => { hevyApiKey = process.env.HEVY_API_KEY || ""; hasApiKey = !!hevyApiKey; if (!hasApiKey) { throw new Error( "HEVY_API_KEY is not set in environment variables. Integration tests cannot run without a valid API key.\n\n" + "For local development:\n" + "1. Create a .env file in the project root\n" + "2. Add HEVY_API_KEY=your_api_key to the file\n\n" + "For GitHub Actions:\n" + "1. Go to your GitHub repository\n" + "2. Click on Settings > Secrets and variables > Actions\n" + "3. Click on New repository secret\n" + "4. Set the name to HEVY_API_KEY and the value to your Hevy API key\n" + "5. Click Add secret", ); } }); beforeEach(async () => { // Create server instance server = new McpServer({ name: "hevy-mcp-test", version: "1.0.0", }); // Create Hevy client const hevyClient = createClient(hevyApiKey, HEVY_API_BASEURL); // Register tools registerWorkoutTools(server, hevyClient); // Create client client = new Client({ name: "hevy-mcp-test-client", version: "1.0.0", }); // Connect client and server const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); await Promise.all([ client.connect(clientTransport), server.connect(serverTransport), ]); }); afterEach(async () => { if (server) { await server.close(); } }); afterAll(async () => { if (client) { await client.close(); } }); describe("Get Workouts", () => { it("should be able to get workouts", async () => { const args = { page: 1, pageSize: 5, }; if (!client) throw new Error("Client not initialized"); const result = await client.request( { method: "tools/call", params: { name: "get-workouts", arguments: args, }, }, CallToolResultSchema, ); expect(result).toBeDefined(); const responseData = JSON.parse(result.content[0].text as string); // Validate the response schema with Zod GetWorkoutsResponseSchema.parse(responseData); expect(responseData).toBeDefined(); expect(Array.isArray(responseData)).toBe(true); expect(responseData.length).toBeGreaterThan(0); expect(responseData[0].id).toBeDefined(); expect(responseData[0].title).toBeDefined(); expect(responseData[0].title.length).toBeGreaterThanOrEqual(3); // title is formatted as title expect(responseData[0].createdAt).toBeDefined(); // start_time is formatted as date }); }); });

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/chrisdoc/hevy-mcp'

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