Hey, thank you for putting this together and sharing it publicly — digging into it and trying to get transcripts working was a genuinely interesting MCP server learning experience for me. Unfortunately I wasn't able to get get_transcript working in my own testing, so I wanted to share what I found in case it's useful to you or anyone else running into the same thing.
Claude's Assessment: This report was investigated and together with Claude
get_transcript silently returns empty text for every video
What I found
get_transcript currently returns an empty string for every video I tried, with no error surfaced anywhere — the server responds 200 OK, so nothing looks broken from the outside, but the transcript field is blank.
What seems to be causing it
src/lib/youtube.ts uses the youtube-transcript npm package (v1.2.1), which scrapes the video's watch page for a captionTracks list, then fetches the transcript text from a signed URL embedded there.
Digging into that signed URL, it now has an IP binding baked into its signature:
https://www.youtube.com/api/timedtext?v=...&ip=0.0.0.0&ipbits=0&...&sparams=ip,ipbits,expire,...&signature=...
My read is: when the request isn't coming from what YouTube considers a genuine browser session, it issues the URL pre-signed against a dummy 0.0.0.0 address. The follow-up fetch to that URL still returns 200 OK, but with an empty body — no error, just silently no captions. I confirmed this by fetching the signed URL directly across multiple videos and multiple fmt= variants (json3, vtt, srv1, srv3); none returned content, and adding Referer/Origin/cookie headers to mimic a browser didn't change the outcome either.
My best guess is this is YouTube hardening against unofficial scraping generally (cloud/datacenter IP ranges — AWS, GCP, Azure, and by extension Cloudflare Workers — are commonly blocked/degraded this way), rather than anything specific to this repo's request shape — but I can't say that with certainty.
What I tried next
In my own fork, I swapped youtube-transcript for youtubei.js (calls YouTube's internal InnerTube API instead of scraping the page). That resolved the specific issue above — video metadata and caption-track listing worked fine — but info.getTranscript() then hit a hard 400 from YouTube's get_transcript endpoint specifically, across all client contexts I tested (WEB/IOS/TV/ANDROID). My guess is that endpoint now needs a PoToken (proof-of-origin token), which looks like a substantially bigger fix (BotGuard attestation) than a library swap, and seems to be an open problem across the wider YouTube-scraping ecosystem right now rather than something unique to this repo.
I'm happy to share the diff for the youtubei.js swap if it's useful as a starting point, even though it doesn't fully resolve things on its own — it at least turns "silently returns wrong data" into a clear thrown error.
To reproduce
curl -X POST https://<your-worker>/mcp -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"get_transcript","arguments":{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ","language":"en"}}
}'
Returns 200 OK with result.content[0].text empty.
Hey, thank you for putting this together and sharing it publicly — digging into it and trying to get transcripts working was a genuinely interesting MCP server learning experience for me. Unfortunately I wasn't able to get
get_transcriptworking in my own testing, so I wanted to share what I found in case it's useful to you or anyone else running into the same thing.Claude's Assessment: This report was investigated and together with Claude