npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cyanheads/met-museum-mcp-server

v0.6.0

Published

Search the Metropolitan Museum of Art collection, fetch full artwork records and open-access images via MCP. STDIO or Streamable HTTP.

Readme

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

Public Hosted Server: https://met-museum.caseyjhand.com/mcp


Overview

The Metropolitan Museum of Art's public Collection API. Search the collection by keyword and filters, then fetch full object records — metadata, provenance, and CC0 open-access images — from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.

Tools

| 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, image availability, on-view 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 |

Capability reference

met_list_departments tool

  • No input required — returns all 19 curatorial departments in one call
  • Each entry pairs departmentId (numeric) with displayName (e.g., "European Paintings", "Egyptian Art")
  • departmentId values are the valid inputs for met_search_collections's departmentId filter

met_search_collections tool

  • Keyword q (required) matches title, artist name, culture, medium, tags, and other text fields; broad terms return large ID sets
  • Filters: departmentId (validated against met_list_departments; an unrecognized ID is rejected), medium (a case-sensitive classification as the Met spells it — "Paintings", "Sculpture" — not a material like "Oil on canvas"), dateBegin/dateEnd (integer years, negative = BCE, both required together), geoLocation (one country/region/city), hasImages, isOnView
  • isHighlight accepts true only — the search ignores false, so omit the filter instead of passing it. Public-domain (CC0) status is read per object from met_get_object, not filtered at search
  • Paginate with limit (default 20, max 500) and offset (default 0); nextOffset continues where a page left off (null once no further page is reachable). Paging reaches only the first 10,000 matches of a search — total still reports the full count, and a response whose total exceeds 10,000 says so in a notice
  • Returns total, returned, truncated, remaining, nextOffset, and the resolved offset; object IDs resolve to full records via met_get_object (up to 20 per call)
  • Typed errors: no_results (its recovery names the filters that removed every match, or points at the keyword when it matches nothing on its own), invalid_date_range, invalid_filter (blank q, medium, or geoLocation), invalid_department — each carries a recovery hint

met_get_object tool

  • Accepts 1–20 IDs per call; a repeated ID is fetched and returned once, at its first position
  • Partial-success batching — a 404 or fetch failure doesn't fail the whole call; failed[] reports per-ID error detail, and the call fails only when every ID fails (all_not_found / all_failed)
  • Full record: metadata, provenance, artist/constituent data (Getty ULAN + Wikidata URLs), controlled-vocabulary tags (Getty AAT + Wikidata), a nine-field geography findspot block, and structured measurements — sparse fields are empty string or null, never fabricated
  • Records are never truncated individually — a call whose combined records exceed a serialized-bytes budget returns fewer of them, listing the rest in deferred[] with sizes to re-request; content[] re-renders the admitted records, so the delivered response runs roughly twice the budget
  • isPublicDomain/hasCC0Image gate image URLs — non-public-domain objects return empty primaryImage, primaryImageSmall, and additionalImages
  • Canonical objectURL and per-object objectWikidata_URL for human follow-up and external enrichment

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.

Met Museum-specific:

  • 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_object
  • Linked data on every object — Getty ULAN and AAT URLs, Wikidata entity URLs for artists, tags, and works

Agent-friendly output:

  • Provenance on every record — isPublicDomain and hasCC0Image flags distinguish CC0 objects from works with inaccessible images, so agents can reason about what they can actually display
  • Partial failure reporting — met_get_object returns objects and failed arrays so callers receive successful records alongside structured per-ID error context
  • Truncation signaling — met_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; the text rendering marks each page (truncated), (complete), (window end) when paging stops at the 10,000-match window short of total, or (offset beyond result set) when the offset ran past what paging reaches
  • Byte-budget disclosure — met_get_object reports deferred[] records with their sizes when a batch exceeds its serialized-response budget, so callers can size a follow-up call precisely

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/mcp

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).
  • No API key required — the Met Collection API is public and unauthenticated.

Installation

  1. Clone the repository:
git clone https://github.com/cyanheads/met-museum-mcp-server.git
  1. Navigate into the directory:
cd met-museum-mcp-server
  1. Install dependencies:
bun install
  1. Configure 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 | |:---|:---|:---| | 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 declares stateless in createApp(), so it applies whenever the variable is unset; an explicit value overrides it. (auto, the framework schema default, resolves to stateful.) | 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 root; each endpoint appends its own version (/v1.1/search, /v1/objects/{id}, /v1/departments). A value ending in /v1 or /v1.1 is read as its root. Override for local stubs. | https://collectionapi.metmuseum.org/public/collection | | 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.

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:http
  • Run 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-server

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.

Project structure

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

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 request-scoped logging, ctx.state for tenant-scoped storage
  • Register new tools via the arrays in createApp() in src/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

Data attribution

Data from The Metropolitan Museum of Art Collection API (CC0).

License

Apache-2.0 — see LICENSE for details.