@thenavidm/youtube-mcp-cli 2.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +108 -38
  2. package/SKILL.md +6 -3
  3. package/dist/app.d.ts +9 -0
  4. package/dist/app.js +70 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/config.js +5 -4
  7. package/dist/config.js.map +1 -1
  8. package/dist/doctor.d.ts +13 -5
  9. package/dist/doctor.js +60 -59
  10. package/dist/doctor.js.map +1 -1
  11. package/dist/guide.d.ts +5 -0
  12. package/dist/guide.js +16 -0
  13. package/dist/guide.js.map +1 -0
  14. package/dist/index.d.ts +5 -9
  15. package/dist/index.js +9 -129
  16. package/dist/index.js.map +1 -1
  17. package/dist/npx.d.ts +2 -0
  18. package/dist/npx.js +14 -0
  19. package/dist/npx.js.map +1 -0
  20. package/dist/tools/account.js +4 -3
  21. package/dist/tools/account.js.map +1 -1
  22. package/dist/tools/kit.d.ts +20 -32
  23. package/dist/tools/kit.js +63 -56
  24. package/dist/tools/kit.js.map +1 -1
  25. package/dist/tools/research.js +4 -3
  26. package/dist/tools/research.js.map +1 -1
  27. package/dist/tools/transcripts.js +2 -1
  28. package/dist/tools/transcripts.js.map +1 -1
  29. package/dist/youtube/transcripts.d.ts +2 -2
  30. package/dist/youtube/transcripts.js +5 -3
  31. package/dist/youtube/transcripts.js.map +1 -1
  32. package/dist/youtube/ytdlp.js +3 -1
  33. package/dist/youtube/ytdlp.js.map +1 -1
  34. package/package.json +12 -8
  35. package/dist/cli.d.ts +0 -55
  36. package/dist/cli.js +0 -439
  37. package/dist/cli.js.map +0 -1
  38. package/dist/safety.d.ts +0 -50
  39. package/dist/safety.js +0 -84
  40. package/dist/safety.js.map +0 -1
  41. package/dist/server.d.ts +0 -10
  42. package/dist/server.js +0 -28
  43. package/dist/server.js.map +0 -1
  44. package/dist/tools/types.d.ts +0 -6
  45. package/dist/tools/types.js +0 -2
  46. package/dist/tools/types.js.map +0 -1
  47. package/dist/transport/http.d.ts +0 -23
  48. package/dist/transport/http.js +0 -83
  49. package/dist/transport/http.js.map +0 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <img src="https://cdn.navid.media/connectors/youtube-icon.png" alt="YouTube" width="88">
1
+ <img src="https://cdn.navid.me/connectors/youtube-icon.png" alt="YouTube" width="88">
2
2
 
3
3
  # YouTube MCP Server & CLI
4
4
 
@@ -18,7 +18,7 @@ does not return.
18
18
 
19
19
  Connect as many channels as you run, with one login each and no config file.
20
20
 
21
- Built and maintained by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=readme&utm_campaign=youtube-mcp-cli).
21
+ Built and maintained by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=referral&utm_campaign=youtube-mcp-cli&utm_content=readme). Built on [Slipway](https://github.com/thenavidm/slipway), which turns one definition of each tool into the MCP server and the CLI.
22
22
 
23
23
  ```
24
24
  You: what does this video actually say about pricing?
@@ -59,7 +59,7 @@ errors are JSON on stderr whichever output you pick.
59
59
  receives for that tool, which is how you can check the two surfaces really are
60
60
  one thing.
61
61
 
62
- ### MCP server, for AI agents
62
+ ### MCP server, for your AI app
63
63
 
64
64
  `youtube-mcp` is what Claude Code, Claude Desktop, Cursor and the rest launch.
65
65
  You never run it by hand:
@@ -70,6 +70,9 @@ claude mcp add youtube -- npx -y @thenavidm/youtube-mcp-cli@latest
70
70
 
71
71
  Then just ask: _"which of this channel's last 30 videos actually overperformed?"_
72
72
 
73
+ Replying to a comment and deleting a video wait for your approval in the client,
74
+ as [section 9](#9-writing-safely-) explains.
75
+
73
76
  Channels you connected with `youtube-cli login` on this machine are read
74
77
  automatically, so the command needs no credentials. Every other client is in
75
78
  [section 4](#4-connect-your-client-).
@@ -85,7 +88,24 @@ automatically, so the command needs no credentials. Every other client is in
85
88
  They are the same program reading the same tool definitions, so anything one
86
89
  can do, the other can.
87
90
 
88
- ## Contents 📑
91
+ ## Features
92
+
93
+ Every tool is both a command and an MCP tool, with the same name. The command
94
+ is the tool name with dashes.
95
+
96
+ | Capability | CLI command | MCP tool |
97
+ |---|---|---|
98
+ | Transcripts of any public video, no credentials | `youtube-cli get-transcript` / `get-transcripts` / `search-transcript` / `list-transcript-languages` | `get_transcript` / `get_transcripts` / `search_transcript` / `list_transcript_languages` |
99
+ | Research any channel or video | `youtube-cli search-videos` / `get-channel` / `analyze-channel` / `get-video` | `search_videos` / `get_channel` / `analyze_channel` / `get_video` |
100
+ | Your channels and their numbers | `youtube-cli list-accounts` / `get-my-channel` / `get-channel-analytics` / `list-my-videos` | `list_accounts` / `get_my_channel` / `get_channel_analytics` / `list_my_videos` |
101
+ | Comments | `youtube-cli list-comments` / `reply-to-comment` | `list_comments` / `reply_to_comment` |
102
+ | Edit or delete your videos | `youtube-cli update-video` / `delete-video` | `update_video` / `delete_video` |
103
+ | Connect a channel or an API key | `youtube-cli login` / `logout` | not tools |
104
+ | Check your setup | `youtube-cli doctor` | not a tool |
105
+
106
+ All 16 are in [section 7](#7-tools-).
107
+
108
+ ## Contents
89
109
 
90
110
  | # | Section | What is in it |
91
111
  |---|---|---|
@@ -211,8 +231,9 @@ A browser opens, you pick the channel, and it is saved. **Run `youtube-cli
211
231
  login` once per channel.** Then `youtube-cli list-accounts` shows them all.
212
232
  [Section 10](#10-several-channels-) covers using several.
213
233
 
214
- You do not need Google to verify the app. Testing mode is the correct end state
215
- for a tool you run yourself.
234
+ You do not need Google to verify the app, but do click **Publish app** under
235
+ **Audience**. An app left in testing issues refresh tokens that expire after
236
+ seven days, so login would stop working every week.
216
237
 
217
238
  ## 4. Connect your client 🔌
218
239
 
@@ -405,12 +426,12 @@ not: check the client before reconnecting anything.
405
426
  Both surfaces are the same program with the same 16 tools. The
406
427
  difference is when the model pays for them. Measured in Claude Code:
407
428
 
408
- | | MCP server | CLI |
429
+ | Cost | MCP server | CLI |
409
430
  |---|---|---|
410
- | Every message, with every tool loaded | 5,000 tokens | nothing |
431
+ | Every message, with every tool loaded | 4,500 tokens | nothing |
411
432
  | Every message, Claude Code's default | 490 tokens | nothing |
412
- | When YouTube comes up | nothing more, or the tools it picks | 2,300 tokens for `SKILL.md`, once |
413
- | 20 messages with YouTube in 1, every tool loaded | 100,000 tokens | 2,300 tokens |
433
+ | When YouTube comes up | nothing more, or the tools it picks | 2,350 tokens for `SKILL.md`, once |
434
+ | 20 messages with YouTube in 1, every tool loaded | 90,000 tokens | 2,350 tokens |
414
435
 
415
436
  Claude Code's [tool search](https://code.claude.com/docs/en/mcp#scale-with-mcp-tool-search)
416
437
  is on by default: it sends only the tool names and the server instructions,
@@ -423,12 +444,26 @@ To spend less, turn the server off when you are not using it, which in Claude
423
444
  Code is the `/mcp` panel. `YOUTUBE_READ_ONLY=1` takes the 3 write tools off the list, leaving 13.
424
445
  Or install the CLI and add the server on the days it earns its place.
425
446
 
426
- Measured on 2026-09-27 with Claude Code 2.1.257 on Claude Opus 5: one
447
+ Measured on 2026-10-05 with Claude Code 2.1.286 on Claude Opus 5.5: one
427
448
  short prompt with and without the server connected, once with
428
449
  `ENABLE_TOOL_SEARCH=false` and once with the default, the difference read
429
450
  from the API's own usage figures. `SKILL.md` was measured the same way. Other
430
451
  apps and models count tokens a little differently.
431
452
 
453
+ Against 2.0.0, measured the same day: every tool loaded costs 4,458 tokens
454
+ instead of 4,984, tool search 489 instead of 493, and `SKILL.md` 93 more,
455
+ because it now says how approval works over MCP and lists every exit code. In
456
+ Codex 0.159.3 on gpt-6.1-sol, the same task, "find the command that scores a
457
+ channel's recent videos against that channel's own median, and the flags it
458
+ requires", read a median of 83,295 input tokens on 3.0.0 against 83,565 on
459
+ 2.0.0 over the CLI, five runs each: Codex now asks `which` instead of reading
460
+ the full command list, and the general help is shorter. Over MCP, Codex prints
461
+ the tool list with a script and answers from that printout, 6,133 tokens on
462
+ 3.0.0 against 6,126; the 7 more are the description of `confirm` on the two
463
+ irreversible tools. The input totals, a median of 45,053 against 44,924, also
464
+ carry the model's reasoning into its second request, which three of the five
465
+ 2.0.0 runs skipped; the two that kept it read 45,065 and 45,074.
466
+
432
467
  ## 7. Tools 🛠️
433
468
 
434
469
  Every tool is also a command: the tool name with dashes. `*` marks a write, `!`
@@ -499,21 +534,26 @@ Everything a script needs to branch on.
499
534
  | `--select a,b.c` | only the named fields of a JSON result, dotted paths descend |
500
535
 
501
536
  Results go to stdout. Errors go to stderr, always as JSON, so one parse handles
502
- both outcomes:
537
+ both outcomes. `code` names the kind of failure, and `hint` and `details`, such
538
+ as Google's own reason, come along when there is one:
503
539
 
504
540
  ```json
505
- { "error": "No API key is configured. Run `youtube-cli login --api-key KEY` or set YOUTUBE_API_KEY for public data, or `youtube-cli login` for your own channels." }
541
+ {
542
+ "error": "No API key is configured. Run `youtube-cli login --api-key KEY` or set YOUTUBE_API_KEY for public data, or `youtube-cli login` for your own channels.",
543
+ "code": "not_configured"
544
+ }
506
545
  ```
507
546
 
508
547
  | Code | Means |
509
548
  |---|---|
510
549
  | `0` | it worked |
511
- | `2` | you typed it wrong, or a guarded write was refused for want of `--confirm` |
550
+ | `1` | an unexpected error |
551
+ | `2` | you typed it wrong, an unknown command, a write hidden by `YOUTUBE_READ_ONLY`, or a guarded write refused for want of `--confirm` |
512
552
  | `3` | not found |
513
553
  | `4` | authentication failed: reconnect the channel |
514
554
  | `5` | an API error upstream |
515
555
  | `7` | rate limited or out of quota: wait |
516
- | `10` | nothing configured: run `youtube-cli login` or `login --api-key` |
556
+ | `10` | nothing configured: run `youtube-cli login` or `login --api-key`, or install yt-dlp for transcripts |
517
557
 
518
558
  So a script can tell a mistake it should fix from a failure it should retry:
519
559
 
@@ -533,19 +573,27 @@ Writes work by default, because managing a channel is the point.
533
573
 
534
574
  Two tools are guarded: `reply_to_comment`, because it is public the moment it
535
575
  lands and notifies someone, and `delete_video`, because YouTube removes a video
536
- immediately with no trash and no undo. Both refuse without `--confirm` in the
537
- terminal or `confirm: true` through MCP. The CLI goes through the same guard as
538
- the server, so the rules are identical.
576
+ immediately with no trash and no undo. Both wait for your approval. The CLI goes
577
+ through the same guard as the server, so the rules are identical.
578
+
579
+ Over MCP a person approves each of the two where the client can ask: Claude Code
580
+ (2.1.246 and later) shows its own prompt, and a client that can show forms asks
581
+ with an approval form whose one box starts unticked. Each approval is signed,
582
+ bound to that exact call and works once. Where a client can do neither, the
583
+ model's `confirm: true` counts, and it should pass it only when you asked for
584
+ that exact reply or delete. `YOUTUBE_CONFIRM=model` makes `confirm: true` enough
585
+ everywhere, for an agent with no person to ask. In a terminal it is `--confirm`,
586
+ which `--agent` never adds.
539
587
 
540
588
  `update_video` is not guarded. A title is one keystroke to put back, and asking
541
- to confirm reversible things teaches a model to confirm everything reflexively,
542
- which is worse protection than not asking.
589
+ to approve reversible things teaches people and models to approve everything
590
+ reflexively, which is worse protection than not asking.
543
591
 
544
592
  | Setting | Effect |
545
593
  |---|---|
546
594
  | `YOUTUBE_READ_ONLY=1` | Every write disappears from the tool list and the command list |
547
595
  | `YOUTUBE_ALLOW_DESTRUCTIVE=0` | `update_video` stays, the two irreversible tools are blocked |
548
- | `YOUTUBE_AUDIT_LOG=<path>` | One JSON line per attempted write, allowed and blocked alike |
596
+ | `YOUTUBE_AUDIT_LOG=<path>` | One JSON line per attempted write, allowed and blocked alike, and who approved it |
549
597
 
550
598
  Comments, titles, descriptions and transcripts are written by other people. The
551
599
  tool descriptions and the shipped `SKILL.md` tell the model to treat them as
@@ -670,6 +718,11 @@ are in its output.
670
718
  | A command refuses and lists your channels | Two or more are connected. Pass `--account` |
671
719
  | Every write command has vanished | `YOUTUBE_READ_ONLY=1` is set |
672
720
  | Server missing in Claude Desktop | Use the absolute path to `npx`, check the JSON, and fully quit the app |
721
+ | "will not run without --confirm" | Working as intended: a reply is public and a delete is permanent. See [section 9](#9-writing-safely-) |
722
+ | `claude -p` will not reply or delete | Headless Claude Code refuses tools that need a person. Give that agent `YOUTUBE_CONFIRM=model` |
723
+ | No approval form appears | The client cannot show forms, so the model's `confirm: true` counts, and only for an action you asked for |
724
+ | YouTube asks yt-dlp to prove it is not a bot | Set `YOUTUBE_YTDLP_COOKIES` to a cookies.txt exported from a browser signed in to YouTube |
725
+ | A piped request gets no answer | Stdin closed before the answer. The MCP stdio binding stops a server when its input ends; keep stdin open until you read the answer, or use the CLI |
673
726
 
674
727
  ## Environment variables
675
728
 
@@ -696,7 +749,8 @@ you ran `youtube-cli login`.
696
749
  |---|---|---|
697
750
  | `YOUTUBE_READ_ONLY` | `0` | `1` hides every write |
698
751
  | `YOUTUBE_ALLOW_DESTRUCTIVE` | `1` | `0` blocks the two irreversible tools |
699
- | `YOUTUBE_AUDIT_LOG` | none | Append-only log of every attempted write |
752
+ | `YOUTUBE_AUDIT_LOG` | none | Append-only log of every attempted write, and who approved it |
753
+ | `YOUTUBE_CONFIRM` | `human` | `model` lets `confirm: true` alone approve over MCP, for an agent with no person to ask |
700
754
 
701
755
  **Tuning**
702
756
 
@@ -705,11 +759,16 @@ you ran `youtube-cli login`.
705
759
  | `YOUTUBE_REQUEST_TIMEOUT_MS` | `30000` | Per-request deadline |
706
760
  | `YOUTUBE_TRANSCRIPT_LANG` | `en` | Default transcript language |
707
761
  | `YOUTUBE_YTDLP_PATH` | `yt-dlp` on PATH | Where yt-dlp is |
762
+ | `YOUTUBE_YTDLP_COOKIES` | none | A cookies.txt from a browser signed in to YouTube, for when YouTube asks yt-dlp to prove it is not a bot |
708
763
  | `YOUTUBE_MCP_HOME` | `~/.youtube-mcp-cli` | Where `login` saves channels |
709
764
  | `YOUTUBE_OAUTH_PORT` | `8765` | The localhost port `login` listens on |
710
765
  | `YOUTUBE_HTTP_PORT` | `8787` | For `--http` |
711
766
  | `YOUTUBE_HTTP_HOST` | `127.0.0.1` | For `--http` |
712
- | `YOUTUBE_HTTP_TOKEN` | none | Bearer token required by `--http` |
767
+ | `YOUTUBE_HTTP_TOKEN` | none | Bearer token for `--http`. Any address but localhost refuses to start without one |
768
+ | `YOUTUBE_HTTP_ALLOWED_ORIGINS` | none | Comma-separated browser origins allowed to connect; a page from any other site is refused |
769
+ | `YOUTUBE_SURFACE` | `full` | `search` lists three tools that find, describe and run the rest |
770
+ | `YOUTUBE_TOOL_TIMEOUT_MS` | none | Give up on any tool after this long |
771
+ | `YOUTUBE_DEBUG` | `0` | `1` prints debug lines on stderr |
713
772
 
714
773
  ## Versions
715
774
 
@@ -790,10 +849,11 @@ afternoon by hand.
790
849
  <details>
791
850
  <summary><b>Can it delete one of my videos by accident?</b></summary>
792
851
 
793
- It cannot delete anything without `--confirm` or `confirm: true`, which a model
794
- has to set deliberately after reading a description saying the action is
795
- permanent. If you want the possibility gone entirely, set `YOUTUBE_READ_ONLY=1`
796
- and every write disappears.
852
+ It cannot delete anything without your approval: Claude Code shows its own
853
+ prompt for each delete, a client that can show forms asks with one, and
854
+ elsewhere the model has to pass `confirm: true` deliberately after reading a
855
+ description saying the action is permanent. If you want the possibility gone
856
+ entirely, set `YOUTUBE_READ_ONLY=1` and every write disappears.
797
857
 
798
858
  </details>
799
859
 
@@ -823,6 +883,16 @@ the app to stop that, or run `youtube-cli login` again when it happens.
823
883
 
824
884
  </details>
825
885
 
886
+ <details>
887
+ <summary><b>Can it reply to a comment without me asking?</b></summary>
888
+
889
+ It replies when you ask it to. A reply is public the moment it lands and
890
+ notifies the person you replied to, so each one waits for your approval in the
891
+ client, as a delete does. `YOUTUBE_READ_ONLY=1` removes replying, editing and
892
+ deleting from the list entirely.
893
+
894
+ </details>
895
+
826
896
  <details>
827
897
  <summary><b>How do I disconnect it?</b></summary>
828
898
 
@@ -833,19 +903,19 @@ the Cloud project removes the API key and the OAuth client together.
833
903
 
834
904
  </details>
835
905
 
836
- ## Questions 💬
906
+ ## Questions
837
907
 
838
908
  Run into a problem or have a question? [Open an issue](https://github.com/thenavidm/youtube-mcp-cli/issues) and I will help.
839
909
 
840
- ## About the author 👋
910
+ ## About the author
841
911
 
842
- Navid Moazzez is a leading AI business strategist, and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. This YouTube MCP server is one piece of that system.
912
+ Navid Moazzez is a leading AI business strategist, and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. He creates useful free tools, MCP servers and CLIs that creators and founders can use in their own workflows.
843
913
 
844
914
  **Links**
845
915
 
846
- - Personal website: [navid.me](https://navid.me?utm_source=github&utm_medium=readme&utm_campaign=youtube-mcp-cli)
847
- - Link in bio: [navid.bio](https://navid.bio?utm_source=github&utm_medium=readme&utm_campaign=youtube-mcp-cli)
848
- - Navid Media: [navid.media](https://navid.media?utm_source=github&utm_medium=readme&utm_campaign=youtube-mcp-cli)
916
+ - Personal website: [navid.me](https://navid.me?utm_source=github&utm_medium=referral&utm_campaign=youtube-mcp-cli&utm_content=readme)
917
+ - Link in bio: [navid.bio](https://navid.bio?utm_source=github&utm_medium=referral&utm_campaign=youtube-mcp-cli&utm_content=readme)
918
+ - Navid Media: [navid.media](https://navid.media?utm_source=github&utm_medium=referral&utm_campaign=youtube-mcp-cli&utm_content=readme)
849
919
  - YouTube: [@thenavidm](https://youtube.com/@thenavidm?sub_confirmation=1) and [@thenavidai](https://youtube.com/@thenavidai?sub_confirmation=1)
850
920
  - X: [@thenavidm](https://x.com/thenavidm)
851
921
  - Instagram: [@thenavidm](https://instagram.com/thenavidm)
@@ -853,19 +923,19 @@ Navid Moazzez is a leading AI business strategist, and the host of the AI Creato
853
923
 
854
924
  If this is useful, star the repo and come say hi on [X](https://x.com/thenavidm).
855
925
 
856
- ## Dependencies 📦
926
+ ## Dependencies
857
927
 
858
928
  | Library | License | What it does |
859
929
  |---|---|---|
860
- | [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) | MIT | The MCP server and transports |
930
+ | [Slipway](https://github.com/thenavidm/slipway) | Apache-2.0 | The MCP server and the CLI from one definition of each tool, with the write guard |
931
+ | [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) | Apache-2.0 | The MCP protocol and transports, through Slipway |
861
932
  | [zod](https://github.com/colinhacks/zod) | MIT | Tool argument schemas and validation |
862
- | [zod-to-json-schema](https://github.com/StefanTerdell/zod-to-json-schema) | ISC | Turns those schemas into what an MCP client receives |
863
933
 
864
934
  [yt-dlp](https://github.com/yt-dlp/yt-dlp) is an optional external command, used
865
935
  only to fetch caption tracks. It is not bundled and is never loaded into this
866
936
  process.
867
937
 
868
- ## License ⚖️
938
+ ## License
869
939
 
870
940
  [MIT](./LICENSE). Free to use, modify, and share.
871
941
 
@@ -874,4 +944,4 @@ trademark of Google LLC.
874
944
 
875
945
  ---
876
946
 
877
- © 2026 [NM Media](https://navid.media?utm_source=github&utm_medium=readme&utm_campaign=youtube-mcp-cli). Made with ❤️ by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=readme&utm_campaign=youtube-mcp-cli).
947
+ © 2026 [Navid Media](https://navid.media?utm_source=github&utm_medium=referral&utm_campaign=youtube-mcp-cli&utm_content=readme). Made with ❤️ by [Navid Moazzez](https://navid.me?utm_source=github&utm_medium=referral&utm_campaign=youtube-mcp-cli&utm_content=readme).
package/SKILL.md CHANGED
@@ -52,7 +52,7 @@ The CLI describes itself, so nothing here needs to list 16 tools and go stale:
52
52
  ```bash
53
53
  youtube-cli # every command, one line each, writes marked
54
54
  youtube-cli <command> --help # arguments, types, which are required
55
- youtube-cli schema <command> # the exact JSON Schema an MCP client receives
55
+ youtube-cli which <words> # the command for a task, without the full list
56
56
  ```
57
57
 
58
58
  The command is the tool name with dashes: `list_comments` runs as
@@ -111,7 +111,8 @@ user.
111
111
  | Code | Meaning |
112
112
  |---|---|
113
113
  | 0 | Success |
114
- | 2 | Usage error, or a write refused for want of `--confirm` |
114
+ | 1 | Unexpected error |
115
+ | 2 | Usage error: wrong or missing arguments, an unknown command, a write hidden by `YOUTUBE_READ_ONLY=1`, or a write refused for want of `--confirm` |
115
116
  | 3 | Not found |
116
117
  | 4 | Authentication failed, reconnect the channel |
117
118
  | 5 | API error upstream |
@@ -132,7 +133,9 @@ specific thing.
132
133
  **`--confirm` is enforced, not advisory.** `reply-to-comment` is public the
133
134
  moment it lands and notifies the person. `delete-video` is final: no trash, and
134
135
  the views, comments and URL go with it. Both refuse without `--confirm`. Pass it
135
- when the user has actually asked, never to get past the refusal.
136
+ when the user has actually asked, never to get past the refusal. Over MCP the
137
+ person approves each in the client's own prompt or form; `confirm: true` counts
138
+ only where the client cannot ask.
136
139
 
137
140
  `update-video` is not guarded, because a title is a keystroke to put back. Only
138
141
  the fields you pass change.
package/dist/app.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The YouTube app: everything Slipway needs to ship the MCP server and the CLI.
3
+ *
4
+ * This file only describes. It never starts anything, so `slipway check` and
5
+ * tests can import it; `index.ts` is what runs.
6
+ */
7
+ import { type ToolContext } from "./tools/kit.js";
8
+ export declare const VERSION: string;
9
+ export declare const app: import("@thenavidm/slipway").App<ToolContext>;
package/dist/app.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The YouTube app: everything Slipway needs to ship the MCP server and the CLI.
3
+ *
4
+ * This file only describes. It never starts anything, so `slipway check` and
5
+ * tests can import it; `index.ts` is what runs.
6
+ */
7
+ import { createRequire } from "node:module";
8
+ import { slipway } from "@thenavidm/slipway";
9
+ import { loadConfig } from "./config.js";
10
+ import { doctor } from "./doctor.js";
11
+ import { INSTRUCTIONS } from "./guide.js";
12
+ import { ALL_TOOLS } from "./tools/index.js";
13
+ import { makeContext } from "./tools/kit.js";
14
+ const require = createRequire(import.meta.url);
15
+ export const VERSION = require("../package.json").version;
16
+ const signIn = async (_io, args) => {
17
+ const { login } = await import("./auth.js");
18
+ return login([...args]);
19
+ };
20
+ export const app = slipway({
21
+ name: "youtube",
22
+ title: "YouTube",
23
+ version: VERSION,
24
+ package: "@thenavidm/youtube-mcp-cli",
25
+ description: "YouTube transcripts for any public video, channel research, and your own channels' videos, comments and analytics",
26
+ instructions: INSTRUCTIONS,
27
+ // Transcripts need no credentials, so nothing here is required before the first call.
28
+ context: () => makeContext(loadConfig()),
29
+ secrets: ({ config }) => [config.apiKey, ...config.accounts.flatMap((account) => [account.refreshToken, account.accessToken])],
30
+ tools: ALL_TOOLS,
31
+ doctor,
32
+ // yt-dlp, the API key and every channel's token each fail differently, and only a request tells, so doctor makes one per source every time, as 2.0 did.
33
+ doctorNetwork: true,
34
+ login: {
35
+ usage: "login [--api-key KEY]",
36
+ help: "connect a channel, once per channel; --api-key saves a research key",
37
+ run: signIn,
38
+ },
39
+ commands: [
40
+ { name: "auth", usage: "auth [--api-key KEY]", help: "the same as login, by the name 1.x used", hidden: true, run: signIn },
41
+ {
42
+ name: "logout",
43
+ usage: "logout <channel> | logout --api-key",
44
+ help: "forget a saved channel, or the saved API key",
45
+ run: async (_io, args) => {
46
+ const { logout } = await import("./auth.js");
47
+ return logout([...args]);
48
+ },
49
+ },
50
+ ],
51
+ settings: [
52
+ { env: "YOUTUBE_API_KEY", description: "Public search and channel lookup, or `login --api-key`.", secret: true },
53
+ { env: "YOUTUBE_ACCOUNTS", description: "Several channels at once, as a JSON array.", secret: true },
54
+ { env: "YOUTUBE_REFRESH_TOKEN", description: "One channel.", secret: true },
55
+ { env: "YOUTUBE_ACCESS_TOKEN", description: "One channel, short-lived, for testing.", secret: true, tuning: true },
56
+ { env: "YOUTUBE_CHANNEL_NAME", description: "What to call that one channel. Defaults to default.", tuning: true },
57
+ { env: "YOUTUBE_CLIENT_ID", description: "Your OAuth client, which `login` needs." },
58
+ { env: "YOUTUBE_CLIENT_SECRET", description: "Its secret.", secret: true },
59
+ { env: "YOUTUBE_MCP_HOME", description: "Where `login` saves channels. Defaults to ~/.youtube-mcp-cli.", tuning: true },
60
+ { env: "YOUTUBE_TRANSCRIPT_LANG", description: "Default transcript language. Defaults to en.", tuning: true },
61
+ { env: "YOUTUBE_YTDLP_PATH", description: "Path to yt-dlp, if it is not on PATH.", tuning: true },
62
+ { env: "YOUTUBE_YTDLP_COOKIES", description: "A cookies.txt from a browser signed in to YouTube, for the bot check.", secret: true },
63
+ { env: "YOUTUBE_OAUTH_CLIENT_ID", description: "Another name for YOUTUBE_CLIENT_ID.", tuning: true },
64
+ { env: "YOUTUBE_OAUTH_CLIENT_SECRET", description: "Another name for YOUTUBE_CLIENT_SECRET.", secret: true, tuning: true },
65
+ { env: "YOUTUBE_OAUTH_PORT", description: "The localhost port `login` listens on. Defaults to 8765.", tuning: true },
66
+ { env: "YOUTUBE_REQUEST_TIMEOUT_MS", description: "Per-request deadline. Defaults to 30000.", tuning: true },
67
+ ],
68
+ links: { repository: "https://github.com/thenavidm/youtube-mcp-cli" },
69
+ });
70
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAc,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAoB,MAAM,gBAAgB,CAAC;AAE/D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,OAAO,GAAY,OAAO,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAC;AAE3F,MAAM,MAAM,GAAG,KAAK,EAAE,GAAU,EAAE,IAAuB,EAAmB,EAAE;IAC5E,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAC5C,OAAO,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG,OAAO,CAAc;IACtC,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,4BAA4B;IACrC,WAAW,EAAE,mHAAmH;IAChI,YAAY,EAAE,YAAY;IAC1B,sFAAsF;IACtF,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC;IACxC,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IAC9H,KAAK,EAAE,SAAS;IAChB,MAAM;IACN,wJAAwJ;IACxJ,aAAa,EAAE,IAAI;IACnB,KAAK,EAAE;QACL,KAAK,EAAE,uBAAuB;QAC9B,IAAI,EAAE,qEAAqE;QAC3E,GAAG,EAAE,MAAM;KACZ;IACD,QAAQ,EAAE;QACR,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,yCAAyC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE;QAC3H;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,qCAAqC;YAC5C,IAAI,EAAE,8CAA8C;YACpD,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;gBACvB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;gBAC7C,OAAO,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YAC3B,CAAC;SACF;KACF;IACD,QAAQ,EAAE;QACR,EAAE,GAAG,EAAE,iBAAiB,EAAE,WAAW,EAAE,yDAAyD,EAAE,MAAM,EAAE,IAAI,EAAE;QAChH,EAAE,GAAG,EAAE,kBAAkB,EAAE,WAAW,EAAE,4CAA4C,EAAE,MAAM,EAAE,IAAI,EAAE;QACpG,EAAE,GAAG,EAAE,uBAAuB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE;QAC3E,EAAE,GAAG,EAAE,sBAAsB,EAAE,WAAW,EAAE,wCAAwC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAClH,EAAE,GAAG,EAAE,sBAAsB,EAAE,WAAW,EAAE,qDAAqD,EAAE,MAAM,EAAE,IAAI,EAAE;QACjH,EAAE,GAAG,EAAE,mBAAmB,EAAE,WAAW,EAAE,yCAAyC,EAAE;QACpF,EAAE,GAAG,EAAE,uBAAuB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE;QAC1E,EAAE,GAAG,EAAE,kBAAkB,EAAE,WAAW,EAAE,+DAA+D,EAAE,MAAM,EAAE,IAAI,EAAE;QACvH,EAAE,GAAG,EAAE,yBAAyB,EAAE,WAAW,EAAE,8CAA8C,EAAE,MAAM,EAAE,IAAI,EAAE;QAC7G,EAAE,GAAG,EAAE,oBAAoB,EAAE,WAAW,EAAE,uCAAuC,EAAE,MAAM,EAAE,IAAI,EAAE;QACjG,EAAE,GAAG,EAAE,uBAAuB,EAAE,WAAW,EAAE,uEAAuE,EAAE,MAAM,EAAE,IAAI,EAAE;QACpI,EAAE,GAAG,EAAE,yBAAyB,EAAE,WAAW,EAAE,qCAAqC,EAAE,MAAM,EAAE,IAAI,EAAE;QACpG,EAAE,GAAG,EAAE,6BAA6B,EAAE,WAAW,EAAE,yCAAyC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAC1H,EAAE,GAAG,EAAE,oBAAoB,EAAE,WAAW,EAAE,0DAA0D,EAAE,MAAM,EAAE,IAAI,EAAE;QACpH,EAAE,GAAG,EAAE,4BAA4B,EAAE,WAAW,EAAE,0CAA0C,EAAE,MAAM,EAAE,IAAI,EAAE;KAC7G;IACD,KAAK,EAAE,EAAE,UAAU,EAAE,8CAA8C,EAAE;CACtE,CAAC,CAAC"}
package/dist/config.js CHANGED
@@ -12,6 +12,7 @@
12
12
  * by `youtube-cli login --api-key`. Transcripts need none of these.
13
13
  */
14
14
  import { loadStore } from "./accounts/store.js";
15
+ import { NotConfiguredError, UsageError } from "@thenavidm/slipway";
15
16
  function bool(value, fallback) {
16
17
  if (value === undefined || value.trim() === "")
17
18
  return fallback;
@@ -56,11 +57,11 @@ function envAccounts() {
56
57
  parsed = JSON.parse(raw);
57
58
  }
58
59
  catch {
59
- throw new Error("YOUTUBE_ACCOUNTS is not valid JSON. It should be an array like " +
60
+ throw new NotConfiguredError("YOUTUBE_ACCOUNTS is not valid JSON. It should be an array like " +
60
61
  '[{"name":"Main","refresh_token":"1//..."}].');
61
62
  }
62
63
  if (!Array.isArray(parsed))
63
- throw new Error("YOUTUBE_ACCOUNTS must be a JSON array.");
64
+ throw new NotConfiguredError("YOUTUBE_ACCOUNTS must be a JSON array.");
64
65
  return parsed.map((entry, i) => {
65
66
  const a = entry;
66
67
  const name = a.name ?? a.account_name ?? a.channel ?? `account-${i + 1}`;
@@ -118,12 +119,12 @@ export function resolveAccount(config, requested) {
118
119
  const match = accounts.find((a) => a.id === want || a.name.toLowerCase() === want) ??
119
120
  accounts.find((a) => a.name.toLowerCase().includes(want) || a.id.includes(want));
120
121
  if (!match) {
121
- throw new Error(`No connected channel matches "${requested}". Connected: ${accounts.map((a) => a.name).join(", ")}. Call list_accounts to see them.`);
122
+ throw new UsageError(`No connected channel matches "${requested}". Connected: ${accounts.map((a) => a.name).join(", ")}. Call list_accounts to see them.`);
122
123
  }
123
124
  return match;
124
125
  }
125
126
  if (accounts.length > 1) {
126
- throw new Error(`${accounts.length} channels are connected (${accounts.map((a) => a.name).join(", ")}). Pass account=<name or @handle> so this runs against the right one.`);
127
+ throw new UsageError(`${accounts.length} channels are connected (${accounts.map((a) => a.name).join(", ")}). Pass account=<name or @handle> so this runs against the right one.`);
127
128
  }
128
129
  return accounts[0];
129
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/doctor.d.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  /**
2
- * `youtube-cli doctor`: say what is set up and what is not, in the order that
3
- * matters. Most setup problems here are a missing API in the Cloud project or
4
- * an OAuth client that does not match the token, and neither is obvious from
5
- * the error the API returns at call time.
2
+ * `youtube-cli doctor`: check each of the three things this server can reach,
3
+ * the way it would reach them.
4
+ *
5
+ * Transcripts need yt-dlp and nothing else, research needs an API key, and a
6
+ * connected channel needs a refresh token that still works. Each fails for a
7
+ * different reason with a different fix, so each is checked on its own, with a
8
+ * real request, as 2.0 did. Slipway runs this on every `doctor`, after its own
9
+ * checks.
6
10
  */
7
- export declare function doctor(): Promise<number>;
11
+ import type { DoctorCheck } from "@thenavidm/slipway";
12
+ import type { ToolContext } from "./tools/kit.js";
13
+ export declare function doctor({ config }: ToolContext, options: {
14
+ network: boolean;
15
+ }): Promise<DoctorCheck[]>;