About musicbrainz-mcp-server
An MCP server for querying MusicBrainz music metadata and Cover Art Archive images. It supports entity search, identifier resolution, relationship browsing, and cover-art retrieval.
Key features
- 01Search artists, releases, recordings, works, and labels
- 02Look up entities by MBID
- 03Resolve ISRC, ISWC, and barcodes
- 04Browse linked entities and discographies
- 05Retrieve release and release-group cover art
Use cases
- 01Find an artist’s releases and collaborations
- 02Identify a recording from an ISRC
- 03Inspect a release’s tracks and label details
- 04Retrieve album cover images
MCP support
Exposes 10 tools and a JSON resource for MusicBrainz entities to MCP clients. Supports STDIO and Streamable HTTP transports.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://musicbrainz.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-musicbrainz https://musicbrainz.caseyjhand.com/mcp{"mcpServers":{"cyanheads-musicbrainz":{"type":"http","url":"https://musicbrainz.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-musicbrainz":{"type":"http","url":"https://musicbrainz.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-musicbrainz":{"type":"http","url":"https://musicbrainz.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-musicbrainz":{"serverUrl":"https://musicbrainz.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
10| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Maximum results to return (1–100). |
| query | string | Yes | Lucene query string; must contain non-whitespace text. Plain text matches names/titles; field scoping (e.g. `artist:`, `country:`, `tag:`) is supported. Sent to MusicBrainz exactly as given. |
| offset | integer | No | Result offset for pagination (0-based). |
| entityType | enum | Yes | Which entity type to search.artist | release-group | release | recording | work | label |
Details
From the project README@cyanheads/musicbrainz-mcp-server
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
Overview
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.
Tools
| 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 |
Resources
| 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.
Capability reference
musicbrainz_search_entities tool
- One
entityTypeper call (artist,release-group,release,recording,work,label) and a Lucenequerywith field scoping (artist:radiohead AND country:GB); positive integerlimit(default 25, values above 100 clamp to 100 with a notice),offsetfor paging - Returns the effective
offsetand upstreamtotalCount. Continuation usesoffset + 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 offset - Each hit carries
mbid,name, and the raw 0–100scorein MusicBrainz order, plus type-specific fields such asartistCredit,isrcs,iswcs, andlength. Release rows usestatus(Official, Bootleg, …); artist, release-group, work, and label subtypes usetype. A whitespace-only query fails asblank_query
musicbrainz_get_artist tool
mbid, plusinc_release_groupsandinc_relationships(both defaulttrue) to drop the heavier sub-resources- Type, gender, country, area,
lifeSpan, aliases, and tags, plusreleaseGroups(one page),relationships(band membership, collaborations), andexternalLinks(Wikidata, Discogs, official site)
musicbrainz_get_release_group tool
mbidonly; returnsprimaryType,secondaryTypes,firstReleaseDate,artistCreditwithartistCreditString, tags, and one page ofreleases(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 tool
mbid,media_offset(default 0), andmedia_limit(default 20, no maximum); returns orderedmediawith complete tracks per medium (position,title,lengthas m:ss,recordingId),labelInfo(label andcatalogNumber),barcode,status,date,country,packaging,language/script, andreleaseGroupIdmediaTotalandtrackTotalcount all normalized media and track occurrences; upstream per-mediumtrackCountis preserved.mediaOffsetidentifies the window. When more media remain,truncated,shown,cap, and a notice give the nextmedia_offset; empty end pages report exhaustion. The release resource retains the complete raw tracklistcoverArtis the availability stub from the release record; callmusicbrainz_get_cover_artfor image URLs
musicbrainz_get_recording tool
mbid, plusinc_relationships(defaulttrue) for performer, producer, and engineer credits, work links to the composition, and external links- Returns
length,isrcs,artistCredit,firstReleaseDate, one upstream page ofreleases(up to 25),relationships, andexternalLinks releaseAppearanceSummaryreportsshown,cap: 25, andcompleteness: a short present page iscomplete, a full or absent page without an exact count isunknown, and an exact upstream count exceeding the returned page provestruncated.totalCountis omitted when unknown; no count request is added. Enumerate appearances withmusicbrainz_browse_entities(target_type=release,link.recording=<mbid>,offset=0), because embedded and browse order may differ
musicbrainz_get_work tool
mbid, plusinc_relationships(defaulttrue) for writer, composer, and lyricist credits, movements and arrangements, the recordings that perform it, and external links- Returns
type,languages,iswcs, aliases, and tags. Only the first 25 recording relationships are kept (other relationships and links are all kept);totalCountgives the full count, andtruncated,shown, andcapappear when some were cut - To list every recording of a work, browse
recordingbywork, then callmusicbrainz_get_recordingfor relationship attributes and dates - Follow a
relationshipsentry withtargetType: "work"using itstargetIdin anothermusicbrainz_get_workcall.directiondistinguishes parent/child links; optionalorderingKeypreserves the upstream sequence key (including zero), andtargetDisambiguationdistinguishes arrangements. Relationships retain upstream array order, which need not match movement order
musicbrainz_get_label tool
mbidonly; returns type, country, area,lifeSpan,labelCode(the LC number without its prefix), aliases, tags, andexternalLinks- Releases are not embedded; list them with
musicbrainz_browse_entities(target_type=release,link.label)
musicbrainz_lookup_identifier tool
id_typeisrc→ recordings,iswc→ works,barcode→ releases; a barcode is UPC/EAN digits and returns up to 25 ranked matches, each with ascore- ISRC accepts compact
GBAYE9701274or printedGB-AYE-97-01274, ignoring case and surrounding whitespace. ISWC acceptsT-010.140.236-1orT0101402361, with optional group punctuation, ignoring whitespace and case. Results echo the canonical compact ISRC orT-DDD.DDD.DDD-CISWC; malformed codes fail before a request result.kind(recordings|works|releases) names the arm that came back; failures areinvalid_identifieroridentifier_not_found
musicbrainz_browse_entities tool
target_typeplus exactly one parent MBID inlink;releaseGroup/release_groupaliasrelease-group. Positive integerlimitdefaults to 25; values above 100 clamp to 100 with a notice. SetMUSICBRAINZ_CLAMP_OVERSIZED_LIMITS=offto enforce maximum 100 for both search and browse- Reports upstream
totalCount; while more remain,truncatedis set and a nonempty page gives the nextoffsetusing 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 usestatus; other entities usetype - A missing, extra, or malformed link fails as
invalid_link, an unknown parent asentity_not_found. For ordered tracks of an edition usemusicbrainz_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 tool
mbidandentity_type:release(default) orrelease-group, which resolves to arepresentativeRelease;limitdefaults to 25 and clamps above 100, andoffsetdefaults to 0. These windows apply after the archive index is cached and are independent of the search/browse clamp settingimagesretain archive order withfront/back,types,imageUrl, and 250/500/1200px thumbnails.totalCountis exact,offsetidentifies the window, andhasArtreflects the full archive even on an empty end page. A single notice combines any clamp, continuation, exhaustion, or no-art guidance;truncated,shown, andcapappear when more images remain- An unknown MBID fails as
entity_not_found; if MusicBrainz can't confirm the MBID exists, the empty set comes back with a notice saying so
musicbrainz://{entity_type}/{mbid} resource
entity_typeisartist,release-group,release,recording,work, orlabel; returns the raw MusicBrainz record asapplication/json- Fetches the same default linked data as the matching
get_*tool; failures areinvalid_mbidandentity_not_found - Work JSON includes raw work-to-work relationships and keeps the first 25 recording relationships;
recordingRelationshipSummarygives the exact recording count and whether any were cut - Recording JSON carries the same
releaseAppearanceSummaryas the recording tool without changing cached raw data. Release JSON retains every medium and track; the tool's media window does not apply to resources
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.
MusicBrainz-specific:
- Keyless client for the MusicBrainz Web Service v2 and the Cover Art Archive. Every request carries the descriptive
User-AgentMusicBrainz requires,musicbrainz-mcp-server/<version> ( <contact> ), withMUSICBRAINZ_CONTACTas the contact - Entities are addressed by MBID (a hyphenated UUID); uppercase and surrounding whitespace are normalized. Malformed or all-zero IDs fail as
invalid_mbid(invalid_linkfor browse); a well-formed unknown ID fails asentity_not_found - MusicBrainz calls are held to ~1 request/second across all clients of an instance, so long browse runs take a while
- Lookups fold discography, relationships, tracklists, and external links into one request; responses are cached (24 h by default) and transient upstream errors are retried with backoff
Agent-friendly output:
- Artist release-groups, release-group editions, and recording release appearances embed one page (25); browse enumerates the full set. Recording appearances disclose completeness without a count request. Work recording relationships are capped at 25 with the exact count reported; labels embed no releases
- Search echoes the effective query; search and browse report the exact upstream total. Missing or invalid totals fail as malformed upstream responses instead of inventing a count
- Discriminated outputs:
musicbrainz_lookup_identifierreturns akind-tagged union, so callers branch on data, not string parsing - Raw upstream relevance
score, not a derived confidence; missing upstream fields stay absent rather than invented
Getting started
Public Hosted Instance
A 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"
}
}
}
Self-Hosted / Local
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": "[email protected]"
}
}
}
}
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": "[email protected]"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"musicbrainz-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "[email protected]",
"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 [email protected] 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 server ships a default contact, but set
MUSICBRAINZ_CONTACTto your own email or URL for any shared or hosted deployment.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/musicbrainz-mcp-server.git
- Navigate into the directory:
cd musicbrainz-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env and set MUSICBRAINZ_CONTACT (optional but recommended)
Configuration
| 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.
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, packaging bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against the linter rules
Docker
docker build -t musicbrainz-mcp-server .
docker run --rm -e [email protected] -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.
Project structure
| 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/. |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools and resources via the barrels in
src/mcp-server/*/definitions/index.ts - Route every upstream call through the services, never a direct
fetch(), so the User-Agent, rate limiter, and cache apply - Wrap external API data: 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
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.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.