Search the Art Institute of Chicago collection: artworks, artists, exhibitions, and audio guides.
Search the Art Institute of Chicago collection: artworks, artists, exhibitions, and audio guides via MCP. STDIO or Streamable HTTP.
The Art Institute of Chicago's collection through the museum's public API: about 133,000 artworks, plus artists, exhibitions, and audio-guide stops. Search artworks with text, structured filters, and facet counts; read full records with provenance, exhibition history, and rights-aware IIIF image URLs; resolve artists to ids; find exhibitions by topic or date; and search audio-guide transcripts. Runs as a stdio process or a local Streamable HTTP server, with no API key.
| Tool | Description |
|---|---|
artic_search_artworks | Search artworks by text and filters (artist, department, type, style, subject, classification, place, gallery, years, public domain, on view, has image), with facet counts and date sorting |
artic_get_artworks | Fetch full records for up to 10 artworks: description, provenance, exhibition and publication history, image URLs with rights status, related media |
artic_search_artists | Find artists, cultures, and organizations by name or id, with life dates, artwork counts, and sample works |
artic_search_exhibitions | Search past, current, and upcoming exhibitions by text and date, with the artworks shown when the museum lists them |
artic_search_audio_guide | Search the museum's audio-guide stops by text: stop title, MP3 URL, and transcript |
artic_lookup_vocabulary | List the values a search filter accepts (departments, types, styles, subjects, places, galleries, and more) with artwork counts |
| Resource | Description |
|---|---|
artic://artworks/{id} | One artwork record as JSON, with the API license text and description attribution |
The same record is available from artic_get_artworks for clients that don't surface resources.
artic_search_artworks toolquery (every word must match; "exact phrase", -exclude, and a | b work) plus filters artist, artist_id, department, artwork_type, style, subject, classification, place_of_origin, gallery, year_from / year_to (date-span overlap, negative for BCE), public_domain_only, on_view_only, and has_image, combined with ANDsort is relevance, date_asc, or date_desc, and sort_applied reports popularity when relevance had no query textfacets adds the top 15 values for up to seven fields (artist rows carry artist_id); limit: 0 returns counts onlyartic_get_artworks toolids per call (artwork page URLs are read as their id); sections picks the heavy text: description and provenance by default, plus exhibition_history, publication_history, and cataloguemissing_ids for ids the museum doesn't have and deferred_ids for records past a 100,000-byte response budgetinclude_related_media (default on) loads up to 20 linked lectures and audio stops per call; description_attribution appears whenever CC BY description text is returnedartic_search_artists toolquery (all name words must match) or up to 25 ids, not both; query mode adds artists_only (default true), born_from / born_to, and up to 25 agents per pageartwork_count, up to three sample_works (the museum's highlights first), life years, and alt_names; ids mode reports missing_idsartic_search_exhibitions toolquery, when (current, upcoming, past, or the default any), and date_from / date_to (YYYY-MM-DD, matched by run overlap); up to 25 per page, pages 1–40sort is relevance, start_desc, or start_asc, defaulting to relevance with a query and start_desc without; status is the museum's label and doesn't say whether a show is open (when does)artist_ids, and the artworks shown when the museum lists themartic_search_audio_guide toolquery is required and matches stop titles and transcripts (every word); up to 20 stops per page (default 5)title, audio_url (MP3), and transcript but no artwork id; every response carries license_text and source_citation, since the content is for noncommercial educational and personal useartic_lookup_vocabulary toolvocabulary is one of department, artwork_type, style, subject, classification, place_of_origin, gallery, material, technique, or theme; optional contains substring (case-insensitive), public_domain_only, and up to 100 values (default 25)artwork_count, in the exact form the matching artic_search_artworks filter accepts; filter_param names that filter and is absent for material, technique, and theme, which work as query textartic://artworks/{id} resource{ artwork, license_text, description_attribution?, notice? } as application/json, where artwork is the artic_get_artworks record with its default sections and related mediaartwork_not_found; ids come from artic_search_artworksBuilt on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Art Institute-specific:
api.artic.edu/api/v1); IIIF image URLs are built from each record (843 px for every image, 1686 px and a IIIF manifest for public-domain works), never fetcheddate_display stays the authorityAgent-friendly output:
image.rights (public_domain / in_copyright) on every image, with the 1686 px URL only where reuse is allowed; the API's license_text verbatim; description_attribution when CC BY text is returned; and source_citation on audio-guide resultsartic_get_artworks reports missing_ids and deferred_ids, and when a secondary lookup (related media, artist counts) fails, the primary records still return with a notice naming what is missingtotalCount, has_more, next_page, and a notice with the next page, the 1,000-match ceiling, or the filter to loosen after zero hits; facet and vocabulary values come back in the exact form the filters acceptThe Art Institute of Chicago licenses its API data by surface, and the server passes the API's own license_text through with every artwork, artist, exhibition, and audio-guide result:
| Content | Terms |
|---|---|
| Artwork metadata, artists, exhibitions, vocabulary terms, related media | CC0 |
Artwork description text | CC BY 4.0: credit the Art Institute of Chicago and cite the record's web_url |
| Artwork images | Reusable only for public-domain works (image.rights: "public_domain", CC0); other images need a rights check |
| Audio-guide content | Noncommercial educational and personal use, with copyright notices kept and the source cited |
This server is an independent project and is not affiliated with or endorsed by the Art Institute of Chicago.
rate_limited.description, and in a general sample 94% lack provenance. About 1% of artists have a biography, and there is no nationality field, only artist_display prose.gelatin silver (developing-out-paper) pr). Filters match them only as stored, so pass values as artic_lookup_vocabulary lists them.<script>; the call fails as request_blocked.status doesn't indicate whether a show is open.Add the following to your MCP client configuration file. No API key is needed; AIC_CONTACT tells the museum how to reach you (see Configuration).
{
"mcpServers": {
"art-institute-chicago-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/art-institute-chicago-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"AIC_CONTACT": "you@example.com"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"art-institute-chicago-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/art-institute-chicago-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"AIC_CONTACT": "you@example.com"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"art-institute-chicago-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "-e", "AIC_CONTACT=you@example.com", "ghcr.io/cyanheads/art-institute-chicago-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
AIC_CONTACT to an email or URL.git clone https://github.com/cyanheads/art-institute-chicago-mcp-server.git
cd art-institute-chicago-mcp-server
bun install
cp .env.example .env
# edit .env and set AIC_CONTACT
| Variable | Description | Default |
|---|---|---|
AIC_CONTACT | Contact the museum can reach (an email or URL), sent in the AIC-User-Agent header the Art Institute API asks clients to include. Printable ASCII only; the server refuses to start on any other character. The default points at this repository; set your own contact for any deployment. | https://github.com/cyanheads/art-institute-chicago-mcp-server |
AIC_REQUESTS_PER_MINUTE | Outbound requests per minute to api.artic.edu, 1–600. The default stays under the API's published limit of 60 a minute; raise it only if the museum grants a higher one. | 50 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. .env.example and the Docker image set stateless. | auto |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <app-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for every server setting and the common framework overrides.
Build and run the production version:
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more
bun run test # Runs the test suite
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point: registers the tools and resource, sets the server instructions, and starts and stops the API service. |
src/config | AIC_CONTACT and AIC_REQUESTS_PER_MINUTE parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts) and the artwork output schema they share. |
src/mcp-server/resources | The artic://artworks/{id} resource. |
src/services/aic | Art Institute API client: pacing, retries, response cache, HTML-to-text, IIIF URL construction, and the artwork and artist record builders. |
tests/ | Unit and integration tests, mirroring the src/ structure. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for logging, ctx.enrich for paging and noticessrc/mcp-server/*/definitions/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y @cyanheads/art-institute-chicago-mcp-serverMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-cyanheads-art-institute-chicago-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/art-institute-chicago-mcp-server"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceio.github.cyanheads/art-institute-chicago-mcp-server works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.