io.github.cyanheads/musicbrainz-mcp-server
Search MusicBrainz artists, releases, works, labels; resolve ISRC/ISWC/barcode; fetch cover art.
Que pouvez-vous faire avec io.github.cyanheads/musicbrainz-mcp-server ?
- 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
- 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...
- 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
Installation
Ajoutez ceci à la configuration MCP de votre client (Claude Desktop : claude_desktop_config.json ; Cursor : .cursor/mcp.json ; VS Code et les autres utilisent la même forme « mcpServers »).
claude mcp add --transport http musicbrainz-mcp-server 'https://musicbrainz.caseyjhand.com/mcp'
{
"mcpServers": {
"musicbrainz-mcp-server": {
"type": "http",
"url": "https://musicbrainz.caseyjhand.com/mcp"
}
}
}
@cyanheads/musicbrainz-mcp-serverclaude mcp add musicbrainz-mcp-server -e 'MUSICBRAINZ_CLAMP_OVERSIZED_LIMITS=true' -e 'MUSICBRAINZ_CONTACT=<MUSICBRAINZ_CONTACT>' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/musicbrainz-mcp-server@0.2.1
{
"mcpServers": {
"musicbrainz-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/musicbrainz-mcp-server@0.2.1"
],
"env": {
"MUSICBRAINZ_CLAMP_OVERSIZED_LIMITS": "true",
"MUSICBRAINZ_CONTACT": "<MUSICBRAINZ_CONTACT>",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Variables d'environnement
MUSICBRAINZ_CLAMP_OVERSIZED_LIMITSClamp search/browse page limits above 100 with a notice; off restores maximum-100 validation.MUSICBRAINZ_CONTACTContact (email or URL) embedded in the mandatory descriptive MusicBrainz User-Agent. Not start-blocking — the server ships a default contact — but operators running a shared or hosted instance should set their own so MusicBrainz can reach them about traffic.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
@cyanheads/musicbrainz-mcp-serverclaude mcp add musicbrainz-mcp-server -e 'MUSICBRAINZ_CLAMP_OVERSIZED_LIMITS=true' -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'MUSICBRAINZ_CONTACT=<MUSICBRAINZ_CONTACT>' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/musicbrainz-mcp-server@0.2.1
{
"mcpServers": {
"musicbrainz-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/musicbrainz-mcp-server@0.2.1"
],
"env": {
"MUSICBRAINZ_CLAMP_OVERSIZED_LIMITS": "true",
"MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
"MUSICBRAINZ_CONTACT": "<MUSICBRAINZ_CONTACT>",
"MCP_HTTP_HOST": "127.0.0.1",
"MCP_HTTP_PORT": "3010",
"MCP_HTTP_ENDPOINT_PATH": "/mcp",
"MCP_AUTH_MODE": "none",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Variables d'environnement
MUSICBRAINZ_CLAMP_OVERSIZED_LIMITSClamp search/browse page limits above 100 with a notice; off restores maximum-100 validation.MCP_TRANSPORT_TYPESelects the HTTP transport.MUSICBRAINZ_CONTACTContact (email or URL) embedded in the mandatory descriptive MusicBrainz User-Agent. Not start-blocking — the server ships a default contact — but operators running a shared or hosted instance should set their own so MusicBrainz can reach them about traffic.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
Documentation
Tirée du README du projet sur GitHub, actualisée chaque semaine. Les liens ouvrent GitHub.
Sommaire
@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.
10 Tools • 1 Resource
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": "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
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 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.
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.
Questions fréquentes
Qu'est-ce que io.github.cyanheads/musicbrainz-mcp-server ?
Search MusicBrainz artists, releases, works, labels; resolve ISRC/ISWC/barcode; fetch cover art.
Comment installer io.github.cyanheads/musicbrainz-mcp-server ?
Il fonctionne comme serveur distant. Dans Claude Code : claude mcp add --transport http musicbrainz-mcp-server 'https://musicbrainz.caseyjhand.com/mcp'. Pour les autres clients, collez la configuration JSON de cette page dans leurs réglages MCP.
Faut-il une clé API pour io.github.cyanheads/musicbrainz-mcp-server ?
Son entrée au registre n'indique aucune clé ni secret obligatoire. Certaines fonctions peuvent tout de même demander un compte auprès du service auquel il se connecte.
io.github.cyanheads/musicbrainz-mcp-server est-il open source ?
Oui. Son code est sur GitHub sous licence Apache-2.0.
Qui maintient io.github.cyanheads/musicbrainz-mcp-server ?
Il est publié par cyanheads. AI.tn le référence sans le maintenir ni le recommander.
Issu du registre MCP officiel. Être listé n'est pas une recommandation : vérifiez le code et les permissions d'un serveur avant de lui donner accès à vos données.