full-text-search
Search the Art Institute of Chicago collection metadata for artworks containing specific terms, with pagination support for browsing results.
Instructions
Search for artworks in the Art Institute of Chicago collection whose metadata contains mention of the query term.Pagination is supported with the page parameter
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The term to search the metadata for. | |
| limit | No | The number of resources to return per page. | |
| page | No | The page of results to return. Used for pagination. |
Implementation Reference
- src/tools/FullTextSearchTool.ts:23-42 (handler)The executeCore method implements the tool logic: constructs the search URL, calls the Art Institute API, parses response, attaches pagination, and formats the artwork list.public async executeCore(input: z.infer<typeof this.inputSchema>) { const { query, limit, page } = input; const url = new URL(`${this.apiBaseUrl}/artworks/search`); url.searchParams.set('page', `${page}`); url.searchParams.set('limit', `${limit}`); url.searchParams.set('q', query); const parsedData = await this.safeApiRequest( url, { method: 'GET' }, artworkSearchResponseSchema, ); // Attach pagination info to each artwork for formatting parsedData.data.forEach((artwork) => { (artwork as any)._pagination = parsedData.pagination; }); return this.formatArtworkList(parsedData.data, query); } }
- src/tools/FullTextSearchTool.ts:5-9 (schema)Input schema defining parameters for the full-text search tool: query (required), limit and page (optional with defaults).const fullTextSearchSchema = z.object({ query: z.string().describe('The term to search the metadata for.'), limit: z.number().optional().default(10).describe('The number of resources to return per page.'), page: z.number().optional().default(1).describe('The page of results to return. Used for pagination.'), });
- src/index.ts:69-74 (registration)Registers the full-text-search tool with the MCP server using its name, description, input schema, and bound execute method.this.server.tool( this.fullTextSearchTool.name, this.fullTextSearchTool.description, this.fullTextSearchTool.inputSchema.shape, this.fullTextSearchTool.execute.bind(this.fullTextSearchTool), );
- src/schemas/schemas.ts:36-51 (schema)Output schema used to validate the API response from the artworks/search endpoint in the tool handler.export const artworkSearchResponseSchema = z.object({ preference: z.string().nullable(), pagination: paginationSchema, data: z.array(z.object({ _score: z.number(), id: z.number(), api_model: z.string(), api_link: z.string(), is_boosted: z.boolean(), title: z.string(), thumbnail: thumbnailSchema.nullable(), timestamp: z.string(), })), info: apiInfoSchema, config: apiConfigSchema, });
- src/tools/BaseTool.ts:64-89 (helper)Helper method used by the tool to format the list of search results into a readable text response, including pagination info.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 }], }; }