Skip to main content
Glama
AlonDrilich

internet-radio-mcp

by AlonDrilich

internet-radio-mcp

An open-source Model Context Protocol (MCP) server for internet radio. It lets Claude, Cursor, VS Code Copilot and other MCP clients search radio stations worldwide and get their direct stream URLs. It also lists top and trending stations, countries and genres.

The station data comes from Radio Browser, a community-maintained, public-domain directory with over 50,000 stations that have working streams. The server is built by 72FM, a free web radio player built on the same directory. Every result includes a listen_url that plays the station in the browser on 72FM, as well as the station's own stream_url.

Stations belong to their broadcasters. Neither 72FM nor this server owns, operates or curates them. Anyone can add or edit entries in the directory, so a stream can occasionally be offline.

  • No API key, no account, read-only.

  • 5 tools, 1 prompt, stdio transport.

  • Runtime dependencies: @modelcontextprotocol/server (the official MCP TypeScript SDK, v2) and zod.

Example questions

  • "Find jazz stations in Brazil"

  • "What are the most popular stations in Japan?"

  • "Give me the stream URL for BBC World Service"

  • "What's trending on internet radio right now?"

  • "Which countries have the most radio stations?"

  • "What genres can I search for? Then find me some lofi stations."

Related MCP server: radio-browser-mcp

Install

Requires Node.js 20 or newer. The server runs straight from GitHub with npx, so there is nothing to install globally.

Claude Code

claude mcp add internet-radio -- npx -y github:AlonDrilich/internet-radio-mcp

Then run /mcp in a session to confirm that internet-radio is connected.

Claude Desktop

Open Settings → Developer → Edit Config. This opens claude_desktop_config.json: on macOS it is at ~/Library/Application Support/Claude/claude_desktop_config.json, and on Windows at %APPDATA%\Claude\claude_desktop_config.json. Add:

{
  "mcpServers": {
    "internet-radio": {
      "command": "npx",
      "args": ["-y", "github:AlonDrilich/internet-radio-mcp"]
    }
  }
}

Restart Claude Desktop.

Cursor

Add the server to ~/.cursor/mcp.json to use it everywhere, or to .cursor/mcp.json to use it in one project:

{
  "mcpServers": {
    "internet-radio": {
      "command": "npx",
      "args": ["-y", "github:AlonDrilich/internet-radio-mcp"]
    }
  }
}

VS Code (GitHub Copilot, Agent mode)

Add the server to .vscode/mcp.json, or run MCP: Add Server from the Command Palette:

{
  "servers": {
    "internet-radio": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "github:AlonDrilich/internet-radio-mcp"]
    }
  }
}

Other clients

Any MCP client that can launch a stdio server can use the same command: npx -y github:AlonDrilich/internet-radio-mcp.

The first launch downloads the package from GitHub, which takes a few seconds. Later launches use the npx cache.

Tools

All tools are read-only and annotated with readOnlyHint: true and openWorldHint: true. Each result contains:

  • a one-line summary,

  • the same data as JSON text,

  • structuredContent that matches the tool's outputSchema.

Broken streams (streams that failed the directory's last automated check) are excluded from searches.

Tool

Arguments

Returns

search_stations

name?, tag? (genre), countrycode? (ISO 3166-1 alpha-2, e.g. BR), language? (e.g. portuguese), order = votes | clickcount | bitrate (default votes), limit 1–50 (default 10)

Matching stations

get_station

id (Radio Browser stationuuid)

One station

top_stations

by = votes | clicks | trending (default votes), countrycode?, tag?, limit 1–50 (default 10)

Most voted, most played, or trending stations

list_countries

min_stations? (default 1), limit?

Country name, ISO code, station count and 72FM country page (https://72fm.com/radio/<iso2>)

list_genres

limit 1–100 (default 30)

Top genre tags by station count. Placeholder and non-genre tags are filtered out (e.g. undefined, radio, fm, and country, region or language names).

Station fields

{
  "id": "963fa65f-0601-11e8-ae97-52543be04c81",
  "name": "Antena 1 São Paulo, SP (ZYD823 94,7 MHz FM) [aac]",
  "country": "Brazil",
  "countrycode": "BR",
  "language": "portuguese",
  "tags": ["adult contemporary", "jazz", "pop", "smooth jazz"],
  "codec": "AAC+",
  "bitrate": 96,
  "homepage": "http://antena1.com.br/",
  "stream_url": "http://antena1.newradio.it/stream?ext=.mp3",
  "favicon": null,
  "votes": 33238,
  "lastcheckok": true,
  "listen_url": "https://72fm.com/station/963fa65f-0601-11e8-ae97-52543be04c81"
}
  • stream_url is the directory's resolved stream URL, or the original URL when no resolved one exists.

  • listen_url plays the station in the browser on 72FM.

  • tags holds up to 8 tags.

Prompt

find_radio(request) finds stations for a mood, place, activity or genre, for example "calm jazz for a rainy evening" or "radio from Lisbon".

Reliability

The server queries the Radio Browser mirrors in this order, with an 8-second timeout for each:

  1. de1.api.radio-browser.info

  2. de2.api.radio-browser.info

  3. all.api.radio-browser.info

If all three fail, the tool returns a clear error (isError: true) and the server keeps running. Requests identify themselves with User-Agent: internet-radio-mcp/1.0 (+https://72fm.com).

You can change this behavior with two optional environment variables:

  • RADIO_BROWSER_MIRRORS: comma-separated base URLs to use instead of the defaults.

  • RADIO_BROWSER_TIMEOUT_MS: the timeout for each mirror, in milliseconds (default 8000).

Development

git clone https://github.com/AlonDrilich/internet-radio-mcp
cd internet-radio-mcp
npm install
npm run typecheck   # tsc checkJs over the JSDoc-typed sources
npm run smoke       # spawns the server over stdio and calls every tool against the live API
npx @modelcontextprotocol/inspector node src/index.js   # interactive testing

The source is plain ES modules with JSDoc types (src/), so there is no build step. That is why npx github:… works without an npm publish.

Data and credits

  • The station directory data comes from Radio Browser and is in the public domain. Thanks to its maintainers and contributors. If you use this server heavily, please consider supporting Radio Browser.

  • Streams, names and logos belong to their respective broadcasters.

  • 72FM is a free web radio player built on the Radio Browser directory.

License

MIT © Alon Drilich (72FM)

Available Tools

5 tools
get_stationGet station detailsA
Read-onlyIdempotent

Get one radio station by its Radio Browser id (stationuuid, as returned by search_stations or top_stations), including its direct stream_url and a listen_url to play it in the browser on 72FM. Station data from the Radio Browser community directory (radio-browser.info, public domain). Stations belong to their broadcasters; 72FM does not own, operate or curate them.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesThe station id (Radio Browser stationuuid).

Output Schema

ParametersJSON Schema
NameRequiredDescription
sourceYes
stationYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, open-world behavior, so safety is covered. The description adds meaningful context beyond that: the tool surfaces a direct stream_url plus a listen_url for browser playback, and notes the data comes from a community directory. It does not discuss failure behavior for an unknown id, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first two sentences are tight and front-loaded with the retrieval purpose, the id source, and the useful return fields. The third sentence about broadcaster ownership and 72FM not curating stations is legal boilerplate that does not help an agent select or invoke the tool, so the description is somewhat larger than its job requires.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value details are not strictly required, yet the description still names the key outputs (stream_url, listen_url) and the data source. For a one-parameter idempotent lookup this is nearly complete; only error/not-found behavior is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is documented with a UUID pattern, so the baseline is already met. The description goes further by clarifying the id is a Radio Browser stationuuid obtained from sibling tools, adding provenance the schema does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource: retrieve one radio station by its Radio Browser id. It also names the sibling tools that produce that id (search_stations, top_stations), so the agent can distinguish this lookup tool from the discovery tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description tells the agent the id is 'as returned by search_stations or top_stations', which implies when this tool is the right follow-up call. It stops short of an explicit when-not-to-use statement, but the context is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_countriesList countriesA
Read-onlyIdempotent

List countries that have internet radio stations in the Radio Browser directory, with ISO 3166-1 alpha-2 codes, working-station counts, and the 72FM country page for each. Sorted by station count, highest first.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of countries to return (default: all).
min_stationsNoOnly include countries with at least this many stations.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
sourceYes
countriesYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so safety is covered. The description goes beyond that by disclosing the sort order (station count, highest first) and the fact that only countries with currently working stations are included, which is real behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single well-formed sentence that front-loads the scope (countries with stations) and closes with the ordering rule. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not explain return values, yet it usefully summarizes them anyhow. Scope, ordering, and the working-station filter are all covered; only when-to-use guidance against sibling tools is absent, which is a minor gap for a simple read-only listing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so limit and min_stations are fully documented in the schema itself. The description adds no syntax or format detail for either parameter, so the baseline 3 applies; the mention of station counts loosely relates to min_stations but adds no new semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (List) plus resource (countries) with explicit scope: only countries that have internet radio stations in the directory. It also enumerates the payload (ISO 3166-1 alpha-2 codes, working-station counts, 72FM page), which distinguishes it from siblings like search_stations and list_genres that operate on different resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The purpose implies a discovery/browse role, so an agent can infer this is the entry point for enumerating countries before filtering stations. However, it never states when to prefer this over siblings such as list_genres or search_stations, nor any prerequisite or exclusion. Usage is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_genresList popular genresA
Read-onlyIdempotent

List the most common genre/format tags in the Radio Browser directory by number of working stations. Placeholder and non-genre tags (country, region and language names, "radio", "fm", etc.) are filtered out. Use a returned name as the tag argument of search_stations or top_stations.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoNumber of genres to return (1-100, default 30).

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
genresYes
sourceYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description adds genuinely new behavioral context: results are ordered by count of working stations and placeholder/non-genre tags (country, region, language, 'radio', 'fm') are filtered out, which an agent could not infer from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: purpose first, behavioral filtering second, routing guidance last. No filler, every sentence carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A low-complexity, single-parameter read tool with full annotations and an output schema; the description covers purpose, filtering behavior, ordering, and the chaining target, leaving nothing material unexplained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single limit parameter is fully documented in the schema (1-100, default 30). The description adds no further syntax or semantics for it, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (genre/format tags in the Radio Browser directory) plus the ranking criterion (by number of working stations). The explicit filtering note distinguishes it from siblings like list_countries, which return the very country/region names this tool strips out.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit downstream usage — feed a returned name into search_stations or top_stations as the tag argument — which is strong contextual guidance. It stops short of stating when NOT to use it (e.g., use list_countries for country facets), so it is clear context without exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_stationsSearch radio stationsA
Read-onlyIdempotent

Search internet radio stations in the Radio Browser community directory by name, genre tag, country and/or language. Broken streams are excluded. Returns stream URLs plus a listen_url to play each station in the browser on 72FM. Station data from the Radio Browser community directory (radio-browser.info, public domain). Stations belong to their broadcasters; 72FM does not own, operate or curate them.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoGenre or format tag, e.g. "jazz", "classical", "news", "lofi". See list_genres.
nameNoPart of the station name, e.g. "BBC World Service" or "jazz fm".
limitNoMaximum number of stations to return (1-50, default 10).
orderNoSort order, highest first: votes (community votes, default), clickcount (recent plays), bitrate.votes
languageNoBroadcast language in English, lowercase works best, e.g. "portuguese", "japanese".
countrycodeNoTwo-letter ISO 3166-1 alpha-2 country code, e.g. "BR" for Brazil, "JP" for Japan. See list_countries.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
sourceYes
stationsYes

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds genuinely non-structured behavior: broken streams are filtered out, results include stream URLs plus a browser listen_url, and the data provenance/licensing caveat. It does not mention rate limits or result stability, keeping it out of 5 territory.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core capability is front-loaded in the first sentence and the practical behavior (broken streams excluded, listen_url) follows. The final two sentences of provenance/ownership boilerplate are useful for trust but are not strictly about invocation, making it slightly longer than necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not detail return fields, and it correctly avoids that. Combined with 100% schema coverage and full annotation coverage, an agent has what it needs to call the tool, though filter-combination semantics and pagination/result-size behavior remain unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all six parameters (tag, name, limit, order, language, countrycode) are already documented in the schema with examples and constraints. The description only restates the filter dimensions generically and adds no syntax, defaults, or combination semantics beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Search) and resource (internet radio stations) plus the filter dimensions and the data source (Radio Browser community directory). It is immediately distinguishable from get_station and top_stations by implication, but never names or contrasts those siblings explicitly, which is what a 5 would require.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The filter axes ('by name, genre tag, country and/or language') imply when the tool is useful, and the schema points to list_genres/list_countries for discovering valid values. However, there is no explicit when-to-use versus get_station or top_stations, no statement of how filters combine (AND vs OR), and no guidance on empty results.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

top_stationsTop radio stationsA
Read-onlyIdempotent

List the most popular internet radio stations: by community votes, by recent clicks (plays), or trending (rising click trend). Optionally limit to one country and/or genre tag. Broken streams are excluded. Station data from the Radio Browser community directory (radio-browser.info, public domain). Stations belong to their broadcasters; 72FM does not own, operate or curate them.

ParametersJSON Schema
NameRequiredDescriptionDefault
byNovotes = most voted (default); clicks = most played recently; trending = biggest recent click trend.votes
tagNoOptional genre tag, e.g. "rock".
limitNoMaximum number of stations to return (1-50, default 10).
countrycodeNoTwo-letter ISO 3166-1 alpha-2 country code, e.g. "BR" for Brazil, "JP" for Japan. See list_countries.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
sourceYes
stationsYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/openWorld/destructive=false, so the safety profile is covered. The description adds real behavioral value: broken streams are excluded, results come from the Radio Browser community directory, and ranking options are explained. This goes beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and ranking modes are front-loaded in the first sentence, and filtering and exclusion behavior follow logically. The closing sentences on data provenance and broadcaster ownership are somewhat tangential to tool selection, but the overall structure remains tight and readable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return-value explanation is unnecessary, and the description covers ranking semantics, optional filters, and stream-quality behavior. An agent has enough to invoke it correctly; only explicit sibling routing is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters (by, tag, limit, countrycode) are already documented in the schema, including the enum meanings and ISO code pattern. The description restates the optional country/genre filtering without adding syntax or format detail beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('List the most popular internet radio stations') and enumerates the three ranking modes. It is clearly distinguishable from siblings like search_stations and get_station, which would serve different intents.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use it (to browse popularity-ranked stations) and clarifies the three ranking modes, but it never names an alternative such as search_stations or states when this tool is the wrong choice. Usage is inferable rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv1.0.0
    • First observedget_station
    • First observedlist_countries
    • First observedlist_genres
    • First observedsearch_stations
    • First observedtop_stations

TDQS

A4.1/5.0

Scored across 5 tools

Disambiguation5/5

Each tool targets a distinct discovery intent: search_stations (filtered search), get_station (single lookup by id), top_stations (popularity ranking), list_countries and list_genres (metadata enumerations). search_stations and top_stations both return stations but are cleanly differentiated by filtering vs. popularity ranking, and the descriptions reinforce this.

Naming Consistency4/5

Four of five names follow a verb_noun pattern (search_stations, get_station, list_countries, list_genres), which is highly predictable. top_stations deviates by dropping the verb, but it remains readable and idiomatic, so the deviation is minor.

Tool Count5/5

Five tools is well-scoped for a read-only radio directory: search, retrieve, rank, and two metadata enumerations. Every tool earns its place and there is no redundancy or bloat.

Completeness4/5

The surface covers the core discovery lifecycle: find stations by multiple facets, fetch one by id, rank by popularity, and enumerate the country/genre facets that drive search. Minor gaps exist (e.g., no bitrate/codec filtering, no pagination or advanced query options), but these are workable around.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Internet radio for Claude and your terminal with ~25,000 verified live stations from 197 countries. Control playback, search, and get recommendations through natural language.
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    MCP server that enables natural language control of internet radio from Claude Code, with access to 30,000+ global stations, auto-playback via mpv, and a real-time status line with audio spectrum visualization.
    7
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Internet radio + AI DJ for Claude. 55,000+ stations across 197 countries. Search, play, and get recommendations through natural language.
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that wraps the Radio Browser API to search radio stations, list countries, and discover genres. Enables AI agents to find and browse radio stations without authentication.
    0
    MIT