ytscholar
A local MCP server for mining, storing, and retrieving YouTube transcripts as evidence for LLM clients.
Get transcript: fetch a single YouTube video's transcript/subtitles by URL or 11-char ID, with optional preferred languages, auto-translation, and local storage.
Research topic: search YouTube for a topic, fetch transcripts for top
max_videosresults, ingest them into the local knowledge base, and return an ingestion report plus stats.Search knowledge: run keyword/semantic search over already-learned transcripts, returning relevant passages with timestamped deep links; supports
kresults and optional topic filter.Knowledge stats: report what the agent has learned: videos, chunks, topics, and whether semantic embeddings are active.
Provides tools for researching YouTube videos by topic, fetching transcripts from video URLs or IDs, and searching an accumulated local knowledge base with timestamped deep links to the exact source moments.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ytscholar research the history of the Roman Empire"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ytscholar ππΊ
A local YouTube evidence layer (MVP). It finds the top YouTube videos on a topic, pulls their transcripts, and grows a local knowledge base β then exposes searchable, source-aware evidence and full transcripts to LLM clients, so the model can research, compare sources, and synthesize with citations you can verify by clicking.
It runs entirely on your machine: no API keys, no cloud service, no subscription. You can use it from the CLI or as an MCP server inside Claude Desktop, Cursor, Cline, or any MCP-compatible client.
Design boundary: ytscholar collects, stores, and retrieves evidence. It does not reason β no claim extraction, no summarizing, no contradiction detection. Analysis and synthesis belong to the LLM client consuming this data.
Status: MVP. The core loop β research β store β evidence retrieval with timestamped citations β works and is covered by offline tests (the network path was also validated manually against real YouTube). It is deliberately small. See Limitations for what it is not.
What it does
Research a topic. Give it a subject; it finds the top YouTube videos for it, fetches their transcripts, and ingests them into a local knowledge base.
Transcribe a link. Give it a video URL/id; it returns the full transcript (with optional machine translation).
Search what it has learned. Ask a question; it retrieves the most relevant passages from everything ever ingested, each with a deep link that opens the source video at the right moment (
https://youtu.be/VIDEO_ID?t=SECONDS).Retrieve evidence, source-aware. The same retrieval, grouped by video and channel β so a model (or you) can see whether the evidence comes from genuinely different sources or from one channel repeated.
No YouTube Data API key is required. Search uses yt-dlp; transcripts use
youtube-transcript-api with a yt-dlp caption-download fallback.
Related MCP server: mcptube-vision
Why
Fetching one transcript is a solved problem β several tools do it. ytscholar's value is the accumulation and the evidence layer: every ingest grows a persistent local knowledge base, and retrieval returns evidence with precise, clickable sources plus source-diversity analysis. An LLM client can search for evidence, judge how independent the sources are, and pull a full transcript when it needs complete context β then do the actual reasoning itself. That makes ytscholar a small "research memory" you own: a SQLite file you can back up, inspect, or delete.
Architecture
Exactly what the code does today β ytscholar ends at evidence; the LLM client does the analysis:
YouTube
β
Video Discovery yt-dlp ytsearch{N} (YouTube's own ranking);
hard cap per run (default 15); 30-day cache
β
Full Transcript youtube-transcript-api (primary)
β yt-dlp caption download + VTT parse (fallback)
β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β Full Transcript β Chunking (~900 chars; each chunk keeps β
β Storage β its start timestamp) β FTS5 index β
βββββββββββββββββββββββ΄ββββββββββββββββββββββββ¬ββββββββββββββββββββ
β
Evidence Retrieval passages + video/channel grouping
(FTS5 bm25; optional experimental re-rank)
β
LLM client analysis + synthesis β not part of
(Claude / GLM / β¦) with verifiable citations ytscholarytscholar never discards the full transcript: chunking and FTS5 exist for
retrieval; get_transcript always returns the complete stored text.
Features
Only what exists and works today:
5 CLI commands:
research,transcript,search,evidence,stats5 MCP tools over the same core:
research_topic,get_transcript,search_knowledge,search_evidence,knowledge_statsKeyword retrieval via SQLite FTS5 with bm25 ranking; optional topic filter
Evidence retrieval: passages grouped by video and channel, with
unique_channels,channel_distribution, and an independence warning (deterministic β channel variety only, no AI)Full transcripts kept in the DB and retrievable at any time
Timestamped deep links on every search/evidence hit
Per-video failure isolation β one broken video never kills a research run
Politeness rails: hard per-run video cap, delay between requests, 30-day cache (no re-fetching what it already knows)
Proxy and browser-cookie support for restricted networks (validated against a real filtered-network setup)
Clean, actionable CLI errors instead of tracebacks
Offline test suite (40 tests: URL/VTT parsing, chunking, storage, metadata merging, FTS retrieval, cache freshness, topic filter, evidence grouping, semantic re-rank plumbing, thread-safety, network timeouts) + CI on Python 3.10β3.12
Installation
The package is not on PyPI yet β install from source:
git clone https://github.com/Elahe-z/ytscholar
cd ytscholar
pip install -e . # core: CLI + MCP server, keyword (FTS5) retrievalPython 3.10+ is required. The optional [embeddings] extra is described in
Search.
Configuration
All configuration is via environment variables (no config files, no secrets in the repo):
Variable | Default | Meaning |
|
| Base dir for the knowledge DB |
|
| Preferred transcript languages, e.g. |
|
| Hard cap on videos per research call |
|
| Seconds between transcript fetches |
|
| Per-request network timeout (seconds) |
|
| Pause between HTTP requests inside one yt-dlp run (seconds); guards against bot-wall re-triggering on VPN IPs |
|
| Skip re-fetching a video seen within N days |
|
|
|
|
| sentence-transformers model |
|
| Approx chars per retrieval chunk |
| (from | Proxy for reaching YouTube |
| (from | HTTPS proxy for reaching YouTube |
| (unset) | Browser to read YouTube cookies from ( |
| (unset) | Path to an exported |
Usage
# Learn a topic from its top videos (English topics give the best ranking):
ytscholar-cli research "retrieval augmented generation" --max 5
# Ask questions about everything learned so far:
ytscholar-cli search "how does RAG reduce hallucinations"
# Evidence with source/channel analysis (human-readable):
ytscholar-cli evidence "how does RAG reduce hallucinations" --pretty
# Get one video's transcript without storing it:
ytscholar-cli transcript "https://youtu.be/VIDEO_ID" --text-only --no-store
# What does the agent know?
ytscholar-cli statsOn a network where YouTube is filtered, point the agent at your proxy first β see Restricted networks.
Tip: transcripts are usually English, so phrase search queries in English
for the best keyword matches.
Search
Search is keyword-based by default:
The query is sanitized (alphanumeric tokens only β no FTS syntax injection is possible) and turned into an OR-query of its word tokens.
SQLite FTS5 matches chunks with bm25 ranking (lower = better) over the entire knowledge base, optionally filtered by topic (exact match).
A wider candidate pool (β₯30) is fetched, ranked, and the top
kreturned.Each hit carries
video_id,title,channel,start_seconds,text,score, and alinkdeep link built from the chunk's stored start time.
Optional semantic re-rank (experimental). With
pip install "ytscholar[embeddings]" (pulls in torch, hundreds of MB) and
YTSCHOLAR_EMBEDDINGS=1, chunks are embedded at ingest time and query
vectors re-rank the FTS candidates by cosine similarity. This path is
disabled by default; without it everything works via plain keyword search.
It is still experimental: the re-rank plumbing (vector packing, the cosine
ranking, and its fallbacks) is covered by tests that inject a stand-in
embedder, but no test exercises a real sentence-transformers model, and
retrieval quality with one has not been measured.
One behaviour to know about in a mixed knowledge base: chunks stored before embeddings were enabled carry no vector, and the re-rank ranks only vectorised chunks β so older material drops out of the ranking until it is re-ingested. (If nothing in the candidate pool has a vector, search falls back to the keyword ranking intact.)
Known search limitations (see also Limitations): queries are matched as OR-ed words (no quoted-phrase support), and there is no synonym matching in keyword mode.
Evidence retrieval (v0.2)
ytscholar-cli evidence / MCP search_evidence runs the same retrieval
engine, then groups the hits so source diversity is visible:
{
"passages": [
{
"video_id": "β¦", "title": "β¦", "channel": "β¦",
"start_seconds": 763.1,
"link": "https://youtu.be/β¦?t=763",
"text": "β¦passage textβ¦", "score": 7.85
}
],
"videos": [
{ "video_id": "β¦", "title": "β¦", "channel": "β¦", "url": "β¦", "passages": 3 }
],
"unique_channels": 2,
"channel_distribution": { "Channel A": 3, "Channel B": 1 },
"total_matching_videos": 9,
"k": 6,
"independent": false,
"warning": "3 of 4 videos behind these passages come from the same channel ('Channel A'). Evidence may not be fully independent. These figures describe the top 6 passages only: 9 videos match this query in total. Raise k to judge source diversity over the full match set."
}The point: N passages do not mean N sources. If four matching videos come
from two channels β three of them from the same one β the model should know
that. independent is a deterministic channel-variety heuristic (true = no
single channel holds a strict majority of the videos behind the returned
passages); it makes no stronger epistemic claim.
The diversity figures describe the top-k window, not the whole knowledge
base. Grouping runs over the k passages actually returned, so a small k
can make a diverse match set look concentrated (or the reverse).
total_matching_videos reports how many videos match the query in total; when
it exceeds the number of videos listed, the warning says so and raising k
gives a fuller picture. Typical model workflow:
search_evidence(query) β judge sources β get_transcript(video_id) for any
source that needs full context β synthesize with citations.
Research
research_topic(topic, max_videos) does exactly this, in order:
Clamps the video count to
min(max_videos, YTSCHOLAR_MAX_VIDEOS).Searches YouTube via
yt-dlp(ytsearchN, flat metadata) β the order is YouTube's own relevance ranking.For each result: if the video was fetched within the cache TTL (default 30 days), it is marked
cachedand skipped β no re-download.Otherwise the transcript is fetched (primary API, then yt-dlp fallback), chunked (~900 chars, timestamps preserved), and stored under that topic.
A short polite delay runs between videos.
One video failing (no captions, network error) only marks that video
no_transcript/errorwith the reason β the run continues.Returns a per-video report plus overall knowledge-base stats.
Statuses you will see: ingested, cached, no_transcript, error.
Storage / Memory
Single SQLite database:
~/.ytscholar/knowledge.db(override the location withYTSCHOLAR_HOME).Tables:
videos(metadata + full transcript text +fetched_at) andchunks(text, start time, optional embedding), plus an FTS5 full-text index kept in sync by triggers. WAL mode for safe concurrent reads.The DB is the agent's memory: it persists across sessions, it is safe to copy/back up, and deleting it resets what the agent knows.
It lives outside the repository β no personal data ships with the code.
MCP
An MCP server over stdio ships with the package (ytscholar command). Same
five operations as the CLI, for use inside Claude Desktop, Cursor, Cline, β¦
(research_topic, get_transcript, search_knowledge, search_evidence,
knowledge_stats). Designed for the model workflow:
research_topic to ingest β search_evidence to find evidence and judge
source diversity β get_transcript(video_id) when full context is needed β
the model does the analysis and synthesis.
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"ytscholar": {
"command": "ytscholar",
"env": {
"YTSCHOLAR_DEFAULT_LANGS": "en",
"YTSCHOLAR_HTTPS_PROXY": "http://127.0.0.1:12334"
}
}
}
}Cursor (~/.cursor/mcp.json):
{ "mcpServers": { "ytscholar": { "command": "ytscholar" } } }If ytscholar is not on the client's PATH, use the absolute path
(which ytscholar) or "command": "python", "args": ["-m", "ytscholar.server"].
Example prompts once connected: "Research 'retrieval augmented generation' from the top 5 YouTube videos", then "From what you've learned, how does re-ranking improve RAG?" β answers come with timestamped citations.
Limitations
Honest list for this MVP:
Keyword search only (by default): OR-ed word tokens, no phrase support, no synonyms. English queries against English transcripts work well; Persian queries won't match English content.
Semantic re-rank is experimental β implemented and off by default. Its plumbing is tested with a stand-in embedder, but no real model is exercised and retrieval quality is unmeasured.
independentin evidence retrieval is a heuristic: it reflects channel variety only (same-creator concentration), not true epistemic independence β two channels may still repeat the same primary source. It is also computed over thekreturned passages, not the full match set; seetotal_matching_videos.get_transcriptreturns the full transcript text; for very long videos this is a large payload for an LLM context.A single-video
transcriptlooks the real title/channel up viayt-dlp(one extra request, only when storing). If that lookup fails it stores the video with no title rather than guessing β and never overwrites metadata a previous richer ingest already recorded.The
topicfilter is an exact, case-sensitive match on the string passed toresearch.Ingest relies on scraping (
yt-dlp/youtube-transcript-api): YouTube layout changes or IP blocks can break it. Cookies/proxy options mitigate.Video selection trusts YouTube's ranking as-is: no duration, language, or caption-availability filtering up front.
Roadmap
Not implemented β kept deliberately out of this MVP:
Claim extraction, contradiction detection, source lineage, evidence graphs (these are the LLM client's job; future versions may assist with them)
Quoted-phrase queries and per-video diversity in search results
Transcript length caps for LLM consumption
Validate the embeddings path against a real model (quality, not just plumbing) and make semantic mode first-class
Optional tiny HTTP API over the same core, for workflow tools (n8n etc.)
Publish to PyPI (
pip install ytscholar)
Restricted networks (Iran and similar)
If pip install fails with No matching distribution found, your network is
blocking pypi.org. Point pip at a local mirror:
pip install -e . -i https://mirror-pypi.runflare.com/simple/ \
--trusted-host mirror-pypi.runflare.comTo reach YouTube itself, run your VPN/proxy and point the agent at it:
export YTSCHOLAR_HTTPS_PROXY="http://127.0.0.1:PORT"
ytscholar-cli transcript "https://youtu.be/VIDEO_ID" --text-onlyHiddify users: the local mixed (HTTP+SOCKS) port is 12334 once the core is connected, so:
export YTSCHOLAR_HTTPS_PROXY=http://127.0.0.1:12334(Ports like17078belong to the app itself, not the proxy β they refuse connections.)
If YouTube answers IpBlocked / "Sign in to confirm you're not a bot"
(common on VPN/datacenter IPs), pass your browser's cookies:
export YTSCHOLAR_COOKIES_FROM_BROWSER="firefox" # or chrome / brave / edgeIf your YouTube login lives in a non-default Chrome profile, name it:
YTSCHOLAR_COOKIES_FROM_BROWSER="chrome:Profile 10". On Linux, reading
Chrome cookies additionally needs pip install secretstorage in the same
environment. (Cookies apply to the yt-dlp paths β search and the caption
fallback β which is exactly what unblocks mining when the primary API is
rate-limited.)
Or export a cookies.txt (browser extension) and set
YTSCHOLAR_COOKIES_FILE=/path/to/cookies.txt.
Development
pip install -e ".[dev]"
pytest -q # 40 offline tests β no network, no heavy deps neededCI (.github/workflows/ci.yml) runs this suite on Python 3.10β3.12 for every
push and pull request.
License
MIT β see LICENSE.
Available Tools
4 toolsget_transcriptA
Return the transcript/subtitles for a single YouTube video.
Args: video: A YouTube URL or an 11-character video id. languages: Optional comma-separated preferred languages in priority order, e.g. "en" or "fa,en". Empty = server default. translate_to: Optional target language code to auto-translate the transcript into (uses YouTube's translation), e.g. "en". store: If true (default), also add this transcript to the local knowledge base so future searches can draw on it.
Returns a dict with the plain-text transcript, language, and metadata.
Inputs: video (required), store, languages, translate_to.
knowledge_statsA
Report what the agent has learned so far: videos, chunks, topics, and whether semantic embeddings are active. Useful to check memory state.
Inputs: no named parameters.
research_topicA
Research a topic by mining the transcripts of the top YouTube videos.
Searches YouTube for the topic, takes the top max_videos results, pulls
each transcript, and ingests them into the agent's growing knowledge base.
This is how the agent "learns" a subject. Use search_knowledge afterward
to ask questions grounded in what was ingested.
Args: topic: The subject to research, e.g. "retrieval augmented generation". max_videos: How many top videos to mine (capped by server config). languages: Optional comma-separated preferred transcript languages.
Returns a per-video ingestion report plus updated knowledge-base stats.
Inputs: topic (required), languages, max_videos.
search_knowledgeA
Semantic/keyword search over everything the agent has already learned.
Retrieves the most relevant transcript passages from the local knowledge base, each with a deep link that opens the source video at the exact timestamp. Answer the user's question using these passages as evidence.
Args: query: Natural-language question or keywords. k: Number of passages to return. topic: Optional filter to a topic previously passed to research_topic.
Inputs: query (required), k, topic.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelogβ¦
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: fetching transcripts, researching a topic (which itself uses transcripts), searching the knowledge base, and reporting stats. Even though research_topic uses get_transcript internally, their high-level functions are unambiguous.
All tools follow a verb_noun pattern: get_transcript, research_topic, search_knowledge, knowledge_stats. The pattern is consistent, though 'research_topic' and 'knowledge_stats' are slightly less uniform than 'get_' or 'search_' prefixes, but still readable.
With only 4 tools, the set is lean and well-scoped for a YouTube transcript knowledge-base server. Each tool is essential: ingestion (get_transcript), bulk learning (research_topic), retrieval (search_knowledge), and monitoring (knowledge_stats). No bloat.
The core workflow of ingest, research, search, and stats is covered. Minor gaps include lack of a tool to delete knowledge or list all topics explicitly, but these are not critical for the primary use case of learning and querying.
Maintenance
Related MCP Connectors
Transcribe YouTube via Whisper. Summaries, chapters, semantic-search across your corpus.
Personal YouTube AI knowledge base powered by RAG. Query your subscribed YouTube channels.
Search and query the transcripts of YouTube expert channels you follow, with cited answers.
YouTube transcripts, search, channel/playlist listings and upload tracking for AI agents.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceBuilds a searchable knowledge base from YouTube video transcripts with hybrid semantic and keyword search. Allows LLM assistants to search, organize, and retrieve timestamped information from videos you've watched.3-
- AlicenseNot gradedqualityDmaintenanceTransforms YouTube videos into a persistent, structured knowledge base using transcripts and visual frame analysis, enabling knowledge compounding and natural language querying.165MIT
- FlicenseNot gradedqualityDmaintenanceFetches YouTube transcripts and enables semantic search within them using local embeddings, allowing an LLM to retrieve relevant passages with timestamps.-
- FlicenseNot gradedqualityAmaintenanceEnables users to ingest YouTube videos into a persistent, cross-referenced knowledge base by extracting transcripts, analyzing scene-change frames with vision models, and providing agentic search and cited answers through MCP clients like Claude and Copilot.-