Discogs MCP is a Model Context Protocol (MCP) server for your Discogs music collection. Connect it to an AI assistant such as Claude and you can search what you own, look up a release, ask for something to play, and keep your collection, wantlist, and folders up to date by talking to it. It runs on Cloudflare Workers, signs in with your Discogs account through OAuth, and keeps a snapshot of your collection in Workers KV so that most questions get answered without a round trip to the Discogs API.
One thing to know before you go further: discogs-mcp.com is my own instance, and it's locked to my Discogs account. Anyone else gets a 403. You'll need to deploy your own copy, which runs on Cloudflare's free Workers plan and takes about ten minutes. If you'd rather not do it by hand, there's a prompt you can hand to a coding agent. The reason for all this is the Discogs rate limit, and I explain it below.
Once a client is connected, you ask questions in plain language and the assistant calls the right tools. A few things that work well:
- "What do I own that would suit a rainy Sunday afternoon?"
- "Which Blue Note CDs do I have from the sixties?"
- "Find the original UK pressing of this on Discogs and add it to my wantlist."
- "How is my collection split by decade and format?"
- "Move everything in my Unsorted folder that's rated five stars into Favourites."
Searching your collection takes natural-language queries. Mood words ("mellow", "energetic", "something for a dinner party") map onto genres and styles, "recent" and "oldest" are understood, and results are deduplicated at the master-release level so you don't get six pressings of the same album back. If the keyword pass finds nothing, the tool hands the collection to the assistant so it can pick for you.
Searching the whole Discogs catalog works the same way. It covers releases, masters, artists, and labels, and flags anything you already own.
Beyond search there are tools for collection statistics (genre, decade, format, and ratings), recommendations by genre, decade, mood, or similarity, and the day-to-day admin: adding and removing releases, moving them between folders, rating them, managing your wantlist, creating and renaming folders, and editing custom fields. The full list is under Tools, resources, and prompts.
Four times a day a scheduled job refreshes a snapshot of your collection in KV. Collection searches read from that snapshot instead of paging through the Discogs API, which keeps them fast and saves your rate-limit budget for the calls that need it.
The Discogs API allows 60 requests a minute, counted per source IP, and one person browsing a large collection can use all of that. A shared instance would spend most of its time rate-limited, so each person runs their own Worker with their own Discogs app credentials. Your copy talks to Discogs with your key, and nobody else's traffic counts against it.
Workers do share Cloudflare's outbound IP addresses with other Workers, so you can occasionally see a lower remaining budget than your own traffic explains. If that becomes a problem, see routing Discogs calls through your own IP.
The Deploy to Cloudflare button does most of the work. It clones this repo into your GitHub account, creates the KV namespaces and the Durable Object in your Cloudflare account, prompts you for two secrets, and sets up Workers Builds so that pushes to your fork redeploy automatically.
Go to discogs.com/settings/developers and create an application. The name doesn't matter, and the callback URL can be a placeholder for now; you'll set the real one once the Worker exists. Keep the Consumer Key and Consumer Secret handy.
When prompted, provide:
| Secret | Value |
|---|---|
DISCOGS_CONSUMER_KEY |
from step 1 |
DISCOGS_CONSUMER_SECRET |
from step 1 |
When the deploy finishes, Cloudflare shows your Worker URL, something like https://discogs-mcp.<your-subdomain>.workers.dev. The MCP endpoint is /mcp on that host.
Back in your Discogs app settings, set the Callback URL to:
https://discogs-mcp.<your-subdomain>.workers.dev/discogs-callback
This step is optional, and I recommend it. Without it, anyone who finds your Worker URL can sign in with their own Discogs account and spend your rate-limit budget. Edit wrangler.toml in your fork and set ALLOWED_DISCOGS_USER_ID under [vars]:
[vars]
# A single user
ALLOWED_DISCOGS_USER_ID = "123456"
# Or a comma-separated list
ALLOWED_DISCOGS_USER_ID = "123456,789012,345678"Your numeric ID is the id field at https://api.discogs.com/users/<your-username>. Push the change and Workers Builds redeploys.
If you'd rather not use the button (you want a plain local clone, or the button doesn't work on your Cloudflare account), the manual path is short:
git clone https://github.com/rianvdm/discogs-mcp.git
cd discogs-mcp
npm install
# Create the two KV namespaces and paste the returned IDs into wrangler.toml,
# replacing the empty `id = ""` values in the top-level [[kv_namespaces]] blocks
wrangler kv namespace create MCP_SESSIONS
wrangler kv namespace create OAUTH_KV
# Set the two secrets
wrangler secret put DISCOGS_CONSUMER_KEY
wrangler secret put DISCOGS_CONSUMER_SECRET
npm run deployThen follow steps 3 and 4 above.
If you use Claude Code, Codex, or a similar agent with shell access, you can hand it the whole job. It can't register the Discogs app or click through the OAuth screen for you (both happen in your browser), but it can do everything else: clone the repo, create the KV namespaces, store the secrets, deploy, look up your Discogs user ID, lock the instance to it, configure your client, and verify the result. Paste this and answer its questions as they come:
I want to self-host Discogs MCP from https://github.com/rianvdm/discogs-mcp
so I can use my Discogs collection from an MCP client. Read the README in that
repo, especially "Deploy your own copy", "Connect an MCP client", and "Running
it well", then do the setup for me.
Ground rules:
- Use the manual deploy path with wrangler, in a clone on this machine, so I
end up with a local copy of the code.
- Ask before anything that costs money or changes my Cloudflare account beyond
creating this Worker, its two KV namespaces, and its Durable Object.
- Don't paste secrets into chat or into files that are tracked by git. Use
`wrangler secret put` for secrets and `.dev.vars` (gitignored) for local dev.
Steps I expect:
1. Check that Node 22, npm, and wrangler are installed and that wrangler is
logged in to my Cloudflare account. Tell me how to fix anything missing.
2. Tell me to register a Discogs app at https://www.discogs.com/settings/developers
with a placeholder callback URL, and wait for me to give you the Consumer
Key and Consumer Secret.
3. Clone the repo, install dependencies, create the MCP_SESSIONS and OAUTH_KV
namespaces, put their IDs into wrangler.toml, store the two secrets,
and deploy. Tell me the Worker URL.
4. Tell me the exact callback URL to set on the Discogs app and wait for me to
confirm I've done it.
5. Ask for my Discogs username, look up my numeric user ID at
https://api.discogs.com/users/<username>, set ALLOWED_DISCOGS_USER_ID in
wrangler.toml, and redeploy.
6. Ask which MCP client I use and configure it for the new endpoint.
7. Verify: call the server's ping and auth_status tools through the client
(or MCP Inspector), walk me through the one-time OAuth sign-in, then run a
search_collection query to confirm it returns my releases. Check
get_cache_stats to see whether the first collection snapshot has landed.
8. Optional, only if I say yes when you ask: set up the Discogs egress relay
described under "Route Discogs calls through your own IP". That needs an
always-on machine with its own IP, a Cloudflare Tunnel, a reverse proxy that
forwards to https://api.discogs.com with Host and X-Forwarded-Host set, and
a Cloudflare Access service token in front of it. Explain the trade-offs
before starting, and read src/rate-limiter/relay.ts for the details.
When you're done, summarise what you created, where the secrets live, and how
to update the deployment later.
The agent will stop at steps 2 and 4 because they need you in a browser. Everything else should run through without you.
Replace https://your-worker.workers.dev with your own URL in each of these.
Claude Desktop: Settings > Integrations > Add Integration, then enter https://your-worker.workers.dev/mcp.
Claude Code:
claude mcp add --transport http discogs https://your-worker.workers.dev/mcpWindsurf (~/.codeium/windsurf/mcp_config.json):
{
"mcpServers": {
"discogs": {
"serverUrl": "https://your-worker.workers.dev/mcp"
}
}
}Continue.dev, Zed, and other clients that only speak stdio can go through mcp-remote:
{
"mcpServers": {
"discogs": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://your-worker.workers.dev/mcp"]
}
}
}To poke at the server without a full client, MCP Inspector works well:
npx @modelcontextprotocol/inspector https://your-worker.workers.dev/mcpThe first time a client connects, it opens a browser window where you authorize the app on Discogs, and then sends you back. The server implements MCP's OAuth 2.1 flow with Discogs as the identity provider, so there's nothing to copy and paste. A session lasts seven days before you're asked to sign in again.
Three tools work before you sign in:
| Tool | Description |
|---|---|
ping |
Test connectivity to the server |
server_info |
Server version, capabilities, and how Discogs traffic is routed |
auth_status |
Check whether you're signed in, with login instructions if not |
Everything else needs an authenticated session.
Search and discovery:
| Tool | Description |
|---|---|
search_collection |
Search your collection with natural language, genre filters, mood-aware ranking, and master-level dedup |
search_discogs |
Search the full Discogs catalog (releases, masters, artists, labels), marking results you already own |
get_release |
Full details for one release: tracklist, formats, labels, notes |
get_collection_stats |
Genre breakdown, decade analysis, format distribution, and ratings |
get_recommendations |
Picks from your own collection by genre, decade, mood, or similarity to a release |
Collection management:
| Tool | Description |
|---|---|
add_to_collection |
Add a release to a folder (defaults to Uncategorized) |
remove_from_collection |
Remove a specific release instance from a folder |
move_release |
Move a release instance between folders |
rate_release |
Rate a release from 0 (no rating) to 5 stars |
Wantlist:
| Tool | Description |
|---|---|
get_wantlist |
List releases on your wantlist, paginated |
add_to_wantlist |
Add a release to your wantlist |
remove_from_wantlist |
Remove a release from your wantlist |
Folders:
| Tool | Description |
|---|---|
list_folders |
List all folders with release counts |
create_folder |
Create a folder |
edit_folder |
Rename a folder (system folders can't be renamed) |
delete_folder |
Delete an empty folder (system folders can't be deleted) |
Custom fields:
| Tool | Description |
|---|---|
list_custom_fields |
List the custom fields defined on your collection |
edit_custom_field |
Set a custom field value on a specific release instance |
Diagnostics:
| Tool | Description |
|---|---|
get_cache_stats |
Cache entry counts, the snapshot's size and fetch time, and the progress of any sync in flight |
refresh_collection |
Rebuild the collection snapshot now instead of waiting for the next scheduled sync |
The server also exposes three MCP resources:
discogs://collection # Complete collection (JSON)
discogs://release/{id} # One release
discogs://search?q={query} # Search results
And three prompts, for clients that support them:
| Prompt | Description | Arguments |
|---|---|---|
browse_collection |
Browse and explore your collection | |
find_music |
Find specific music in your collection | query |
collection_insights |
Statistics and observations about your collection |
On the free plan, the limit that matters is CPU time: 10 ms per invocation, for tool calls and the scheduled sync alike. The sync stores one page at a time to stay inside that budget, and the snapshot it builds keeps only the fields search needs (about 450 bytes per release). That comfortably covers collections up to roughly 2,000 releases. Past that, reading the snapshot on every search starts to crowd the budget, and a collection of 4,000 or more can see search_collection or refresh_collection fail with a bare execution error and no message. That's the runtime terminating the invocation, and it isn't a Discogs error. The fix is Workers Paid ($5 a month), which raises the CPU budget to 30 seconds. Nothing else about the deployment changes.
Whatever plan you're on, get_cache_stats reports the snapshot's item count and fetch time, plus the page count of any sync in progress, so you can see whether the scheduled sync is landing.
Discogs throttles by source IP, and a Worker's outbound requests leave from Cloudflare's shared egress IPs. Other Workers talking to Discogs from the same location eat into your 60 requests a minute, which is why a first request after hours of idle can already report a low X-Discogs-Ratelimit-Remaining.
If it bites, point the Worker at a relay you run. A Cloudflare Tunnel to any always-on machine (a home Mac, a small VPS) with a local reverse proxy that forwards to https://api.discogs.com and sets both Host and X-Forwarded-Host to api.discogs.com is enough. cloudflared alone can't do this, because it overwrites X-Forwarded-Host. Put a Cloudflare Access application with a service-token policy in front of the tunnel hostname, then:
# wrangler.toml: DISCOGS_RELAY_ORIGIN = "https://relay.example.com"
wrangler secret put RELAY_ACCESS_CLIENT_ID
wrangler secret put RELAY_ACCESS_CLIENT_SECRETLeave DISCOGS_RELAY_ORIGIN empty to call Discogs directly, which is the default. If the relay is unreachable, the Worker falls back to a direct call for that request and logs it, so a machine that's switched off degrades to the shared-IP behaviour and nothing stops working. The implementation and the reasoning behind it are in src/rate-limiter/relay.ts.
ping and server_info report how Discogs traffic is leaving (direct, or via the relay) and whether the relay has fallen back to direct calls. For the rate limiter's live state (remaining budget, queue depth, circuit-breaker status, relay fallbacks), set a DEBUG_TOKEN secret and call GET /debug/budget?token=<DEBUG_TOKEN>. Without the secret, the endpoint returns 404, so a self-hosted instance never exposes it by accident.
Dev secrets live in .dev.vars, which is gitignored. The same Discogs app you registered for production is fine for local use.
cp .dev.vars.example .dev.vars # then fill in DISCOGS_CONSUMER_KEY and DISCOGS_CONSUMER_SECRET
npm run dev # Worker on http://localhost:8787
npx @modelcontextprotocol/inspector http://localhost:8787/mcpThe default [vars] block in wrangler.toml leaves ALLOWED_DISCOGS_USER_ID empty, so a local instance accepts any Discogs account.
Tests run inside workerd through @cloudflare/vitest-pool-workers and need Node 22 (see .nvmrc):
npm test # vitest in watch mode
npx vitest run # one pass, then exit
npm run lint # ESLint; CI runs lint, the tests, and a dry-run buildCI deploys to production when main changes. The architecture, code conventions, and testing notes are in CLAUDE.md, and pull requests are welcome.
MIT.