Navidrome AssistantCAUTION
Analyze listening patterns, build playlists, find missing albums, discover similar artists via Last.fm, fetch synced lyrics, and explore global radio. Play it all through your speakers via mpv, with a built-in web UI that makes any device with a brower act as a remote. Gives full control of your Nav
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
An MCP (Model Context Protocol) server for Navidrome. Claude Desktop, Claude Code, Cursor, and other MCP clients can browse your library, build playlists, discover new music, and play audio through your machine's speakers.
Table of Contents
- Features
- Available Tools
- Installation & Setup
- Troubleshooting
- Development
- License
- Support
Features
🎵 Music Library
Browse and search songs, albums, artists, genres, and tags. Filters cover query, starred status, year range, sort order, and tag values, and they combine: "all my starred jazz albums from the 90s, sorted by year" or "every song tagged Soundtrack with a 5-star rating". Tag analysis tools show what is in your library, so you don't have to guess at filter values.
🔊 Local Audio Playback
Requires `mpv` on the host running the MCP server (see Installing mpv).
Audio plays through your machine's speakers with no browser or Navidrome web UI. Search and play in one step: "play 5 random starred albums", "queue everything I've starred from the 90s sorted by year", or "add 10 random rock songs to whatever's already playing, shuffled". Albums have three shuffle modes: keep order, randomize album order, or interleave tracks.
The queue is editable during playback: reorder or shuffle without interrupting the current song, and removing the current track advances to the next. Saved Navidrome radio stations (Icecast, SHOUTcast) stream through mpv with live ICY metadata, so you can see what the station is playing. Plays scrobble back to Navidrome, so play counts and recent activity stay in sync. mpv starts on first use, can survive MCP client restarts through a per-user socket (see MPV Remote setup for the lifetime rules), and works on Linux, macOS, and Windows 11.
This works with vo
b77b10557d9cOBSERVED · 2026-10-07Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add navidrome-mcp --env NAVIDROME_PASSWORD=${NAVIDROME_PASSWORD} -- npx -y [email protected]{
"mcpServers": {
"navidrome-mcp": {
"command": "npx",
"args": [
"-y",
"[email protected]"
],
"env": {
"NAVIDROME_PASSWORD": "${NAVIDROME_PASSWORD}"
}
}
}
}Exposed tools (69)
53 read · 10 write · 6 destructive. Blast radius: 6 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
add_tracks_to_playlist | write | Add multiple types of content to a playlist in a single efficient operation. Supports any combination of individual songs, complete albums, artist discographies, or specific disc tracks. |
clear_play_queue | destructive | Clear the live play queue and stop playback. Use to fully halt audio output. |
clear_saved_queue | destructive | Clear the saved playback queue stored on the Navidrome server (the queue shown in the web interface). Does not affect live playback. |
click_station | read | Register a play click for a radio station (helps with popularity metrics). Call this when starting playback. |
create_playlist | write | Create a new playlist with a name, optional description, and visibility setting |
create_radio_station | write | Create one or more radio stations. Always provide stations as a JSON array - use a single-item array for one station. Each station requires name and streamUrl, with optional homePageUrl. |
delete_playlist | destructive | Delete a playlist (owner or admin only) |
delete_radio_station | destructive | Delete an internet radio station by ID |
discover_radio_stations | read | Discover internet radio stations worldwide via Radio Browser API. Search by genre/tag, country, language, quality, and more. Returns validated streams with metadata, sorted by popularity by default. |
get_album | read | Returns the full record for a single album by ID. Same fields as search_albums results — use this when you already have the album ID. Does NOT include the album\ |
get_album_info | read | Deep-dive on ONE album: full tracklist with durations, release year/type, genres, wiki summary, |
get_artist | read | Returns the full record for a single artist by ID. Same fields as search_artists results (id, name, albumCount, songCount, plus optional playCount/rating/starred). For biography, similar artists, and top tracks, use the Last.fm tools (get_artist_info, get_similar_artists, get_top_tracks_by_artist). |
get_artist_albums | read | Get an artist |
get_artist_info | read | Get detailed artist information from Last.fm |
get_play_queue | read | Return the current live mpv play queue with track metadata and the index of the currently-playing track. Read-only; does not start mpv if it isn |
get_playlist | read | Get detailed information about a specific playlist by ID |
get_playlist_tracks | read | Get all tracks in a playlist (supports JSON or M3U export). Response shape is discriminated by |
get_radio_filters | read | Get available filter options for radio station discovery (tags, countries, languages, codecs) |
get_radio_station | read | Get detailed information about a specific radio station by ID |
get_saved_queue | read | Read the saved playback queue stored on the Navidrome server. This is the queue shown in the web interface and synced across Navidrome clients — it is not live playback state and reading it does not affect any audio. |
get_similar_artists | read | Get similar artists using Last.fm API |
get_similar_tracks | read | Get similar tracks using Last.fm API |
get_song | read | Returns the full record for a single song by ID. Same fields as search_songs results — use this when you already have the song ID and want the canonical SongDTO without searching. To list a song\ |
get_song_playlists | read | Get all playlists that contain a specific song |
get_station_by_uuid | read | Get detailed information about a specific radio station by its UUID |
get_tag_distribution | read | Analyze tag usage patterns and distribution across the music library. Shows statistics for metadata categories with their usage counts. Supports: |
get_top_tracks_by_artist | read | Get top tracks for an artist from Last.fm |
get_trending_music | read | Get trending music charts from Last.fm |
list_most_played | read | List most played songs, albums, or artists |
list_playlists | read | List all playlists accessible to the user with clean, LLM-friendly data |
list_radio_stations | read | List all internet radio stations from Navidrome |
list_recently_played | read | List recently played tracks with time filtering |
list_starred_items | read | List starred/favorited songs, albums, or artists. If the goal is to PLAY the starred items (not just show them), use |
list_top_rated | read | List top-rated songs, albums, or artists |
move_in_play_queue | write | Move the play-queue entry at index |
next | read | Skip to the next track in the local mpv playlist. Reports an empty queue when nothing is playing (does not start mpv). |
now_playing | read | Report the current local playback state — title, artist, album, position, duration, paused, and queue index/length. Reads from the engine |
open_settings | read | Open the Navidrome MCP settings page in a browser and return its local URL. |
pause | read | Pause local audio playback (mpv). Reports nothing to pause when no playback is active (does not start mpv). Position is preserved so resume continues from the same spot. |
ping | read | returns pong |
play_albums | read | Play one or many albums through the local speakers via mpv. |
play_albums_search | read | ONE-SHOT search + enqueue for albums — runs the album search AND pipes every matched album |
play_playlist | read | ONE-SHOT load a Navidrome playlist into the local mpv queue — fetches every track in the playlist AND enqueues them in a single call. PREFER THIS over the two-step pattern ( |
play_queue_index | read | Jump directly to the play-queue entry at the given index — equivalent to clicking a track row in the web UI. Does NOT reorder the queue, only moves the play head. Unpauses if paused. Reports an empty queue when nothing is playing (does not start mpv). Discovery flow: call |
play_radio_station | read | Play a radio station through the local mpv speakers (requires mpv on the host). Replaces the entire live play queue with this single radio stream — radio is mutually exclusive with songs/albums in the play queue, matching Navidrome\ |
play_songs | read | Play one or many songs through the local speakers via mpv. |
play_songs_search | read | ONE-SHOT search + enqueue for songs — runs the song search AND pipes the matched track IDs into mpv in a single call. PREFER THIS over the two-step pattern ( |
playback_status | read | Probe the playback engine. Returns whether mpv is currently spawned, its detected path/version, and current volume/idle state. Does NOT spawn mpv if the engine is not already running. |
previous | read | Skip to the previous track in the local mpv playlist. Reports an empty queue when nothing is playing (does not start mpv). |
remove_from_play_queue | destructive | Remove the play-queue entry at the given index. mpv auto-advances if the removed track was currently playing. |
remove_tracks_from_playlist | destructive | Remove tracks from a playlist by their |
reorder_playlist_track | read | Reorder a track within a playlist to a new position. Positions are 1-based and match the |
resume | read | Resume local audio playback (mpv). Reports nothing to resume when no playback is active (does not start mpv) — use a play tool to begin. |
save_queue | write | Save a playback queue to the Navidrome server so it appears in the web interface and syncs to other Navidrome clients. Does not start playback. |
search_albums | read | Search for albums by name with advanced filtering and sorting options. Leave query empty to list all albums.\n\nTIP: Use \ |
search_all | read | Search across all content types (artists, albums, songs) with advanced filtering and sorting options. Leave query empty to list all results.\n\nNote: |
search_artists | read | Search for artists by name with advanced filtering and sorting options. Leave query empty to list all artists.\n\nTIP: Use \ |
search_by_tags | read | Search for tags by type (e.g., list all genres, find release types, etc.). Defaults to genre if no tagName specified. Use this to explore metadata categories like genres, release types, media formats, and more. |
search_lyrics | read | Search LRCLIB for the lyrics of a track by title and artist. Returns candidate records, each with an lrclibId to pass to get_lyrics. Also returns the matching library song when there is one, so its own file lyrics can be used instead. |
search_songs | read | Search for songs by title with advanced filtering and sorting options. Leave query empty to list all songs.\n\nNote: the query runs Navidrome\ |
seek | write | Move the playback position within the current track. |
set_rating | write | Set a rating (0-5 stars) for a song, album, or artist |
set_volume | write | Set mpv |
shuffle_play_queue | write | Randomize the order of items in the current live play queue. Does not change membership. The currently-playing track keeps playing (it is not restarted) and is moved to the top of the queue; the rest of the queue is shuffled around it. |
star_item | read | Star/favorite a song, album, or artist |
test_connection | read | Report Navidrome MCP configuration/connection status. |
unstar_item | read | Unstar/unfavorite a song, album, or artist |
update_playlist | write | Update a playlist\ |
vote_station | read | Vote for a radio station to increase its popularity |
Trust audit
CAUTIONgrade C · trust 80/100 Install with care. The audit found things worth knowing before you trust its output.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | WARN |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (6 observation(s))
- Network
- declared (6 observation(s))
- Shell
- declared (4 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (25)
CMD ["node", "-e", "require('node:http').get('http://127.0.0.1:3000/healthz',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"]const WAKE_VIDEO_SRC = `${WAKE_VIDEO_SCHEME}video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAMBbW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAE4gAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAclear_play_queue, clear_saved_queue, delete_playlist, delete_radio_station, remove_from_play_queue, remove_tracks_from_playlist
.prettierignore
.prettierrc.json
const token = crypto.createHash('md5').update(password + salt).digest('hex');const expectedToken = crypto.createHash('md5').update(password + salt).digest('hex');} from '../../constants/timeouts.js';
import { logger } from '../../utils/logger.js';import { logger } from '../../utils/logger.js';import type { Config } from '../../config.js';import { logger } from '../../utils/logger.js';`http://169.254.169.254/` (AWS/GCP/Azure metadata service) can
MCP-->>Client: 401 + resource_metadata="http://169.254.169.254/..."
Client->>Internal: GET http://169.254.169.254/latest/meta-data/
expect(isPrivateOrLocalIp('169.254.169.254')).toBe(true);expect(isPrivateOrLocalIp('::ffff:169.254.169.254')).toBe(true);3. The player logs the LAN URLs it's reachable on at bind time (e.g. `http://192.168.1.42:8808`). Open one in your phone's browser and bookmark it.
node dist/web/main.js # serves http://127.0.0.1:8808 and opens your browser
curl -s -X POST http://127.0.0.1:3000/mcp \
Deploy the default export on your runtime — `wrangler dev server.ts` puts it on `http://127.0.0.1:8787`; `deno serve server.ts` and `bun run server.ts` serve the same `{ fetch }` shape. POST a `tools/@modelcontextprotocol/sdk, file-type, undici, zod, @eslint-community/eslint-plugin-eslint-comments, @eslint/js, @types/node, @typescript-eslint/eslint-plugin
TOKEN=$(curl -s -X POST http://localhost:4533/auth/login \
Web applications should send a user to [last.fm/api/auth](https://www.last.fm/api/auth), sending an API key as a parameter, in order to authenticate the user. This should be an HTTP GET request. Your
Send your api key along with an api signature and your authentication token as arguments to the [auth.getSession](https://www.last.fm/api/show/auth.getSession) API method call. The parameters for this
Gates applied: no_behavioural_pass.
b77b10557d9cfull audit observations/trust-audit/mcp-server/blakeem__navidrome-assistant.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-07 | b77b10557d9c | CAUTION | C | 80 | first audit |
Questions
What is the Navidrome Assistant MCP server?
Analyze listening patterns, build playlists, find missing albums, discover similar artists via Last.fm, fetch synced lyrics, and explore global radio. Play it all through your speakers via mpv, with a built-in web UI that makes any device with a brower act as a remote. Gives full control of your Nav
What tools does Navidrome Assistant expose?
69 in total: 53 read-only, 10 that write, and 6 that can delete or overwrite (clear_play_queue, clear_saved_queue, delete_playlist, delete_radio_station, remove_from_play_queue). Every one is listed on this page with its risk.
Is Navidrome Assistant safe to connect to an agent?
With care. The audit graded it C (80/100) and found 25 things worth knowing before you trust this server, listed below with the exact line each was found on. Separately from the audit: 6 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does Navidrome Assistant need?
It reads NAVIDROME_PASSWORD from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does Navidrome Assistant run?
It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as navidrome-mcp at 2.3.0.
How current is this page?
The grade is for one exact copy of the source (b77b10557d9c), read on 2026-10-07. The repository is watched and re-audited when it changes.