Plugin JSON-RPC protocol specification
Plugin JSON-RPC protocol specification
Transport
JSON-RPC 2.0 over the plugin’s stdin/stdout. See ADR-001 and ADR-006.
- Each message is exactly one JSON object on one line, terminated by
\n. - The core writes requests to the plugin’s stdin.
- The plugin writes responses to its stdout.
- Stderr is reserved for plugin logging/diagnostics.
- The plugin must flush stdout after each response.
- Maximum message size: 10MB per message. Messages exceeding this limit are rejected with PARSE_ERROR (-32700).
- Notifications (requests without an
idfield) are logged at WARN level and ignored. No reply is sent.
Per-method timeouts
| Method | Timeout |
|---|---|
ping |
2s |
search |
30s |
get_track |
10s |
get_album |
10s |
get_artist |
10s |
stream |
5s |
Methods
ping
Check plugin liveness and re-confirm capabilities.
Request:
{"jsonrpc":"2.0","id":1,"method":"ping"}
Response:
{"jsonrpc":"2.0","id":1,"result":{"status":"ok","version":"1.0.0","capabilities":["search","stream","get_track","get_album","get_artist"]}}
The capabilities array in the response doubles as capability re-confirmation. If a plugin initializes partially, it omits capabilities that failed to initialize.
search
Search for content matching a query string.
Request:
{"jsonrpc":"2.0","id":1,"method":"search","params":{"query":"Imagine Dragons","limit":50}}
limit is optional. Defaults to 50.
Response:
{"jsonrpc":"2.0","id":1,"result":{"results":[...]}}
Each result is a SearchResult object (see data-models.md). Results array may be empty.
get_track
Get detailed track information.
Request:
{"jsonrpc":"2.0","id":1,"method":"get_track","params":{"content_id":"plA-123"}}
Response:
{"jsonrpc":"2.0","id":1,"result":{"track":{...}}}
Response is a full Track object (see data-models.md).
Error:
{"jsonrpc":"2.0","id":1,"error":{"code":3,"message":"CONTENT_NOT_FOUND"}}
get_album
Get album metadata with track list.
Request:
{"jsonrpc":"2.0","id":1,"method":"get_album","params":{"content_id":"plA-456"}}
Response:
{"jsonrpc":"2.0","id":1,"result":{"album":{...}}}
Response is an Album object (see data-models.md). tracks field is an array of TrackStub objects — full track details are fetched via get_track.
get_artist
Get artist information.
Request:
{"jsonrpc":"2.0","id":1,"method":"get_artist","params":{"content_id":"plA-789"}}
Response:
{"jsonrpc":"2.0","id":1,"result":{"artist":{...}}}
Response is an Artist object (see data-models.md).
stream
Resolve a content ID to a streamable URL.
Request:
{"jsonrpc":"2.0","id":1,"method":"stream","params":{"content_id":"plA-123"}}
Response:
{"jsonrpc":"2.0","id":1,"result":{"url":"https://...","content_type":"audio/mpeg","duration_ms":235000,"file_size_bytes":null,"expires_at":"2026-08-01T12:00:00Z"}}
Response is a StreamInfo object (see data-models.md).
Error codes
| Code | Name | When |
|---|---|---|
| -32700 | PARSE_ERROR | Invalid JSON was received |
| -32600 | INVALID_REQUEST | The JSON sent is not a valid request object |
| -32601 | METHOD_NOT_FOUND | The method does not exist / is not supported |
| -32602 | INVALID_PARAMS | Invalid method parameter(s) |
| -32603 | INTERNAL_ERROR | Internal JSON-RPC error |
| 1 | PLUGIN_CRASHED | Plugin process exited unexpectedly before responding |
| 2 | PLUGIN_TIMEOUT | Plugin did not respond within the configured timeout |
| 3 | CONTENT_NOT_FOUND | The requested content ID does not exist in this plugin |
| 4 | UNSUPPORTED_FORMAT | The audio source format cannot be decoded |
| 5 | NOT_IMPLEMENTED | The capability is declared but not yet functional |
References
- ADR-001 (stdin/stdout IPC)
- ADR-006 (URL-only streaming)
- FR-PLUGIN-4, FR-PLUGIN-5, FR-PLUGIN-6 (functional.md)