Synara MCP (listen history)
Synara exposes a read-only Model Context Protocol server so an AI assistant can query a user's listening history in detail: raw listens, top lists, timelines, summaries and the dashboard statistics. Nothing exposed over MCP can modify data.
Endpoint
| Item | Value |
|---|---|
| URL | POST /mcp on the Synara server |
| Transport | Streamable HTTP, stateless (every request is authenticated on its own) |
| Body | JSON-RPC 2.0 (Content-Type: application/json) |
| Accept | application/json, text/event-stream |
GET and DELETE on /mcp answer 405; there is no long-lived session and no Mcp-Session-Id header.
Authentication
Create an API key with the mcp scope (through the API key settings of any client, or IApiKeyService.createApiKey(label, ["mcp"])). Send it with every request as one of
Authorization: Bearer <key>X-API-Key: <key>?apiKey=<key>
Requests without a valid key that carries the mcp scope get 401. All tools only ever return data belonging to the key's user.
Claude Code
claude mcp add --transport http synara https://your-server/mcp --header "Authorization: Bearer synara_..."
Claude Desktop / other clients
Add a remote MCP server with the URL https://your-server/mcp and a custom Authorization: Bearer synara_... header.
Conventions
- Time inputs accept ISO-8601 (
2024-03-01,2024-03-01T12:00:00Z,2024-03-01T12:00interpreted intimezone) or epoch milliseconds. - Time outputs are objects
{ "epochMs": 1709294400000, "iso": "2024-03-01T13:00:00+01:00" }. timezoneis an IANA zone name (Europe/Berlin) and defaults to UTC. It controls day, week and month boundaries and the ISO output offset.fromis inclusive,tois exclusive; both are optional (open-ended).- Ids are the library's song, artist and album UUIDs. Use
search_libraryto resolve names to ids. - Listens imported from ListenBrainz that could not be matched to a library song are still included. They carry
unmatchedmetadata (track, artist and release names plus MusicBrainz ids) instead ofsong, and appear in top lists withmatched: falseand noid. - Every tool is annotated
readOnlyHint = trueandidempotentHint = true.
Tools
search_library
Resolve names to library ids.
| Parameter | Type | Default | Notes |
|---|---|---|---|
query |
string (required) | Free-text search | |
types |
array of songs, artists, albums |
all | |
limit |
integer 1..50 | 10 | Per type |
Returns { songs: [...], artists: [{ id, name }], albums: [{ id, name }] }. Songs contain id, title, artists, album, durationMs, releaseDate, genres, isrc, recordingMbid, explicit.
get_listens
Raw listens, newest first, keyset-paginated.
| Parameter | Type | Default |
|---|---|---|
from, to |
time | open |
limit |
integer 1..1000 | 100 |
cursor |
string from a previous page | |
songId, artistId, albumId |
uuid | |
source |
LOCAL or LISTENBRAINZ |
both |
qualifiedOnly |
boolean | false |
timezone |
IANA zone | UTC |
Returns { listens: [...], nextCursor, hasMore }. Each listen has id, listenedAt, msPlayed (raw client report, may be null), playedMs (effective played duration), qualified (counts as a full play: at least three minutes or half the song, and always when no play time was reported), source, and either song or unmatched.
get_listening_summary
Totals for a window, optionally scoped to one song, artist or album.
| Parameter | Type | Default |
|---|---|---|
from, to |
time | open |
songId, artistId, albumId |
uuid | |
timezone |
IANA zone | UTC |
Returns listenCount, listenedMs, uniqueSongs, uniqueArtists, uniqueAlbums, firstListen, lastListen, hourOfDay (24 counts, local time), dayOfWeek (7 counts, Monday first) and daysWithListens.
get_top
Ranked songs, artists or albums for a window.
| Parameter | Type | Default |
|---|---|---|
kind |
songs, artists, albums (required) |
|
from, to |
time | open |
limit |
integer 1..200 | 20 |
offset |
integer | 0 |
orderBy |
listenCount or listenedMs |
listenCount |
artistId, albumId |
uuid (scope the ranking) | |
timezone |
IANA zone | UTC |
Returns { kind, orderBy, offset, limit, total, entries } where each entry has rank, matched, id, name, artistName, albumName, mbid, listenCount, listenedMs, firstListen, lastListen.
get_listen_timeline
Listen counts per bucket.
| Parameter | Type | Default |
|---|---|---|
bucket |
hour, day, week, month, year (required) |
|
from, to |
time | open |
songId, artistId, albumId |
uuid | |
timezone |
IANA zone | UTC |
Buckets are aligned to local boundaries in timezone (weeks start on Monday) and empty buckets inside the range are included. A request that would produce more than 2000 buckets returns an error; narrow the window or use a coarser bucket.
get_listening_stats
The same aggregate the clients' statistics page shows: listen count with previous-period comparison, top songs, artists and albums, listen clock, streaks and new discoveries.
| Parameter | Type | Default |
|---|---|---|
range |
DAY, WEEK, LAST_WEEK, MONTH, LAST_MONTH, YEAR, LAST_YEAR, ALL_TIME (required) |
|
timezone |
IANA zone | UTC |
topLimit |
integer 1..100 | 10 |
topOrder |
LISTEN_COUNT or LISTENED_MS |
LISTEN_COUNT |
For arbitrary windows combine get_listening_summary, get_top and get_listen_timeline.
get_now_playing
No parameters. Returns the song the user is currently playing with startedAt, positionMs and playing, or null.
Example
curl -s https://your-server/mcp \
-H "Authorization: Bearer synara_..." \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_top","arguments":{"kind":"artists","from":"2024-01-01","to":"2025-01-01","limit":5,"timezone":"Europe/Berlin"}}}'