navidrome-mcp
The navidrome-mcp server enhances Navidrome by building mood-aware, personalized playlists that combine your library's metadata, ListenBrainz listening history, Last.fm tags, and your own curated playlists. You can:
Discover & inspect: Get library overviews (genres, decades, mood playlists, tag vocabularies), check mood labelling coverage, profile vibe playlists (top artists, genres, time-of-day patterns), and analyze listening habits (recent, top, hourly/weekday patterns, rediscover, trending).
Search & filter: Perform compound searches across the entire library using flexible filters: mood axes (energy, valence, intensity, organic), mood descriptors, vibes, Last.fm tags, genres, year/date ranges, BPM, duration, play/listen counts, recency, time-of-day fit, starred status, with per-artist/album diversity caps and personal affinity ranking.
Mood & similarity: Enrich the library so every track gets a mood profile, find similar tracks using Navidrome's similarity agents and co-occurrence in curated playlists, and understand what each vibe means in your library.
Listening history: Analyse ListenBrainz data to see recent plays, top tracks/artists, hour-of-day/weekday habits, rising/falling trends, and forgotten favourites.
Playlist management: Create, update (replace/append), delete, and list playlists; also define rule-based smart playlists that Navidrome continuously re-evaluates.
Daylist automation: Get a real-time listening context for the current hour (time, dominant vibes, artists, recent listens), generate a personalized playlist with a unique title, and publish it as a rolling daylist that avoids repeating recent tracks.
Maintenance: Refresh the local index from Navidrome/ListenBrainz to keep data current, and run mood enrichment to enable whole-library mood search.
Provides a descriptive tag vocabulary (e.g. 'nu-disco', 'melancholy', 'shoegaze') used for mood-based playlist generation, with background tag fetching enabled via LASTFM_API_KEY.
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, and the source the play-count backfill below is built from |
Last.fm | A real descriptive tag vocabulary ( |
Only the first is required. Listen history, Last.fm tags and your own playlists each improve ranking and time-of-day fit where they exist, and none of them is load-bearing: the same query means the same thing in a library that has none of them.
Listen history has two failure modes worth knowing about
Both were live here until 2026-08-10, and both are silent.
The history can be a prefix, and used to stay one. ListenBrainz publishes a rate-limit
budget on every response (X-RateLimit-Remaining, X-RateLimit-Reset-In; observed 30
requests per 5 seconds). Overrunning it does not return 429. The server stalls responses,
first to seconds and then to tens of seconds, and eventually closes the connection
(UND_ERR_SOCKET). The walk then stopped and kept its prefix, which is a perfectly valid
history: nothing distinguishes a quarter of a large account from all of a small one.
What made that permanent rather than merely unlucky is that the walk always restarted from the newest listen, so every later sync re-fetched what it already had and stopped at the same wall. The index sat at 32k of 126k for months, including through an explicit full resync. Requests are now paced against the published budget, a retry waits for the window to turn over instead of spending what is left of it, and an interrupted walk resumes from the OLDEST listen held. A sync that still cannot finish leaves the index usable and says so, and the next start picks the walk up where it stopped.
One play can arrive twice. Scrobbling to both Last.fm and ListenBrainz while also
running ListenBrainz's Last.fm importer delivers every play from two submitters. The
timestamps differ, because Last.fm stamps a scrobble when it is submitted and a direct
submitter stamps it at playback start, so nothing that keys on an exact time notices.
Measured here: a median 219 seconds apart, inflating about a quarter of recent listens.
dedupeListens collapses a pair only when a different submitter reported it, since two
plays close together from the same submitter are what a genuine repeat looks like. The
window and the reasoning are checked by npm run check:dedupe.
LISTENBRAINZ_HISTORY_DAYS bounds a cold start and defaults to effectively the whole
account. Note that an incremental sync resumes from the newest listen already held, so
listens backfilled with older timestamps need refresh_index with full_listens.
Related MCP server: Navidrome-MCP
Where mood comes from
Not from here. This server has no LLM client and no way to label a track. Mood is
produced by navidrome-mood, a Navidrome
plugin that judges each track and writes the values into the audio files as tags. This
server reads those tags and does everything downstream: filtering, cohesion, sequencing,
playlist writing.
The split is deliberate and one-directional. The plugin never calls this server and is useful without it: its tags drive Navidrome's own smart playlists, and Music Assistant and every Subsonic client can read them too. This server depends on the plugin only for mood; install it if you want mood-aware playlists, skip it and everything else still works.
Keeping a second labelling path here as a fallback would mean maintaining the same vocabulary in two languages and shipping two answers to one question. There is deliberately no fallback.
What the plugin writes, per track: energy, valence, intensity, acousticness, density, how fast it feels, whether it is sung, two to four vocabulary terms, the times of day it fits, the vibe regions it falls in, and for a track in none of them, the region it came closest to.
That last one is why mood_vibes_near exists. Region membership is strict, and about a
third of a library falls outside every region; most of those are ordinary tracks a little
past an edge rather than unusual music between the regions. Setting mood_vibes_near
unions them in, which on a 9,195 track library takes the share reachable by region from
65% to 94%. Leave it off when the region's character is the point.
The vocabulary is defined, not derived. Each of its 52 terms carries an explicit anchor
in mood-space, and each of the 14 vibes is a named region with a centre and a radius, so the
same track gets the same coordinates in anyone's library. Deriving the words from one
collection instead would bake that collection's shape into them: a rock-heavy library yields
riffy and bass-heavy, which say nothing useful about a jazz one.
The radii are the one part fitted to a collection rather than defined, and the split is deliberate. A centre says what a vibe means and must not move; a radius says how close counts as close, which depends on how tightly the music clusters. Fitting them against an even spread of the coordinate space produced regions wider than the typical gap between any two tracks in a real library, so they are fitted against a measured distribution instead. Coordinates therefore travel between libraries unchanged; region membership is calibrated.
Words alone cannot carry cohesion, which is why the axes exist. Measured on a real library,
tender covered both Debussy's Suite bergamasque and Metallica's Nothing Else Matters:
both labels correct, and useless as a playlist filter. Distance in mood-space separates them.
Call mood_coverage to see how much of a library is labelled. When the answer is none it
says which of the three causes applies (plugin never run, plugin ran but wrote nothing, or
tags written but not declared in Navidrome's own config file) because those need
different fixes and all three otherwise read as an empty library.
Backfilling Navidrome's play counts
Navidrome counts only what Navidrome served. Its scrobbler is outbound only and
IncPlayCount is play_count + 1, so there is no import path: a library
listened to for years before Navidrome existed shows a handful of plays, and
every smart playlist, client sort and play_count_min filter reads that
number rather than the real one. On the library this was built against it was
976 plays against a ListenBrainz history of 123,157 listens.
Run it, and that column becomes the count for everything. Ranking, sorting and
the count filters read Navidrome and nothing else; the connector's own listen
total stops being scored beside it, because after a backfill the two describe
the same plays and weighing both counts the same evidence twice. Skip it and
describe_library says so, rather than leaving every ordering quietly wrong.
scripts/ closes the gap. Two steps, because they run in different places:
tsx scripts/plan-playcounts.ts /data/navidrome-mcp/index.json playcounts.json
python3 scripts/apply-playcounts.py playcounts.json /data/navidrome.db # dry run
python3 scripts/apply-playcounts.py playcounts.json /data/navidrome.db --writeThe planner matches the history to tracks with the same key this server uses for
everything else, so a fix to the matcher fixes both at once. The applier is
standard-library Python because it has to run wherever navidrome.db is, which
is often a machine with no node; pointing it at a Docker volume works:
docker run --rm -v <volume>:/data -v "$PWD":/host python:3.12-slim \
python /host/apply-playcounts.py /host/playcounts.json /data/navidrome.db --writeFive things worth knowing before running it:
Do not use Navidrome's
/rest/scrobbleendpoint instead, however much more supported it looks. Navidrome forwards a scrobble to ListenBrainz and Last.fm, so replaying a decade of history through it submits that history back to the service it came from and corrupts it permanently.The write is a floor, not an assignment.
max(existing, imported)means Navidrome's own counting is never rolled back and a second run changes nothing. Onlyplay_countandplay_dateare touched;starredandratingshare the row and are the user's own judgements.A play can land on more than one file. Nothing in a scrobble says which copy was played, so a library holding both a single and an album version credits both. 486 of 7,580 matched tracks were in that position here. Each track's own count stays defensible; the library-wide total is inflated.
Not every listen matches. 50,781 of 123,157 matched nothing, which is mostly music heard elsewhere and never acquired. The planner reports that number every run: a sudden jump means the matcher broke, not that taste changed.
Matching on identifiers instead is not the safer option it looks like, and is worth understanding before anyone tries to "fix" the fuzzy match. Two reasons. Coverage: 222 of 9,200 files here carry a genuine MusicBrainz recording id. A further 839 carry a Discogs id in the MusicBrainz-named
musicbrainz_trackidtag, which grades as total disagreement against ListenBrainz and means nothing. Semantics: even where both sides hold real ids, they disagree about a third of the time, and the sampled disagreements are all the same song under a different recording, never a different song. ListenBrainz maps a scrobble to its own canonical recording, which is rarely the exact pressing on disk. An id join would therefore reject plays this one correctly credits. It would be more precise and match less.
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.
It re-syncs itself once it goes stale, half an hour by default, in the background on whatever tool call notices.
NAVIDROME_SYNC_TTL_MINchanges the window and0turns it off. This is not a nicety: a snapshot that loads cleanly used to be treated as current forever, so music added after the last manualrefresh_indexnever appeared, and a restart did not help. It also catches the gap where the mood plugin labels a track minutes after Navidrome imports it, which otherwise froze that track in the index unlabelled.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.npm run check:vocabasserts what typechecking cannot about this side's copy of the vocabulary: every synonym resolves and is reachable, no term or region name contains a character Navidrome splits tag values on, and every hour of the day is claimed by some region. The anchors and region geometry live in the plugin and are asserted there.
Tools
Tool | Purpose |
| Orientation: size, genres, decades, vibe regions, tag vocabulary |
| How much of the library is labelled, and what to fix when none of it is |
| The workhorse: full compound filtering, diversity caps, affinity ranking |
| What a vibe actually consists of in this library, and how tightly it clusters |
| Expand from seeds via agents + playlist co-occurrence |
| recent / top / by_hour / by_weekday / rediscover / trending |
| Read playlists |
| Write playlists |
| Self-updating rules-based playlists |
| What suits right now: the hour, which vibes fit it, what dominates it, what was just heard |
| Publish one revision of a rolling playlist, by title |
| Re-sync from Navidrome / ListenBrainz |
Prompt: daylist - refreshes the daylist playlist for the current hour.
Rolling playlists
A rolling playlist is one that gets rewritten on a schedule: daylist hourly, mix: chill
and the rest whenever they are asked for. Its title is fixed for its whole life and the
phrase that changes goes in the description, which is what commit_playlist enforces: it
matches on the title, never renames what it finds, and creates a playlist only when no
playlist carries that title yet. A generator that renamed its own output instead would lose
track of it and make a new one on the next run, and nobody notices that until the sidebar
holds forty near-identical lists.
search_tracks's exclude_recent_runs keeps a rolling playlist off its own recent tracks.
It is scoped to one playlist, so the hourly daylist moving fast does not starve the others.
Configuration
Env var | Required | Notes |
| yes | e.g. |
| yes | Playlists are created as this user |
| no |
|
| no | Listen history is a public read; no token needed |
| no | Defaults to Navidrome's bundled public key |
| no | Default |
| no | Snapshot location. Default |
| no |
|
| no | Default |
Licence
MIT
Available Tools
15 toolscommit_daylistPublish the daylistA
Write the daylist in one atomic step: replace the rolling daylist playlist's tracks, rename it to the new title, set its description, and record the run so future daylists can avoid repeating these tracks. Creates the playlist on first use.
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | The daylist's name for this hour, in his voice, e.g. 'golden hour synth cruise'. | |
| track_ids | Yes | ||
| description | No | One line on why these tracks, shown as the playlist comment. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden and delivers: it discloses the multi-step side effects (replace, rename, set description, record run) and the first-use creation behavior. It also explains the purpose of recording the run (avoid future repeats), which goes beyond basic operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise: two sentences, with the first enumerating all core actions and the second addressing first-use creation. Every word earns its place, and the structure front-loads the main purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex multi-step tool with no output schema and no annotations, the description is remarkably complete: it explains the atomic nature, the specific operations, the run recording, and first-time behavior. No critical gaps are evident for the intended use case.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers two of three parameters with descriptions, and the tool description maps each parameter to its action (track_ids→tracks, title→new title, description→description). This adds meaningful context, especially for track_ids which lacks a schema description, supporting a score above the 3 baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states what the tool does: writes the daylist in one atomic step, replacing tracks, renaming, setting description, and recording the run. It uses a specific verb ('write') and resource ('daylist'), and distinguishes itself from generic create_playlist/update_playlist by describing the combined operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use this tool: when publishing the daylist as a single atomic operation. It does not explicitly contrast with sibling tools like update_playlist, but the specialized wording implies this is the dedicated tool for daylist commits, making the usage context clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_playlistCreate a playlistA
Create a new playlist from an explicit list of track ids (use search_tracks to source them).
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| public | No | ||
| comment | No | Shown as the playlist description in Navidrome. | |
| track_ids | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It only states the creation action without disclosing permissions, side effects, input validation, or return value. This is insufficient for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no redundant wording. It earns its place by providing the core action and a sourcing hint without waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple create tool with no annotations and no output schema, the description gives enough to initiate a basic creation. However, it omits behavioral details like return object and optional parameter effects, making it partially incomplete for an agent that needs full invocation confidence.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 25%, so the description must compensate. It clarifies that track_ids is an explicit list and suggests search_tracks for sourcing, adding value for the primary parameter. However, it does not explain public or comment parameters beyond the schema, leaving gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates a new playlist from an explicit list of track IDs, which distinguishes it from the sibling create_smart_playlist. It also references search_tracks for sourcing, making the purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly directs users to search_tracks to source track IDs, providing a clear workflow. It implies use when you have specific track IDs, contrasting with smart playlists, but does not explicitly list when-not-to-use cases or alternative tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_smart_playlistCreate a smart (self-updating) playlistA
Create a playlist defined by RULES rather than a fixed track list. Navidrome re-evaluates it continuously, so it stays current without regeneration — ideal for standing playlists like '90s rock I haven't played in a year'.
Rules are Navidrome's native criteria format: {"all":[{"is":{"genre":"Rock"}},{"inTheRange":{"year":[1990,1999]}},{"notInTheLast":{"lastPlayed":365}}],"sort":"playCount","order":"desc","limit":100}
Operators: is, isNot, gt, lt, contains, notContains, startsWith, endsWith, inTheRange, before, after, inTheLast, notInTheLast. Combine with all (AND) / any (OR), which may nest. Fields include: title, album, artist, albumartist, genre, year, dateadded, datemodified, lastplayed, playcount, rating, starred, loved, comment, bpm, length, filepath, filetype.
Note: rules operate on Navidrome's own fields only — ListenBrainz listen counts and Last.fm tags are NOT available here. For those, use search_tracks plus create_playlist.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| rules | Yes | Navidrome smart-playlist criteria object. | |
| public | No | ||
| comment | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that Navidrome continuously re-evaluates rules, so playlists stay current without regeneration. It also reveals a key limitation: rules operate only on Navidrome's own fields, not ListenBrainz or Last.fm. With no annotations provided, this carries the full burden well, though it omits return values or error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but well-structured, opening with a clear purpose, then a concrete example, followed by operator/field lists and a limitations note. It is long, but every section earns its place given the complexity of the rules parameter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complex nested rules object and no annotations/output schema, the description covers the critical aspects: rule syntax, operators, fields, and unsupported data. It could add what the API returns or error scenarios, but it is largely complete for invoking the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description provides an extensive explanation of the rules parameter, including a JSON example, a list of all operators, combinators (all/any), nesting, and available fields. This goes far beyond the schema's generic 'criteria object' description and fully compensates for the low schema coverage of other parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool 'Create a playlist defined by RULES rather than a fixed track list', distinguishing it from the sibling create_playlist. It also provides a concrete use case ('90s rock I haven't played in a year') and emphasizes the self-updating behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly positions the tool for standing/self-updating playlists with an example, and explicitly directs users to search_tracks plus create_playlist when ListenBrainz/Last.fm fields are needed. The contrast with fixed track lists is clear, giving both when-to-use and when-not-to-use context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
daylist_contextGet daylist context for right nowARead-only
Everything needed to generate this hour's daylist: local time and part of day, which of his curated moods he actually reaches for at this hour (measured as lift over that mood's own average, so it is not just playlist size), the artists/genres/tags that dominate this hour historically, what he has heard in the last few days, and the titles of recent daylists so the new one does not repeat them.
| Name | Required | Description | Default |
|---|---|---|---|
| hour_of_day | No | Override the current hour. | |
| recent_runs | No | How many past daylists to report. Default 8. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only provide readOnlyHint: true, so the description carries the burden of explaining behavior. It does so richly: it discloses the computed mood lift metric, historical dominance data, and the purpose of recent daylist titles. This goes well beyond the annotation, though it does not cover edge cases or error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence beginning with 'Everything needed...'. It is dense but contains no fluff, and each clause earns its place. The long list-style structure is slightly run-on but efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by fully enumerating the returned context: time/part of day, mood lifts, artists/genres/tags, recent listens, and recent daylist titles. Combined with complete schema coverage for the two optional parameters, it is thoroughly complete for a read-only context tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with both parameters (hour_of_day, recent_runs) already described. The description adds no new parameter syntax or format details; it only implicitly relates them to the daylist generation workflow. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb and resource: 'Get daylist context'. It enumerates the exact contents (local time, part of day, mood lifts, artists/genres/tags, recent listens, recent daylist titles), making it easy for an agent to understand what the tool provides and how it differs from siblings like get_vibe_profile or listening_history.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says 'Everything needed to generate this hour's daylist', which gives clear context for when to use this tool. It does not explicitly name alternative tools or exclusion criteria, but the purpose is well-scoped relative to the listed siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_playlistDelete a playlistBDestructive
Permanently delete a playlist. Does not touch the audio files.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| playlist_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only provide destructiveHint: true. The description adds meaningful context: 'Permanently delete' reinforces irreversibility, and 'Does not touch the audio files' clarifies a key behavioral boundary. This goes beyond what the annotation alone conveys.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences that immediately state the action and a crucial caveat. There is no filler or redundancy; every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple delete operation, the description covers purpose and safety, and the destructiveHint annotation adds context. However, it omits guidance on parameter selection and the fact that both parameters are optional, which is a notable gap given the schema provides no descriptions and there is no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the description makes no mention of the parameters 'name' and 'playlist_id.' The agent receives no guidance on which to use, whether they are alternatives, or which is required (especially since both are optional in the schema). The description fails to compensate for the schema's lack of parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Permanently delete a playlist.' It clearly distinguishes from sibling tools like update_playlist and get_playlist, and adds the clarifying statement 'Does not touch the audio files' to define the scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to use this tool versus alternatives. It does not mention prerequisites (e.g., needing a playlist_id from list_playlists) or explicitly say 'use when you want to remove a playlist.' The context of siblings is not leveraged to explain when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_libraryDescribe the music libraryARead-only
Orientation for the whole library: size, genre and decade distribution, the user's own curated mood playlists (his personal vibe vocabulary), the Last.fm tag vocabulary available for filtering, and listening-history coverage. Call this FIRST when you need to build a playlist and do not yet know what the library contains.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, and the description adds meaningful context about the scope and content returned (size, distributions, curated playlists, tag vocabulary, history coverage). It provides useful behavioral disclosure for a read-only overview tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that begins with the core purpose, enumerates key outputs, and ends with actionable usage guidance. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter read-only orientation tool, the description fully covers the returned content and when to use it. No output schema is needed given the clear narrative enumeration of results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Tool has zero parameters, so no parameter documentation is needed. Baseline 4 is appropriate because the description fully explains what information the tool provides without needing to describe inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the tool provides an orientation for the entire music library, listing specific outputs (size, distributions, playlists, tags, history). It distinguishes itself from siblings by framing itself as the first call when library contents are unknown.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs to 'Call this FIRST' when building a playlist without prior library knowledge, giving a clear trigger condition. It does not name specific alternatives or when-not-to-use, but the context is sufficiently clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
enrich_moodsLabel the library's moodsA
Run (or check) the one-time pass that gives EVERY track a mood: energy, valence, intensity, acoustic-vs-electronic, feeling descriptors, which curated vibe it reads as, and what times of day it fits.
This is what makes mood search work across the whole library rather than only the tracks already on a playlist. The library's own metadata cannot support it — genres are a few dozen coarse buckets, and BPM/ReplayGain/MusicBrainz IDs are present on under 3% of files. Results are cached permanently, so this normally runs once and then only picks up newly-added music.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Only label this many tracks (useful for a cheap trial run). Omit for all. | |
| status_only | No | Just report coverage without starting a run. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the one-time permanent caching, the scope ('every track'), and the check-vs-run modes, plus why it cannot rely on existing metadata. However, it doesn't state the return format or authorization requirements, and the mutation is not explicitly flagged as a write, though 'cached permanently' implies persistent side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two paragraphs; the first states the core purpose and outputs, the second provides rationale and persistence behavior. Every sentence adds value, though the first sentence is long and packed with attributes, making it slightly dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema, the description explains the tool's role, prerequisites, caching, and the two modes (run/check), which covers the key behavior. It doesn't specify what a successful run returns (e.g., coverage counts), but the schema's status_only parameter hints at that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents both parameters. The description reinforces the semantics by mentioning 'check' for status_only and 'trial run' for limit, but adds no new parameter-specific details beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the action ('Run (or check)') and the resource ('one-time pass that gives EVERY track a mood'), enumerating the specific mood attributes. It distinguishes from sibling tools by explaining it enables library-wide mood search, unlike playlist-scoped capabilities.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides clear context on when to use: to enable mood search across the whole library, and explains why existing metadata is insufficient (genres are coarse, BPM/ReplayGain/MusicBrainz IDs under 3%). It doesn't explicitly name alternatives but implicitly differentiates from playlist-only operations and mentions the caching behavior for 'runs once'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_playlistGet a playlist's tracksARead-only
Full track list of one playlist, by id or name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| limit | No | ||
| playlist_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already indicates a safe read operation; the description adds the detail that the full track list is returned and that lookup can be by id or name. It does not disclose the existence of the limit parameter, which may implicitly restrict the 'full' list, nor does it describe return structure or pagination, so behavioral transparency is moderate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that immediately states the resource and selection method. It is free of fluff and front-loads the core action, achieving maximum conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only tool with no output schema, the description covers the primary use case and the id/name selection mechanism. However, the limit parameter is not mentioned, and there is no guidance on how the result set behaves (e.g., default limit, pagination), leaving a notable gap given the schema provides no parameter descriptions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It clarifies that name and playlist_id are alternative selectors, but it ignores the limit parameter entirely. Given three undocumented parameters and the need to explain all, this partial coverage is insufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves the full track list of a single playlist, with explicit selection by id or name. It distinguishes itself from siblings like list_playlists (which lists playlists) and search_tracks (which searches tracks globally), making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied: use this tool when you need a playlist's tracks and know the playlist's id or name. However, there is no explicit comparison to alternatives such as describe_library or list_playlists, nor any 'when not to use' guidance, leaving room for confusion in selecting among similar tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_vibe_profileProfile a curated mood playlistARead-only
What one of the user's own mood playlists actually consists of: top artists, genres, tags, era and tempo, when during the day he plays it, and representative tracks. Use this to ground an abstract mood request in what that word means in HIS library.
| Name | Required | Description | Default |
|---|---|---|---|
| vibe | Yes | Curated playlist name, e.g. 'golden hour'. | |
| sample | No | Representative tracks to include. Default 12. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered. The description adds value by disclosing the output composition (artists, genres, tags, etc.), which is behavioral context beyond the annotation. No contradictions found.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded, and every phrase earns its place. It efficiently conveys purpose, scope, and usage direction without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description effectively enumerates the return components, giving the agent a solid mental model of the result. It does not cover error handling or edge cases, but for a read-only profiling tool the provided information is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema fully documents 'vibe' and 'sample' with examples and defaults. The description adds no extra parameter meaning beyond what the schema provides, earning the baseline score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool profiles a user's mood playlist by listing its composition: top artists, genres, tags, era, tempo, play time, and representative tracks. It distinguishes from siblings like get_playlist by emphasizing 'mood playlist' and grounding abstract mood requests in the user's library.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a clear use case: 'Use this to ground an abstract mood request in what that word means in HIS library.' This tells the agent when to apply the tool. It does not explicitly mention alternatives or exclusions, but the context is strong enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listening_historyAnalyse listening historyARead-only
Query the ListenBrainz history: recent plays, top artists/tracks over a window, hour-of-day and weekday habits, rising/falling trends, and long-loved-but-forgotten tracks worth resurfacing. This is the only source of timestamped history — Navidrome itself keeps only a play count and a last-played time.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Window in days. Default 30. | |
| mode | Yes | Which analysis to run. | |
| limit | No | ||
| hour_of_day | No | For mode 'by_hour'. Defaults to now. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, so no destructive behavior is expected. The description adds valuable context beyond the annotation by explaining the data source limitation (Navidrome keeps only play count and last-played), which helps the agent judge the tool's unique value. It does not disclose return format, but the read-only nature and enumeration of modes reduce the need.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with zero wasted words. The first sentence lists the full scope of analyses in a compact list; the second sentence adds a crucial differentiator (only timestamped source). It is front-loaded with the main purpose and immediately useful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, moderate parameter count, and read-only annotation, the description is sufficiently complete. It explains what the tool offers, why it exists, and the key constraint (only timestamped history). The mode enumeration covers the input schema's required parameter, and the context around Navidrome's limitation completes the picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 75% (days, mode, hour_of_day described; limit has min/max). The description enriches the enum values by grouping them into meaningful categories (recent, top, habits, trends, rediscover), which helps an agent select the correct mode. It does not add detail for limit, but the schema already provides constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Query') and resource ('ListenBrainz history'), and enumerates the distinct analyses: recent plays, top artists/tracks, hour-of-day/weekday habits, trends, and rediscovery. It also differentiates from siblings by noting it is the only source of timestamped history, while Navidrome retains only play count and last-played time.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies when to use this tool: whenever timestamped listening history is needed, since it is the only source. It does not explicitly name alternatives or provide 'when-not' guidance, but the contrast with Navidrome's limited data provides strong contextual usage direction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_playlistsList playlistsARead-only
All playlists in Navidrome, including which are curated mood playlists and which are smart (self-updating).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already declares a safe read operation. The description adds value by explaining the content of the response—it differentiates curated mood playlists and smart playlists—which is helpful context beyond the annotation. However, it does not disclose details like return structure or any potential filtering or performance considerations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that efficiently communicates the tool's purpose and the key distinguishing feature of its output. There is no waste or unnecessary repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list-all tool with no parameters and no output schema, the description is mostly complete: it states the scope (all playlists) and the added value (type distinction). It could be more explicit about the return format, but given the lack of parameters and the simplicity of the operation, the description is adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is nothing to explain. The baseline for 0 params is 4, and the description does not need to add parameter information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists all playlists in Navidrome and further specifies the distinction between curated mood playlists and smart (self-updating) playlists. This goes beyond just repeating the name and distinguishes it from sibling tools like get_playlist and create_playlist.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool is for viewing all playlists, but it does not explicitly state when to use this versus get_playlist for a single playlist or other alternatives. The context 'All playlists' gives a clear scope, but no exclusions or alternative tool references are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refresh_indexRefresh the local indexA
Re-sync from Navidrome and/or ListenBrainz. The index is a cache: the library is pulled in full (~20s) and listens incrementally. Call this if the library changed and results look stale.
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | Default 'all'. | |
| full_listens | No | Re-pull the entire listen history, not just new ones. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations, but description discloses behavior well: full library pull (~20s), incremental listens, and cache semantics. It doesn't state side effects like network dependency or potential cache invalidation, but is reasonably transparent for a cache refresh.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three focused sentences: action, behavior, when-to-use. No wasted words; front-loads the verb.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, timing, and usage trigger. Missing explicit mapping of 'and/or' sources to scope, but output schema is absent and the tool is simple, so it's largely complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers 100% of parameters with descriptions. Description adds context about the pull behavior (full vs incremental) that maps to scope/full_listens, but doesn't explicitly link parameters to behavior, so marginal value beyond schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Uses specific verb 're-sync' and identifies resources (Navidrome, ListenBrainz). Clearly distinguishes from sibling tools that manage playlists or query data; this tool maintains a local cache.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit condition: 'Call this if the library changed and results look stale.' While alternatives aren't named, it clearly places this tool as the refresh mechanism for all read-oriented siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_tracksSearch tracks with full compound filteringARead-only
The main query tool, over the WHOLE library. Every filter composes: real year/date ranges, play and listen recency, inferred mood axes (energy/valence/intensity/organic), mood descriptors, curated OR inferred vibe membership, Last.fm tags, duration, time-of-day fit, plus per-artist diversity caps and personal-affinity ranking.
For mood requests prefer mood_vibes / moods / the axis ranges over vibes: vibes matches only the ~3,800 tracks actually on a curated playlist, while the mood fields cover all 9,000+.
| Name | Required | Description | Default |
|---|---|---|---|
| seed | No | Makes 'random'/'affinity' reproducible. | |
| sort | No | Default 'affinity': a personal-fit blend of listens, plays, curated membership and recency. | |
| tags | No | Last.fm tags, e.g. ['shoegaze','melancholy']. | |
| limit | No | ||
| moods | No | Inferred feeling descriptors, e.g. ['hazy','wistful','anthemic']. Any-of, substring. | |
| query | No | Free text matched against title, artist, album and tags. | |
| vibes | No | Restrict to tracks on these curated playlists, e.g. ['golden hour','textured']. | |
| albums | No | ||
| genres | No | Any-of match on the library's own genres. | |
| offset | No | ||
| artists | No | Only these artists (substring match). | |
| bpm_max | No | ||
| bpm_min | No | ||
| decades | No | e.g. ['1990s','2000s']. | |
| starred | No | ||
| year_max | No | ||
| year_min | No | ||
| fits_time | No | One of: early morning, morning, midday, afternoon, golden hour, evening, late night. | |
| tags_mode | No | Default 'any'. | |
| energy_max | No | ||
| energy_min | No | Inferred mood axis 0-100: sleepy/still -> frantic. | |
| mood_vibes | No | Tracks that READ AS one of his curated vibes, whether or not they are filed on that playlist. Matches hand-curated membership, the mood pass, and tag-similarity predictions — so it reaches the whole library, not just the ~3,800 playlisted tracks. Prefer this over `vibes` for any mood request. | |
| day_of_week | No | 0 = Sunday. | |
| hour_of_day | No | Only tracks he has actually listened to at this local hour. | |
| organic_max | No | ||
| organic_min | No | 0-100: fully electronic -> fully acoustic. | |
| valence_max | No | ||
| valence_min | No | 0-100: bleak/melancholy -> bright/joyful. | |
| exclude_tags | No | ||
| never_played | No | ||
| exclude_moods | No | ||
| exclude_vibes | No | ||
| intensity_max | No | ||
| intensity_min | No | 0-100: gentle -> heavy/aggressive. | |
| max_per_album | No | ||
| exclude_genres | No | ||
| max_per_artist | No | Cap tracks per artist. Use 1-2 for playlists. | |
| play_count_max | No | ||
| play_count_min | No | ||
| released_after | No | ISO date, matched against the release date. | |
| exclude_artists | No | ||
| include_missing | No | Include tracks whose file is missing. Default false. | |
| released_before | No | ||
| duration_max_sec | No | ||
| duration_min_sec | No | ||
| listen_count_max | No | ||
| listen_count_min | No | Lifetime ListenBrainz listens. | |
| added_before_days | No | Added at least N days ago. | |
| added_within_days | No | Added to the library in the last N days. | |
| exclude_track_ids | No | ||
| played_within_days | No | ||
| listened_within_days | No | ||
| not_played_within_days | No | Exclude anything played in the last N days. | |
| exclude_recent_daylists | No | Exclude everything used by the last N daylist runs. Use ~6 for hourly rotation. | |
| not_listened_within_days | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true, the safety profile is already known. The description adds valuable behavioral context: the whole-library scope, that every filter composes, and the critical distinction that 'vibes' only matches ~3,800 curated tracks while mood fields cover all 9,000+. It also explains the mood_vibes prediction logic. This goes beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but efficient. Two well-structured sentences cover the full scope and a crucial usage warning. The first sentence enumerates filter families without fluff; the second directly addresses a common misuse. It earns its length given the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite lacking an output schema and having 55 parameters, the description provides a strong conceptual overview and key operational details (mood vs vibes, whole-library scope, compound filtering). It doesn't mention pagination or return structure, but those are likely implicit given the filter list. It is adequate for an agent to select and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 47%, so the description must compensate. It groups all 55 parameters into meaningful categories (year/date ranges, recency, mood axes, descriptors, vibe membership, tags, duration, time-of-day, diversity caps, affinity ranking). It adds semantic depth by explaining how mood-related filters work differently from vibes, and clarifies max_per_artist usage. This is more than the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it is 'The main query tool, over the WHOLE library' with a comprehensive list of filter categories. It distinguishes itself from siblings by emphasizing its primary search role and explicitly contrasting 'vibes' vs 'mood_vibes' to guide usage. This is a specific verb+resource+scope with clear differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit guidance for mood requests: 'prefer mood_vibes / moods / the axis ranges over vibes' and explains why, which functions as a when-to-use within the tool. It also establishes itself as the main query tool. However, it does not mention when to use sibling tools like similar_tracks or listening_history, so it lacks full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
similar_tracksFind similar tracks in the libraryARead-only
Expand from seed tracks or artists. Combines Navidrome's agent-backed similarity (Last.fm/Deezer/ListenBrainz) with co-occurrence in the user's own curated playlists — tracks he himself repeatedly files alongside the seed. Results are restricted to what is actually in the library.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| artists | No | Seed artist names. | |
| track_ids | No | Seed track ids. | |
| exclude_seed_artists | No | Drop the seeds' own artists. Default true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already signals a safe read, and the description adds useful behavioral context by revealing the underlying similarity sources (Navidrome agents, Last.fm/Deezer/ListenBrainz, and co-occurrence in the user's own playlists) and the library restriction. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three concise sentences, each adding value. The description front-loads the core action and then provides necessary context on sources and constraints without waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has no output schema, and the description doesn't specify the response structure (e.g., what fields are returned for each track). It clarifies that results are library-only but leaves the return format implicit, which is a moderate gap for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 75%, so the schema handles most parameter meaning. The description reinforces that 'track_ids' and 'artists' serve as seeds, but it doesn't clarify the undocumented 'limit' parameter or add meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Expand') and identifies the resource ('seed tracks or artists') with clear scope ('Results are restricted to what is actually in the library'). It distinguishes this from siblings like search_tracks by explaining its similarity/co-occurrence mechanism.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description conveys clear context: use this tool when you have seed tracks/artists and want library-restricted recommendations. It doesn't explicitly mention when not to use it or name alternatives, but the context is clear enough for an agent to decide.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_playlistUpdate a playlistA
Rename a playlist, change its description, and/or replace or append its tracks. Replacing is the normal way to refresh a rolling playlist in place.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | How to apply track_ids. Default 'replace'. | |
| name | No | Existing playlist name, if not passing an id. | |
| public | No | ||
| comment | No | ||
| new_name | No | ||
| track_ids | No | ||
| playlist_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the two modes (replace vs append) and their intended use, but it does not describe side effects such as whether unspecified fields are preserved, permissions required, or what happens with missing track_ids. This is a moderate level of transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no fluff. It front-loads the actions in the first sentence and provides a rationale in the second, making it efficient and easy to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 7 optional parameters, no output schema, and no annotations, the description is not fully complete. It covers the primary use cases but omits details like the relationship between name and playlist_id, the effect of public, and whether at least one field must be provided. However, the core behavior is clear enough for many agents.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 29%, so the description must add meaning for the other parameters. It does explain the roles of mode, track_ids, new_name, and comment through the action phrases, but playlist_id and public are left undocumented. The description partially compensates for the schema gaps but not fully.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function with specific verbs: 'Rename a playlist, change its description, and/or replace or append its tracks.' It also provides a use case ('refresh a rolling playlist in place'), which distinguishes it from sibling tools like create_playlist or delete_playlist.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear context for when to use replace mode ('Replacing is the normal way to refresh a rolling playlist in place'), but it does not explicitly compare this tool to alternatives or state when not to use it. Sibling differentiation is implied by the purpose, but no direct exclusions or alternative tool references are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
15 tool updates
v1.0.0- First observed
commit_daylist - First observed
create_playlist - First observed
create_smart_playlist - First observed
daylist_context - First observed
delete_playlist - First observed
describe_library - First observed
enrich_moods - First observed
get_playlist - First observed
get_vibe_profile - First observed
list_playlists - First observed
listening_history - First observed
refresh_index - First observed
search_tracks - First observed
similar_tracks - First observed
update_playlist
TDQS
Most tools have distinct purposes, but create_playlist vs create_smart_playlist and update_playlist vs commit_daylist could cause confusion. Descriptions help clarify boundaries, though an agent might occasionally select the wrong one.
The majority follow a verb_noun pattern (list_, delete_, create_, update_), but a few depart with noun phrases like similar_tracks, listening_history, and daylist_context. The names are still readable and predictable, with no chaotic mixes.
15 tools is at the upper edge of the ideal range, but each tool addresses a distinct facet of the library/playlist domain. The count feels justified and not bloated.
Playlist CRUD is well covered, including smart playlists. Minor gaps exist: no direct way to edit smart playlist rules, and no standalone track detail tool. However, search_tracks and update_playlist cover most needs.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
The media memory layer for AI agents and their humans. Your AI client gets 29 tools to search your collection, add items, update ratings, preview music, and find patterns across everything you've read, watched, and listened to.
Audio features + harmonic set-building for tracks by name/ISRC. Spotify audio-features replacement.
Last.fm artist/album/track metadata (free API key required)
Search MusicBrainz artists, releases, works, labels; resolve ISRC/ISWC/barcode; fetch cover art.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceGenerates personalized music playlists based on mood analysis using AI sentiment detection and emoji understanding. Integrates with Last.fm API to create playlists with multi-language support and provides streaming links for Spotify, Apple Music, and YouTube.1Apache 2.0
- AlicenseNot gradedqualityAmaintenanceAnalyze listening patterns, create custom playlists, discover missing albums, validate radio streams, and provide personalized recommendations through natural language.28585AGPL 3.0
- AlicenseNot gradedqualityDmaintenanceGenerates .m3u playlists on the user's PC based on their current mood or theme, using metadata from local music files.5GPL 3.0
- AlicenseCqualityCmaintenanceSyncs YouTube Music liked songs, analyzes them for DJ metadata like BPM and key, and enables creating playlists from previews.10MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/312-dev/navidrome-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server