@mkterswingman/5mghost-yonder 0.0.17 ā 0.0.19
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.
- package/dist/cli/index.js +8 -2
- package/dist/cli/installSkills.d.ts +1 -0
- package/dist/cli/installSkills.js +39 -0
- package/dist/cli/setup.js +29 -8
- package/dist/cli/setupCookies.d.ts +5 -1
- package/dist/cli/setupCookies.js +9 -1
- package/dist/utils/launcher.js +8 -0
- package/dist/utils/openClaw.d.ts +1 -0
- package/dist/utils/openClaw.js +3 -0
- package/dist/utils/skills.d.ts +16 -0
- package/dist/utils/skills.js +56 -0
- package/package.json +2 -1
- package/skills/use-yt-mcp/SKILL.md +117 -0
package/dist/cli/index.js
CHANGED
|
@@ -24,6 +24,7 @@ Commands:
|
|
|
24
24
|
setup Run first-time setup (OAuth + cookies + MCP registration)
|
|
25
25
|
serve Start the MCP server (stdio transport)
|
|
26
26
|
smoke Run installer smoke checks
|
|
27
|
+
install-skills Install the bundled yt-mcp analysis skill into supported AI clients
|
|
27
28
|
setup-cookies Refresh YouTube cookies using browser login
|
|
28
29
|
runtime Manage required runtimes
|
|
29
30
|
check Check auth, runtime, cookies, and connectivity
|
|
@@ -81,9 +82,14 @@ async function main() {
|
|
|
81
82
|
await runSmoke(process.argv.slice(3));
|
|
82
83
|
break;
|
|
83
84
|
}
|
|
85
|
+
case "install-skills": {
|
|
86
|
+
const { runInstallSkills } = await import("./installSkills.js");
|
|
87
|
+
await runInstallSkills();
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
84
90
|
case "setup-cookies": {
|
|
85
|
-
const { runSetupCookies } = await import("./setupCookies.js");
|
|
86
|
-
await runSetupCookies();
|
|
91
|
+
const { runSetupCookies, parseSetupCookiesArgs } = await import("./setupCookies.js");
|
|
92
|
+
await runSetupCookies({}, parseSetupCookiesArgs(process.argv.slice(3)));
|
|
87
93
|
break;
|
|
88
94
|
}
|
|
89
95
|
case "uninstall": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runInstallSkills(): Promise<void>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { buildSkillInstallPlan, installSkillTarget, } from "../utils/skills.js";
|
|
5
|
+
function detectCli(name) {
|
|
6
|
+
try {
|
|
7
|
+
execFileSync(name, ["--version"], { stdio: "pipe" });
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function resolvePackageRoot() {
|
|
15
|
+
return join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
16
|
+
}
|
|
17
|
+
export async function runInstallSkills() {
|
|
18
|
+
const packageRoot = resolvePackageRoot();
|
|
19
|
+
const availableCliNames = [
|
|
20
|
+
"claude-internal",
|
|
21
|
+
"claude",
|
|
22
|
+
"codex-internal",
|
|
23
|
+
"codex",
|
|
24
|
+
"gemini-internal",
|
|
25
|
+
"gemini",
|
|
26
|
+
].filter(detectCli);
|
|
27
|
+
const plan = buildSkillInstallPlan(packageRoot, {
|
|
28
|
+
availableCliNames,
|
|
29
|
+
includeOpenClaw: process.env.YT_MCP_INSTALL_OPENCLAW_SKILL === "1",
|
|
30
|
+
});
|
|
31
|
+
if (plan.length === 0) {
|
|
32
|
+
console.log("[yt-mcp] No supported AI client detected for bundled skill install.");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
for (const target of plan) {
|
|
36
|
+
installSkillTarget(target);
|
|
37
|
+
console.log(`[yt-mcp] Installed bundled skill for ${target.label}: ${target.targetDir}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
package/dist/cli/setup.js
CHANGED
|
@@ -6,6 +6,7 @@ import { runOAuthFlow } from "../auth/oauthFlow.js";
|
|
|
6
6
|
import { hasSIDCookies } from "../utils/cookies.js";
|
|
7
7
|
import { buildLauncherCommand, writeLauncherFile } from "../utils/launcher.js";
|
|
8
8
|
import { checkAll } from "../runtime/installers.js";
|
|
9
|
+
import { runInstallSkills } from "./installSkills.js";
|
|
9
10
|
import { getOpenClawConfigPath, isOpenClawInstallLikelyInstalled, writeOpenClawConfig, } from "../utils/openClaw.js";
|
|
10
11
|
import { getCodexInternalConfigPath, writeCodexInternalConfig, } from "../utils/codexInternal.js";
|
|
11
12
|
import { MCP_REGISTER_TIMEOUT_MS, classifyRegistrationFailure, } from "../utils/mcpRegistration.js";
|
|
@@ -122,6 +123,9 @@ export function getCookieSetupDeferredHint() {
|
|
|
122
123
|
];
|
|
123
124
|
}
|
|
124
125
|
export async function runSetup() {
|
|
126
|
+
const installerMode = process.env.YT_MCP_INSTALLER_MODE === "1";
|
|
127
|
+
const skipCookieStep = installerMode || process.env.YT_MCP_SETUP_SKIP_COOKIES === "1";
|
|
128
|
+
const quietSummary = installerMode || process.env.YT_MCP_SETUP_QUIET_SUMMARY === "1";
|
|
125
129
|
console.log("\nš yt-mcp setup\n");
|
|
126
130
|
ensureConfigDir();
|
|
127
131
|
const hasBrowser = canOpenBrowser();
|
|
@@ -235,7 +239,10 @@ export async function runSetup() {
|
|
|
235
239
|
}
|
|
236
240
|
// āā Step 4: YouTube Cookies āā
|
|
237
241
|
console.log("Step 4/5: YouTube cookies...");
|
|
238
|
-
if (
|
|
242
|
+
if (skipCookieStep) {
|
|
243
|
+
console.log(" ā¹ļø Deferred to installer cookie flow");
|
|
244
|
+
}
|
|
245
|
+
else if (!hasBrowser) {
|
|
239
246
|
for (const line of getCookieSetupDeferredHint()) {
|
|
240
247
|
console.log(line);
|
|
241
248
|
}
|
|
@@ -261,6 +268,7 @@ export async function runSetup() {
|
|
|
261
268
|
console.log("Step 5/5: Registering MCP in AI clients...");
|
|
262
269
|
const launcherCommand = buildLauncherCommand();
|
|
263
270
|
let registered = false;
|
|
271
|
+
let skillsInstalled = false;
|
|
264
272
|
for (const { bin, label, command } of buildSetupCliCandidates({
|
|
265
273
|
file: launcherCommand.command,
|
|
266
274
|
args: launcherCommand.args,
|
|
@@ -293,6 +301,14 @@ export async function runSetup() {
|
|
|
293
301
|
console.log(` ā ļø Codex CLI (internal) auto-register failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
294
302
|
}
|
|
295
303
|
}
|
|
304
|
+
try {
|
|
305
|
+
process.env.YT_MCP_INSTALL_OPENCLAW_SKILL = isOpenClawInstallLikelyInstalled(detectCli) ? "1" : "0";
|
|
306
|
+
await runInstallSkills();
|
|
307
|
+
skillsInstalled = true;
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
console.log(` ā ļø Bundled skill install failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
311
|
+
}
|
|
296
312
|
if (!registered) {
|
|
297
313
|
console.log(" ā¹ļø No supported CLI found. Add manually to your AI client:");
|
|
298
314
|
}
|
|
@@ -323,18 +339,23 @@ export async function runSetup() {
|
|
|
323
339
|
}
|
|
324
340
|
`);
|
|
325
341
|
console.log(` OpenClaw uses ${PATHS.sharedAuthJson} for PAT/JWT, so env.YT_MCP_TOKEN is optional after setup.`);
|
|
342
|
+
if (skillsInstalled) {
|
|
343
|
+
console.log(" ā
Installed bundled yt-mcp analysis skill for detected AI clients");
|
|
344
|
+
}
|
|
326
345
|
console.log(" Media downloads:");
|
|
327
346
|
console.log(" - `start_download_job` / `poll_download_job` are job-based local tools");
|
|
328
347
|
console.log(" - Batch limit: 5 YouTube videos per job");
|
|
329
348
|
console.log(" - Output path: ~/Downloads/yt-mcp/YYYY-MM-DD_<video_id>");
|
|
330
349
|
console.log(" - `ffmpeg` is required for video download modes");
|
|
331
350
|
console.log("");
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
351
|
+
if (!quietSummary) {
|
|
352
|
+
console.log("ā
Setup complete!");
|
|
353
|
+
if (hasBrowser) {
|
|
354
|
+
console.log(' Open your AI client and try: "ęē“¢ Python ęēØ"');
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
console.log(" Set YT_MCP_TOKEN in your MCP env config, then restart your AI client.");
|
|
358
|
+
}
|
|
359
|
+
console.log("");
|
|
338
360
|
}
|
|
339
|
-
console.log("");
|
|
340
361
|
}
|
|
@@ -51,6 +51,9 @@ export interface SetupCookiesDeps {
|
|
|
51
51
|
runManualCookieSetup: typeof runManualCookieSetup;
|
|
52
52
|
log: (message: string) => void;
|
|
53
53
|
}
|
|
54
|
+
export interface SetupCookiesOptions {
|
|
55
|
+
importOnly?: boolean;
|
|
56
|
+
}
|
|
54
57
|
type SetupCookiesChromium = Awaited<ReturnType<SetupCookiesDeps["loadChromium"]>>;
|
|
55
58
|
interface CdpCookie {
|
|
56
59
|
name: string;
|
|
@@ -76,5 +79,6 @@ export declare function runManualCookieSetup(chromium: SetupCookiesChromium, dep
|
|
|
76
79
|
/**
|
|
77
80
|
* Interactive cookie setup ā opens a visible browser for user to log in.
|
|
78
81
|
*/
|
|
79
|
-
export declare function
|
|
82
|
+
export declare function parseSetupCookiesArgs(argv: string[]): SetupCookiesOptions;
|
|
83
|
+
export declare function runSetupCookies(overrides?: Partial<SetupCookiesDeps>, options?: SetupCookiesOptions): Promise<void>;
|
|
80
84
|
export {};
|
package/dist/cli/setupCookies.js
CHANGED
|
@@ -361,7 +361,12 @@ export async function runManualCookieSetup(chromium, deps) {
|
|
|
361
361
|
/**
|
|
362
362
|
* Interactive cookie setup ā opens a visible browser for user to log in.
|
|
363
363
|
*/
|
|
364
|
-
export
|
|
364
|
+
export function parseSetupCookiesArgs(argv) {
|
|
365
|
+
return {
|
|
366
|
+
importOnly: argv.includes("--import-only"),
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
export async function runSetupCookies(overrides = {}, options = {}) {
|
|
365
370
|
const deps = buildSetupCookiesDeps(overrides);
|
|
366
371
|
deps.log("\nšŖ YouTube Cookie Setup\n");
|
|
367
372
|
deps.ensureConfigDir();
|
|
@@ -376,5 +381,8 @@ export async function runSetupCookies(overrides = {}) {
|
|
|
376
381
|
if (imported) {
|
|
377
382
|
return;
|
|
378
383
|
}
|
|
384
|
+
if (options.importOnly) {
|
|
385
|
+
throw new Error("No reusable YouTube session found in local Chrome/Edge profiles");
|
|
386
|
+
}
|
|
379
387
|
await deps.runManualCookieSetup(chromium, deps);
|
|
380
388
|
}
|
package/dist/utils/launcher.js
CHANGED
|
@@ -26,6 +26,10 @@ const npmCacheDir = ${JSON.stringify(npmCacheDir)};
|
|
|
26
26
|
const args = process.argv.slice(2);
|
|
27
27
|
const targetArgs = args.length > 0 ? args : ["serve"];
|
|
28
28
|
|
|
29
|
+
function isSkillInstallerMode(subArgs) {
|
|
30
|
+
return subArgs[0] === "install-skills";
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
function isRepairableNpxFailure(stderr) {
|
|
30
34
|
const lower = stderr.toLowerCase();
|
|
31
35
|
return (lower.includes("_npx/") || lower.includes("_npx\\\\"))
|
|
@@ -38,6 +42,7 @@ function runNpx(subArgs, captureStdErrOnly = false) {
|
|
|
38
42
|
return spawnSync(npxBin, ["--yes", packageSpec, ...subArgs], {
|
|
39
43
|
env: { ...process.env, npm_config_cache: npmCacheDir },
|
|
40
44
|
// Why: probe runs before MCP starts; stdout must stay silent or it will corrupt stdio transport.
|
|
45
|
+
// The skill installer is an explicit one-shot CLI path, so it can inherit stdio safely.
|
|
41
46
|
stdio: captureStdErrOnly ? ["ignore", "ignore", "pipe"] : "inherit",
|
|
42
47
|
});
|
|
43
48
|
}
|
|
@@ -70,6 +75,9 @@ function ensurePackageReady() {
|
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
ensurePackageReady();
|
|
78
|
+
if (isSkillInstallerMode(targetArgs)) {
|
|
79
|
+
process.env.YT_MCP_INSTALL_SKILLS = "1";
|
|
80
|
+
}
|
|
73
81
|
const finalRun = runNpx(targetArgs, false);
|
|
74
82
|
process.exit(finalRun.status ?? 0);
|
|
75
83
|
`;
|
package/dist/utils/openClaw.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface OpenClawServerConfig {
|
|
|
6
6
|
env?: Record<string, string>;
|
|
7
7
|
}
|
|
8
8
|
export declare function getOpenClawConfigPath(homeDir?: string): string;
|
|
9
|
+
export declare function getOpenClawSkillsDir(homeDir?: string): string;
|
|
9
10
|
export declare function buildOpenClawServerConfig(launcherCommand: LauncherCommand): OpenClawServerConfig;
|
|
10
11
|
export declare function upsertOpenClawConfigText(currentText: string | null, serverName: string, launcherCommand: LauncherCommand): string;
|
|
11
12
|
export declare function removeOpenClawConfigEntryText(currentText: string | null, serverName: string): {
|
package/dist/utils/openClaw.js
CHANGED
|
@@ -4,6 +4,9 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
export function getOpenClawConfigPath(homeDir = homedir()) {
|
|
5
5
|
return join(homeDir, ".openclaw", "workspace", "config", "mcporter.json");
|
|
6
6
|
}
|
|
7
|
+
export function getOpenClawSkillsDir(homeDir = homedir()) {
|
|
8
|
+
return join(homeDir, ".openclaw", "skills");
|
|
9
|
+
}
|
|
7
10
|
export function buildOpenClawServerConfig(launcherCommand) {
|
|
8
11
|
return {
|
|
9
12
|
transport: "stdio",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LauncherCommand } from "./launcher.js";
|
|
2
|
+
export interface SkillInstallTarget {
|
|
3
|
+
client: string;
|
|
4
|
+
label: string;
|
|
5
|
+
sourceDir: string;
|
|
6
|
+
targetDir: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SkillInstallPlanOptions {
|
|
9
|
+
homeDir?: string;
|
|
10
|
+
availableCliNames?: string[];
|
|
11
|
+
includeOpenClaw?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function getSkillPackageSourcePath(packageRoot: string): string;
|
|
14
|
+
export declare function buildSkillLauncherCommand(launcherPath: string): LauncherCommand;
|
|
15
|
+
export declare function buildSkillInstallPlan(packageRoot: string, options?: SkillInstallPlanOptions): SkillInstallTarget[];
|
|
16
|
+
export declare function installSkillTarget(target: SkillInstallTarget): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, rmSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { getOpenClawSkillsDir } from "./openClaw.js";
|
|
5
|
+
const SKILL_NAME = "use-yt-mcp";
|
|
6
|
+
export function getSkillPackageSourcePath(packageRoot) {
|
|
7
|
+
return join(packageRoot, "skills", SKILL_NAME);
|
|
8
|
+
}
|
|
9
|
+
export function buildSkillLauncherCommand(launcherPath) {
|
|
10
|
+
return {
|
|
11
|
+
command: "node",
|
|
12
|
+
args: [launcherPath, "install-skills"],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function buildSkillInstallPlan(packageRoot, options = {}) {
|
|
16
|
+
const homeDir = options.homeDir ?? homedir();
|
|
17
|
+
const availableCliNames = new Set(options.availableCliNames ?? []);
|
|
18
|
+
const sourceDir = getSkillPackageSourcePath(packageRoot);
|
|
19
|
+
const plan = [];
|
|
20
|
+
const cliTargets = [
|
|
21
|
+
{ client: "claude-internal", label: "Claude Code (internal)", dir: join(homeDir, ".claude-internal", "skills") },
|
|
22
|
+
{ client: "claude", label: "Claude Code", dir: join(homeDir, ".claude", "skills") },
|
|
23
|
+
{ client: "codex-internal", label: "Codex CLI (internal)", dir: join(homeDir, ".codex-internal", "skills") },
|
|
24
|
+
{ client: "codex", label: "Codex CLI / Codex App", dir: join(homeDir, ".codex", "skills") },
|
|
25
|
+
{ client: "gemini-internal", label: "Gemini CLI (internal)", dir: join(homeDir, ".gemini-internal", "skills") },
|
|
26
|
+
{ client: "gemini", label: "Gemini CLI", dir: join(homeDir, ".gemini", "skills") },
|
|
27
|
+
];
|
|
28
|
+
for (const target of cliTargets) {
|
|
29
|
+
if (!availableCliNames.has(target.client)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
plan.push({
|
|
33
|
+
client: target.client,
|
|
34
|
+
label: target.label,
|
|
35
|
+
sourceDir,
|
|
36
|
+
targetDir: join(target.dir, SKILL_NAME),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (options.includeOpenClaw) {
|
|
40
|
+
plan.push({
|
|
41
|
+
client: "openclaw",
|
|
42
|
+
label: "OpenClaw",
|
|
43
|
+
sourceDir,
|
|
44
|
+
targetDir: join(getOpenClawSkillsDir(homeDir), SKILL_NAME),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return plan;
|
|
48
|
+
}
|
|
49
|
+
export function installSkillTarget(target) {
|
|
50
|
+
if (!existsSync(target.sourceDir)) {
|
|
51
|
+
throw new Error(`Bundled skill not found: ${target.sourceDir}`);
|
|
52
|
+
}
|
|
53
|
+
mkdirSync(dirname(target.targetDir), { recursive: true });
|
|
54
|
+
rmSync(target.targetDir, { recursive: true, force: true });
|
|
55
|
+
cpSync(target.sourceDir, target.targetDir, { recursive: true });
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mkterswingman/5mghost-yonder",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"description": "Internal MCP client with local data tools and remote API proxy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"dist/",
|
|
37
|
+
"skills/",
|
|
37
38
|
"scripts/download-ytdlp.mjs",
|
|
38
39
|
"scripts/install.sh",
|
|
39
40
|
"scripts/install.ps1",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: use-yt-mcp
|
|
3
|
+
preamble-tier: 3
|
|
4
|
+
version: 1.2.0
|
|
5
|
+
description: |
|
|
6
|
+
Use when the user wants YouTube analysis through yt-mcp: channel performance,
|
|
7
|
+
video stats, subtitles, comments, trending, or batch YouTube data work.
|
|
8
|
+
Also use when the user pastes YouTube links such as youtube.com/watch,
|
|
9
|
+
youtube.com/shorts, youtube.com/live, or youtu.be URLs.
|
|
10
|
+
Keywords: YouTube, é¢é, č§é¢, åå¹, čÆč®ŗ, åę, ęę¾é, trending, yt-mcp, youtube.com, youtu.be.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Use yt-mcp
|
|
14
|
+
|
|
15
|
+
Focus on YouTube analysis with yt-mcp MCP tools. Answer the analysis question first. Only switch into setup or troubleshooting when the user explicitly asks for it or a tool call fails.
|
|
16
|
+
|
|
17
|
+
## 0. Hard Constraints
|
|
18
|
+
|
|
19
|
+
- For YouTube data tasks, always use `mcp__yt-mcp__*` tools first.
|
|
20
|
+
- Do not route YouTube queries to legacy MCPs or legacy setup skills such as `youtube-data`, `mcp_youtube_data`, `use-youtube-data-mcp`, or `Use YouTube Data MCP` when `yt-mcp` can answer.
|
|
21
|
+
- Do not fetch YouTube metrics, subtitles, comments, channel data, or trending data by browsing the web, scraping pages, or using generic web search. Use `yt-mcp` instead.
|
|
22
|
+
- If `yt-mcp` is unavailable or fails, stop and tell the user it needs setup or troubleshooting. Do not silently fall back to old MCPs or ad-hoc web lookup.
|
|
23
|
+
|
|
24
|
+
## Trigger Hints
|
|
25
|
+
|
|
26
|
+
- Treat pasted YouTube links as an automatic trigger for this skill, even if the user does not explicitly say "YouTube".
|
|
27
|
+
- Common URL forms: `https://www.youtube.com/watch?v=...`, `https://youtu.be/...`, `https://www.youtube.com/shorts/...`, `https://www.youtube.com/live/...`.
|
|
28
|
+
|
|
29
|
+
## 1. Intent -> Tool Routing
|
|
30
|
+
|
|
31
|
+
| User Intent | Tool(s) |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Search videos by keyword | `search_videos` |
|
|
34
|
+
| Get video metrics in bulk | `get_video_stats` |
|
|
35
|
+
| Large video stats job | `start_video_stats_job` -> `poll_video_stats_job` |
|
|
36
|
+
| Get subtitles / transcript | `get_subtitles`, `batch_get_subtitles` |
|
|
37
|
+
| Check subtitle languages | `list_available_subtitles` |
|
|
38
|
+
| Get comments | `get_comments` |
|
|
39
|
+
| Large comments export | `start_comments_job` -> `poll_comments_job` |
|
|
40
|
+
| Get comment replies | `get_comment_replies` |
|
|
41
|
+
| Channel stats | `get_channel_stats` |
|
|
42
|
+
| List channel uploads | `list_channel_uploads` |
|
|
43
|
+
| Trending videos | `get_trending` |
|
|
44
|
+
| Local download | `start_download_job` -> `poll_download_job` |
|
|
45
|
+
|
|
46
|
+
All tools are prefixed `mcp__yt-mcp__` in actual calls.
|
|
47
|
+
|
|
48
|
+
## 2. Analysis Rules
|
|
49
|
+
|
|
50
|
+
- Prefer batch-capable tools when comparing multiple videos or channels.
|
|
51
|
+
- `get_video_stats` accepts up to 1000 items. If the response returns `mode: "file"`, then inline `preview_items` is only a preview sample from a larger dataset and must not be used as the full basis of analysis. Tell the user the complete result is in `output_file` or `download_url`.
|
|
52
|
+
- For large video/comment analyses where completeness matters, prefer async jobs: `start_video_stats_job` -> `poll_video_stats_job`, or `start_comments_job` -> `poll_comments_job`.
|
|
53
|
+
- When using async jobs, poll until status is `completed`, and tell the user if the result is still partial or in progress.
|
|
54
|
+
- Use normalized response fields in analysis: `published_at`, `duration`, `view_count`, `like_count`, `comment_count`, `is_live_replay`.
|
|
55
|
+
- Default channel analysis window to 30 days unless the user specifies another range.
|
|
56
|
+
- Shorts heuristic: parsed ISO 8601 `duration` <= 90 seconds. Live replay: `is_live_replay === true`. Otherwise treat as long-form.
|
|
57
|
+
- Follow the user's language. Use thousand separators like `1,234,567`; avoid `K/M/B` unless the user asks.
|
|
58
|
+
- Do not dump raw JSON unless the user explicitly wants raw output.
|
|
59
|
+
|
|
60
|
+
## 3. Common Workflows
|
|
61
|
+
|
|
62
|
+
### Channel Average Views
|
|
63
|
+
|
|
64
|
+
1. `list_channel_uploads(channel or channel_id, max_results=N)`
|
|
65
|
+
2. For moderate sets, `get_video_stats(videos=[...ids])`; for large sets or when full coverage matters, `start_video_stats_job(videos=[...ids])` then `poll_video_stats_job(job_id)` until completed
|
|
66
|
+
3. Filter by `published_at` within the requested window
|
|
67
|
+
4. Segment into long-form, Shorts, live replay
|
|
68
|
+
5. Report video count, total views, average views, max, min
|
|
69
|
+
|
|
70
|
+
Default output:
|
|
71
|
+
|
|
72
|
+
```md
|
|
73
|
+
## {é¢éå} åęåęļ¼čæ {N} 天ļ¼
|
|
74
|
+
|
|
75
|
+
| ē±»å | č§é¢ę° | ę»ęę¾ | åę | ęé« | ęä½ |
|
|
76
|
+
|---|---:|---:|---:|---:|---:|
|
|
77
|
+
| éæč§é¢ | 12 | 1,234,567 | 102,880 | 456,789 | 12,345 |
|
|
78
|
+
| Shorts | 24 | 2,345,678 | 97,736 | 234,567 | 23,456 |
|
|
79
|
+
| ē“ęåę¾ | 3 | 345,678 | 115,226 | 200,000 | 45,678 |
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Video Summary
|
|
83
|
+
|
|
84
|
+
1. `get_subtitles(video, format="csv")`
|
|
85
|
+
2. Build a timestamped summary from the transcript
|
|
86
|
+
3. Output section headers with timestamps, not a single long paragraph
|
|
87
|
+
|
|
88
|
+
### Comment Analysis
|
|
89
|
+
|
|
90
|
+
1. For normal analysis, `get_comments(video, max_comments=N, order="relevance")`; for larger exports, `start_comments_job` then `poll_comments_job`
|
|
91
|
+
2. Cluster by sentiment or topic
|
|
92
|
+
3. Quote representative comments and keep like counts when useful
|
|
93
|
+
|
|
94
|
+
### Channel Stability
|
|
95
|
+
|
|
96
|
+
1. Fetch uploads and stats
|
|
97
|
+
2. Measure posting frequency, average views, and volatility
|
|
98
|
+
3. Compare recent videos vs earlier videos to judge trend direction
|
|
99
|
+
|
|
100
|
+
## 4. Output Rules
|
|
101
|
+
|
|
102
|
+
- Answer the user's actual question first, then show supporting metrics.
|
|
103
|
+
- For comparisons, prefer compact tables over long prose.
|
|
104
|
+
- State assumptions when the time window, sample size, or language is inferred.
|
|
105
|
+
- If data is partial, say so directly.
|
|
106
|
+
|
|
107
|
+
## 5. Setup Boundary
|
|
108
|
+
|
|
109
|
+
Only discuss CLI when the user asks to install or troubleshoot yt-mcp, or when a tool call fails because of auth/cookies/runtime.
|
|
110
|
+
|
|
111
|
+
Useful commands:
|
|
112
|
+
|
|
113
|
+
- `yt-mcp setup`
|
|
114
|
+
- `yt-mcp setup-cookies`
|
|
115
|
+
- `yt-mcp check`
|
|
116
|
+
|
|
117
|
+
Do not turn a normal analysis request into a setup checklist.
|