MCP server

A stdio Model Context Protocol server that gives AI agents the Tuneping API. It is packaged as the .NET global tool Tuneping.Mcp (command tuneping-mcp) and proxies https://api.tuneping.com/v1; every tool call is an ordinary API request under your key's quota.

Not published yetThe NuGet package is coming; this page will carry the install command. Until then there is nothing to install.

What it is

The server runs as a child process of your MCP client (Claude Desktop, Claude Code, Cursor or any other client that speaks stdio) and talks JSON-RPC on stdin and stdout. It gives the agent what internet radio stations announce as playing right now, a play history, the track and artist catalogue, and wishlists. Results are the API's JSON, unchanged.

Metadata detections, not fingerprinted airplay; about 73 % of directory stations expose a title, about half are songs.

It needs the .NET 10 runtime or later to run, and the .NET 10 SDK to install, because dotnet tool is an SDK command.

Tools and resources

ToolWhat it returnsPlan
search_now_playing(q, country?, limit?)Stations playing a title matching q right nowFree
get_station(station_id)One station by Radio Browser UUIDFree
search_stations(q, country?, tag?)Stations by name, country, tagFree
get_station_now_playing(station_id)The title one station announces nowFree
get_now_playing_batch(station_ids[])Current titles for up to 100 stations (20 without a key)Free
get_station_history(station_id, from?, to?)One station's past titlesDeveloper (10 days), Pro (30 days)
search_tracks(q)Catalogue tracks, trk_… idsFree
search_artists(q)Catalogue artists, art_… idsFree
get_track_plays(track_id, from?, to?, country?)Where and when a track was detectedDeveloper (10 days), Pro (30 days)
get_artist_airplay(artist_id, group_by, from?, to?)Plays per station, country or dayPro
create_wishlist(kind, value, station_filter?)Records detections of an artist, track or query (poll delivery)Developer
list_wishlist_matches(wishlist_id)Matches of one wishlistDeveloper
get_coverage_stats()Coverage figures of the indexFree (no key needed)
ResourceWhat it returnsPlan
tuneping://statsCoverage stats, the same body as get_coverage_statsFree (no key needed)
tuneping://station/{id}One station; now-playing stays a toolFree (no key needed)

The Free tools and both resources work without a key, limited per IP address. get_station_history and get_track_plays return at most 200 rows per call, newest first; a non-null next_cursor means older rows exist, so narrow from/to. get_artist_airplay returns up to 1,000 groups. create_wishlist is the only tool that writes, and it always uses poll delivery: an agent cannot create webhook delivery.

Ids: station ids are Radio Browser UUIDs; tracks trk_…, artists art_…, wishlists wl_…. Dates are RFC 3339 UTC (2026-11-01 or 2026-11-01T00:00:00Z), from inclusive, to exclusive.

Results of the Free tools and the resources carry an attribution member (Data by Tuneping, https://tuneping.com): show "Data by Tuneping" linking to https://tuneping.com when you display the data publicly. See attribution and fair use.

Configuration

The server reads three environment variables and nothing else.

VariableDefaultEffect
TUNEPING_API_KEYunsetOptional. Sent as Authorization: Bearer. Without it the Free tools and both resources work; the Developer and Pro tools answer 401 unauthenticated without sending a request, naming the plan that unlocks them. Keys: sign-up page.
TUNEPING_BASE_URLhttps://api.tuneping.com/v1Absolute https URL including /v1. Plain http only for a loopback host (127.0.0.1, localhost), so the key never crosses a network unencrypted.
TUNEPING_MCP_LOGWarningLog level on stderr (Warning, Information, Debug). Stdout carries JSON-RPC only; the key is never logged.

An invalid TUNEPING_BASE_URL, or a TUNEPING_API_KEY with a space or a non-ASCII character (for example the placeholder tp_live_… pasted unchanged), stops the server at start with exit code 2 and the reason on stderr. tuneping-mcp --version prints the version; it is also sent as User-Agent: tuneping-mcp/<version>.

Client setup

Claude Desktop (claude_desktop_config.json):

{ "mcpServers": { "tuneping": { "command": "tuneping-mcp", "env": { "TUNEPING_API_KEY": "tp_live_…" } } } }

macOS GUI apps do not inherit the shell PATH: use the full path /Users/<you>/.dotnet/tools/tuneping-mcp; on Windows %USERPROFILE%\.dotnet\tools\tuneping-mcp.exe. If .NET is installed outside the default location, add "DOTNET_ROOT": "/Users/<you>/.dotnet" to the env block next to the key.

Claude Code:

claude mcp add tuneping --env TUNEPING_API_KEY=tp_live_… -- tuneping-mcp

or in a project's .mcp.json. Cursor: ~/.cursor/mcp.json or .cursor/mcp.json in the project:

{ "mcpServers": { "tuneping": { "command": "tuneping-mcp", "env": { "TUNEPING_API_KEY": "tp_live_…" } } } }

Without a key, leave out env (or --env) entirely: claude mcp add tuneping -- tuneping-mcp.

Errors

API problems come back as tool errors (isError) with two lines: a summary with the API's status and code and a one-line hint, then the raw problem JSON:

403 forbidden_tier: Your tier keeps 10 days of history; `from` may not be older than 2026-10-24T09:00:00Z. Hint: Unlock with the Pro plan (30 days of history and artist airplay reports); https://tuneping.com/#pricing.
{"type":"https://tuneping.com/docs/errors/#forbidden_tier","title":"Upgrade required","status":403,…,"required_tier":"pro"}

The codes are the API's: 401 unauthenticated, 403 forbidden_tier (with required_tier) and forbidden_scope, 404 not_found, 422 validation_failed (with errors[]), 429 rate_limited / quota_exceeded, 503 unavailable. Each is described in the error catalogue. Parameters are checked before any request with the API's own error codes, so a malformed id or date costs no quota. A network failure or timeout is 0 network_error.

A missing or ill-typed required argument (q absent, or limit as a string) gives the SDK's generic An error occurred invoking '<tool>'., because it is rejected before the tool runs; check the argument names and types against tools/list.

Resources have no tool error result: they answer a JSON-RPC error instead, -32002 for an unknown station (-32602 on protocol versions that report unknown resources as invalid parameters) and -32602 for a malformed id.

Rate limits

Every tool call is one API request (a retry is a second one) and counts against the key's rate limit and quota. Without a key the limits are per IP address: 2 requests per second with bursts of 5, 1,000 per day, batches of 20 stations.

A Retry-After of at most 10 seconds on a 429 or 503 is honoured once; nothing else is retried. A spent quota (quota_exceeded) is returned at once. The one write, create_wishlist, sends an Idempotency-Key, so its retry cannot create a second wishlist.

Set TUNEPING_MCP_LOG=Debug to log every API call (method, path and query, status, request id, any Retry-After wait) to stderr; most clients show it in their MCP log.