navidrome-mcp 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/README.md +161 -67
  2. package/assets/navidrome-player.icns +0 -0
  3. package/assets/navidrome-player.ico +0 -0
  4. package/assets/navidrome-player.png +0 -0
  5. package/dist/bootstrap.d.ts +43 -0
  6. package/dist/bootstrap.d.ts.map +1 -0
  7. package/dist/bootstrap.js +52 -0
  8. package/dist/bootstrap.js.map +1 -0
  9. package/dist/client/auth-manager.d.ts.map +1 -1
  10. package/dist/client/auth-manager.js +14 -3
  11. package/dist/client/auth-manager.js.map +1 -1
  12. package/dist/client/navidrome-client.d.ts.map +1 -1
  13. package/dist/client/navidrome-client.js +34 -5
  14. package/dist/client/navidrome-client.js.map +1 -1
  15. package/dist/config/map-config.d.ts +29 -0
  16. package/dist/config/map-config.d.ts.map +1 -0
  17. package/dist/config/map-config.js +97 -0
  18. package/dist/config/map-config.js.map +1 -0
  19. package/dist/config/schema.d.ts +65 -0
  20. package/dist/config/schema.d.ts.map +1 -0
  21. package/dist/config/schema.js +95 -0
  22. package/dist/config/schema.js.map +1 -0
  23. package/dist/config/seed.d.ts +58 -0
  24. package/dist/config/seed.d.ts.map +1 -0
  25. package/dist/config/seed.js +190 -0
  26. package/dist/config/seed.js.map +1 -0
  27. package/dist/config/store-path.d.ts +32 -0
  28. package/dist/config/store-path.d.ts.map +1 -0
  29. package/dist/config/store-path.js +57 -0
  30. package/dist/config/store-path.js.map +1 -0
  31. package/dist/config/store.d.ts +84 -0
  32. package/dist/config/store.d.ts.map +1 -0
  33. package/dist/config/store.js +141 -0
  34. package/dist/config/store.js.map +1 -0
  35. package/dist/config-app/degraded-tools.d.ts +27 -0
  36. package/dist/config-app/degraded-tools.d.ts.map +1 -0
  37. package/dist/config-app/degraded-tools.js +61 -0
  38. package/dist/config-app/degraded-tools.js.map +1 -0
  39. package/dist/config-app/main.d.ts +20 -0
  40. package/dist/config-app/main.d.ts.map +1 -0
  41. package/dist/config-app/main.js +38 -0
  42. package/dist/config-app/main.js.map +1 -0
  43. package/dist/config-app/public/app.js +224 -0
  44. package/dist/config-app/public/index.html +137 -0
  45. package/dist/config-app/public/styles.css +120 -0
  46. package/dist/config-app/routes.d.ts +28 -0
  47. package/dist/config-app/routes.d.ts.map +1 -0
  48. package/dist/config-app/routes.js +183 -0
  49. package/dist/config-app/routes.js.map +1 -0
  50. package/dist/config-app/server.d.ts +48 -0
  51. package/dist/config-app/server.d.ts.map +1 -0
  52. package/dist/config-app/server.js +155 -0
  53. package/dist/config-app/server.js.map +1 -0
  54. package/dist/config.d.ts +36 -35
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +47 -204
  57. package/dist/config.js.map +1 -1
  58. package/dist/constants/defaults.d.ts +20 -1
  59. package/dist/constants/defaults.d.ts.map +1 -1
  60. package/dist/constants/defaults.js +20 -1
  61. package/dist/constants/defaults.js.map +1 -1
  62. package/dist/constants/timeouts.d.ts +19 -4
  63. package/dist/constants/timeouts.d.ts.map +1 -1
  64. package/dist/constants/timeouts.js +19 -4
  65. package/dist/constants/timeouts.js.map +1 -1
  66. package/dist/index.js +103 -33
  67. package/dist/index.js.map +1 -1
  68. package/dist/resources/index.js +3 -3
  69. package/dist/resources/index.js.map +1 -1
  70. package/dist/schemas/common.d.ts +10 -7
  71. package/dist/schemas/common.d.ts.map +1 -1
  72. package/dist/schemas/common.js +35 -20
  73. package/dist/schemas/common.js.map +1 -1
  74. package/dist/schemas/pagination.d.ts +5 -0
  75. package/dist/schemas/pagination.d.ts.map +1 -1
  76. package/dist/schemas/pagination.js +22 -10
  77. package/dist/schemas/pagination.js.map +1 -1
  78. package/dist/schemas/validation.d.ts +15 -3
  79. package/dist/schemas/validation.d.ts.map +1 -1
  80. package/dist/schemas/validation.js +43 -12
  81. package/dist/schemas/validation.js.map +1 -1
  82. package/dist/services/filter-cache-manager.d.ts +2 -1
  83. package/dist/services/filter-cache-manager.d.ts.map +1 -1
  84. package/dist/services/filter-cache-manager.js +35 -25
  85. package/dist/services/filter-cache-manager.js.map +1 -1
  86. package/dist/services/library-manager.d.ts +1 -0
  87. package/dist/services/library-manager.d.ts.map +1 -1
  88. package/dist/services/library-manager.js +50 -29
  89. package/dist/services/library-manager.js.map +1 -1
  90. package/dist/services/playback/mpv-process.d.ts +11 -0
  91. package/dist/services/playback/mpv-process.d.ts.map +1 -1
  92. package/dist/services/playback/mpv-process.js +28 -2
  93. package/dist/services/playback/mpv-process.js.map +1 -1
  94. package/dist/services/playback/playback-engine.d.ts +59 -19
  95. package/dist/services/playback/playback-engine.d.ts.map +1 -1
  96. package/dist/services/playback/playback-engine.js +180 -36
  97. package/dist/services/playback/playback-engine.js.map +1 -1
  98. package/dist/services/playback/scrobble-tracker.d.ts +20 -1
  99. package/dist/services/playback/scrobble-tracker.d.ts.map +1 -1
  100. package/dist/services/playback/scrobble-tracker.js +80 -4
  101. package/dist/services/playback/scrobble-tracker.js.map +1 -1
  102. package/dist/tools/handlers/playback-handlers.d.ts.map +1 -1
  103. package/dist/tools/handlers/playback-handlers.js +54 -16
  104. package/dist/tools/handlers/playback-handlers.js.map +1 -1
  105. package/dist/tools/handlers/playlist-handlers.d.ts.map +1 -1
  106. package/dist/tools/handlers/playlist-handlers.js +20 -10
  107. package/dist/tools/handlers/playlist-handlers.js.map +1 -1
  108. package/dist/tools/handlers/queue-handlers.d.ts.map +1 -1
  109. package/dist/tools/handlers/queue-handlers.js +10 -0
  110. package/dist/tools/handlers/queue-handlers.js.map +1 -1
  111. package/dist/tools/handlers/radio-handlers.d.ts.map +1 -1
  112. package/dist/tools/handlers/radio-handlers.js +26 -9
  113. package/dist/tools/handlers/radio-handlers.js.map +1 -1
  114. package/dist/tools/handlers/registry.d.ts.map +1 -1
  115. package/dist/tools/handlers/registry.js +4 -15
  116. package/dist/tools/handlers/registry.js.map +1 -1
  117. package/dist/tools/handlers/search-handlers.d.ts.map +1 -1
  118. package/dist/tools/handlers/search-handlers.js +20 -0
  119. package/dist/tools/handlers/search-handlers.js.map +1 -1
  120. package/dist/tools/handlers/tag-handlers.js +1 -1
  121. package/dist/tools/handlers/tag-handlers.js.map +1 -1
  122. package/dist/tools/handlers/user-preferences-handlers.d.ts.map +1 -1
  123. package/dist/tools/handlers/user-preferences-handlers.js +14 -9
  124. package/dist/tools/handlers/user-preferences-handlers.js.map +1 -1
  125. package/dist/tools/lastfm-discovery.d.ts.map +1 -1
  126. package/dist/tools/lastfm-discovery.js +223 -158
  127. package/dist/tools/lastfm-discovery.js.map +1 -1
  128. package/dist/tools/library.d.ts.map +1 -1
  129. package/dist/tools/library.js +18 -21
  130. package/dist/tools/library.js.map +1 -1
  131. package/dist/tools/listening-history.d.ts.map +1 -1
  132. package/dist/tools/listening-history.js +112 -80
  133. package/dist/tools/listening-history.js.map +1 -1
  134. package/dist/tools/lyrics.d.ts.map +1 -1
  135. package/dist/tools/lyrics.js +35 -39
  136. package/dist/tools/lyrics.js.map +1 -1
  137. package/dist/tools/media-library.d.ts.map +1 -1
  138. package/dist/tools/media-library.js +14 -10
  139. package/dist/tools/media-library.js.map +1 -1
  140. package/dist/tools/playback.d.ts +38 -14
  141. package/dist/tools/playback.d.ts.map +1 -1
  142. package/dist/tools/playback.js +162 -21
  143. package/dist/tools/playback.js.map +1 -1
  144. package/dist/tools/playlist-management/playlist-crud.d.ts.map +1 -1
  145. package/dist/tools/playlist-management/playlist-crud.js +118 -24
  146. package/dist/tools/playlist-management/playlist-crud.js.map +1 -1
  147. package/dist/tools/playlist-management/playlist-export.d.ts.map +1 -1
  148. package/dist/tools/playlist-management/playlist-export.js +23 -10
  149. package/dist/tools/playlist-management/playlist-export.js.map +1 -1
  150. package/dist/tools/playlist-management/track-management.d.ts.map +1 -1
  151. package/dist/tools/playlist-management/track-management.js +24 -11
  152. package/dist/tools/playlist-management/track-management.js.map +1 -1
  153. package/dist/tools/queue-management.d.ts.map +1 -1
  154. package/dist/tools/queue-management.js +80 -64
  155. package/dist/tools/queue-management.js.map +1 -1
  156. package/dist/tools/radio-discovery.d.ts.map +1 -1
  157. package/dist/tools/radio-discovery.js +137 -68
  158. package/dist/tools/radio-discovery.js.map +1 -1
  159. package/dist/tools/radio-validation/index.d.ts +0 -6
  160. package/dist/tools/radio-validation/index.d.ts.map +1 -1
  161. package/dist/tools/radio-validation/index.js +6 -5
  162. package/dist/tools/radio-validation/index.js.map +1 -1
  163. package/dist/tools/radio-validation/network-validator.d.ts +2 -1
  164. package/dist/tools/radio-validation/network-validator.d.ts.map +1 -1
  165. package/dist/tools/radio-validation/network-validator.js +101 -75
  166. package/dist/tools/radio-validation/network-validator.js.map +1 -1
  167. package/dist/tools/radio-validation/recommendation-engine.d.ts.map +1 -1
  168. package/dist/tools/radio-validation/recommendation-engine.js +9 -6
  169. package/dist/tools/radio-validation/recommendation-engine.js.map +1 -1
  170. package/dist/tools/radio-validation/stream-detector.d.ts +2 -3
  171. package/dist/tools/radio-validation/stream-detector.d.ts.map +1 -1
  172. package/dist/tools/radio-validation/stream-detector.js +13 -7
  173. package/dist/tools/radio-validation/stream-detector.js.map +1 -1
  174. package/dist/tools/radio-validation/validation-core.d.ts.map +1 -1
  175. package/dist/tools/radio-validation/validation-core.js +46 -20
  176. package/dist/tools/radio-validation/validation-core.js.map +1 -1
  177. package/dist/tools/radio.d.ts.map +1 -1
  178. package/dist/tools/radio.js +199 -169
  179. package/dist/tools/radio.js.map +1 -1
  180. package/dist/tools/search/filter-resolver.d.ts +13 -0
  181. package/dist/tools/search/filter-resolver.d.ts.map +1 -1
  182. package/dist/tools/search/filter-resolver.js +65 -3
  183. package/dist/tools/search/filter-resolver.js.map +1 -1
  184. package/dist/tools/search/parallel-searcher.js +3 -3
  185. package/dist/tools/search/parallel-searcher.js.map +1 -1
  186. package/dist/tools/search/result-aggregator.d.ts +28 -3
  187. package/dist/tools/search/result-aggregator.d.ts.map +1 -1
  188. package/dist/tools/search/result-aggregator.js +44 -17
  189. package/dist/tools/search/result-aggregator.js.map +1 -1
  190. package/dist/tools/search/search-orchestrator.d.ts +2 -1
  191. package/dist/tools/search/search-orchestrator.d.ts.map +1 -1
  192. package/dist/tools/search/search-orchestrator.js +5 -5
  193. package/dist/tools/search/search-orchestrator.js.map +1 -1
  194. package/dist/tools/tags.d.ts.map +1 -1
  195. package/dist/tools/tags.js +38 -13
  196. package/dist/tools/tags.js.map +1 -1
  197. package/dist/tools/test.js +3 -3
  198. package/dist/tools/test.js.map +1 -1
  199. package/dist/tools/user-preferences.d.ts +24 -0
  200. package/dist/tools/user-preferences.d.ts.map +1 -1
  201. package/dist/tools/user-preferences.js +200 -126
  202. package/dist/tools/user-preferences.js.map +1 -1
  203. package/dist/transformers/album-transformer.d.ts +6 -2
  204. package/dist/transformers/album-transformer.d.ts.map +1 -1
  205. package/dist/transformers/album-transformer.js +44 -25
  206. package/dist/transformers/album-transformer.js.map +1 -1
  207. package/dist/transformers/artist-transformer.d.ts +6 -2
  208. package/dist/transformers/artist-transformer.d.ts.map +1 -1
  209. package/dist/transformers/artist-transformer.js +39 -20
  210. package/dist/transformers/artist-transformer.js.map +1 -1
  211. package/dist/transformers/playlist-transformer.d.ts.map +1 -1
  212. package/dist/transformers/playlist-transformer.js +12 -6
  213. package/dist/transformers/playlist-transformer.js.map +1 -1
  214. package/dist/transformers/shared-transformers.d.ts +27 -0
  215. package/dist/transformers/shared-transformers.d.ts.map +1 -1
  216. package/dist/transformers/shared-transformers.js +31 -7
  217. package/dist/transformers/shared-transformers.js.map +1 -1
  218. package/dist/transformers/song-transformer.d.ts +7 -2
  219. package/dist/transformers/song-transformer.d.ts.map +1 -1
  220. package/dist/transformers/song-transformer.js +55 -25
  221. package/dist/transformers/song-transformer.js.map +1 -1
  222. package/dist/types/core.d.ts +7 -2
  223. package/dist/types/core.d.ts.map +1 -1
  224. package/dist/types/playlists.d.ts +7 -5
  225. package/dist/types/playlists.d.ts.map +1 -1
  226. package/dist/types/tags.d.ts +4 -4
  227. package/dist/types/tags.d.ts.map +1 -1
  228. package/dist/utils/cache.d.ts.map +1 -1
  229. package/dist/utils/cache.js +1 -3
  230. package/dist/utils/cache.js.map +1 -1
  231. package/dist/utils/error-formatter.js +3 -3
  232. package/dist/utils/error-formatter.js.map +1 -1
  233. package/dist/utils/fetch-with-timeout.js +1 -1
  234. package/dist/utils/fetch-with-timeout.js.map +1 -1
  235. package/dist/utils/logger.d.ts +12 -0
  236. package/dist/utils/logger.d.ts.map +1 -1
  237. package/dist/utils/logger.js +24 -9
  238. package/dist/utils/logger.js.map +1 -1
  239. package/dist/utils/message-manager.js +2 -2
  240. package/dist/utils/message-manager.js.map +1 -1
  241. package/dist/utils/network-safety.d.ts.map +1 -1
  242. package/dist/utils/network-safety.js +12 -1
  243. package/dist/utils/network-safety.js.map +1 -1
  244. package/dist/utils/open-browser.d.ts +27 -0
  245. package/dist/utils/open-browser.d.ts.map +1 -0
  246. package/dist/utils/open-browser.js +54 -0
  247. package/dist/utils/open-browser.js.map +1 -0
  248. package/dist/utils/strip-html.js +1 -1
  249. package/dist/utils/strip-html.js.map +1 -1
  250. package/dist/utils/version.d.ts.map +1 -1
  251. package/dist/utils/version.js +10 -6
  252. package/dist/utils/version.js.map +1 -1
  253. package/dist/web/acquire.d.ts +69 -0
  254. package/dist/web/acquire.d.ts.map +1 -0
  255. package/dist/web/acquire.js +134 -0
  256. package/dist/web/acquire.js.map +1 -0
  257. package/dist/web/main.d.ts +20 -0
  258. package/dist/web/main.d.ts.map +1 -0
  259. package/dist/web/main.js +292 -0
  260. package/dist/web/main.js.map +1 -0
  261. package/dist/web/player-runtime.d.ts +48 -0
  262. package/dist/web/player-runtime.d.ts.map +1 -0
  263. package/dist/web/player-runtime.js +62 -0
  264. package/dist/web/player-runtime.js.map +1 -0
  265. package/dist/web/spawn.d.ts +82 -0
  266. package/dist/web/spawn.d.ts.map +1 -0
  267. package/dist/web/spawn.js +184 -0
  268. package/dist/web/spawn.js.map +1 -0
  269. package/dist/webui/broadcaster.d.ts.map +1 -1
  270. package/dist/webui/broadcaster.js +17 -3
  271. package/dist/webui/broadcaster.js.map +1 -1
  272. package/dist/webui/http-helpers.d.ts +7 -0
  273. package/dist/webui/http-helpers.d.ts.map +1 -1
  274. package/dist/webui/http-helpers.js +15 -0
  275. package/dist/webui/http-helpers.js.map +1 -1
  276. package/dist/webui/loopback.d.ts +27 -0
  277. package/dist/webui/loopback.d.ts.map +1 -0
  278. package/dist/webui/loopback.js +34 -0
  279. package/dist/webui/loopback.js.map +1 -0
  280. package/dist/webui/public/app.js +193 -2
  281. package/dist/webui/public/index.html +58 -0
  282. package/dist/webui/public/styles.css +92 -0
  283. package/dist/webui/routes/controls.d.ts +7 -0
  284. package/dist/webui/routes/controls.d.ts.map +1 -1
  285. package/dist/webui/routes/controls.js +11 -17
  286. package/dist/webui/routes/controls.js.map +1 -1
  287. package/dist/webui/routes/cover.d.ts.map +1 -1
  288. package/dist/webui/routes/cover.js +28 -1
  289. package/dist/webui/routes/cover.js.map +1 -1
  290. package/dist/webui/routes/health.d.ts +35 -0
  291. package/dist/webui/routes/health.d.ts.map +1 -0
  292. package/dist/webui/routes/health.js +42 -0
  293. package/dist/webui/routes/health.js.map +1 -0
  294. package/dist/webui/routes/player.d.ts +47 -0
  295. package/dist/webui/routes/player.d.ts.map +1 -0
  296. package/dist/webui/routes/player.js +127 -0
  297. package/dist/webui/routes/player.js.map +1 -0
  298. package/dist/webui/routes/playlists.d.ts +37 -0
  299. package/dist/webui/routes/playlists.d.ts.map +1 -0
  300. package/dist/webui/routes/playlists.js +56 -0
  301. package/dist/webui/routes/playlists.js.map +1 -0
  302. package/dist/webui/routes/snapshot.d.ts +1 -1
  303. package/dist/webui/routes/snapshot.d.ts.map +1 -1
  304. package/dist/webui/routes/snapshot.js +4 -2
  305. package/dist/webui/routes/snapshot.js.map +1 -1
  306. package/dist/webui/routes/static-files.d.ts.map +1 -1
  307. package/dist/webui/routes/static-files.js +6 -1
  308. package/dist/webui/routes/static-files.js.map +1 -1
  309. package/dist/webui/server.d.ts +5 -2
  310. package/dist/webui/server.d.ts.map +1 -1
  311. package/dist/webui/server.js +45 -5
  312. package/dist/webui/server.js.map +1 -1
  313. package/package.json +15 -6
  314. package/scripts/make-launcher.mjs +388 -0
  315. package/dist/webui/index.d.ts +0 -74
  316. package/dist/webui/index.d.ts.map +0 -1
  317. package/dist/webui/index.js +0 -165
  318. package/dist/webui/index.js.map +0 -1
package/README.md CHANGED
@@ -24,15 +24,15 @@ Browse and search songs, albums, artists, genres, and tags with rich filtering:
24
24
 
25
25
  Audio plays through your machine's speakers, no browser or Navidrome web UI needed. Search and play in a single step: *"play 5 random starred albums"*, *"queue everything I've starred from the 90s sorted by year"*, *"add 10 random rock songs to whatever's already playing, shuffled"*. Three shuffle modes for albums (keep order, randomize album order, fully interleave tracks).
26
26
 
27
- The live queue is actively manipulable: move a track to the front and it starts playing, shuffle and the new top plays, remove the current track and the next one auto-advances. Saved Navidrome radio stations (Icecast, SHOUTcast, etc.) stream through mpv with ICY metadata flowing through so you can see what the station is currently playing. Plays scrobble back to Navidrome so your recently-played and play counts stay in sync with what you actually listen to through mpv. mpv is lazy-spawned on first use, survives MCP client restarts via a per-user socket, and works on Linux, macOS, and Windows 11.
27
+ The live queue is actively manipulable: reorder and shuffle tracks without interrupting what's playing shuffle keeps the current song going and reshuffles the rest around it — and removing the current track auto-advances to the next. Saved Navidrome radio stations (Icecast, SHOUTcast, etc.) stream through mpv with ICY metadata flowing through so you can see what the station is currently playing. Plays scrobble back to Navidrome so your recently-played and play counts stay in sync with what you actually listen to through mpv. mpv is lazy-spawned on first use, survives MCP client restarts via a per-user socket, and works on Linux, macOS, and Windows 11.
28
28
 
29
29
  This design is built for conversational control and pairs cleanly with voice transports (Whisper STT + TTS) to build a hands-free music device on a Raspberry Pi or always-on machine.
30
30
 
31
- ### 🎛️ MPV Remote (Web Control Panel)
31
+ ### 🎛️ MPV Remote (Standalone Web Player)
32
32
 
33
- > Requires `mpv` (same as Local Audio Playback). On by default; lazy-binds once playback starts.
33
+ > Requires `mpv` (same as Local Audio Playback). On by default; starts with the server.
34
34
 
35
- A companion web UI at `http://localhost:8808` for controlling local mpv playback from any browser. Now-playing card with cover art, transport controls (previous / pause-resume / next), seek bar, volume slider, and a queue list with click-to-jump. Updates live via Server-Sent Events so a phone laid on the desk stays in sync as the assistant feeds the queue. Defaults to localhost-only; flip one env var to expose it on your LAN and use a phone or tablet as a music remote. See [MPV Remote (Web UI)](#mpv-remote-web-ui) for setup and the security note.
35
+ A companion web UI at `http://localhost:8808` for controlling local mpv playback from any browser: a now-playing card with cover art, transport controls, a seek bar, volume, and a live queue you can click to jump around. A built-in playlist picker starts any Navidrome playlist straight from the page, so it works as a real remote, not just a now-playing mirror. Expose it on your LAN to use a phone or tablet to control playback. See [MPV Remote (Web UI)](#mpv-remote-web-ui) for setup, lifetime, and the security note.
36
36
 
37
37
  ### 🎶 Playlists
38
38
 
@@ -40,13 +40,13 @@ Create, update, reorder, and delete playlists conversationally. Add content flex
40
40
 
41
41
  ### 🎼 Music Discovery (Last.fm)
42
42
 
43
- > Requires `LASTFM_API_KEY`. Free key at [last.fm/api](https://www.last.fm/api/account/create).
43
+ > Requires a Last.fm API key (free at [last.fm/api](https://www.last.fm/api/account/create)), set in the settings page.
44
44
 
45
45
  Find similar artists and tracks, fetch biographies and top tracks, and browse global music charts. Combine with your library to do gap analysis (*"albums missing from my top 5 artists, ranked by popularity"*), rediscover overlooked music (*"tracks similar to my favorites that I own but never play"*), or build curated "Best Of" playlists scoped to what you actually own.
46
46
 
47
47
  ### 🎤 Synchronized Lyrics
48
48
 
49
- > Requires `LYRICS_PROVIDER=lrclib` and `LRCLIB_USER_AGENT`. No API key needed.
49
+ > Enabled in the settings page (LRCLIB provider + a user agent). No API key needed.
50
50
 
51
51
  Fetch time-synced lyrics with millisecond-precision timestamps (LRC format) and plain-text fallbacks from LRCLIB's community database. Matched automatically by title, artist, album, and duration.
52
52
 
@@ -54,7 +54,7 @@ Fetch time-synced lyrics with millisecond-precision timestamps (LRC format) and
54
54
 
55
55
  Manage Navidrome radio stations and discover new ones globally. Stream URLs are validated before adding (MP3, AAC, OGG, FLAC detection) and SHOUTcast/Icecast metadata is extracted automatically. Bulk maintenance is supported: *"validate all my stations and remove the broken ones"* or *"test these 10 URLs and add the working ones"*.
56
56
 
57
- Global station discovery via Radio Browser (requires `RADIO_BROWSER_USER_AGENT`) covers thousands of stations filterable by genre, country, language, codec, bitrate, and popularity, with vote and click registration so your usage feeds the community ranking.
57
+ Global station discovery via Radio Browser (requires a Radio Browser user agent, set in the settings page) covers thousands of stations filterable by genre, country, language, codec, bitrate, and popularity, with vote and click registration so your usage feeds the community ranking.
58
58
 
59
59
  ### 📊 Listening Analytics
60
60
 
@@ -66,7 +66,7 @@ Star/unstar songs, albums, and artists, set 0-5 star ratings, and list everythin
66
66
 
67
67
  ### 📚 Multi-Library Support
68
68
 
69
- Filter all operations to a subset of your Navidrome libraries, either by setting a default in your client config (`NAVIDROME_DEFAULT_LIBRARIES`) or by switching active libraries at runtime.
69
+ Filter all operations to a subset of your Navidrome libraries, either by setting a default in the settings page (**Default libraries**, `library.defaultLibraryIds`) or by switching active libraries at runtime.
70
70
 
71
71
  ## Installation
72
72
 
@@ -98,6 +98,11 @@ pnpm build
98
98
 
99
99
  ### Configure Your MCP Client
100
100
 
101
+ The MCP client config does just one thing: tell it how to *launch* the server. Your
102
+ Navidrome credentials and all options live in a local `settings.json`, edited through a
103
+ browser-based settings page (no secrets in the client JSON or environment). The settings
104
+ page opens automatically on first run (see [First-run setup](#first-run-setup)).
105
+
101
106
  For Claude Desktop, edit `claude_desktop_config.json` (locations: `%APPDATA%/Claude/` on Windows, `~/Library/Application Support/Claude/` on macOS, `~/.config/Claude/` on Linux). Other MCP clients use the same JSON shape.
102
107
 
103
108
  ```json
@@ -105,17 +110,7 @@ For Claude Desktop, edit `claude_desktop_config.json` (locations: `%APPDATA%/Cla
105
110
  "mcpServers": {
106
111
  "navidrome": {
107
112
  "command": "npx",
108
- "args": ["navidrome-mcp"],
109
- "env": {
110
- "NAVIDROME_URL": "http://your-server:4533",
111
- "NAVIDROME_USERNAME": "your_username",
112
- "NAVIDROME_PASSWORD": "your_password",
113
- "NAVIDROME_DEFAULT_LIBRARIES": "1,2",
114
- "LASTFM_API_KEY": "your_api_key",
115
- "RADIO_BROWSER_USER_AGENT": "Navidrome-MCP/2.0 (+https://github.com/Blakeem/Navidrome-MCP)",
116
- "LYRICS_PROVIDER": "lrclib",
117
- "LRCLIB_USER_AGENT": "Navidrome-MCP/2.0 (+https://github.com/Blakeem/Navidrome-MCP)"
118
- }
113
+ "args": ["navidrome-mcp"]
119
114
  }
120
115
  }
121
116
  }
@@ -128,17 +123,41 @@ For a manual build, replace `command`/`args` with:
128
123
  "args": ["/absolute/path/to/Navidrome-MCP/dist/index.js"]
129
124
  ```
130
125
 
131
- **Required:** `NAVIDROME_URL`, `NAVIDROME_USERNAME`, `NAVIDROME_PASSWORD`.
126
+ ### First-run setup
132
127
 
133
- **Optional:**
134
- - `NAVIDROME_DEFAULT_LIBRARIES`: comma-separated library IDs to activate by default; omit for all libraries.
135
- - `LASTFM_API_KEY`: enables Last.fm discovery features.
136
- - `RADIO_BROWSER_USER_AGENT`: enables Radio Browser global station discovery. Replace the project URL with your own.
137
- - `LYRICS_PROVIDER=lrclib` + `LRCLIB_USER_AGENT`: enables lyrics fetching.
138
- - `MPV_PATH`: point at the mpv binary if it's not on `PATH` (e.g. `"C:\\Program Files\\mpv\\mpv.exe"`).
139
- - `WEBUI_PORT` / `WEBUI_HOST` / `WEBUI_EXPOSE` / `WEBUI_ENABLED`: configure the [MPV Remote web UI](#mpv-remote-web-ui) — defaults to `localhost:8808` and lazy-binds once mpv is playing.
128
+ On first start without configuration, the **settings page** opens automatically in your
129
+ browser. This happens whether you launched the MCP server or the standalone web player
130
+ (`navidrome-web`) first; either one, run unconfigured, brings it up. If a browser can't
131
+ open (e.g. over SSH), the URL is printed to the console, and the unconfigured MCP server
132
+ also exposes an `open_settings` tool that returns it. You can open the settings page any
133
+ time with:
140
134
 
141
- Features turn on automatically when their config is present. Restart your MCP client after changing the config.
135
+ ```bash
136
+ npx navidrome-config
137
+ ```
138
+
139
+ Enter your Navidrome URL, username, and password (plus any optional features), click
140
+ **Test connection**, then **Save**. This writes a local `settings.json` (shape:
141
+ [`settings.example.json`](settings.example.json)). Settings load at startup and don't
142
+ hot-reload, so restart whatever you launched to apply them: the MCP client (quit and
143
+ reopen, e.g. Claude Desktop) or the web player (re-run `navidrome-web`). If the web
144
+ player brought up the settings page itself, it stays open for further edits and
145
+ self-closes when idle; re-launch `navidrome-web` to start playing. Upgrading from the old
146
+ env-based setup? The form pre-fills from your previous `env`/`.env` values; verify and
147
+ save.
148
+
149
+ **Required:** Navidrome URL, username, password.
150
+
151
+ **Optional (set in the settings page):**
152
+ - **Default libraries:** comma-separated library IDs to activate by default; blank = all.
153
+ - **Last.fm API key:** enables Last.fm discovery features.
154
+ - **Radio Browser user agent:** enables global station discovery.
155
+ - **Lyrics provider (LRCLIB)** + user agent: enables lyrics fetching.
156
+ - **mpv path:** point at the mpv binary if it's not on `PATH`; blank auto-detects.
157
+ - **Transcode format:** defaults to `raw` (streams the original file untouched for best quality and reliable seeking). Set a codec (e.g. `mp3`, `opus`) to transcode for slow/metered links; the bitrate applies then.
158
+ - **Web UI** (port / host / expose / enabled / auto-open browser): configures the [MPV Remote web UI](#mpv-remote-web-ui) (defaults to `localhost:8808`).
159
+
160
+ Features turn on automatically when their settings are present. Restart your MCP client after saving.
142
161
 
143
162
  ### Installing mpv (optional)
144
163
 
@@ -164,66 +183,109 @@ scoop install mpv
164
183
  choco install mpv
165
184
  ```
166
185
 
167
- > Use the full package ID `shinchiro.mpv` to skip the disambiguation prompt; the Microsoft Store also lists an unofficial third-party `mpv` package, and plain `winget install mpv` will ask you to pick. The shinchiro build is the community standard that [mpv.io](https://mpv.io/installation/) itself points to for Windows.
186
+ > Use the full ID `shinchiro.mpv`; plain `winget install mpv` prompts you to disambiguate from an unofficial Store package. The shinchiro build is the one [mpv.io](https://mpv.io/installation/) points to for Windows.
168
187
  >
169
- > **Windows `PATH` note.** The `shinchiro.mpv` winget package installs to `C:\Program Files\MPV Player\` on Windows 11 and does **not** add itself to `PATH`. You have two options:
170
- > - Add the install folder to your user or system `PATH` (System Properties → Environment Variables → Path → New → `C:\Program Files\MPV Player`), then open a new terminal so the change takes effect.
171
- > - Or set `MPV_PATH` in your MCP client config to the full `mpv.exe` path, e.g. `"MPV_PATH": "C:\\Program Files\\MPV Player\\mpv.exe"`.
188
+ > **Windows `PATH` note.** The `shinchiro.mpv` package installs to `C:\Program Files\MPV Player\` and does **not** add itself to `PATH`. Either:
189
+ > - Add that folder to your `PATH` (System Properties → Environment Variables → Path → New), then open a new terminal, or
190
+ > - Set **mpv path** in the settings page (`playback.mpvPath`) to the full `mpv.exe` path, e.g. `C:\Program Files\MPV Player\mpv.exe`.
172
191
  >
173
- > Other install methods (scoop, chocolatey, manual zip from mpv.io) drop `mpv.exe` in a different folder. If `mpv --version` doesn't work in a fresh terminal after install, locate `mpv.exe` and apply one of the two fixes above.
192
+ > Other install methods (scoop, choco, manual zip) use different folders. If `mpv --version` fails in a fresh terminal, locate `mpv.exe` and apply one of the fixes above.
174
193
 
175
194
  Or a pre-built binary from [mpv.io](https://mpv.io/installation/). Verify with `mpv --version`, then restart your MCP client so the server re-detects mpv.
176
195
 
177
196
  ### A Note on ChatGPT Desktop
178
197
 
179
- ChatGPT's MCP support (web and desktop) requires a hosted HTTPS endpoint and is not currently compatible with local stdio servers like this one. If you really want to make it work with ChatGPT, you can wrap a stdio server in HTTPS using a bridge like [`mcp-remote`](https://www.npmjs.com/package/mcp-remote), but that adds operational complexity for a self-hosted music server. Otherwise, use Claude Desktop, Claude Code, Cursor, or another client with native stdio support. Re-check once OpenAI adds first-party stdio MCP support.
198
+ ChatGPT's MCP support (web and desktop) requires a hosted HTTPS endpoint and isn't compatible with local stdio servers like this one. You can bridge a stdio server to HTTPS with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote), but for a self-hosted music server it's simpler to use Claude Desktop, Claude Code, Cursor, or another client with native stdio support.
180
199
 
181
200
  ## MPV Remote (Web UI)
182
201
 
183
- When local audio playback is active, the MCP server runs a companion web interface that doubles as a now-playing display and a transport-control remote. Open it in any browser on the host (or anywhere on your LAN once exposed).
202
+ When local audio playback is active, the server runs a companion web interface: a now-playing display and transport-control remote. Open it in any browser on the host (or anywhere on your LAN once exposed).
184
203
 
185
204
  [![MPV Remote web interface](navidome-mcp-mpv-remote-small.png)](navidome-mcp-mpv-remote-large.png)
186
205
 
187
206
  ### What it does
188
207
 
189
- - **Now-playing card** cover art, title, artist, album, and queue position. A `Live` indicator confirms the SSE stream is healthy.
190
- - **Transport controls** previous / pause-resume / next, with a seek bar showing current position and remaining time.
191
- - **Volume slider** drives mpv's internal volume control (independent of your OS volume).
192
- - **Queue list** every track in the current mpv queue with title, artist · album, and duration. Click any row to jump to it.
193
- - **Live state updates** Server-Sent Events push state changes the instant they happen, throttled to ~1 Hz so the progress bar runs smoothly without flooding the network. Connections auto-reconnect on disconnect.
208
+ - **Now-playing card:** cover art, title, artist, album, and queue position. A `Live` indicator confirms the SSE stream is healthy.
209
+ - **Transport controls:** previous / pause-resume / next, with a seek bar showing position and remaining time.
210
+ - **Volume slider:** drives mpv's internal volume (independent of your OS volume).
211
+ - **Queue list:** every track with title, artist · album, and duration. Click a row to jump to it; the **clear** icon empties the queue and stops playback.
212
+ - **Playlist picker:** the playlist icon opens your Navidrome playlists; pick one to start it (Replace or Add to queue, with optional Shuffle).
213
+ - **Gear + power buttons (host only):** the top bar shows a **gear** (player settings, including "keep playing after the MCP server closes") and a **power** button that stops mpv and the player. Both are hidden for remote (LAN) browsers.
214
+ - **Live updates:** Server-Sent Events push state changes as they happen (throttled to ~1 Hz) and auto-reconnect on disconnect.
215
+
216
+ ### Enabling & lifetime
217
+
218
+ On by default, it starts with the server as a separate `navidrome-web` process; the port binds immediately, so the page and its playlist picker are reachable before anything plays. Hosts without mpv don't start it.
219
+
220
+ **Does it keep playing after you close the AI?**
221
+
222
+ - **Default (off):** the MCP-launched player and mpv stop when you close or restart the MCP server.
223
+ - **Keep playing after the MCP server closes** (`webui.persistAfterMcpExit`, in the settings page or the in-player gear modal): the player keeps running after you close the AI; stop it later with the **power** button.
224
+ - **Launched it yourself** (`navidrome-web`, below): always runs independently; the MCP server attaches to it and never shuts it down.
225
+
226
+ mpv stops exactly when the player stops (no background idle timeout).
227
+
228
+ To disable the panel entirely, uncheck **Enable the companion control panel** in the settings page (`webui.enabled`).
194
229
 
195
- ### Enabling
230
+ ### Running it standalone (without an MCP client)
196
231
 
197
- The web UI is **on by default** and binds **lazily**: the port only opens once mpv has something playing, OR when the server reattaches to a pre-existing mpv queue across MCP restarts. Hosts without mpv installed see no listener at all.
232
+ Launch the player directly to run it independently of any MCP client. It reads the `settings.json` and opens your browser automatically. A standalone launch always persists: it runs in the background until you stop it with the **power** button in the UI. It **coexists** with an MCP-launched instance: whoever binds the configured port first owns it and the other connects to it (an MCP server attaches rather than replacing or stopping it). Logs go to `navidrome-web.log` in your config directory.
198
233
 
199
- To turn it off entirely, set `WEBUI_ENABLED=false` in your MCP client's env block.
234
+ > **Configure first.** The player needs your Navidrome details in `settings.json`. If it isn't configured yet, launching it brings up the **settings page** instead of the player (see [First-run setup](#first-run-setup)). Fill it in and Save, then re-launch `navidrome-web` to start playing. The setup page self-closes when idle, so it never lingers. You can also configure ahead of time with `npx navidrome-config`.
235
+
236
+ #### Desktop shortcut (recommended)
237
+
238
+ Generate a double-clickable icon for your platform. It starts the player in the background with **no terminal window** and opens your browser; if a player is already running, it just opens the browser. Stop it with the **power** button in the UI.
239
+
240
+ ```bash
241
+ navidrome-web-shortcut # after: npm install -g navidrome-mcp
242
+ # or, from a dev clone (see Development):
243
+ pnpm make:launcher
244
+ ```
245
+
246
+ This bakes the absolute paths to your `node` and the built player into the shortcut, so it works without anything on your `PATH`. It writes:
247
+
248
+ - **Linux:** `Navidrome Player.desktop` on your Desktop **and** in your app menu (`~/.local/share/applications`). On GNOME, right-click → *Allow Launching* the first time.
249
+ - **macOS:** `Navidrome Player.app` on your Desktop (drag to `/Applications` if you like).
250
+ - **Windows:** `Navidrome Player.vbs` on your Desktop **and** Start Menu. (If your Desktop is redirected into OneDrive, it lands there.)
251
+
252
+ Re-run the generator any time you move or rebuild the project to refresh the baked-in paths.
253
+
254
+ #### From the command line
255
+
256
+ ```bash
257
+ navidrome-web # after: npm install -g navidrome-mcp
258
+ # or, from a dev clone / manual build:
259
+ node dist/web/main.js
260
+ ```
200
261
 
201
262
  ### Configuration
202
263
 
203
- All variables are optional. Add them alongside `NAVIDROME_URL` etc. in your MCP client's `env` block, then restart the client.
264
+ All of these are optional and live in the **Web UI** section of the settings page (`navidrome-config`); the keys below are their `settings.json` paths. Restart the client after saving (except `persistAfterMcpExit`, which the in-player gear modal applies live).
204
265
 
205
- | Variable | Default | Effect |
266
+ | Setting (`settings.json`) | Default | Effect |
206
267
  |---|---|---|
207
- | `WEBUI_ENABLED` | `true` | Set to `false` to disable the panel entirely. |
208
- | `WEBUI_PORT` | `8808` | Port the HTTP server listens on. Pick a free port if 8808 is taken on your host. |
209
- | `WEBUI_HOST` | `127.0.0.1` | Bind address. Override only if you know which interface you want usually `WEBUI_EXPOSE` is the right knob. |
210
- | `WEBUI_EXPOSE` | `false` | Set to `true` to bind on `0.0.0.0` so other devices on your LAN can reach the panel. |
268
+ | `webui.enabled` | `true` | Disable the panel entirely. |
269
+ | `webui.port` | `8808` | Port the HTTP server listens on. Pick a free port if 8808 is taken on your host. |
270
+ | `webui.host` | `127.0.0.1` | Bind address. Override only if you know which interface you want; usually **Expose on LAN** is the right knob. |
271
+ | `webui.expose` | `false` | Bind on `0.0.0.0` so other devices on your LAN can reach the panel. |
272
+ | `webui.autoOpenBrowser` | `false` | Open the player in your browser automatically when the MCP server starts. (Running `navidrome-web` directly always opens a browser regardless.) |
273
+ | `webui.persistAfterMcpExit` | `false` | Keep an MCP-launched player (and mpv) running after the MCP server closes/restarts. Toggle it live in the in-player gear modal too. |
211
274
 
212
- When `WEBUI_EXPOSE=true`, the MCP server logs the LAN URLs it's reachable on at bind time (e.g. `http://192.168.1.42:8808`). Open one of those on your phone or tablet.
275
+ When **Expose on LAN** is enabled, the player logs the LAN URLs it's reachable on at bind time (e.g. `http://192.168.1.42:8808`). Open one of those on your phone or tablet.
213
276
 
214
277
  ### Using it as a phone/tablet remote
215
278
 
216
- 1. Set `"WEBUI_EXPOSE": "true"` in your MCP client's env block.
217
- 2. Restart the MCP client.
218
- 3. Trigger any playback (e.g. ask the assistant to *"play all my starred songs"*) this is what causes the web UI to bind.
219
- 4. Open the LAN URL from the startup log on your phone's browser. Bookmark it for one-tap access — the page is a single static HTML/CSS/JS bundle, no install required.
279
+ 1. Enable **Expose on LAN** in the settings page and Save.
280
+ 2. Restart the MCP client (or restart `navidrome-web`).
281
+ 3. Open the LAN URL from the startup log in your phone's browser. The player is reachable immediately; start a playlist from the picker without touching the assistant. Bookmark it for one-tap access (the page is a single static bundle, no install required).
220
282
 
221
283
  ### Security note
222
284
 
223
- The web UI has **no authentication** anyone who can reach the port can pause, skip, seek, change volume, and jump around the queue.
285
+ The web UI has **no authentication**: anyone who can reach the port can pause, skip, seek, change volume, and jump around the queue.
224
286
 
225
- - On `WEBUI_HOST=127.0.0.1` (the default) it's only reachable from the host machine, which is safe.
226
- - On `WEBUI_EXPOSE=true` it's reachable from anything on the LAN. That's usually fine on a trusted home network, but **do not expose it directly to the public internet**. There's no rate-limiting, no auth, and the control API allows queue manipulation.
287
+ - With `webui.host=127.0.0.1` (the default) it's only reachable from the host machine, which is safe.
288
+ - With **Expose on LAN** (`webui.expose=true`) it's reachable from anything on the LAN. That's usually fine on a trusted home network, but **do not expose it directly to the public internet**. There's no rate-limiting, no auth, and the control API allows queue manipulation and starting playlists. The **player settings and the power button are loopback-only** (and hidden in the UI for remote browsers), so a phone on your LAN can control playback but can't change settings or shut the server down. The browser-based main settings page is likewise never exposed.
227
289
 
228
290
  ## Available Tools
229
291
 
@@ -297,7 +359,7 @@ Tools marked **conditional** are only registered when the corresponding configur
297
359
  | `get_tag_distribution` | Tag usage counts across the library |
298
360
  | `get_filter_options` | Discover available filter values for search operations |
299
361
 
300
- ### Last.fm Discovery (requires `LASTFM_API_KEY`)
362
+ ### Last.fm Discovery (requires a Last.fm API key)
301
363
 
302
364
  | Tool | Description |
303
365
  |------|-------------|
@@ -307,7 +369,7 @@ Tools marked **conditional** are only registered when the corresponding configur
307
369
  | `get_top_tracks_by_artist` | Top tracks for an artist |
308
370
  | `get_trending_music` | Trending artists, tracks, and tags from Last.fm charts |
309
371
 
310
- ### Lyrics (requires `LYRICS_PROVIDER=lrclib` + `LRCLIB_USER_AGENT`)
372
+ ### Lyrics (requires the LRCLIB provider, set in the settings page)
311
373
 
312
374
  | Tool | Description |
313
375
  |------|-------------|
@@ -323,7 +385,7 @@ Tools marked **conditional** are only registered when the corresponding configur
323
385
  | `delete_radio_station` | Delete a station |
324
386
  | `validate_radio_stream` | Test an http(s) stream URL for accessibility and audio content |
325
387
 
326
- ### Global Radio Discovery (requires `RADIO_BROWSER_USER_AGENT`)
388
+ ### Global Radio Discovery (requires a Radio Browser user agent)
327
389
 
328
390
  | Tool | Description |
329
391
  |------|-------------|
@@ -335,7 +397,7 @@ Tools marked **conditional** are only registered when the corresponding configur
335
397
 
336
398
  ### Local Playback (requires [`mpv`](https://mpv.io/))
337
399
 
338
- Audio plays through the host's speakers. mpv is lazy-spawned on first use and survives MCP client restarts via a per-user IPC socket.
400
+ Audio plays through the host's speakers. mpv is lazy-spawned on first use and survives MCP client restarts via a per-user IPC socket. Playback streams the original file by default; set **Transcode format** to a codec for constrained bandwidth (see [First-run setup](#first-run-setup)).
339
401
 
340
402
  | Tool | Description |
341
403
  |------|-------------|
@@ -355,8 +417,8 @@ Audio plays through the host's speakers. mpv is lazy-spawned on first use and su
355
417
  | `playback_status` | Engine health probe (running, mpv version, idle) without spawning mpv |
356
418
  | `get_play_queue` | Snapshot of the live queue with metadata and current-track index |
357
419
  | `clear_play_queue` | Clear the queue and stop playback |
358
- | `shuffle_play_queue` | Randomize queue order (membership unchanged) |
359
- | `move_in_play_queue` | Move a queue entry between indices |
420
+ | `shuffle_play_queue` | Randomize queue order (membership unchanged); the current track keeps playing and is lifted to the top |
421
+ | `move_in_play_queue` | Move a queue entry between indices; never changes what's currently playing |
360
422
  | `remove_from_play_queue` | Remove an entry; mpv auto-advances if the current track is removed |
361
423
  | `play_queue_index` | Jump directly to the queue entry at the given index; does not reorder |
362
424
 
@@ -364,8 +426,8 @@ Audio plays through the host's speakers. mpv is lazy-spawned on first use and su
364
426
 
365
427
  **Connection problems**
366
428
  - Verify Navidrome is running and reachable
367
- - Ensure `NAVIDROME_URL` includes the protocol (`http://` or `https://`)
368
- - Test credentials with `curl` or a browser first
429
+ - Ensure the **Navidrome URL** in the settings page includes the protocol (`http://` or `https://`)
430
+ - Use the settings page's **Test connection** button (or test credentials with `curl` / a browser) before saving
369
431
 
370
432
  **macOS-specific**
371
433
  - See the [macOS Troubleshooting Guide](docs/MACOS_TROUBLESHOOTING.md) (commonly: Node.js path not found; fix with symlinks or full paths)
@@ -386,8 +448,10 @@ Audio plays through the host's speakers. mpv is lazy-spawned on first use and su
386
448
  ```bash
387
449
  git clone https://github.com/Blakeem/Navidrome-MCP.git
388
450
  cd Navidrome-MCP
389
- cp .env.example .env
390
- # Edit .env with your credentials
451
+ pnpm install
452
+ pnpm build
453
+ node dist/config-app/main.js # opens the settings page; fill in + Save
454
+ # (writes settings.json to your OS config dir; see settings.example.json)
391
455
 
392
456
  pnpm dev # hot reload
393
457
  pnpm test # watch-mode tests
@@ -396,6 +460,36 @@ pnpm check:all # lint + typecheck + dead-code
396
460
  pnpm build # production bundle
397
461
  ```
398
462
 
463
+ ### Testing the standalone web player from a dev build
464
+
465
+ This is the from-source path for trying the player **before it's published to npm** (the published package may lag behind `dev`). It applies to the MCP server too; both run from the same `dist/`.
466
+
467
+ ```bash
468
+ # 1. Build (also bundles the web UI's static assets into dist/)
469
+ pnpm build
470
+
471
+ # 2. Configure if needed; writes settings.json to your OS config dir
472
+ node dist/config-app/main.js # opens the settings page; fill in + Save
473
+
474
+ # 3. Run the standalone player directly
475
+ node dist/web/main.js # serves http://127.0.0.1:8808 and opens your browser
476
+ ```
477
+
478
+ To make a double-clickable icon out of that build (no global install needed):
479
+
480
+ ```bash
481
+ pnpm make:launcher # writes a shortcut to your Desktop + app menu
482
+ ```
483
+
484
+ **Windows notes** (PowerShell):
485
+
486
+ - Use `pnpm build` then `node dist\web\main.js`, same as above with backslashes.
487
+ - `pnpm make:launcher` writes `Navidrome Player.vbs` to your Desktop **and** Start Menu; it launches `node dist\web\main.js` with **no console window** and bakes in the absolute path to *this* checkout, so don't move the folder afterward (re-run it if you do).
488
+ - If a redirected/OneDrive Desktop hides the file, the Start Menu copy still works (Start → type "Navidrome").
489
+ - mpv must be installed and discoverable for playback to start; set `playback.mpvPath` in the settings page if it isn't on `PATH`.
490
+
491
+ When you publish, `npm install -g navidrome-mcp` puts `navidrome-web`, `navidrome-config`, and `navidrome-web-shortcut` on the user's `PATH`, so the same flows become `navidrome-web` / `navidrome-config` / `navidrome-web-shortcut` with no clone or build.
492
+
399
493
  Testing with [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
400
494
 
401
495
  ```bash
Binary file
Binary file
Binary file
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Navidrome MCP Server - Shared runtime bootstrap
3
+ * Copyright (C) 2025
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published
7
+ * by the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ import type { Config } from './config.js';
19
+ import { NavidromeClient } from './client/navidrome-client.js';
20
+ /**
21
+ * The fully-initialized core every entry point needs to operate: the resolved
22
+ * config plus an authenticated, ready-to-use client. The library and filter
23
+ * caches and the playback engine are module singletons configured as a side
24
+ * effect of this call, so they don't need to be returned.
25
+ */
26
+ interface Runtime {
27
+ config: Config;
28
+ client: NavidromeClient;
29
+ }
30
+ /**
31
+ * Shared startup sequence used by both the MCP server (`src/index.ts`) and,
32
+ * later, the standalone web server. Resolves config, authenticates the client,
33
+ * primes the library/filter caches, and configures the playback engine so any
34
+ * transport-agnostic tool impl can run identically regardless of who launched
35
+ * the process.
36
+ *
37
+ * Deliberately does NOT attach the scrobbler — scrobbling ownership is
38
+ * process-conditional (the playback survivor scrobbles; see the standalone-web
39
+ * spec §6.4), so each entry point wires it itself after calling this.
40
+ */
41
+ export declare function createRuntime(): Promise<Runtime>;
42
+ export {};
43
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAM/D;;;;;GAKG;AACH,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAqBtD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Navidrome MCP Server - Shared runtime bootstrap
3
+ * Copyright (C) 2025
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published
7
+ * by the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ import { loadConfig } from './config.js';
19
+ import { NavidromeClient } from './client/navidrome-client.js';
20
+ import { libraryManager } from './services/library-manager.js';
21
+ import { filterCacheManager } from './services/filter-cache-manager.js';
22
+ import { playbackEngine } from './services/playback/playback-engine.js';
23
+ import { logger } from './utils/logger.js';
24
+ /**
25
+ * Shared startup sequence used by both the MCP server (`src/index.ts`) and,
26
+ * later, the standalone web server. Resolves config, authenticates the client,
27
+ * primes the library/filter caches, and configures the playback engine so any
28
+ * transport-agnostic tool impl can run identically regardless of who launched
29
+ * the process.
30
+ *
31
+ * Deliberately does NOT attach the scrobbler — scrobbling ownership is
32
+ * process-conditional (the playback survivor scrobbles; see the standalone-web
33
+ * spec §6.4), so each entry point wires it itself after calling this.
34
+ */
35
+ export async function createRuntime() {
36
+ const config = await loadConfig();
37
+ logger.setDebug(config.debug);
38
+ const client = new NavidromeClient(config);
39
+ await client.initialize();
40
+ // Initialize library manager with user data and configuration.
41
+ await libraryManager.initialize(client, config);
42
+ // Initialize filter cache manager for enhanced search functionality.
43
+ await filterCacheManager.initialize(client, config);
44
+ // Configure the singleton engine with the loaded config so tools can
45
+ // lazy-spawn mpv on first invocation. Gated on the playback feature (mpv
46
+ // detected) — `buildStreamUrl()` and every play_* tool depend on it.
47
+ if (config.features.playback) {
48
+ playbackEngine.configure(config);
49
+ }
50
+ return { config, client };
51
+ }
52
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAa3C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;IAE1B,+DAA+D;IAC/D,MAAM,cAAc,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD,qEAAqE;IACrE,MAAM,kBAAkB,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpD,qEAAqE;IACrE,yEAAyE;IACzE,qEAAqE;IACrE,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC7B,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../../src/client/auth-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAQ3C,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAIhC,OAAO,CAAC,cAAc,CAA8B;gBAExC,MAAM,EAAE,MAAM;IAIpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IASnC;;;OAGG;IACH,UAAU,IAAI,IAAI;IAKZ,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;YAYnB,mBAAmB;CAiClC"}
1
+ {"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../../src/client/auth-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAQ3C,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAIhC,OAAO,CAAC,cAAc,CAA8B;gBAExC,MAAM,EAAE,MAAM;IAIpB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IASnC;;;OAGG;IACH,UAAU,IAAI,IAAI;IAKZ,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;YAYnB,mBAAmB;CA2ClC"}
@@ -47,10 +47,10 @@ export class AuthManager {
47
47
  this.tokenExpiry = null;
48
48
  }
49
49
  async getToken() {
50
- if (this.token === null || this.token === undefined || this.token === '' || this.tokenExpiry === null || this.tokenExpiry === undefined || this.tokenExpiry <= new Date()) {
50
+ if (this.token === null || this.token === '' || this.tokenExpiry === null || this.tokenExpiry <= new Date()) {
51
51
  await this.authenticate();
52
52
  }
53
- if (this.token === null || this.token === undefined || this.token === '') {
53
+ if (this.token === null || this.token === '') {
54
54
  throw new Error(ErrorFormatter.authentication('token not available after authentication'));
55
55
  }
56
56
  return this.token;
@@ -77,7 +77,18 @@ export class AuthManager {
77
77
  if (!response.ok) {
78
78
  throw new Error(ErrorFormatter.authentication(`${response.status} ${response.statusText}`));
79
79
  }
80
- const data = (await response.json());
80
+ let data;
81
+ try {
82
+ data = (await response.json());
83
+ }
84
+ catch {
85
+ // 200 OK but body wasn't valid JSON (empty body, HTML error page from a
86
+ // proxy, etc.) — surface with auth context instead of a bare SyntaxError.
87
+ throw new Error(ErrorFormatter.authentication('invalid JSON in /auth/login response'));
88
+ }
89
+ if (typeof data.token !== 'string' || data.token === '') {
90
+ throw new Error(ErrorFormatter.authentication('server returned no token'));
91
+ }
81
92
  this.token = data.token;
82
93
  this.tokenExpiry = new Date(Date.now() + this.config.tokenExpiry * 1000); // Convert seconds to milliseconds
83
94
  logger.debug('Authentication successful');
@@ -1 +1 @@
1
- {"version":3,"file":"auth-manager.js","sourceRoot":"","sources":["../../src/client/auth-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-manager.js","sourceRoot":"","sources":["../../src/client/auth-manager.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"navidrome-client.d.ts","sourceRoot":"","sources":["../../src/client/navidrome-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAW3C,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,MAAM,EAAE,MAAM;IAMpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC;;;;;;;;OAQG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxC;;;;OAIG;IACG,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;IAKzE;;;;;;;;OAQG;IACG,eAAe,CAAC,CAAC,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAuB7C;;;;OAIG;IACG,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;IAK1F;;;;OAIG;IACG,+BAA+B,CAAC,CAAC,EACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAM7C;;;;OAIG;IACH,OAAO,CAAC,4BAA4B;IAgBpC;;;;;;OAMG;IACG,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAO,GACxC,OAAO,CAAC,OAAO,CAAC;IAsDnB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;YASZ,OAAO;YAsCP,aAAa;CA0B5B"}
1
+ {"version":3,"file":"navidrome-client.d.ts","sourceRoot":"","sources":["../../src/client/navidrome-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAW3C,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,MAAM,EAAE,MAAM;IAMpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC;;;;;;;;OAQG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxC;;;;OAIG;IACG,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;IAKzE;;;;;;;;OAQG;IACG,eAAe,CAAC,CAAC,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAuB7C;;;;OAIG;IACG,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;IAK1F;;;;OAIG;IACG,+BAA+B,CAAC,CAAC,EACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAM7C;;;;OAIG;IACH,OAAO,CAAC,4BAA4B;IAgBpC;;;;;;OAMG;IACG,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAAO,GACxC,OAAO,CAAC,OAAO,CAAC;IAsDnB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;YAsBZ,OAAO;YA+CP,aAAa;CAiC5B"}