github TypeScript re-analysis due

Blakeem/Navidrome-MCP

github

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 Navidrome library using natural language.

maintainer
Blakeem
license
AGPL-3.0
first seen
2026-06-12
last seen
2026-08-26
releases · 30d
0
short id

Drift inferred · capture-to-capture

tool count over time

06-12 22:01 08-12 20:22 now
60t
60t
60t
capabilities 60 tools
transport stdio · streamable-http · http counts 60 tools · 0 res · 0 prompts permission surface via README inference

tools

  • add_tracks_to_playlist

    Add songs, albums, artist discographies, or specific discs in one operation

  • clear_saved_queue

    Clear the Navidrome saved queue

  • click_station

    Register a play click for popularity metrics

  • create_playlist

    Create a new playlist

  • create_radio_station

    Create one or more stations (JSON array, optional validateBeforeAdd)

  • delete_playlist

    Delete a playlist

  • delete_radio_station

    Delete a station

  • discover_radio_stations

    Find stations globally via Radio Browser

  • get_album

    Detailed album metadata by ID

  • get_album_info

    Album detail: tracklist with durations, year and type, genres, wiki summary, popularity, and library membership. Works for albums you don't own

  • get_artist

    Detailed artist metadata by ID

  • get_artist_albums

    Full discography with release types and years (MusicBrainz), genres and popularity (Last.fm), and an in-library flag per album. Answers "what albums by X am I missing?"

  • get_artist_info

    Artist biography and tags

  • get_filter_options

    Discover available filter values for search operations

  • get_lyrics

    Lyrics for one song, by Navidrome song ID or by LRCLIB record ID. Time-synced (LRC) lines when the source carries them

  • get_playlist

    Get playlist metadata by ID

  • get_playlist_tracks

    Get playlist contents (JSON or M3U)

  • get_radio_filters

    Available filter values (tags, countries, languages, codecs)

  • get_radio_station

    Detailed info for a station by ID

  • get_saved_queue

    Read the Navidrome saved queue (web UI sync)

  • get_similar_artists

    Find artists similar to a given artist

  • get_similar_tracks

    Find tracks similar to a given track

  • get_song

    Detailed song metadata by ID

  • get_song_playlists

    List all playlists containing a given song

  • get_station_by_uuid

    Detailed Radio Browser station info

  • get_tag_distribution

    Tag usage counts across the library

  • get_top_tracks_by_artist

    Top tracks for an artist

  • get_trending_music

    Trending artists, tracks, and tags from Last.fm charts

  • get_user_details

    User profile, available libraries, and active-library status

  • list_most_played

    Most-played songs, albums, or artists

  • list_playlists

    View all accessible playlists

  • list_radio_stations

    List all saved Navidrome radio stations

  • list_recently_played

    Recent listening activity with optional time-range filter

  • list_starred_items

    View starred songs, albums, or artists

  • list_top_rated

    View highest-rated items

  • pause

    Pause playback (position preserved)

  • play_albums

    Play one or many albums. mode plus shuffle: 'none' \

  • play_albums_search

    Search and play albums in one step. Accepts all search_albums filters plus mode and shuffle

  • play_playlist

    Load a playlist's tracks into the queue by playlistId. Supports mode and shuffle

  • play_radio_station

    Play a saved Navidrome radio station. Replaces the queue, since radio cannot mix with songs or albums

  • play_songs

    Play one or many songs. mode: 'replace' \

  • play_songs_search

    Search and play songs in one step. Accepts all search_songs filters plus mode and shuffle

  • remove_tracks_from_playlist

    Remove tracks by position

  • reorder_playlist_track

    Move a track to a new position

  • resume

    Resume playback

  • save_queue

    Save a queue to Navidrome for web UI sync

  • search_albums

    Search albums with advanced filters and sorting

  • search_all

    Search across artists, albums, and songs with filters and sorting

  • search_artists

    Search artists with advanced filters and sorting

  • search_by_tags

    Search by tag values (genre, releasetype, media, etc.)

  • search_lyrics

    Search LRCLIB by title and artist. Returns candidate records plus the matching library song. Requires the LRCLIB provider, set in the settings page

  • search_songs

    Search songs with advanced filters and sorting

  • set_active_libraries

    Set which libraries are active for all search/list operations

  • set_rating

    Set a 0-5 star rating

  • star_item

    Star a song, album, or artist

  • test_connection

    Verify Navidrome connectivity and report feature/tool availability

  • unstar_item

    Remove a star

  • update_playlist

    Update name, description, or visibility

  • validate_radio_stream

    Test an http(s) stream URL for accessibility and audio content

  • vote_station

    Vote for a station

skills & danger signals github-tarball
prompt-surface shipped agent-instruction files + hidden-content / dangerous-code findings — quoted from the analyzed source

analyzed commit 8ab5e86 · analyzer v33 · 3w ago

skills & prompt files 2

danger signals1

code evidence vv2.1.0 · github-tarball
evidence-backed findings quoted directly from the published source artifact — not inferred

code files: 223

filesystem 18

  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/scripts/build-webui.mjs :12 import { cpSync, existsSync, mkdirSync } from 'node:fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/scripts/make-launcher.mjs :51 } from 'node:fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/scripts/playback-poc.ts :27 import { existsSync } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/config-app/server.ts :20 import { existsSync } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/config/seed.ts :19 import { readFileSync } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/config/store.ts :29 } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/services/playback/mpv-process.ts :20 import { accessSync, constants } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/services/playback/playback-engine.ts :20 import { existsSync } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/utils/version.ts :5 import { readFileSync } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/web/main.ts :34 import { appendFileSync, mkdirSync } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/web/spawn.ts :20 import { existsSync } from 'node:fs';
  • fs Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/static-files.ts :19 import { existsSync } from 'node:fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/integration/coordination/helpers.ts :16 import { existsSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/meta/dead-code-detection.test.ts :9 import { readFileSync, readdirSync, existsSync } from 'fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config-app/settings-server.test.ts :11 import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config/config-resolve.test.ts :7 import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config/seed.test.ts :11 import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
  • fs (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config/store.test.ts :6 import { mkdtempSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';

shell / exec 10

  • shell (weak) Blakeem-Navidrome-MCP-8ab5e86/scripts/make-launcher.mjs :42 import { spawnSync } from 'node:child_process';
  • shell (weak) Blakeem-Navidrome-MCP-8ab5e86/scripts/playback-poc.ts :25 import { spawn, type ChildProcess } from 'node:child_process';
  • shell Blakeem-Navidrome-MCP-8ab5e86/src/services/playback/mpv-process.ts :19 import { spawn, execSync, type ChildProcess } from 'node:child_process';
  • shell Blakeem-Navidrome-MCP-8ab5e86/src/services/playback/playback-engine.ts :19 import type { ChildProcess } from 'node:child_process';
  • shell Blakeem-Navidrome-MCP-8ab5e86/src/utils/open-browser.ts :19 import { spawn } from 'node:child_process';
  • shell Blakeem-Navidrome-MCP-8ab5e86/src/web/spawn.ts :19 import { spawn } from 'node:child_process';
  • shell (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/integration/coordination/fixtures/ipc-parent.mjs :8 import { spawn } from 'node:child_process';
  • shell (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/integration/coordination/helpers.ts :15 import { type ChildProcess, spawn } from 'node:child_process';
  • shell (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/meta/dead-code-detection.test.ts :11 import { execSync } from 'child_process';
  • shell (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/services/playback/mpv-process.test.ts :94 const actual = await vi.importActual<typeof import('node:child_process')>('node:child_process');

network 45

  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/scripts/playback-poc.ts :26 import { createConnection, type Socket } from 'node:net';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/client/navidrome-client.ts :279 // to GET in fetch().
  • net Blakeem-Navidrome-MCP-8ab5e86/src/config-app/public/app.js :188 const res = await fetch(path, {
  • net Blakeem-Navidrome-MCP-8ab5e86/src/config-app/routes.ts :19 import type { IncomingMessage, ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/config-app/server.ts :19 import { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/services/filter-cache-manager.ts :80 // fetch (the whole point of cache-disabled mode is freshness).
  • net Blakeem-Navidrome-MCP-8ab5e86/src/services/playback/mpv-ipc.ts :19 import { createConnection, type Socket } from 'node:net';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/services/playback/playback-engine.ts :22 import { createConnection } from 'node:net';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/tools/radio.ts :501 * an uncached fetch (the post-create id-resolution path).
  • net Blakeem-Navidrome-MCP-8ab5e86/src/tools/user-preferences.ts :219 // `minRating` is applied client-side AFTER the fetch (Navidrome's REST list
  • net Blakeem-Navidrome-MCP-8ab5e86/src/transport/http.ts :19 import { createServer, type Server as HttpServer, type IncomingMessage, type ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/utils/fetch-with-timeout.ts :162 * fetch() wrapper that:
  • net Blakeem-Navidrome-MCP-8ab5e86/src/utils/network-safety.ts :20 import { Agent, buildConnector, fetch as undiciFetch } from 'undici';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/web/acquire.ts :19 import { get as httpGet, type Server } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/web/main.ts :35 import type { Server } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/broadcaster.ts :19 import type { ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/http-helpers.ts :19 import type { IncomingMessage, ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/loopback.ts :19 import type { IncomingMessage } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/public/app.js :148 const res = await fetch(path, opts);
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/controls.ts :19 import type { IncomingMessage, ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/cover.ts :19 import type { ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/events.ts :19 import type { ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/health.ts :19 import type { IncomingMessage, ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/network-info.ts :19 import type { ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/player.ts :19 import type { IncomingMessage, ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/playlists.ts :19 import type { IncomingMessage, ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/snapshot.ts :19 import type { ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/routes/static-files.ts :21 import type { ServerResponse } from 'node:http';
  • net Blakeem-Navidrome-MCP-8ab5e86/src/webui/server.ts :24 } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/integration/coordination/helpers.ts :17 import { createConnection } from 'node:net';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/integration/coordination/lifecycle.test.ts :54 await fetch(`http://127.0.0.1:${port}/api/shutdown`, { method: 'POST' }).catch(() => undefined);
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/integration/coordination/port-as-lock.test.ts :10 import { createServer as createHttpServer } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/client/auth-manager.test.ts :67 it('5 concurrent authenticate() calls trigger only 1 fetch (single-flight)', async () => {
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config-app/settings-server.test.ts :52 fetch(`${base}/api/settings`, {
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/tools/radio-discovery.test.ts :278 // Only one fetch (for codecs), not four
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/tools/radio-validation.test.ts :619 // Only one fetch (HEAD) — audio sampling skipped because headers are conclusive.
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/tools/search-artist-filters.test.ts :7 * /api/artist sub-fetch (Navidrome silently ignores them; sending them is a
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/tools/search.test.ts :403 it.skipIf(shouldSkipLiveTests())('searchAll offset paginates each sub-fetch (no longer hardcoded _start=0)', async () => {
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/transport/http-transport.test.ts :18 import { request as httpRequest } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/utils/network-safety.test.ts :7 import { createServer, type Server } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/web/acquire.test.ts :10 import type { Server } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/webui/broadcaster.test.ts :11 import type { ServerResponse } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/webui/http-helpers.test.ts :9 import type { IncomingMessage } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/webui/routes.test.ts :21 import type { IncomingMessage, ServerResponse } from 'node:http';
  • net (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/webui/static-files.test.ts :12 import type { ServerResponse } from 'node:http';

secrets 5

  • secrets (weak) Blakeem-Navidrome-MCP-8ab5e86/scripts/ci-test-env.js :19 process.env.NAVIDROME_PASSWORD = 'ci-dummy-password';
  • secrets (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/helpers/env-detection.ts :30 process.env.NAVIDROME_PASSWORD
  • secrets (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config-app/settings-server.test.ts :99 process.env['NAVIDROME_PASSWORD'] = 'firstrunpass';
  • secrets (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config/config-resolve.test.ts :220 process.env['NAVIDROME_PASSWORD'] = 'env-pass';
  • secrets (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/config/seed.test.ts :57 process.env['NAVIDROME_PASSWORD'] = 'envpass';

install hooks 1

  • prepare Blakeem-Navidrome-MCP-8ab5e86/package.json :25 pnpm build

declared dependencies 20

  • @modelcontextprotocol/sdk@^1.17.4
  • file-type@^19.5.0
  • undici@^7.28.0
  • zod@^4.1.4
  • @eslint-community/eslint-plugin-eslint-comments@^4.7.2
  • @eslint/js@^9.34.0
  • @types/node@^24.3.0
  • @typescript-eslint/eslint-plugin@^8.41.0
  • @typescript-eslint/parser@^8.41.0
  • @vitest/coverage-v8@^3.2.4
  • @vitest/ui@^3.2.4
  • eslint@^9.34.0
  • eslint-config-prettier@^9.1.0
  • eslint-plugin-unicorn@^64.0.0
  • nodemon@^3.1.10
  • prettier@^3.6.2
  • ts-unused-exports@^11.0.1
  • tsx@^4.20.5
  • typescript@^5.9.2
  • vitest@^3.2.4

perm:untrusted 1

  • untrusted (weak) Blakeem-Navidrome-MCP-8ab5e86/tests/integration/coordination/lifecycle.test.ts :67 const list = (await (await fetch(`http://127.0.0.1:${port}/api/playlists`)).json()) as {

transport_posture 2

  • binds all interfaces (0.0.0.0) Blakeem-Navidrome-MCP-8ab5e86/tests/unit/transport/http-transport.test.ts :260 host: '0.0.0.0',
  • network-listening, binds all interfaces, no auth detected Blakeem-Navidrome-MCP-8ab5e86/tests/unit/webui/routes.test.ts :147 handleHealth(fakeReq(LAN_PEER), cap.res, configWith({ expose: false, host: '0.0.0.0' }));