
Finding the perfect music for your project has always been a time-consuming task. Whether you're developing a mobile game, creating video content, or building an interactive experience, searching through thousands of tracks can take hours.
Enter the Epidemic Sound MCP Server — a game-changing integration that brings AI-powered music discovery directly into your development workflow. Combined with Claude (Anthropic's AI assistant), you can now search, discover, and curate music using natural language prompts without ever leaving your coding environment.
In this guide, we'll walk you through everything you need to know to set up and use this powerful combination.
MCP (Model Context Protocol) is an open standard developed by Anthropic that allows AI assistants like Claude to connect with external tools and services. Think of it as a bridge that lets Claude interact with real-world APIs and databases.
Epidemic Sound's MCP Server is their implementation of the Model Context Protocol, designed specifically for music discovery. Instead of manually browsing their catalog of 50,000+ tracks, you can now:
"Find upbeat electronic tracks for a mobile puzzle game"
"Search for calm, ambient music with piano, around 80 BPM"
"I need tense orchestral music for a boss battle scene"
"Find short 10-second loops suitable for UI interactions"
Before you begin, make sure you have:
Important: MCP servers require a local environment. They do not work in web browsers or mobile apps.
If you don't have Node.js installed, download and install the LTS version:
# Verify installation
node --version
npm --version
You should see version numbers for both commands.
Option A: Claude Desktop (GUI)
Option B: Claude Code (CLI)
# Install Claude Code globally
npm install -g @anthropic-ai/claude-code
# Verify installation
claude --version
Using Claude Code CLI:
# Add the Epidemic Sound MCP server with user scope
claude mcp add epidemicsound --scope user
Or manually edit the configuration file:
Find your config file:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json~/.config/Claude/claude_desktop_config.jsonAdd the following configuration:
{
"mcpServers": {
"epidemicsound": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-epidemicsound"],
"env": {
"EPIDEMIC_SOUND_CLIENT_ID": "your-client-id",
"EPIDEMIC_SOUND_CLIENT_SECRET": "your-client-secret"
}
}
}
}
On first use, you'll be prompted to authenticate via OAuth:
# List all configured MCP servers
claude mcp list
# Check the Epidemic Sound connection
claude mcp get epidemicsound
You should see the Epidemic Sound server listed and connected.
After configuration, restart Claude Desktop or your Claude Code session:
# If using Claude Code, simply start a new session
claude
Once connected, you can search for music using natural language:
You: Find energetic rock tracks for a racing game
Claude: I found several tracks that would work well for a racing game:
1. "Full Throttle" by Horizon Blue
- Genre: Rock/Alternative
- BPM: 140
- Duration: 3:24
- Mood: Energetic, Driving
2. "Speed Demon" by Electric Avenue
- Genre: Hard Rock
- BPM: 155
- Duration: 2:58
- Mood: Intense, Powerful
[Preview links and download options...]
You: I'm building a memory matching game for kids. I need 8 distinct
short musical clips that are easy to remember and differentiate.
Each should be about 5-10 seconds, family-friendly, and cover
different musical styles.
Claude: Here are 8 distinct clips perfect for a memory game:
1. Classical Piano Melody - Gentle, recognizable tune
2. Upbeat Ukulele Strum - Happy, playful feel
3. Jazz Saxophone Riff - Smooth, memorable hook
4. Electronic Synth Pulse - Modern, catchy beat
5. Acoustic Guitar Fingerpicking - Warm, folk-style
6. Orchestral Strings Swell - Dramatic, cinematic
7. Reggae Bass Groove - Relaxed, rhythmic pattern
8. Flute & Harp Fantasy - Magical, whimsical tone
Each clip has been selected for maximum memorability and distinction...
You: Search for UI sound effects - button clicks, success chimes,
and error sounds for a mobile app
Claude: Found these UI sound effects:
Button Clicks:
- "Soft Click" - Subtle, modern feel
- "Mechanical Press" - Tactile feedback sound
- "Digital Tap" - Clean, minimalist
Success Sounds:
- "Achievement Unlocked" - Celebratory chime
- "Level Complete" - Uplifting melody
- "Coin Collect" - Classic game feedback
Error/Alert Sounds:
- "Gentle Warning" - Non-intrusive alert
- "Soft Buzz" - Subtle error indicator
- "Try Again" - Encouraging tone
After finding tracks via Claude, integrate them into your Python project:
# music_config.py
from dataclasses import dataclass
from datetime import timedelta
from typing import List
@dataclass
class MusicTrack:
id: str
title: str
artist: str
file_path: str
duration: timedelta
# Tracks discovered via Epidemic Sound MCP
GAME_MUSIC_TRACKS: List[MusicTrack] = [
MusicTrack(
id="track_001",
title="Puzzle Master",
artist="Ambient Keys",
file_path="assets/sounds/music/puzzle_master.mp3",
duration=timedelta(seconds=12),
),
MusicTrack(
id="track_002",
title="Mind Games",
artist="Electronic Dreams",
file_path="assets/sounds/music/mind_games.mp3",
duration=timedelta(seconds=10),
),
# ... more tracks
]
# FastAPI endpoint example
from fastapi import FastAPI
from fastapi.responses import FileResponse
app = FastAPI()
@app.get("/api/tracks")
async def get_tracks():
return [
{
"id": track.id,
"title": track.title,
"artist": track.artist,
"duration_seconds": track.duration.total_seconds(),
}
for track in GAME_MUSIC_TRACKS
]
@app.get("/api/tracks/{track_id}/stream")
async def stream_track(track_id: str):
track = next((t for t in GAME_MUSIC_TRACKS if t.id == track_id), None)
if track:
return FileResponse(track.file_path, media_type="audio/mpeg")
return {"error": "Track not found"}
<!-- components/MusicPlayer.vue -->
<template>
<UCard>
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-lg font-semibold">{{ currentTrack?.title }}</h3>
<UBadge color="primary">{{ currentTrack?.artist }}</UBadge>
</div>
</template>
<div class="space-y-4">
<!-- Progress bar -->
<UProgress :value="progress" />
<!-- Controls -->
<div class="flex items-center justify-center gap-4">
<UButton
icon="i-heroicons-backward"
color="gray"
variant="ghost"
@click="previousTrack"
/>
<UButton
:icon="isPlaying ? 'i-heroicons-pause' : 'i-heroicons-play'"
size="lg"
@click="togglePlay"
/>
<UButton
icon="i-heroicons-forward"
color="gray"
variant="ghost"
@click="nextTrack"
/>
</div>
<!-- Track list -->
<UDivider />
<div class="space-y-2">
<UButton
v-for="track in tracks"
:key="track.id"
block
:color="currentTrack?.id === track.id ? 'primary' : 'gray'"
variant="soft"
@click="selectTrack(track)"
>
{{ track.title }} - {{ track.artist }}
</UButton>
</div>
</div>
</UCard>
</template>
<script setup lang="ts">
interface MusicTrack {
id: string
title: string
artist: string
src: string
category: string
mood: string
bpm: number
}
// Tracks curated via Epidemic Sound MCP
const tracks: MusicTrack[] = [
{
id: 'es_001',
title: 'Digital Sunrise',
artist: 'Synth Wave Collective',
src: '/audio/music/digital_sunrise.mp3',
category: 'electronic',
mood: 'uplifting',
bpm: 120,
},
{
id: 'es_002',
title: 'Ocean Breeze',
artist: 'Ambient Nature',
src: '/audio/music/ocean_breeze.mp3',
category: 'ambient',
mood: 'calm',
bpm: 70,
},
]
const currentTrack = ref<MusicTrack | null>(tracks[0])
const isPlaying = ref(false)
const progress = ref(0)
const audio = ref<HTMLAudioElement | null>(null)
onMounted(() => {
audio.value = new Audio()
audio.value.addEventListener('timeupdate', updateProgress)
audio.value.addEventListener('ended', nextTrack)
})
function updateProgress() {
if (audio.value) {
progress.value = (audio.value.currentTime / audio.value.duration) * 100
}
}
function selectTrack(track: MusicTrack) {
currentTrack.value = track
if (audio.value) {
audio.value.src = track.src
audio.value.play()
isPlaying.value = true
}
}
function togglePlay() {
if (!audio.value || !currentTrack.value) return
if (isPlaying.value) {
audio.value.pause()
} else {
if (!audio.value.src) {
audio.value.src = currentTrack.value.src
}
audio.value.play()
}
isPlaying.value = !isPlaying.value
}
function nextTrack() {
const currentIndex = tracks.findIndex(t => t.id === currentTrack.value?.id)
const nextIndex = (currentIndex + 1) % tracks.length
selectTrack(tracks[nextIndex])
}
function previousTrack() {
const currentIndex = tracks.findIndex(t => t.id === currentTrack.value?.id)
const prevIndex = currentIndex === 0 ? tracks.length - 1 : currentIndex - 1
selectTrack(tracks[prevIndex])
}
</script>
// services/musicService.ts
interface MusicTrack {
id: string
title: string
artist: string
filePath: string
mood: string
bpm: number
duration: number
}
interface SearchFilters {
mood?: string
minBpm?: number
maxBpm?: number
category?: string
}
class MusicService {
private tracks: MusicTrack[] = []
private audioContext: AudioContext | null = null
private currentSource: AudioBufferSourceNode | null = null
constructor() {
// Tracks curated via Epidemic Sound MCP
this.tracks = [
{
id: 'puzzle_001',
title: 'Puzzle Master',
artist: 'Ambient Keys',
filePath: '/audio/puzzle_master.mp3',
mood: 'calm',
bpm: 85,
duration: 120,
},
{
id: 'action_001',
title: 'Speed Runner',
artist: 'Electric Dreams',
filePath: '/audio/speed_runner.mp3',
mood: 'energetic',
bpm: 140,
duration: 180,
},
]
}
searchTracks(filters: SearchFilters): MusicTrack[] {
return this.tracks.filter(track => {
if (filters.mood && track.mood !== filters.mood) return false
if (filters.minBpm && track.bpm < filters.minBpm) return false
if (filters.maxBpm && track.bpm > filters.maxBpm) return false
return true
})
}
async playTrack(trackId: string): Promise<void> {
const track = this.tracks.find(t => t.id === trackId)
if (!track) throw new Error('Track not found')
if (!this.audioContext) {
this.audioContext = new AudioContext()
}
// Stop current playback
this.stop()
const response = await fetch(track.filePath)
const arrayBuffer = await response.arrayBuffer()
const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer)
this.currentSource = this.audioContext.createBufferSource()
this.currentSource.buffer = audioBuffer
this.currentSource.connect(this.audioContext.destination)
this.currentSource.start()
}
stop(): void {
if (this.currentSource) {
this.currentSource.stop()
this.currentSource = null
}
}
getRandomTrack(mood?: string): MusicTrack {
const filtered = mood
? this.tracks.filter(t => t.mood === mood)
: this.tracks
return filtered[Math.floor(Math.random() * filtered.length)]
}
}
export const musicService = new MusicService()
The more context you provide, the better results you'll get:
"Find music for my game"
"Find calm, ambient music for the menu screen of a puzzle game
targeted at adults. Should feel modern and minimalist,
around 70-90 BPM, with soft synths or piano."
Combine multiple mood descriptors for nuanced results:
"Find tracks that are both mysterious AND playful -
like exploring a whimsical haunted house"
Ask for variations to build a cohesive soundtrack:
"I like this track. Can you find 5 similar tracks
that would work well together as a playlist?"
Include technical specs when needed:
"Find tracks that loop seamlessly, are exactly 30 seconds long,
and have no vocals - suitable for background gameplay music"
When using Epidemic Sound tracks in your projects, remember:
| Use Case | License Required |
|---|---|
| Personal projects | Personal subscription |
| Commercial games | Commercial license |
| YouTube/Streaming | Creator subscription |
| Client work | Commercial license |
Always verify your license covers your intended use case. Visit Epidemic Sound Licensing for details.
# Debug MCP connections
claude --mcp-debug
# Check if the server is properly configured
claude mcp list
The Epidemic Sound MCP integration with Claude represents a significant leap forward in creative workflows. By combining AI-powered natural language search with one of the world's largest royalty-free music libraries, developers and creators can:
Whether you're building games, creating content, or developing interactive experiences, this integration streamlines the entire music discovery process.
Have questions or want to share your experience? Reach out to us at hello@musictechlab.io
Building something similar or facing technical challenges? We've been there.
Let's talk — no sales pitch, just honest engineering advice.
How to manage tenants in the multitenant app based on django_tenants and saleor.io platform
Saleor is a great e-commerce open-source platform for building modern online stores with a multi-tenant management system.
How We Built a Notion Backup Tool in 3 Days with Python
A practical case study of building an automated Notion to Markdown sync tool. Why we're leaving Notion, how we preserved years of documentation, and why we're open-sourcing the solution.