Skip to main content
Glama

Podcast MCP

A lightweight MCP server that turns a podcast script into a finished MP3, designed to run on Render Free. Three CPU-only TTS engines, switched with TTS_ENGINE:

  • piper (Render default) — Piper TTS with rhasspy voices (~63 MB each, GPL-licensed engine). Clear voices and the only engine that fits the free 512MB instance under real load (~230 MB steady, ~370 MB peak, measured).

  • kitten (local default) — KittenTTS Nano. Small download, but onnxruntime peaks at ~550 MB during generation — gets OOM-killed on Render Free.

  • kokoro (opt-in) — Kokoro-82M via ONNX. The most natural voices; needs a paid instance.

The reasoning stays in your main app; this service only does audio:

Report App (its own LLM)
   ↓  report → HOST/GUEST dialogue script
Podcast MCP on Render
   ↓  1. parse script into speaker turns
   ↓  2. split turns into TTS-safe chunks
   ↓  3. KittenTTS generates host + guest audio
   ↓  4. merge with natural pauses → MP3
   ↓  5. serve file at /audio/<name>.mp3
returns audio_url
   ↓
Report App shows audio player

Endpoints

Path

What

POST /mcp

MCP streamable-HTTP endpoint (stateless, JSON responses)

GET /health

Health check (used by Render)

GET /audio/{filename}

Serves generated MP3/WAV files

Related MCP server: mcp-podcast-generator

MCP tools

generate_podcast_from_script

generate_podcast_from_script(
    script: str,            # "HOST: ...\nGUEST: ..." (any speaker labels work)
    title: str = "",
    host_voice: str = "",   # empty = engine default (piper: en_US-hfc_male-medium)
    guest_voice: str = "",  # empty = engine default (piper: en_US-hfc_female-medium)
    speed: float = 1.0,
)

Returns:

{
  "success": true,
  "type": "podcast",
  "title": "Q2 Business Review",
  "audio_url": "https://podcast-mcp.onrender.com/audio/q2-business-review-a1b2c3d4.mp3",
  "duration_seconds": 312.4,
  "turns": 14,
  "voices": {"HOST": "Jasper", "GUEST": "Bella"}
}

Script format (markdown decoration and [cues] are tolerated; unlabeled lines continue the previous speaker):

HOST: Welcome back to the show. Today we're looking at the Q2 results.
GUEST: Thanks for having me. The headline: revenue grew 18 percent.
HOST: Let's break that down...

generate_video_from_sections

Renders a narrated slide video (MP4): one slide per section — title, bullet points, optional PIL-drawn bar chart — shown for the length of its narration. Send the same structured media_content your LLM produces for the podcast to keep both outputs consistent:

{
  "title": "Q2 Portfolio Review",
  "sections": [
    {
      "title": "Performance",
      "narration": "Your portfolio returned 2.41 percent while the benchmark returned 3.77 percent.",
      "key_points": ["Portfolio: 2.41%", "Benchmark: 3.77%"],
      "visual": {"type": "bar_chart", "data": {"Portfolio": 2.41, "Benchmark": 3.77}}
    }
  ]
}

Call with {"sections": [...], "title": "...", "voice": "", "speed": 1.0} → returns {"success": true, "type": "video", "video_url": "...", "duration_seconds": ...}. visual.type supports bar_chart (needs data) and bullet_summary (default). Run it in parallel with the podcast tool from one shared JSON:

podcast, video = await asyncio.gather(
    session.call_tool("generate_podcast_from_script", {"script": script, "title": title}),
    session.call_tool("generate_video_from_sections", {"sections": sections, "title": title}),
)

(Note: on the single-CPU free instance the two run back-to-back internally — parallel calls are safe, just not faster.)

text_to_speech

text_to_speech(text: str, voice: str = "", speed: float = 1.0, format: str = "mp3")

list_voices

Returns the active engine, its voices, and the current defaults.

  • piper: en_US-hfc_male-medium (default host), en_US-hfc_female-medium (default guest), plus ryan/amy/lessac/joe/kristin/kusal and en_GB voices; any voice name from rhasspy/piper-voices works and is downloaded on demand.

Languages (piper engine)

Piper voices are natively trained per language (~35 languages in the rhasspy catalog) — this is real multilingual speech, not phonemization tricks. Write the script in the target language and pick voices whose locale matches:

Language

Example host / guest voices

English

en_US-hfc_male-medium / en_US-hfc_female-medium

Dutch

nl_NL-mls-medium / nl_BE-nathalie-medium

German

de_DE-thorsten-medium

French / Spanish

fr_FR-siwis-medium / es_ES-davefx-medium

Hindi

hi_IN-rohan-medium / hi_IN-priyamvada-medium

Telugu

te_IN-venkatesh-medium / te_IN-maya-medium

A voice speaks only its own language — don't mix an en_US voice with a Dutch script. Note: the kitten engine is English-only (espeak can phonemize 100+ languages, but the acoustic model is trained on English, so other languages come out garbled — don't advertise it as multilingual).

  • kokoro: 27 English voices — af_*/am_* American female/male, bf_*/bm_* British (e.g. af_heart, af_bella, am_michael, am_adam, bf_emma, bm_george).

  • kitten: Bella, Jasper, Luna, Bruno, Rosie, Hugo, Kiki, Leo.

Calling it from your report app

With the official Python MCP client:

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async def make_podcast(script: str, title: str) -> str:
    async with streamablehttp_client("https://podcast-mcp.onrender.com/mcp") as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool(
                "generate_podcast_from_script",
                {"script": script, "title": title},
            )
            return result.structuredContent["audio_url"]

Or add it to any MCP-capable agent as a remote server with URL https://<your-service>.onrender.com/mcp.

Deploy on Render (free)

  1. Push this repo to GitHub.

  2. In Render: New → Blueprint, pick the repo — render.yaml provisions a free Docker web service with /health checks.

  3. Done. RENDER_EXTERNAL_URL is used automatically to build audio_urls (override with PUBLIC_BASE_URL if you put a domain in front).

Notes for the free tier:

  • First boot downloads the two default piper voices (~126 MB) into /tmp in a background preload, so the service is healthy immediately; the first tool call may wait on it.

  • The instance sleeps after idle; the first request after a sleep takes ~1 min plus the model re-download (the disk is wiped on sleep/restart).

  • Keep TTS_ENGINE=piper on the free instance — kitten and kokoro exceed 512 MB under load and get OOM-killed (502s mid-generation). They work on paid instances.

  • Audio files live on ephemeral disk and are deleted after AUDIO_TTL_HOURS (24h default) or on restart — have your app fetch/cache the MP3 promptly if it must keep it.

Configuration (env vars)

Var

Default

Purpose

TTS_ENGINE

kitten (render.yaml sets piper)

piper (free-tier safe), kitten, or kokoro (needs paid RAM)

LOW_MEMORY_MODE

1

Disables onnxruntime's memory arena + caps threads. Set 0 on big instances for speed

TTS_PACE

0.6

Duty-cycle pacing: per-chunk sleep = chunk time × this, so health checks stay alive on 0.1-CPU instances. Set 0 on real CPUs

PIPER_MODEL_DIR

models/piper (/tmp/piper in Docker)

Where Piper voice files are cached

KOKORO_VARIANT

int8

int8 (114 MB), fp16 (164 MB), or fp32 (326 MB)

KOKORO_MODEL_DIR

models/kokoro (/tmp/kokoro in Docker)

Where Kokoro model files are cached

KITTEN_MODEL

KittenML/kitten-tts-nano-0.8

Full-precision nano (~56MB). The -int8 variant is smaller but has known quality issues

DEFAULT_HOST_VOICE / DEFAULT_GUEST_VOICE

engine defaults

Override default voices

PUBLIC_BASE_URL

RENDER_EXTERNAL_URL or localhost

Base for returned audio_url

AUDIO_DIR

audio_output (/tmp/podcast_audio in Docker)

Where files are written

AUDIO_TTL_HOURS

24

Delete generated files older than this

MAX_SCRIPT_CHARS

20000

Reject oversized scripts

PRELOAD_MODEL

1

Load the model in the background at boot

Run locally

Works with plain pip on Windows/Mac/Linux (KittenTTS 0.8.1 bundles espeak via espeakng-loader, no system packages needed):

pip install -r requirements.txt
python server.py

Then the MCP endpoint is http://localhost:8000/mcp. Or with Docker (same image Render uses):

docker build -t podcast-mcp .
docker run -p 8000:8000 podcast-mcp

Pure-logic tests (no model needed):

python test_logic.py

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vivekprojects-GIT/Podcast_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server