mcp-headless-youtube-transcript 0.6.0 → 0.7.0
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/CHANGELOG.md +6 -0
- package/build/index.js +79 -1
- package/package.json +14 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.6.1] - 2025-01-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Binary Execution**: Fixed npx execution issue by explicitly defining files array in package.json
|
|
12
|
+
- **File Permissions**: Ensured binary file maintains proper execute permissions when published
|
|
13
|
+
|
|
8
14
|
## [0.6.0] - 2025-01-24
|
|
9
15
|
|
|
10
16
|
### Added
|
package/build/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
// @ts-ignore - Types are defined in global.d.ts
|
|
6
|
-
import { getSubtitles, getChannelVideos, searchChannelVideos, getVideoComments, searchYouTubeGlobal } from 'headless-youtube-captions';
|
|
6
|
+
import { getSubtitles, getChannelVideos, searchChannelVideos, getVideoComments, searchYouTubeGlobal, getVideoMetadata } from 'headless-youtube-captions';
|
|
7
7
|
import { extractVideoId, extractChannelIdentifier, formatChannelUrl, truncateText, isValidYouTubeUrl, getSearchCacheKey } from './utils.js';
|
|
8
8
|
// In-memory caches
|
|
9
9
|
const transcriptCache = new Map();
|
|
@@ -205,6 +205,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
205
205
|
required: ['query'],
|
|
206
206
|
},
|
|
207
207
|
},
|
|
208
|
+
{
|
|
209
|
+
name: 'get_video_metadata',
|
|
210
|
+
description: 'Extract comprehensive video metadata including description, upload date, like count',
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
properties: {
|
|
214
|
+
videoId: {
|
|
215
|
+
type: 'string',
|
|
216
|
+
description: 'YouTube video ID or full URL',
|
|
217
|
+
},
|
|
218
|
+
expandDescription: {
|
|
219
|
+
type: 'boolean',
|
|
220
|
+
description: 'Whether to expand truncated descriptions. Defaults to true',
|
|
221
|
+
default: true,
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
required: ['videoId'],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
208
227
|
{
|
|
209
228
|
name: 'navigate_search_result',
|
|
210
229
|
description: 'Navigate to a video or channel page from search results',
|
|
@@ -541,6 +560,65 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
541
560
|
cleanupExpiredCache();
|
|
542
561
|
}
|
|
543
562
|
}
|
|
563
|
+
if (name === 'get_video_metadata') {
|
|
564
|
+
try {
|
|
565
|
+
const { videoId, expandDescription = true } = args;
|
|
566
|
+
// Extract video ID from URL if needed
|
|
567
|
+
const extractedVideoId = extractVideoId(videoId);
|
|
568
|
+
if (!extractedVideoId) {
|
|
569
|
+
throw new Error('Invalid YouTube video ID or URL');
|
|
570
|
+
}
|
|
571
|
+
// Check cache first - reuse the same cache key pattern
|
|
572
|
+
let cachedMetadata = getCachedTranscript(extractedVideoId, `metadata_${expandDescription}`);
|
|
573
|
+
if (cachedMetadata) {
|
|
574
|
+
try {
|
|
575
|
+
const parsedMetadata = JSON.parse(cachedMetadata);
|
|
576
|
+
return {
|
|
577
|
+
content: [
|
|
578
|
+
{
|
|
579
|
+
type: 'text',
|
|
580
|
+
text: JSON.stringify(parsedMetadata, null, 2),
|
|
581
|
+
},
|
|
582
|
+
],
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
catch (e) {
|
|
586
|
+
// Invalid cached data, proceed with fresh extraction
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
// Get video metadata using headless-youtube-captions
|
|
590
|
+
const metadata = await getVideoMetadata({
|
|
591
|
+
videoID: extractedVideoId,
|
|
592
|
+
expandDescription: expandDescription,
|
|
593
|
+
});
|
|
594
|
+
// Cache the result (using the transcript cache infrastructure)
|
|
595
|
+
setCachedTranscript(extractedVideoId, `metadata_${expandDescription}`, JSON.stringify(metadata));
|
|
596
|
+
return {
|
|
597
|
+
content: [
|
|
598
|
+
{
|
|
599
|
+
type: 'text',
|
|
600
|
+
text: JSON.stringify(metadata, null, 2),
|
|
601
|
+
},
|
|
602
|
+
],
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
catch (error) {
|
|
606
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
607
|
+
return {
|
|
608
|
+
content: [
|
|
609
|
+
{
|
|
610
|
+
type: 'text',
|
|
611
|
+
text: `Error getting video metadata: ${errorMessage}`,
|
|
612
|
+
},
|
|
613
|
+
],
|
|
614
|
+
isError: true,
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
finally {
|
|
618
|
+
// Cleanup expired cache entries after each request
|
|
619
|
+
cleanupExpiredCache();
|
|
620
|
+
}
|
|
621
|
+
}
|
|
544
622
|
if (name === 'navigate_search_result') {
|
|
545
623
|
try {
|
|
546
624
|
const { resultUrl, resultType } = args;
|
package/package.json
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-headless-youtube-transcript",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for extracting YouTube video transcripts using headless-youtube-captions",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "MCP server for extracting YouTube video transcripts, metadata, and comprehensive video information using headless-youtube-captions",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mcp-headless-youtube-transcript": "build/index.js"
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"build/index.js",
|
|
12
|
+
"build/index.d.ts",
|
|
13
|
+
"build/utils.js",
|
|
14
|
+
"build/utils.d.ts",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"CHANGELOG.md"
|
|
18
|
+
],
|
|
10
19
|
"scripts": {
|
|
11
20
|
"build": "tsc",
|
|
12
21
|
"dev": "tsx src/index.ts",
|
|
@@ -21,6 +30,8 @@
|
|
|
21
30
|
"youtube",
|
|
22
31
|
"transcript",
|
|
23
32
|
"captions",
|
|
33
|
+
"metadata",
|
|
34
|
+
"description",
|
|
24
35
|
"search",
|
|
25
36
|
"automation"
|
|
26
37
|
],
|
|
@@ -36,7 +47,7 @@
|
|
|
36
47
|
"license": "MIT",
|
|
37
48
|
"dependencies": {
|
|
38
49
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
39
|
-
"headless-youtube-captions": "^1.
|
|
50
|
+
"headless-youtube-captions": "^1.4.0"
|
|
40
51
|
},
|
|
41
52
|
"devDependencies": {
|
|
42
53
|
"@types/node": "^22.0.0",
|