Skip to main content
Glama
BadWasabeee

beatport-mcp

by BadWasabeee
README.md
# beatport-mcp

An MCP (Model Context Protocol) server that lets Claude search the Beatport catalog and
manage your Beatport playlists. Hand Claude a list of track names and say *"add these to my
Sunset Set playlist"* — it resolves each one to a Beatport track and writes them to the
playlist for you.

Beatport has no obtainable official API access, so this server uses the same auth
workaround as the [beets-beatport4](https://github.com/samplecount/beets-beatport4) plugin:
it borrows the public `client_id` from Beatport's own `/v4/docs/` page and runs a
cookie-session `authorization_code` OAuth flow against your own account.

> **Disclaimer:** This is an unsanctioned workaround in a ToS grey area. Use it for
> personal, non-commercial purposes on your own account only. It can break without notice
> whenever Beatport changes their docs page or API.

## Use cases

- **Tracklist → playlist.** Paste a tracklist from 1001Tracklists, a radio show, a festival
  set, or a screenshot, and have Claude rebuild it as a Beatport playlist ready to buy from.
- **Migrate playlists from other platforms.** Export a Spotify/Apple Music playlist (or a
  rekordbox collection) as text and let Claude re-match every track on Beatport.
- **Set prep with BPM/key data.** Search results include BPM and musical key, so you can
  ask for things like *"find these tracks and add the ones between 122–126 BPM, prefer
  extended mixes"* — useful for harmonic mixing prep.
- **Digging assistant.** *"Search Beatport for the new remixes of X and stage anything
  interesting in my 'To Review' playlist"* — Claude searches, filters, and files them.
- **Crate building by brief.** Describe a vibe (*"peak-time melodic techno, 128–132"*),
  let Claude propose tracks it knows, verify each exists on Beatport, and build the
  playlist in one conversation.

## Tools

| Tool | Description |
|---|---|
| `whoami` | Returns the authenticated account. Auth smoke test. |
| `search_tracks` | Search the catalog. Returns id, title, mix, artists, BPM, key, release per match. |
| `list_playlists` | List all your playlists (id, name, track count, visibility). |
| `create_playlist` | Create a playlist by name. |
| `add_tracks_to_playlist` | Batch-add tracks (by id) to a playlist (by id). |

Tools are deliberately atomic — the "list of songs → playlist" orchestration happens in the
model at runtime: it searches each line, picks the best match, then makes one add call.

## Requirements

- [Bun](https://bun.sh) ≥ 1.0 (`curl -fsSL https://bun.sh/install | bash`)
- A Beatport account (username + password)
- Claude Code or Claude Desktop (or any other MCP client)

## Install

```sh
git clone https://github.com/BadWasabeee/beatport-mcp.git
cd beatport-mcp
bun install
cp .env.example .env   # then edit .env with your Beatport credentials
```

`.env` lives in the project root and is read by the server itself, so your credentials
never need to appear in any MCP client config:

```sh
BEATPORT_USERNAME=you@example.com
BEATPORT_PASSWORD=your-password
```

### Verify it works

```sh
bun run smoke "Bicep Glue"
```

Expected output: your account name, then five candidate tracks with BPM and key. This
exercises the full auth flow plus catalog search.

## Register with Claude

**Claude Code:**

```sh
claude mcp add --scope user beatport -- bun run /ABSOLUTE/PATH/TO/beatport-mcp/src/index.ts
```

**Claude Desktop** — add to `claude_desktop_config.json`
(macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "beatport": {
      "command": "/ABSOLUTE/PATH/TO/bun",
      "args": ["run", "/ABSOLUTE/PATH/TO/beatport-mcp/src/index.ts"]
    }
  }
}
```

Use the absolute path to `bun` (`which bun`) — Claude Desktop doesn't inherit your shell's
PATH. Fully quit and relaunch Claude Desktop afterwards, then start a new conversation.

> Local MCP servers only work in clients running on the same machine (Claude Code, Claude
> Desktop). They are not reachable from claude.ai in a web browser or the mobile apps.

## Usage

In a fresh Claude session:

> Add these to my *Sunset Set* playlist:
> Bicep — Glue, Charlotte de Witte — Doppler, Overmono — So U Kno

Claude will search each track, pick the best match (asking you when it's ambiguous), and
batch-add them. If the playlist doesn't exist, ask it to create one first.

## How auth works

1. Scrapes the public `client_id` from the script bundles on `api.beatport.com/v4/docs/`
   (override with `BEATPORT_CLIENT_ID` if the scrape breaks).
2. `POST /auth/login/` with your credentials establishes a cookie session.
3. `GET /auth/o/authorize/` with those cookies yields an authorization code.
4. `POST /auth/o/token/` exchanges the code for access + refresh tokens.

Tokens persist to `~/.beatport-mcp/token.json` (chmod 600, override the path with
`BEATPORT_TOKEN_PATH`) and refresh automatically on expiry, falling back to a full
re-login if the refresh is rejected. Credentials and tokens are never logged.

## Troubleshooting

- **"BEATPORT_USERNAME and BEATPORT_PASSWORD must be set"** — no `.env` in the project
  root and no env vars passed by the MCP client.
- **"Beatport login failed (HTTP 4xx)"** — wrong credentials, or Beatport is challenging
  the login (try logging into the website once, then retry).
- **"API_CLIENT_ID not found in any /docs/ script bundle"** — Beatport changed their docs
  page. Find the new client id (DevTools → Network on the docs page) and set
  `BEATPORT_CLIENT_ID` in `.env`.
- **Stale auth weirdness** — delete `~/.beatport-mcp/token.json`; the next call re-runs
  the full flow.

## Development

```sh
bun run start        # start the stdio MCP server
bun run smoke [q]    # auth smoke test + optional catalog search
bunx tsc --noEmit    # typecheck
```

- `src/auth.ts` — OAuth flow, token persistence/refresh
- `src/client.ts` — Beatport API client (search, playlists)
- `src/index.ts` — MCP server and tool definitions
- `src/smoke.ts` — standalone CLI check, no MCP client needed

## License

[MIT](LICENSE)