@cyanheads/met-museum-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@cyanheads/met-museum-mcp-serverSearch for Monet paintings with open access images."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://met-museum.caseyjhand.com/mcp
Tools
Three tools for browsing and fetching Metropolitan Museum of Art collection data:
Tool | Description |
| Return all 19 curatorial departments with their numeric IDs and display names |
| Search the collection by keyword with filters for department, date range, medium, geography, on-view status, public-domain status, and highlight designation |
| Fetch full records for one or more object IDs — metadata, provenance, artist info, CC0 image URLs, tags, and Wikidata links |
met_list_departments
Return the 19 curatorial departments at The Metropolitan Museum of Art with their numeric IDs and display names.
departmentIdvalues are the valid inputs for themet_search_collectionsdepartment filter
met_search_collections
Search the Met collection by keyword and optional filters.
Keyword search across title, artist name, culture, medium, tags, and other text fields
Filter by department ID (valid IDs from
met_list_departments)Filter by date range (integer years, negative = BCE)
Filter by medium/classification (e.g.,
"Paintings","Sculptures","Ceramics") — maps to the classification field, not material descriptionsFilter by geographic origin — country, region, or city; multiple values are AND-combined
isPublicDomain=trueselects CC0 open-access objects — confirm CC0 status per object frommet_get_objectEvery filter draws on a partial upstream index: a filtered search omits some objects whose own record satisfies the filter, so absence from the results is not evidence about an object. Drop the filter to widen
A filtered search returns only objects that match the keyword. The Met index answers any filter with a fixed set of unrelated objects alongside the real matches, so the server runs the query a second time with no filters and returns the intersection;
totalcounts that intersection. The two runs go out in parallelThat second run is best-effort. A keyword broad enough to time out on its own (
q=thealone is 2.7 MB) returns the filtered results unchecked rather than failing the call, with anoticeon the response saying they were not verified against the keyword — narrow the keyword to let the check runhasImages=trueincludes any object with images (includes copyrighted works without reusable URLs)isHighlight=truerestricts to collection highlights designated by the MetisPublicDomainandisHighlightaccepttrueonly. The upstream index is unsound on thefalsearm — it returns objects whose own record contradicts the filter — sofalseis rejected; omit the filter instead.hasImagesandisOnVieware unaffected and remain plain booleansisOnView=truerestricts to objects currently on display in a Met galleryPaginate past
limitwithoffset(default 0) — a broad query carries the same timeout risk on every page as on the first; narrow it with filters if paging times outReturns total match count, truncation indicator,
remainingcount,nextOffsetfor the next page (nullonce exhausted), the resolvedoffsetthis page was read from, and up tolimitobject IDs (default 20, max 500)Returned IDs resolve to full records via
met_get_object(up to 20 per call)
met_get_object
Fetch full records for one or more Met Museum object IDs.
Accepts 1–20 IDs per call; a repeated ID is fetched and returned once, at its first position
Partial-success — a single 404 does not fail the whole batch; failed IDs are reported per-ID
Full metadata: title, department, classification, medium, dimensions, date, culture, period, dynasty, accession number, credit line, gallery number
Artist data: display name, biography, nationality, dates, Getty ULAN URL, Wikidata URL
Constituents array for all associated persons (null for anonymous/unattributed works)
Controlled vocabulary tags with Getty AAT and Wikidata URLs
Nested
geographyblock with the nine findspot fields beyondcountry/region—geographyType,city,state,county,subregion,locale,locus,excavation,river— each an empty string when the Met records nothingStructured
measurementsarray: 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 noneRecords are returned whole and never truncated. A call whose records together exceed a cumulative budget on serialized
structuredContentbytes returns fewer of them; the rest are listed indeferred[]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 budgetCanonical metmuseum.org URL for human follow-up
CC0 objects return full-resolution and web-display image URLs plus additional image arrays
Object-level Wikidata URL for enrichment via external knowledge graph tools
Related MCP server: open-museum-mcp
Features
Built on @cyanheads/mcp-ts-core:
Declarative tool definitions — single file per tool, framework handles registration and validation
Unified error handling — handlers throw, framework catches, classifies, and formats
Pluggable auth:
none,jwt,oauthSwappable storage backends:
in-memory,filesystem,Supabase,Cloudflare KV/R2/D1Structured logging with optional OpenTelemetry tracing
STDIO and Streamable HTTP transports
Metropolitan Museum of Art collection:
500K+ artworks spanning 5,000 years from the Met's public collection API
CC0 open-access data from The Metropolitan Museum of Art — free to use without permission or attribution
Parallel batch fetching with configurable concurrency for
met_get_objectLinked data on every object — Getty ULAN and AAT URLs, Wikidata entity URLs for artists, tags, and works
Agent-friendly output:
Provenance on every record —
isPublicDomainandhasCC0Imageflags distinguish CC0 objects from works with inaccessible images, so agents can reason about what they can actually displayPartial failure reporting —
met_get_objectreturnsobjectsandfailedarrays so callers receive successful records alongside structured per-ID error contextTruncation signaling —
met_search_collectionsreturnstotal,returned,truncated,remaining,nextOffset, and the resolvedoffsetfields so agents know when to refine filters, increaselimit, or page further withoffset;offset >= totalmarks a page that is empty because the offset ran past the end rather than because the query is exhausted
Getting started
Public Hosted Instance
A public instance is available at https://met-museum.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"met-museum-mcp-server": {
"type": "streamable-http",
"url": "https://met-museum.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"met-museum-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/met-museum-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"met-museum-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/met-museum-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with Docker:
{
"mcpServers": {
"met-museum-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/met-museum-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/mcpPrerequisites
Bun v1.3.0 or higher (or Node.js v24+).
No API key required — the Met Collection API is public and unauthenticated.
Installation
Clone the repository:
git clone https://github.com/cyanheads/met-museum-mcp-server.gitNavigate into the directory:
cd met-museum-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env as needed (all vars are optional)Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts.
Variable | Description | Default |
| Transport: |
|
| HTTP server port |
|
| HTTP session mode: |
|
| Authentication: |
|
| Log level ( |
|
| Directory for log files (Node.js only) |
|
| Enable OpenTelemetry instrumentation |
|
| Met Collection API base URL (override for local stubs) |
|
| Per-request HTTP timeout in milliseconds |
|
| Max parallel fetches in |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t met-museum-mcp-server .
docker run --rm -p 3010:3010 met-museum-mcp-serverThe 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.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Met Collection API client — HTTP, request timeout, response normalization. |
| Unit and integration tests mirroring |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools via the arrays in
createApp()insrc/index.tsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testData from The Metropolitan Museum of Art Collection API (CC0).
License
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Art MCP — Metropolitan Museum of Art Collection API (free, no auth)
Unlock a world of art with the Met Museum MCP! Use the 'search_artworks' API to find stunning
Query SEC EDGAR filings, XBRL financials, and company data through MCP. STDIO & Streamable HTTP.
Art Institute of Chicago MCP — wraps the ARTIC public API (free, no auth)
Related MCP Servers
- AlicenseAqualityCmaintenanceA MCP Server that lets user ask AI models to discover the collection of the Metropolitan Museum of Art. Adds the discovered art works as Resources on the server.426634MIT
- AlicenseAqualityBmaintenanceFederated, license-verified search across open-access museum collections — currently The Met, Cleveland, AIC, Wikimedia Commons, and Europeana, with more being added. Strict-default-deny rights gate accepts only CC0 / Public Domain Mark, returning reuse-safe artwork with citations in three styles.55111MIT
- AlicenseNot gradedqualityAmaintenanceSearch artists, releases, recordings, works, and labels; traverse relationships; resolve ISRC/ISWC/barcode; fetch cover art via MCP. STDIO or Streamable HTTP.351Apache 2.0
- AlicenseAqualityDmaintenanceMCP server for searching museum collections and viewing artwork images and metadata from multiple museums, including the Met, Art Institute of Chicago, Rijksmuseum, and more.4262MIT