navidrome-mcp
Enables building mood-based playlists for Navidrome by joining your library, listen history, and personal playlist labels from Navidrome, ListenBrainz, and Last.fm.
README
navidrome-mcp
An MCP server for Navidrome that builds playlists which actually match a described mood — grounded in what you own, what you have listened to, and how you yourself have labelled your music.
Why this exists
Navidrome's API alone cannot do this, for three concrete reasons:
- Its REST filtering is exact-match only.
year=1997works;year=1990-1999silently returns nothing. There are no ranges and no AND/OR, so a query like "90s rock I haven't played in a year, max 2 per artist" is not expressible. - It keeps no listen history. Only a
playCountand a lastplayDate. There is no way to ask "what do I put on at 7am on a Tuesday". - Nothing in the library says how a track feels. Measured on a real 9,311-track library: 32 genres with Rock alone covering 47%, BPM present on 24 tracks (0.3%), ReplayGain on 222 (2%), MusicBrainz recording IDs on 222 (2%). That last number also rules out AcousticBrainz as a primary mood source — its audio-derived mood models are keyed by MBID, and resolving the rest via ISRC → MusicBrainz (rate-limited to 1 req/s) would still only reach ~23% of the library.
So this server maintains its own index and joins three sources:
| Source | Provides |
|---|---|
| Navidrome (native + Subsonic APIs) | Authoritative metadata, similarity agents, the playlist write path |
| ListenBrainz | Timestamped listen history — time-of-day and weekday habits |
| Last.fm | A real descriptive tag vocabulary (nu-disco, melancholy, shoegaze) |
It also treats your existing curated playlists as your mood vocabulary. If you have
playlists called golden hour, cranked and slow shreds, those words already mean
something specific in your library — far more than a generic genre ever will.
The mood pass
Those playlists cover maybe 40% of a library, so on their own they can only answer mood questions about tracks you already filed. A one-time enrichment pass closes that gap: every track gets energy, valence, intensity, acoustic-vs-electronic, free-form descriptors, the curated vibe it reads as, and the times of day it fits.
The inference is grounded in your own playlists — they're a hand-labelled training set in your own words — so unfiled tracks land in the same space as the ones you filed. Results are cached permanently, so this runs once and afterwards only picks up new music.
Cost stays small through three things: batching ~40 tracks per request, prompt-caching the
large identical taxonomy prefix (the first batch runs alone, so the rest hit a warm cache
instead of all missing it concurrently), and running with thinking disabled — this is
classification, not reasoning. Set ANTHROPIC_API_KEY to enable it and MOOD_MODEL to
trade quality for spend; without a key everything else still works and only the mood
filters go dark.
Design notes
- In-memory index, no database. A full library pull is ~20s for ~10k tracks; once
local, every compound query is a single array pass. A JSON snapshot on disk makes
restarts instant. Deliberately no native dependency, so it installs under
npm ci --ignore-scriptson Node 20. - The index is a cache, never a source of truth. If the snapshot is missing or unreadable the server just re-syncs.
- Navidrome's own compound engine is still exposed via
create_smart_playlist, for standing playlists that should keep re-evaluating server-side. Note those rules can only see Navidrome's own fields — not ListenBrainz listens or Last.fm tags.
Tools
| Tool | Purpose |
|---|---|
describe_library |
Orientation: size, genres, decades, curated vibes, tag vocabulary |
search_tracks |
The workhorse — full compound filtering, diversity caps, affinity ranking |
get_vibe_profile |
What one of your curated moods actually consists of |
similar_tracks |
Expand from seeds via agents + your own playlist co-occurrence |
listening_history |
recent / top / by_hour / by_weekday / rediscover / trending |
list_playlists, get_playlist |
Read playlists |
create_playlist, update_playlist, delete_playlist |
Write playlists |
create_smart_playlist |
Self-updating rules-based playlists |
daylist_context |
Everything needed to generate this hour's daylist |
commit_daylist |
Publish the rolling daylist atomically |
refresh_index |
Re-sync from Navidrome / ListenBrainz |
Prompt: daylist — generates a Spotify-style daylist for the current hour.
Configuration
| Env var | Required | Notes |
|---|---|---|
NAVIDROME_URL |
yes | e.g. http://host:4533 |
NAVIDROME_USERNAME / NAVIDROME_PASSWORD |
yes | Playlists are created as this user |
NAVIDROME_PROXY |
no | socks5://host:port if Navidrome is only reachable via a proxy hop |
LISTENBRAINZ_USER |
no | Listen history is a public read; no token needed |
LASTFM_API_KEY |
no | Defaults to Navidrome's bundled public key |
NAVIDROME_TZ |
no | Default America/Chicago. Time-of-day analysis depends on this |
NAVIDROME_DATA_DIR |
no | Snapshot location. Default /data/navidrome-mcp |
DAYLIST_PLAYLIST_NAME |
no | Default daylist |
NAVIDROME_ENRICH |
no | 0 disables background Last.fm tag fetching |
Licence
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.