youtube-mcp-cli
AGENTS.md0 starsChanged 14 days agoMITView on GitHub
A YouTube MCP server and CLI: transcripts, research, comments, analytics and channel management, as MCP tools and as shell commands. TypeScript, Node 22+, ESM, built on Slipway. Published as @thenavidm/youtube-mcp-cli, with two binaries on one file: youtube-mcp (the server) and youtube-cli (the commands). stdio and streamable HTTP. Tests run against fakes, never the network. One array, two surfaces. tools/index.ts exports ALL_TOOLS, and Slipway turns each into an MCP tool and a command, through the same handler and the same guard.…
The file
Files
Working on youtube-mcp-cli
A YouTube MCP server and CLI: transcripts, research, comments, analytics and channel management, as MCP tools and as shell commands.
Shape
TypeScript, Node 22+, ESM, built on Slipway. Published as @thenavidm/youtube-mcp-cli, with two
binaries on one file: youtube-mcp (the server) and youtube-cli (the
commands). stdio and streamable HTTP. Tests run against fakes, never the network.
src/
index.ts entry for both binaries: turns on the compile cache, starts the app
app.ts the Slipway app: tools, settings, login, logout, doctor. Slipway
serves MCP, the CLI and --http, and owns the guard, approvals,
annotations and the audit log
guide.ts the server instructions
config.ts env plus the saved channels into settings and accounts
auth.ts login (OAuth, saved per channel) and logout
doctor.ts reports each credential layer separately
accounts/store.ts the encrypted channel file in ~/.youtube-mcp-cli
youtube/ API client, transcripts, the yt-dlp transport
tools/ kit.ts adapts them to Slipway and maps errors to exit codes,
index.ts is ALL_TOOLS, one module per group
scripts/check-counts.mjs fails when a document's tool count disagrees with the serverThe things worth knowing before changing anything
One array, two surfaces. tools/index.ts exports ALL_TOOLS, and Slipway
turns each into an MCP tool and a command, through the same handler and the same
guard. Add a tool to the array and it is a command too. Never describe a tool a
second time.
Exit codes are the house contract: 0 ok, 1 unexpected, 2 usage or a refused
write, 3 not found, 4 auth, 5 API, 7 rate limited, 10 nothing configured.
tools/kit.ts decides which a YouTube failure is: a used-up quota is 7 even as
a 403, a missing transcript, channel or video is 3, and a plain failure from
Google or yt-dlp is 5.
Read-only removes tools rather than refusing them. Slipway leaves every
write off both surfaces when YOUTUBE_READ_ONLY=1. A model cannot misuse a tool
it cannot see.
Approval goes on irreversible tools only. Currently reply_to_comment and
delete_video. Not on update_video. The test is whether the user could undo
it from youtube.com in one action. Over MCP a person approves each where the
client can ask; the refusal says --confirm in a terminal and confirm: true
through MCP.
Channels come from env and from the store. config.ts reads
YOUTUBE_ACCOUNTS or YOUTUBE_REFRESH_TOKEN, then every channel saved by
youtube-cli login, with env winning on a clashing id. Each saved channel keeps
its own OAuth client, because a refresh token only works with the client that
issued it. Tests point YOUTUBE_MCP_HOME at a scratch directory so a real login
on the machine never leaks in.
Transcripts do not use the Captions API. That one needs OAuth and channel
ownership, so it only ever reads your own videos. The track list is scraped from
the watch page, and the track body comes through yt-dlp, because YouTube began
answering the track URL with 200 and an empty body during 2026 unless the request
carries a proof-of-origin token. If transcripts break, check whether the watch
page shape moved before assuming yt-dlp is at fault.
Both OAuth client spellings are read. YOUTUBE_CLIENT_ID and
YOUTUBE_OAUTH_CLIENT_ID, same for the secret. Accepting one and ignoring the
other produces unauthorized_client, which is indistinguishable from a revoked
grant. There is a test for this.
Multi-account refuses rather than defaults. With two or more channels
connected and no account passed, resolveAccount throws and names the
choices. Do not add a fallback to the first one.
Missing setup is not a 401. A call with nothing configured throws a plain error containing "is configured", which the CLI maps to exit 10. A real 401 from Google maps to 4. Keep them apart: they need opposite fixes.
Before you say it works
npm run typecheck && npm run build && npm test && npm run check:counts
npx @modelcontextprotocol/inspector node dist/index.jsThen the binary itself: youtube-cli bare, one --help, one real read such as
youtube-cli list-transcript-languages dQw4w9WgXcQ, a missing argument (exits
2) and nothing configured (exits 10). A green suite says nothing about whether
the server starts and lists its tools.
Setup steps in INSTALL.md come from Google's live documentation, not memory.
The console was reorganized into Google Auth platform and most tutorials
online still describe the old Credentials flow. If you touch those steps,
re-read the source first.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

