get-artwork-by-id
Retrieve detailed information and images for specific artworks from the Art Institute of Chicago collection using unique artwork IDs.
Instructions
Get additional information, including an image if available, about a specific artwork by its ID from the Art Institute of Chicago. Using the value of Artwork ID from the 'search-by-title' tool.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The ID of the artwork to retrieve. | |
| includeImage | No | Whether to include the artwork image in the response. |
Implementation Reference
- src/tools/GetArtworkByIdTool.ts:12-105 (handler)The GetArtworkByIdTool class is the main handler for the 'get-artwork-by-id' tool. It fetches detailed artwork information from the Art Institute of Chicago API, formats it into text, and optionally retrieves and embeds the image.export class GetArtworkByIdTool extends BaseTool<typeof artworkByIdSchema, any> { public readonly name: string = 'get-artwork-by-id'; public readonly description: string = `Get additional information, including an image if available, about a specific artwork by its ID` + ` from the Art Institute of Chicago. ` + `Using the value of Artwork ID from the 'search-by-title' tool.`; public readonly inputSchema = artworkByIdSchema; public readonly imageByTitle = new Map<string, string>(); private readonly fields: string[] = Object.keys(artworkSchema._def.shape()); constructor(private server: McpServer) { super(); } public async executeCore(input: z.infer<typeof this.inputSchema>) { const { id, includeImage } = input; const url = new URL(`${this.apiBaseUrl}/artworks/${id}`); url.searchParams.set('fields', this.fields.join(',')); const parsedResponse = await this.safeApiRequest( url, { method: 'GET' }, artworkResponseSchema, ); const artwork = parsedResponse.data; const text = this.formatArtworkDetails(artwork, `${parsedResponse.config.iiif_url}`); const content = []; content.push({ type: 'text' as const, text }); if (includeImage) { const image = await this.getArtworkImage(artwork, `${parsedResponse.config.iiif_url}`); if (image) { content.push(image); } } return { content }; } private formatArtworkDetails(artwork: z.infer<typeof artworkSchema>, iiif_url: string) { return `Title: ${artwork.title}\n` + `${artwork.alt_titles ? `Alt Titles: ${artwork.alt_titles.join(', ')}\n` : ''}` + `Artist: ${artwork.artist_display}\n` + `Artist ID: ${artwork.artist_id}\n` + `Description: ${artwork.description ?? 'No description available'}\n` + `Image ID: ${artwork.image_id}\n` + `Place of Origin: ${artwork.place_of_origin}\n` + `Dimensions: ${artwork.dimensions}\n` + `Medium: ${artwork.medium_display}\n` + `Credit Line: ${artwork.credit_line}\n` + `Department: ${artwork.department_title}\n` + `Is On View: ${artwork.is_on_view ? 'Yes' : 'No'}\n` + `Main Reference Number: ${artwork.main_reference_number}\n` + `Has not been viewed much: ${artwork.has_not_been_viewed_much ? 'Yes' : 'No'}\n` + `Date Start: ${artwork.date_start ?? 'N/A'}\n` + `Date End: ${artwork.date_end ?? 'N/A'}\n` + `Date: ${artwork.date_display ?? 'N/A'}\n` + `Fiscal Year: ${artwork.fiscal_year ?? 'N/A'}\n` + `Is Public Domain: ${artwork.is_public_domain ? 'Yes' : 'No'}\n` + `Gallery: ${artwork.gallery_title ?? 'N/A'}\n` + `Artwork Type: ${artwork.artwork_type_title}\n` + `Artist Title: ${artwork.artist_title}\n` + `Artist Titles: ${artwork.artist_titles.join(', ')}\n` + `Style Title: ${artwork.style_title ?? 'N/A'}\n` + `Image URL: ${artwork.image_id ? `${iiif_url}/${artwork.image_id}/full/843,/0/default.jpg` : 'N/A'}\n`; } private async getArtworkImage(artwork: z.infer<typeof artworkSchema>, iiif_url: string) { if (artwork.image_id) { try { const imageURL = `${iiif_url}/${artwork.image_id}/full/843,/0/default.jpg`; const imageBase64 = await imageToBase64(imageURL); const title = `${artwork.title} (${artwork.artist_title})`; this.imageByTitle.set(title, imageBase64); this.server.server.notification({ method: 'notifications/resources/list_changed', }); return { type: 'image' as const, data: imageBase64, mimeType: 'image/jpeg', }; } catch (error) { console.error(`Error fetching image for artwork ${artwork.id}:`, error); return { type: 'text' as const, text: `Error fetching image for artwork ${artwork.id}: ${error}`, }; } } return null; } }
- src/tools/GetArtworkByIdTool.ts:7-10 (schema)Input schema for the get-artwork-by-id tool defining parameters id and optional includeImage.const artworkByIdSchema = z.object({ id: z.number().describe('The ID of the artwork to retrieve.'), includeImage: z.boolean().optional().default(true).describe('Whether to include the artwork image in the response.'), });
- src/schemas/schemas.ts:58-91 (schema)Zod schemas for single artwork data (artworkSchema) and API response (artworkResponseSchema) used for validation in the tool handler.export const artworkSchema = z.object({ id: z.number(), title: z.string(), alt_titles: z.array(z.string()).nullable(), thumbnail: thumbnailSchema, main_reference_number: z.string(), has_not_been_viewed_much: z.boolean(), date_start: z.number().nullable(), date_end: z.number().nullable(), date_display: z.string().nullable(), artist_display: z.string(), place_of_origin: z.string(), description: z.string().nullable(), dimensions: z.string(), medium_display: z.string(), credit_line: z.string(), fiscal_year: z.number().nullable(), is_public_domain: z.boolean(), gallery_title: z.string().nullable(), artwork_type_title: z.string(), is_on_view: z.boolean(), department_title: z.string(), artist_title: z.string(), artist_titles: z.array(z.string()), style_title: z.string().nullable(), artist_id: z.number(), image_id: z.string(), }); export const artworkResponseSchema = z.object({ data: artworkSchema, info: apiInfoSchema, config: apiConfigSchema, });
- src/index.ts:64-68 (registration)Registration of the 'get-artwork-by-id' tool with the MCP server using server.tool().this.getArtworkByIdTool.name, this.getArtworkByIdTool.description, this.getArtworkByIdTool.inputSchema.shape, this.getArtworkByIdTool.execute.bind(this.getArtworkByIdTool), );
- src/tools/BaseTool.ts:37-62 (helper)safeApiRequest method from BaseTool, used by the handler for safe API calls with Zod validation.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; }