Skip to main content

MCP Radio (mcp-radio.js)

An MCP (Model Context Protocol) stdio server that lets any AI agent — Claude, opencode, Cursor, etc. — control the whole radio station over its HTTP /api/station/* API. Zero runtime dependencies; runs on plain Node.js.

Running it

node mcp-radio.js # or: npm run mcp

load-env.js (zero-dep) loads <module dir>/.env into process.env (existing env wins) at the top of both mcp-radio.js and ai-providers.js. The file ships with all provider vars commented; STATION_URL / STATION_KEY also live there.

Registering with opencode (verified 2026-08-07)

Add to your project opencode.json (project scope; restart opencode to load):

{
"mcp": {
"loklok-radio": {
"type": "local",
"command": ["node", "mcp-radio.js"]
}
}
}

Verified end-to-end: initializetools/list (28 tools) → station_statusping all pass; injecting OPENAI_API_KEY into .env flips ai_list_providers configured:false→true and ai_chat reaches the provider's real API.

Connection settings

Read from env (or station-ai.json, the AI config file shared with ai-providers.js):

EnvDefaultMeaning
STATION_URLhttp://127.0.0.1:5000The running server.js
STATION_KEY''Must match the server's STATION_KEY, if any (MCP passes x-station-key when set)

Server auth is optionalSTATION_KEY unset = open routes.

AI providers (ai-providers.js)

Zero-dep multi-provider LLM client: openai, anthropic, gemini, groq, openrouter, deepseek, xai, cohere, together, fireworks, perplexity, cerebras. Key resolution: env <PROVIDER>_API_KEYAI_API_KEYstation-ai.json (AI_CONFIG_PATH). station-ai.json is a full 12-provider template with empty apiKey placeholders + stationUrl/stationKey; its config is TTL-cached (5s) so filling in a key applies to a running MCP server without a restart. Exposes chat() + listProviders().

Tools

ToolAction
station_statusFull live snapshot (now playing, queue, rotation, decks, genre split, weights, dayparts, singers, queries, mood) — always call first
set_genre_splitSet ARABIC_HITS / EGYPTIAN_TRENDS / ARAB_TECHNO / ENGLISH probabilities (relative, need not sum to 1), persisted
set_weightsMASHUP_CHANCE, STOCHASTIC_SFX_CHANCE
set_rotationBUFFER_MAX, REFRESH_FRACTION, MUSIC_FRESH_MS, ELEMENT_COOLDOWN, COOLDOWN_PERIOD
set_dayparts / clear_daypartsReplace/clear custom time-of-day windows ({start,end,hard?,weights?}, wraps when start>end)
set_moodPreset (`chill
set_configGeneric deep patch of the scheduler config
list_singers / set_singersCurated singer catalogs per category (mode `replace
set_queriesTrend-search fallback queries per category
fetch_contentTargeted download for a category ({category,target,kind}; shorts → TikTok transcoder)
scrub_contentArchive junk (award shows, lyric videos, news…) from a deck
live_status / live_register / live_remove / live_vote / live_start / live_stopFull live-broadcast control (rank, vote, take the channel live, return to mix)
refresh_contentFull refresh (all categories + sweepers/sfx/mashups + rotation rebuild/push)
rebuild_rotation / skip_track / force_playRotate / skip / force a category to the head
save_config / reset_configPersist current config / wipe station-config.json
station_logTail content or server log
ai_list_providers / ai_chatMulti-provider LLM calls (OpenAI, Anthropic, Gemini, Groq, OpenRouter, DeepSeek, xAI, Cohere, Together, Fireworks, Perplexity, Cerebras…) via ai-providers.js

Protocol

MCP stdio = newline-delimited JSON-RPC 2.0. Implements initialize, ping, resources/list, tools/list, tools/call.

See also