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 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.6.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.3.0"
50
+ "headless-youtube-captions": "^1.4.0"
40
51
  },
41
52
  "devDependencies": {
42
53
  "@types/node": "^22.0.0",