Skip to main content
Glama

mcp-open-library

index.test.ts9.64 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js"; import { describe, it, expect, beforeEach, vi, Mock } from "vitest"; // Use vitest imports import { OpenLibraryBookResponse } from "./types.js"; // Import necessary type import { handleGetBookById } from "./index.js"; // Mock axios using vitest vi.mock("axios"); // Create a mock Axios instance type using vitest Mock type MockAxiosInstance = { get: Mock; // Use Mock from vitest }; describe("handleGetBookById", () => { let mockAxiosInstance: MockAxiosInstance; beforeEach(() => { // Reset mocks before each test using vitest vi.clearAllMocks(); // Create a fresh mock instance for each test using vitest mockAxiosInstance = { get: vi.fn(), // Use vi.fn() }; }); it("should return book details when given a valid OLID", async () => { const mockArgs = { idType: "olid", idValue: "OL7353617M" }; const mockApiResponse: OpenLibraryBookResponse = { records: { "/books/OL7353617M": { recordURL: "https://openlibrary.org/books/OL7353617M/The_Lord_of_the_Rings", data: { title: "The Lord of the Rings", authors: [{ url: "/authors/OL216228A", name: "J.R.R. Tolkien" }], publish_date: "1954", identifiers: { openlibrary: ["OL7353617M"], isbn_10: ["061826027X"], }, number_of_pages: 1216, cover: { medium: "https://covers.openlibrary.org/b/id/8264411-M.jpg", }, key: "/books/OL7353617M", url: "https://openlibrary.org/books/OL7353617M/The_Lord_of_the_Rings", }, details: { info_url: "https://openlibrary.org/books/OL7353617M/The_Lord_of_the_Rings", bib_key: "OLID:OL7353617M", preview_url: "https://archive.org/details/lordofrings00tolk_1", thumbnail_url: "https://covers.openlibrary.org/b/id/8264411-S.jpg", details: { key: "/books/OL7353617M", works: [{ key: "/works/OL45804W" }], title: "The Lord of the Rings", authors: [{ url: "/authors/OL216228A", name: "J.R.R. Tolkien" }], publishers: [{ name: "Houghton Mifflin" }], publish_date: "1954", isbn_10: ["061826027X"], number_of_pages: 1216, }, preview: "restricted", }, }, }, items: [], // Add required items property }; mockAxiosInstance.get.mockResolvedValue({ data: mockApiResponse }); const result = await handleGetBookById(mockArgs, mockAxiosInstance as any); // Cast to any for simplicity expect(mockAxiosInstance.get).toHaveBeenCalledWith( "/api/volumes/brief/olid/OL7353617M.json", ); expect(result).toEqual({ content: [ { type: "text", text: expect.stringContaining('"title": "The Lord of the Rings"'), }, ], }); // Check specific fields in the parsed JSON const parsedResult = JSON.parse(result.content[0].text as string); expect(parsedResult).toHaveProperty("title", "The Lord of the Rings"); expect(parsedResult).toHaveProperty("authors", ["J.R.R. Tolkien"]); expect(parsedResult).toHaveProperty("publish_date", "1954"); expect(parsedResult).toHaveProperty("number_of_pages", 1216); expect(parsedResult).toHaveProperty("isbn_10", ["061826027X"]); // Should be array from details expect(parsedResult).toHaveProperty("olid", ["OL7353617M"]); // Should be array from identifiers expect(parsedResult).toHaveProperty( "open_library_edition_key", "/books/OL7353617M", ); expect(parsedResult).toHaveProperty( "open_library_work_key", "/works/OL45804W", ); expect(parsedResult).toHaveProperty( "cover_url", "https://covers.openlibrary.org/b/id/8264411-M.jpg", ); expect(parsedResult).toHaveProperty( "info_url", "https://openlibrary.org/books/OL7353617M/The_Lord_of_the_Rings", ); expect(parsedResult).toHaveProperty( "preview_url", "https://archive.org/details/lordofrings00tolk_1", ); }); it("should return book details when given a valid ISBN", async () => { const mockArgs = { idType: "isbn", idValue: "9780547928227" }; const mockApiResponse: OpenLibraryBookResponse = { records: { "isbn:9780547928227": { recordURL: "https://openlibrary.org/books/OL25189068M/The_Hobbit", data: { title: "The Hobbit", authors: [{ url: "/authors/OL216228A", name: "J.R.R. Tolkien" }], publish_date: "2012", identifiers: { isbn_13: ["9780547928227"], openlibrary: ["OL25189068M"], }, key: "/books/OL25189068M", url: "https://openlibrary.org/books/OL25189068M/The_Hobbit", }, details: { /* ... potentially more details ... */ } as any, // Cast for brevity }, }, items: [], // Add required items property }; mockAxiosInstance.get.mockResolvedValue({ data: mockApiResponse }); const result = await handleGetBookById(mockArgs, mockAxiosInstance as any); expect(mockAxiosInstance.get).toHaveBeenCalledWith( "/api/volumes/brief/isbn/9780547928227.json", ); expect(result).toEqual({ content: [ { type: "text", text: expect.stringContaining('"title": "The Hobbit"'), }, ], }); const parsedResult = JSON.parse(result.content[0].text as string); expect(parsedResult).toHaveProperty("title", "The Hobbit"); expect(parsedResult).toHaveProperty("isbn_13", ["9780547928227"]); expect(parsedResult).toHaveProperty("olid", ["OL25189068M"]); }); it("should throw McpError for invalid arguments", async () => { const invalidArgs = { idType: "invalid", idValue: "123" }; // Invalid idType await expect( handleGetBookById(invalidArgs, mockAxiosInstance as any), ).rejects.toThrow(McpError); try { await handleGetBookById(invalidArgs, mockAxiosInstance as any); } catch (error) { expect(error).toBeInstanceOf(McpError); expect((error as McpError).code).toBe(ErrorCode.InvalidParams); expect((error as McpError).message).toContain( "Invalid arguments for get_book_by_id", ); expect((error as McpError).message).toContain( "idType must be one of: isbn, lccn, oclc, olid", ); } expect(mockAxiosInstance.get).not.toHaveBeenCalled(); }); it('should return "No book found" message when API returns empty records', async () => { const mockArgs = { idType: "olid", idValue: "OL_NONEXISTENT" }; const mockApiResponse: OpenLibraryBookResponse = { records: {}, items: [], }; // Empty records mockAxiosInstance.get.mockResolvedValue({ data: mockApiResponse }); const result = await handleGetBookById(mockArgs, mockAxiosInstance as any); expect(mockAxiosInstance.get).toHaveBeenCalledWith( "/api/volumes/brief/olid/OL_NONEXISTENT.json", ); expect(result).toEqual({ content: [ { type: "text", text: "No book found for olid: OL_NONEXISTENT", }, ], }); }); it('should return "No book found" message on 404 API error', async () => { const mockArgs = { idType: "isbn", idValue: "0000000000" }; const axiosError = { isAxiosError: true, response: { status: 404, statusText: "Not Found" }, message: "Request failed with status code 404", }; mockAxiosInstance.get.mockRejectedValue(axiosError); const result = await handleGetBookById(mockArgs, mockAxiosInstance as any); expect(mockAxiosInstance.get).toHaveBeenCalledWith( "/api/volumes/brief/isbn/0000000000.json", ); expect(result).toEqual({ content: [ { type: "text", text: "Failed to fetch book data from Open Library.", // Specific message for 404 }, ], }); }); it("should return generic API error message for non-404 errors", async () => { const mockArgs = { idType: "olid", idValue: "OL1M" }; const axiosError = { isAxiosError: true, response: { status: 500, statusText: "Internal Server Error" }, message: "Request failed with status code 500", }; mockAxiosInstance.get.mockRejectedValue(axiosError); const result = await handleGetBookById(mockArgs, mockAxiosInstance as any); expect(mockAxiosInstance.get).toHaveBeenCalledWith( "/api/volumes/brief/olid/OL1M.json", ); expect(result).toEqual({ content: [ { type: "text", text: "Failed to fetch book data from Open Library.", // Generic API error }, ], }); }); it("should return generic error message for non-Axios errors", async () => { const mockArgs = { idType: "olid", idValue: "OL1M" }; const genericError = new Error("Network Failure"); mockAxiosInstance.get.mockRejectedValue(genericError); const result = await handleGetBookById(mockArgs, mockAxiosInstance as any); expect(mockAxiosInstance.get).toHaveBeenCalledWith( "/api/volumes/brief/olid/OL1M.json", ); expect(result).toEqual({ content: [ { type: "text", text: "Error processing request: Network Failure", // Generic processing error }, ], }); }); });

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/8enSmith/mcp-open-library'

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