The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Met Museum MCP Server listing page.
Search the Metropolitan Museum of Art collection, fetch full artwork records and open-access images via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://met-museum.caseyjhand.com/mcp
Three tools for browsing and fetching Metropolitan Museum of Art collection data:
| Tool | Description |
|---|---|
met_list_departments | Return all 19 curatorial departments with their numeric IDs and display names |
met_search_collections | Search the collection by keyword with filters for department, date range, medium, geography, on-view status, public-domain status, and highlight designation |
met_get_object | Fetch full records for one or more object IDs — metadata, provenance, artist info, CC0 image URLs, tags, and Wikidata links |
met_list_departmentsReturn the 19 curatorial departments at The Metropolitan Museum of Art with their numeric IDs and display names.
departmentId values are the valid inputs for the met_search_collections department filtermet_search_collectionsSearch the Met collection by keyword and optional filters.
met_list_departments)"Paintings", "Sculptures", "Ceramics") — maps to the classification field, not material descriptionsisPublicDomain=true selects CC0 open-access objects — confirm CC0 status per object from met_get_objecttotal counts that intersection. The two runs go out in parallelq=the alone is 2.7 MB) returns the filtered results unchecked rather than failing the call, with a notice on the response saying they were not verified against the keyword — narrow the keyword to let the check runhasImages=true includes any object with images (includes copyrighted works without reusable URLs)isHighlight=true restricts to collection highlights designated by the MetisPublicDomain and isHighlight accept true only. The upstream index is unsound on the false arm — it returns objects whose own record contradicts the filter — so false is rejected; omit the filter instead. hasImages and isOnView are unaffected and remain plain booleansisOnView=true restricts to objects currently on display in a Met gallerylimit with offset (default 0) — a broad query carries the same timeout risk on every page as on the first; narrow it with filters if paging times outremaining count, nextOffset for the next page (null once exhausted), the resolved offset this page was read from, and up to limit object IDs (default 20, max 500)met_get_object (up to 20 per call)met_get_objectFetch full records for one or more Met Museum object IDs.
geography block with the nine findspot fields beyond country/region — geographyType, city, state, county, subregion, locale, locus, excavation, river — each an empty string when the Met records nothingmeasurements array: one entry per measured element, each with an open map of axis name to value (centimeters for spatial axes, kilograms for weight). Null when the Met records nonestructuredContent bytes returns fewer of them; the rest are listed in deferred[] with their sizes, to re-request in a follow-up call. content[] re-renders the admitted records, so the delivered response is roughly twice the budgetBuilt on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1Metropolitan Museum of Art collection:
met_get_objectAgent-friendly output:
isPublicDomain and hasCC0Image flags distinguish CC0 objects from works with inaccessible images, so agents can reason about what they can actually displaymet_get_object returns objects and failed arrays so callers receive successful records alongside structured per-ID error contextmet_search_collections returns total, returned, truncated, remaining, nextOffset, and the resolved offset fields so agents know when to refine filters, increase limit, or page further with offset; offset >= total marks a page that is empty because the offset ran past the end rather than because the query is exhaustedA public instance is available at https://met-museum.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
Add the following to your MCP client configuration file.
Or with npx (no Bun required):
Or with Docker:
For Streamable HTTP, set the transport and start the server:
All configuration is validated at startup via Zod schemas in src/config/server-config.ts.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_SESSION_MODE | HTTP session mode: auto, stateful, or stateless. This server explicitly sets stateless; the framework schema default is auto. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error) | info |
LOGS_DIR | Directory for log files (Node.js only) | <project-root>/logs |
OTEL_ENABLED | Enable OpenTelemetry instrumentation | false |
MET_BASE_URL | Met Collection API base URL (override for local stubs) | https://collectionapi.metmuseum.org/public/collection/v1 |
MET_REQUEST_TIMEOUT_MS | Per-request HTTP timeout in milliseconds | 10000 |
MET_BATCH_CONCURRENCY | Max parallel fetches in met_get_object | 5 |
See .env.example for the full list of optional overrides.
Build and run:
Run checks and tests:
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/met-museum-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools and inits the Met service. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts) — met_list_departments, met_search_collections, met_get_object. |
src/services/met | Met Collection API client — HTTP, request timeout, response normalization. |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagecreateApp() in src/index.tsIssues and pull requests are welcome. Run checks and tests before submitting:
Data from The Metropolitan Museum of Art Collection API (CC0).
Apache-2.0 — see LICENSE for details.