Skip to main content
Glama
BaseTool.ts2.64 kB
import type { z } from 'zod'; import { articRateLimiter } from '../utils/RateLimiter'; export abstract class BaseTool<T extends z.ZodType, R> { public abstract readonly name: string; public abstract readonly description: string; public abstract readonly inputSchema: T; protected readonly apiBaseUrl: string = 'https://api.artic.edu/api/v1'; protected constructor() {} public abstract executeCore(input: z.infer<T>): Promise<R>; public async execute(input: z.infer<T>) { try { return await this.executeCore(input); } catch (error) { console.error(`Error executing ${this.name}:`, error); return { content: [{ type: 'text' as const, text: `Error in ${this.name}: ${error}`, }], isError: true, }; } } protected getDefaultHeaders() { return { 'Content-Type': 'application/json', 'AIC-User-Agent': 'artic-mcp (mike.chao.one@gmail.com)', }; } protected async safeApiRequest<S extends z.ZodType>( url: URL | string, options: RequestInit, schema: S, ): Promise<z.infer<S>> { const response = await articRateLimiter.fetch(url.toString(), { ...options, headers: { ...this.getDefaultHeaders(), ...(options.headers || {}), }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const jsonResponse = await response.json(); const parsedResponse = schema.safeParse(jsonResponse); if (!parsedResponse.success) { throw new Error(`Invalid response shape: ${JSON.stringify(parsedResponse.error.issues, null, 2)}`); } return parsedResponse.data; } protected formatArtworkList(artworks: any[], query: string) { if (artworks.length === 0) { return { content: [{ type: 'text' as const, text: `No artworks found for "${query}".` }], isError: false, }; } const artText = artworks.map((artwork) => { return `Title: ${artwork.title}\n` + `Artwork ID: ${artwork.id}\n` + `Thumbnail alt text: ${artwork.thumbnail?.alt_text ?? 'No thumbnail available'}\n` + `Score: ${artwork._score}\n`; }).join('\n-----\n'); const paginationText = artworks.length > 0 ? `\nPagination Info\n` + `Total: ${artworks[0]._pagination?.total || 'Unknown'}\n` + `Total Pages: ${artworks[0]._pagination?.total_pages || 'Unknown'}\n` + `Current Page: ${artworks[0]._pagination?.current_page || 'Unknown'}` : ''; return { content: [{ type: 'text' as const, text: artText + paginationText }], }; } }

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/mikechao/artic-mcp'

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