Skip to main content
Glama
cyanheads

art-institute-chicago-mcp-server

by cyanheads

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Overview

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.

Tools

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

Resources

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.

Related MCP server: artic-mcp

Capability reference

artic_search_artworks tool

  • query (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 AND

  • Up to 12 rows per page (default 10), so a page of long catalog records stays within common tool-output limits, within the first 1,000 matches; sort is relevance, date_asc, or date_desc, and sort_applied reports popularity when relevance had no query text

  • facets adds the top 15 values for up to seven fields (artist rows carry artist_id); limit: 0 returns counts only


artic_get_artworks tool

  • 1–10 ids 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 catalogue

  • Records return in request order, with missing_ids for ids the museum doesn't have and deferred_ids for records past a 100,000-byte response budget

  • include_related_media (default on) loads up to 20 linked lectures and audio stops per call; description_attribution appears whenever CC BY description text is returned


artic_search_artists tool

  • query (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 page

  • Each agent carries artwork_count, up to three sample_works (the museum's highlights first), life years, and alt_names; ids mode reports missing_ids


artic_search_exhibitions tool

  • query, 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–40

  • sort 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)

  • Rows carry dates, gallery, summary, web page, image, artist_ids, and the artworks shown when the museum lists them


artic_search_audio_guide tool

  • query is required and matches stop titles and transcripts (every word); up to 20 stops per page (default 5)

  • Each stop has 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 use


artic_lookup_vocabulary tool

  • vocabulary 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)

  • Values come back most common first with 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 text


artic://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 media

  • An unknown id fails as artwork_not_found; ids come from artic_search_artworks

Features

Built 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:

  • Keyless access to the Art Institute of Chicago public API (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 fetched

  • One shared request pacer under the API's published limit of 60 requests a minute, retries for transient failures inside a 20-second deadline, and an in-process response cache (records 6 hours, searches 15 minutes, vocabularies 24 hours), so a repeated call spends no rate budget

  • Text search requires every word to match, so totals are real and a miss reads as zero hits, while results keep the museum's own relevance order

  • Placeholder years in the museum's data (outside −8000 to 2100) are left out of output, year filters, and date sorts; date_display stays the authority

Agent-friendly output:

  • Rights travel with the data: 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 results

  • Partial results instead of failures: artic_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 missing

  • Paging that names the next move: totalCount, 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 accept

Data and licensing

The 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.

Known limitations

  • Only the first 1,000 matches of any search are reachable without an authenticated key. Broad questions need filters or facets.

  • The API's limit of 60 requests a minute is per egress IP, so every client behind one IP shares it. Bursts queue behind the pacer, and a call that cannot start within its 20-second budget fails as rate_limited.

  • Curatorial text is sparse: about 10% of artworks have a 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.

  • About 15 artworks carry placeholder years and about 4,900 carry no dates; neither matches a year filter.

  • Some vocabulary titles are stored cut at 40 characters in the museum's own data (gelatin silver (developing-out-paper) pr). Filters match them only as stored, so pass values as artic_lookup_vocabulary lists them.

  • The API's firewall refuses any request whose text contains markup such as <script>; the call fails as request_blocked.

  • About 4% of exhibitions list their artworks, and status doesn't indicate whether a show is open.

  • Audio-guide stops have no artwork link. Some titles are file names, and some transcripts are in Spanish.

  • Image URLs can stop resolving when the museum unpublishes or replaces an image, and relevance order follows the museum's own ranking, which may shift as its models change.

Getting started

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

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).

  • No API key or account. The Art Institute API asks clients to identify themselves with a contact; set AIC_CONTACT to an email or URL.

Installation

  1. Clone the repository:

git clone https://github.com/cyanheads/art-institute-chicago-mcp-server.git
  1. Navigate into the directory:

cd art-institute-chicago-mcp-server
  1. Install dependencies:

bun install
  1. Configure environment:

cp .env.example .env
# edit .env and set AIC_CONTACT

Configuration

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.

Running the server

Local development

  • 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

Project structure

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.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic

  • Use ctx.log for logging, ctx.enrich for paging and notices

  • Register new tools and resources in the barrels under src/mcp-server/*/definitions/index.ts

  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Issues are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

This project is licensed under the Apache 2.0 License. See the LICENSE file for details.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Allows you to search for artworks, retrieve detailed information about specific artworks, access image tiles for artworks, and explore user-created collections from the Rijksmuseum.
    29 npm
    72
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    A server that provides access to the Art Institute of Chicago Collection through natural language interactions. This server allows AI models to search the Art Institute of Chicago Collection and have art works available as a Resource.
    6
    15 npm
    5
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying the Cleveland Museum of Art's open access API to search artworks by filters like type, artist, and CC0 status, retrieve details by accession number, find creators, and explore exhibitions.
    251 npm
    1
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables AI agents to search and explore over 570,000 artworks from the Metropolitan Museum of Art and Art Institute of Chicago without needing an API key.
    9
    2
    MIT