A player you can build on
rox has what other players bundle a web server to get: a local JSON-RPC socket, events pushed as things change, an MCP proxy, and an Icecast stream out.
The server rox refuses to be
The usual way a desktop player opens itself up is to embed a web server. That buys remote control and costs everything else: a port on your machine, an auth story, a web UI that abandons the player's own look, and an attack surface a music player has no business having. Every user pays for it so that the few who script their player can.
rox keeps the capability and refuses the delivery. Its machine interface is a local socket, a Unix domain socket on Linux and macOS and a named pipe on Windows, keyed to the data directory so two portable instances never cross. Auth is filesystem permissions: anything that could read your music can already do what the socket allows. Nothing listens on a port, and no HTTP server ships in the binary.
One socket, the whole player
The protocol is JSON-RPC 2.0, one object per line, opened with a version handshake. transport.* drives the deck: toggle, seek, volume, the A-B section. queue.* edits the play order by stable entry id, so the row you moved is still the row you meant. library.* searches, returns the playing track's full tags, and hands over cover art. library.rescan and tasks.* start, watch and stop the rescans and analysis passes, and the start reply carries the track count and time estimate the window would have shown you. Every method reads and drives the same player and library the panels do, so the socket can never say something the UI wouldn't.
The prior art is mpv's JSON IPC and mpd's protocol, and the cost is theirs too: a consumer needs a socket client where a server would have offered curl. roxctl, the reference client in the source tree, covers the shell case, one call per invocation, --json when a script is reading, so roxctl next and roxctl search miles davis work before you've written a line of anything.
Push, so you never poll
A front end that can't subscribe will poll, so events are in the contract from version one. Call subscribe and the socket pushes frames as things move: event.track on turnover, event.playback when play state, volume or mute change, event.queue when the order does.
A consumer that falls behind is cut off rather than waited on, so a stalled reader can never back up into playback. roxctl watch prints the stream as it arrives, which is a now-playing display for a status bar solved in one shell loop.
MCP, which no other player has
Beside the app sits rox-mcp, a thin binary speaking MCP over stdio on one side and the socket on the other. Point Claude or any MCP client at it and the player becomes tools: what's playing, search the library, read the queue, work the transport, start a rescan or an analysis pass. "Queue up something quiet from the 70s" stops being a feature rox would have to grow and becomes a sentence your assistant can act on.
Every tool proxies a socket method, so the MCP surface is by construction a subset of what the socket serves and can't drift ahead of it. And it's opt-in twice over: an AI features toggle, off by default, reveals an MCP settings page with its own switch, and every tool call rechecks the toggles in the running app before it answers. Off means a clear refusal, not a hang.
The audio half
Control is half of a front end; the other half is hearing something. rox connects out to an Icecast server as a source client and pushes the processed stream, encoded to MP3, at the mount you name. The tap comes after the processing chain, so the broadcast is exactly what the speakers get, equalizer and all.
The direction is the point. rox connects out, it never serves: the mount, the listeners and the network face all belong to Icecast. An unreachable server drops chunks on the floor rather than touch local playback, and the sink reconnects on its own clock for as long as the config is in place.
What that opens up
Each piece is useful alone. A media-keys daemon or a status bar widget is the socket and a few lines. A hardware controller, a stream deck or a knob on a microcontroller, is transport.* from whatever can reach a socket. Kiosk duty for a listening room is the queue methods and event.track driving a display.
Put them together and rox is the backend of a personal streaming setup: transport and queue over the socket, audio embedded off the Icecast mount, and a front end you write in whatever you like, with your library playing on the machine that stores it.
Bring a socket client
The socket is on wherever rox runs, rox-mcp ships beside the app, and the MCP page in settings has the config line for your client. roxctl builds from the source in one cargo command.