Search MusicBrainz artists, releases, works, labels; resolve ISRC/ISWC/barcode; fetch cover art.
One address for any MCP client. No sign-in needed on this server.
10 read
Grouped by tool name. At most: only reads or looks up information.
Odel charges nothing per call. The publisher may charge for its own service.
Search artists, releases, recordings, works, and labels; traverse relationships; resolve ISRC/ISWC/barcode; fetch cover art via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://musicbrainz.caseyjhand.com/mcp
Open music metadata from MusicBrainz and the Cover Art Archive: artists, releases, recordings, works, and labels. Search by name, look up by MBID, ISRC, ISWC, or barcode, page through complete discographies, and fetch cover art.
| Tool | Description |
|---|---|
musicbrainz_search_entities | Lucene search over one entity type, returning ranked MBIDs with relevance scores |
musicbrainz_get_artist | Artist profile: type, life span, discography, relationships, external links |
musicbrainz_get_release_group | Release-group (the album across its editions): types, first-release date, editions, cover-art availability |
musicbrainz_get_release | One edition: tracklist, label and catalog number, barcode, packaging |
musicbrainz_get_recording | Recording (one performance): length, ISRCs, releases it appears on, performer and production credits |
musicbrainz_get_work | Work (a composition): type, ISWCs, writers, movements, arrangements, and recordings |
musicbrainz_get_label | Label: type, life span, label code, external links |
musicbrainz_lookup_identifier | Resolve an ISRC, ISWC, or barcode to recordings, works, or releases |
musicbrainz_browse_entities | Page through every entity linked to a parent MBID |
musicbrainz_get_cover_art | Cover Art Archive images for a release or release-group |
| Resource | Description |
|---|---|
musicbrainz://{entity_type}/{mbid} | One entity as raw MusicBrainz JSON, with the matching get_* tool's linked data folded in |
Every entity is also reachable through the get_* tools, so tool-only clients lose nothing. The resource has no list; find MBIDs with musicbrainz_search_entities.
musicbrainz_search_entities toolentityType per call (artist, release-group, release, recording, work, label) and a Lucene query with field scoping (artist:radiohead AND country:GB); positive integer limit (default 25, values above 100 clamp to 100 with a notice), offset for pagingoffset and upstream totalCount. Continuation uses offset + rows returned, including short pages. An empty page at or beyond a positive total reports exhaustion; an unexpectedly empty page before the total reports the discrepancy without suggesting a nonadvancing offsetmbid, name, and the raw 0–100 score in MusicBrainz order, plus type-specific fields such as artistCredit, isrcs, iswcs, and length. Release rows use status (Official, Bootleg, …); artist, release-group, work, and label subtypes use type. A whitespace-only query fails as blank_querymusicbrainz_get_artist toolmbid, plus inc_release_groups and inc_relationships (both default true) to drop the heavier sub-resourceslifeSpan, aliases, and tags, plus releaseGroups (one page), relationships (band membership, collaborations), and externalLinks (Wikidata, Discogs, official site)musicbrainz_get_release_group toolmbid only; returns primaryType, secondaryTypes, firstReleaseDate, artistCredit with artistCreditString, tags, and one page of releases (editions)coverArt (exists, count, front, back) comes from a live Cover Art Archive check; when that check fails the field is omitted with a notice, never reported as "no art"musicbrainz_get_release toolmbid, media_offset (default 0), and media_limit (default 20, no maximum); returns ordered media with complete tracks per medium (position, title, length as m:ss, recordingId), labelInfo (label and catalogNumber), barcode, status, date, country, packaging, language/script, and releaseGroupIdmediaTotal and trackTotal count all normalized media and track occurrences; upstream per-medium trackCount is preserved. mediaOffset identifies the window. When more media remain, truncated, shown, cap, and a notice give the next media_offset; empty end pages report exhaustion. The release resource retains the complete raw tracklistcoverArt is the availability stub from the release record; call musicbrainz_get_cover_art for image URLsmusicbrainz_get_recording toolmbid, plus inc_relationships (default true) for performer, producer, and engineer credits, work links to the composition, and external linkslength, isrcs, artistCredit, firstReleaseDate, one upstream page of releases (up to 25), relationships, and externalLinksreleaseAppearanceSummary reports shown, cap: 25, and completeness: a short present page is complete, a full or absent page without an exact count is unknown, and an exact upstream count exceeding the returned page proves truncated. totalCount is omitted when unknown; no count request is added. Enumerate appearances with musicbrainz_browse_entities (target_type=release, link.recording=<mbid>, offset=0), because embedded and browse order may differmusicbrainz_get_work toolmbid, plus inc_relationships (default true) for writer, composer, and lyricist credits, movements and arrangements, the recordings that perform it, and external linkstype, languages, iswcs, aliases, and tags. Only the first 25 recording relationships are kept (other relationships and links are all kept); totalCount gives the full count, and truncated, shown, and cap appear when some were cutrecording by work, then call musicbrainz_get_recording for relationship attributes and datesrelationships entry with targetType: "work" using its targetId in another musicbrainz_get_work call. direction distinguishes parent/child links; optional orderingKey preserves the upstream sequence key (including zero), and targetDisambiguation distinguishes arrangements. Relationships retain upstream array order, which need not match movement ordermusicbrainz_get_label toolmbid only; returns type, country, area, lifeSpan, labelCode (the LC number without its prefix), aliases, tags, and externalLinksmusicbrainz_browse_entities (target_type=release, link.label)musicbrainz_lookup_identifier toolid_type isrc → recordings, iswc → works, barcode → releases; a barcode is UPC/EAN digits and returns up to 25 ranked matches, each with a scoreGBAYE9701274 or printed GB-AYE-97-01274, ignoring case and surrounding whitespace. ISWC accepts T-010.140.236-1 or T0101402361, with optional group punctuation, ignoring whitespace and case. Results echo the canonical compact ISRC or T-DDD.DDD.DDD-C ISWC; malformed codes fail before a requestresult.kind (recordings | works | releases) names the arm that came back; failures are invalid_identifier or identifier_not_foundmusicbrainz_browse_entities tooltarget_type plus exactly one parent MBID in link; releaseGroup/release_group alias release-group. Positive integer limit defaults to 25; values above 100 clamp to 100 with a notice. Set MUSICBRAINZ_CLAMP_OVERSIZED_LIMITS=off to enforce maximum 100 for both search and browsetotalCount; while more remain, truncated is set and a nonempty page gives the next offset using actual rows returned. Empty pages distinguish zero linked entities, exhaustion, and an unexpected empty page before the total. Clamp and paging guidance share one notice. Release rows use status; other entities use typeinvalid_link, an unknown parent as entity_not_found. For ordered tracks of an edition use musicbrainz_get_release| Target | Accepted parent keys |
|---|---|
artist | area, recording, release, release-group, work |
label | area, release |
release-group | artist, release |
release | area, artist, label, recording, release-group |
recording | artist, release, work |
work | artist |
musicbrainz_get_cover_art toolmbid and entity_type: release (default) or release-group, which resolves to a representativeRelease; limit defaults to 25 and clamps above 100, and offset defaults to 0. These windows apply after the archive index is cached and are independent of the search/browse clamp settingimages retain archive order with front/back, types, imageUrl, and 250/500/1200px thumbnails. totalCount is exact, offset identifies the window, and hasArt reflects the full archive even on an empty end page. A single notice combines any clamp, continuation, exhaustion, or no-art guidance; truncated, shown, and cap appear when more images remainentity_not_found; if MusicBrainz can't confirm the MBID exists, the empty set comes back with a notice saying somusicbrainz://{entity_type}/{mbid} resourceentity_type is artist, release-group, release, recording, work, or label; returns the raw MusicBrainz record as application/jsonget_* tool; failures are invalid_mbid and entity_not_foundrecordingRelationshipSummary gives the exact recording count and whether any were cutreleaseAppearanceSummary as the recording tool without changing cached raw data. Release JSON retains every medium and track; the tool's media window does not apply to resourcesBuilt 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.
MusicBrainz-specific:
User-Agent MusicBrainz requires, musicbrainz-mcp-server/<version> ( <contact> ), with MUSICBRAINZ_CONTACT as the contactinvalid_mbid (invalid_link for browse); a well-formed unknown ID fails as entity_not_foundAgent-friendly output:
musicbrainz_lookup_identifier returns a kind-tagged union, so callers branch on data, not string parsingscore, not a derived confidence; missing upstream fields stay absent rather than inventedA public instance is available at https://musicbrainz.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"musicbrainz-mcp-server": {
"type": "streamable-http",
"url": "https://musicbrainz.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file.
{
"mcpServers": {
"musicbrainz-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/musicbrainz-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"MUSICBRAINZ_CONTACT": "you@example.com"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"musicbrainz-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/musicbrainz-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"MUSICBRAINZ_CONTACT": "you@example.com"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"musicbrainz-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "MUSICBRAINZ_CONTACT=you@example.com",
"ghcr.io/cyanheads/musicbrainz-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 MUSICBRAINZ_CONTACT=you@example.com bun run start:http
# Server listens at http://localhost:3010/mcp
MUSICBRAINZ_CONTACT to your own email or URL for any shared or hosted deployment.git clone https://github.com/cyanheads/musicbrainz-mcp-server.git
cd musicbrainz-mcp-server
bun install
cp .env.example .env
# edit .env and set MUSICBRAINZ_CONTACT (optional but recommended)
| Variable | Description | Default |
|---|---|---|
MUSICBRAINZ_CONTACT | Email or URL sent in the User-Agent; set your own on shared or hosted instances. | repo URL |
MUSICBRAINZ_BASE_URL | MusicBrainz Web Service v2 base URL (e.g. a private mirror). | https://musicbrainz.org/ws/2 |
MUSICBRAINZ_RATE_LIMIT_RPS | Client-side requests-per-second ceiling (0.1–50). | 1 |
MUSICBRAINZ_CACHE_TTL | Response cache TTL in seconds; 0 disables caching. | 86400 |
MUSICBRAINZ_TIMEOUT_MS | Per-request HTTP timeout, in ms. | 30000 |
MUSICBRAINZ_MAX_RETRIES | Retry attempts for transient upstream failures. | 3 |
MUSICBRAINZ_CLAMP_OVERSIZED_LIMITS | Clamp search/browse limits above 100 with a notice; off restores maximum-100 schema validation. Strict boolean (true/false, on/off, 1/0, yes/no). | true |
COVER_ART_BASE_URL | Cover Art Archive base URL. | https://coverartarchive.org |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for the full list of optional overrides.
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, packaging
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against the linter rules
docker build -t musicbrainz-mcp-server .
docker run --rm -e MUSICBRAINZ_CONTACT=you@example.com -p 3010:3010 musicbrainz-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/musicbrainz-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 the resource, inits both services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/services/musicbrainz | MusicBrainz WS/2 client — User-Agent, rate limiter, response cache, retry, domain types. |
src/services/cover-art | Cover Art Archive client — maps a 404 to an empty image set, follows the release-group redirect. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Ten read-only tools across search, lookup, browse, and cover art. |
src/mcp-server/resources | Resource definitions. The musicbrainz://{entity_type}/{mbid} entity mirror. |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md/AGENTS.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 storagesrc/mcp-server/*/definitions/index.tsfetch(), so the User-Agent, rate limiter, and cache applyIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
MusicBrainz core entity data is CC0. The server reads only that core metadata and never fetches annotation text, which carries a different license. Cover art comes from the Cover Art Archive, a joint project of MusicBrainz and the Internet Archive; image URLs are linked, never rehosted, and each image's copyright stays with its rights holders. Cite MusicBrainz and the Cover Art Archive in downstream use.