video-context-mcp-server 1.0.0-beta.2

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 (50) hide show
  1. package/README.md +249 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +122 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/services/ffmpeg.d.ts +47 -0
  7. package/dist/services/ffmpeg.d.ts.map +1 -0
  8. package/dist/services/ffmpeg.js +170 -0
  9. package/dist/services/ffmpeg.js.map +1 -0
  10. package/dist/services/glmClient.d.ts +50 -0
  11. package/dist/services/glmClient.d.ts.map +1 -0
  12. package/dist/services/glmClient.js +196 -0
  13. package/dist/services/glmClient.js.map +1 -0
  14. package/dist/services/kimiClient.d.ts +45 -0
  15. package/dist/services/kimiClient.d.ts.map +1 -0
  16. package/dist/services/kimiClient.js +152 -0
  17. package/dist/services/kimiClient.js.map +1 -0
  18. package/dist/services/providerRouter.d.ts +23 -0
  19. package/dist/services/providerRouter.d.ts.map +1 -0
  20. package/dist/services/providerRouter.js +70 -0
  21. package/dist/services/providerRouter.js.map +1 -0
  22. package/dist/tools/analyzeVideo.d.ts +18 -0
  23. package/dist/tools/analyzeVideo.d.ts.map +1 -0
  24. package/dist/tools/analyzeVideo.js +81 -0
  25. package/dist/tools/analyzeVideo.js.map +1 -0
  26. package/dist/tools/extractFrames.d.ts +22 -0
  27. package/dist/tools/extractFrames.d.ts.map +1 -0
  28. package/dist/tools/extractFrames.js +64 -0
  29. package/dist/tools/extractFrames.js.map +1 -0
  30. package/dist/tools/getVideoInfo.d.ts +18 -0
  31. package/dist/tools/getVideoInfo.d.ts.map +1 -0
  32. package/dist/tools/getVideoInfo.js +34 -0
  33. package/dist/tools/getVideoInfo.js.map +1 -0
  34. package/dist/tools/searchTimestamp.d.ts +25 -0
  35. package/dist/tools/searchTimestamp.d.ts.map +1 -0
  36. package/dist/tools/searchTimestamp.js +110 -0
  37. package/dist/tools/searchTimestamp.js.map +1 -0
  38. package/dist/tools/summarizeVideo.d.ts +18 -0
  39. package/dist/tools/summarizeVideo.d.ts.map +1 -0
  40. package/dist/tools/summarizeVideo.js +117 -0
  41. package/dist/tools/summarizeVideo.js.map +1 -0
  42. package/dist/utils/base64.d.ts +35 -0
  43. package/dist/utils/base64.d.ts.map +1 -0
  44. package/dist/utils/base64.js +50 -0
  45. package/dist/utils/base64.js.map +1 -0
  46. package/dist/utils/tempFiles.d.ts +20 -0
  47. package/dist/utils/tempFiles.d.ts.map +1 -0
  48. package/dist/utils/tempFiles.js +31 -0
  49. package/dist/utils/tempFiles.js.map +1 -0
  50. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,249 @@
1
+ # Video Context MCP Server
2
+
3
+ Video Context MCP Server is a Model Context Protocol (MCP) server that gives GitHub Copilot in VS Code the ability to understand and analyze video content. Supports two AI backends: **Kimi K2.5** (Moonshot AI) and **GLM-4.6V** (Z.AI).
4
+
5
+ ## Current Status
6
+
7
+ - ✅ Project scaffold, MCP registration, ffmpeg helpers, lint/build/format pipeline
8
+ - ✅ Phase 2A complete: core Kimi/GLM client analysis methods implemented
9
+ - ✅ Phase 2B complete: all MCP tool handlers implemented
10
+ - ✅ Phase 2C automated coverage complete: ffmpeg service tests + mocked orchestration tests for AI-dependent tools
11
+ - ✅ Phase 2C reasoning-mode methods complete: `KimiClient.analyzeVideoWithThinking()` and `GLMClient.analyzeWithThinking()`
12
+ - ✅ Phase 2C complete (Tier A): runtime integration validation with real ffmpeg fixtures + deterministic mocked AI-provider orchestration
13
+
14
+ ## Features
15
+
16
+ - 🎬 **Video Q&A** — Ask questions about video content and get AI-powered answers
17
+ - 📝 **Video Summarization** — Generate structured summaries with key scenes and timelines
18
+ - 🖼️ **Frame Extraction** — Extract frames at specific timestamps or intervals
19
+ - 🔍 **Timestamp Search** — Find the exact moment when something happens in a video
20
+ - 📊 **Video Metadata** — Get duration, resolution, fps, codec, and other technical details
21
+ - 🔄 **Dual Backend Support** — Auto-routes to GLM-4.6V (cheap/free) or Kimi K2.5 (large videos)
22
+ - 🎯 **Smart Video Handling** — Extracts keyframes from long videos to reduce token usage
23
+
24
+ ## Installation
25
+
26
+ ### 1. Install Dependencies
27
+
28
+ ```bash
29
+ npm install
30
+ ```
31
+
32
+ ### 2. Configure API Keys
33
+
34
+ You'll need API keys for one or both backends:
35
+
36
+ - **Kimi K2.5 (Moonshot AI)**: [Get API Key](https://platform.moonshot.ai)
37
+ - **GLM-4.6V (Z.AI)**: [Get API Key](https://z.ai/manage-apikey/apikey-list)
38
+
39
+ ### 3. Configure VS Code
40
+
41
+ Recommended: copy `.vscode-template/mcp.json` to `.vscode/mcp.json` and fill in your own keys locally.
42
+
43
+ ```bash
44
+ cp .vscode-template/mcp.json .vscode/mcp.json
45
+ ```
46
+
47
+ Template options:
48
+
49
+ - `.vscode-template/mcp.json` — default (watch enabled, debug disabled)
50
+ - `.vscode-template/mcp.quiet.json` — quiet dev mode (watch enabled, debug disabled)
51
+ - `.vscode-template/mcp.debug.json` — verbose dev mode (watch + node debug enabled)
52
+
53
+ If you want the debug variant directly:
54
+
55
+ ```bash
56
+ cp .vscode-template/mcp.debug.json .vscode/mcp.json
57
+ ```
58
+
59
+ Do not commit real API keys to the repository.
60
+
61
+ You can also create `.vscode/mcp.json` manually:
62
+
63
+ ```json
64
+ {
65
+ "servers": {
66
+ "videoMcp": {
67
+ "type": "stdio",
68
+ "command": "node",
69
+ "args": ["${workspaceFolder}/dist/index.js"],
70
+ "env": {
71
+ "MOONSHOT_API_KEY": "${input:moonshot-key}",
72
+ "Z_AI_API_KEY": "${input:zai-key}"
73
+ }
74
+ }
75
+ },
76
+ "inputs": [
77
+ {
78
+ "type": "promptString",
79
+ "id": "moonshot-key",
80
+ "description": "Moonshot API Key for Kimi K2.5",
81
+ "password": true
82
+ },
83
+ {
84
+ "type": "promptString",
85
+ "id": "zai-key",
86
+ "description": "Z.AI API Key for GLM-4.6V",
87
+ "password": true
88
+ }
89
+ ]
90
+ }
91
+ ```
92
+
93
+ ### 4. Build and Run
94
+
95
+ ```bash
96
+ npm run build
97
+ ```
98
+
99
+ The MCP server will be automatically started by VS Code when Copilot Chat is opened.
100
+
101
+ ### 5. Debugging Behavior in VS Code
102
+
103
+ When your `.vscode/mcp.json` includes a `dev` block such as:
104
+
105
+ ```jsonc
106
+ "dev": {
107
+ "watch": "src/**/*.ts",
108
+ "debug": { "type": "node" }
109
+ }
110
+ ```
111
+
112
+ you may see frequent logs in the **Output** panel under `MCP: videoMcp`.
113
+
114
+ This is expected in development mode:
115
+
116
+ - `watch` restarts/reloads the MCP server when TypeScript files change
117
+ - `debug` enables Node debug integration
118
+ - MCP protocol payloads (tool schemas, discovery events, lifecycle messages) are printed in that output channel
119
+
120
+ If you want less noise, remove either:
121
+
122
+ - `dev.debug` (keeps auto-watch, disables debug integration), or
123
+ - the full `dev` block (disables watch + debug behavior)
124
+
125
+ ## Available Tools
126
+
127
+ | Tool | Description | Parameters |
128
+ | ------------------ | ------------------------------------ | ------------------------------------------------ |
129
+ | `analyze_video` | Ask questions about video content | `videoPath`, `question`, `provider?` |
130
+ | `summarize_video` | Generate a structured video summary | `videoPath`, `provider?` |
131
+ | `extract_frames` | Extract frames from a video | `videoPath`, `mode`, `count/interval/timestamps` |
132
+ | `search_timestamp` | Find when something specific happens | `videoPath`, `query`, `provider?` |
133
+ | `get_video_info` | Get video metadata | `videoPath` |
134
+
135
+ ## Usage Examples
136
+
137
+ ### Analyze Video
138
+
139
+ Ask Copilot Chat:
140
+
141
+ > "Analyze the video at `./demo.mp4` and tell me what happens in it"
142
+
143
+ ### Summarize Video
144
+
145
+ > "Summarize the video at `./long-video.mp4`"
146
+
147
+ ### Extract Frames
148
+
149
+ > "Extract 5 evenly-spaced frames from `./video.mp4`"
150
+
151
+ > "Extract a frame at timestamp 30 seconds from `./video.mp4`"
152
+
153
+ ### Search Timestamp
154
+
155
+ > "In `./video.mp4`, at what timestamp does the person wave?"
156
+
157
+ ### Get Video Info
158
+
159
+ > "Get the video info for `./video.mp4`"
160
+
161
+ ## Backend Comparison
162
+
163
+ | Feature | GLM-4.6V | Kimi K2.5 |
164
+ | -------------- | ----------------------------- | ---------------------------------------------- |
165
+ | Video formats | mp4, avi, mov, wmv, webm, m4v | mp4, mpeg, mov, avi, flv, mpg, webm, wmv, 3gpp |
166
+ | Max video size | 8 MB | 100 MB + file upload API |
167
+ | Price | $0.30 input / $0.90 output | $0.60 input / $3.00 output |
168
+ | Free tier | Yes (GLM-4.6V-Flash) | No |
169
+ | Context window | 128K | 256K |
170
+ | Best for | Short clips, cost efficiency | Large videos, broader format support |
171
+
172
+ The server auto-routes to the best backend based on video size:
173
+
174
+ - Videos ≤ 8 MB → GLM-4.6V (cheaper, free tier available)
175
+ - Videos > 8 MB → Kimi K2.5 (larger support)
176
+
177
+ ## Environment Variables
178
+
179
+ | Variable | Description | Required |
180
+ | ---------------------------- | --------------------------------------- | -------------------------- |
181
+ | `MOONSHOT_API_KEY` | Moonshot AI API key for Kimi K2.5 | Optional (if using GLM) |
182
+ | `Z_AI_API_KEY` | Z.AI API key for GLM-4.6V | Optional (if using Kimi) |
183
+ | `VIDEO_MCP_DEFAULT_PROVIDER` | Default backend (`auto`, `glm`, `kimi`) | Optional (default: `auto`) |
184
+ | `VIDEO_MCP_MAX_FRAMES` | Max frames for summarization | Optional (default: 20) |
185
+
186
+ ## Development
187
+
188
+ ```bash
189
+ # Install dependencies
190
+ npm install
191
+
192
+ # Run in development (auto-restart on changes)
193
+ npm run dev
194
+
195
+ # Build for production
196
+ npm run build
197
+
198
+ # Run type checking
199
+ npm run type-check
200
+
201
+ # Run linter
202
+ npm run lint
203
+
204
+ # Run automated tests
205
+ npm run test
206
+
207
+ # Run tests in watch mode
208
+ npm run test:watch
209
+
210
+ # Run tests with coverage
211
+ npm run test:coverage
212
+
213
+ # Format all files
214
+ npm run format
215
+
216
+ # Check formatting only
217
+ npm run format:check
218
+
219
+ # Lint + Type-check + Format + Build
220
+ npm run ltfb
221
+ ```
222
+
223
+ ## Architecture
224
+
225
+ ```
226
+ video-mcp/
227
+ ├── src/
228
+ │ ├── index.ts # MCP server entry point
229
+ │ ├── tools/ # MCP tool implementations
230
+ │ ├── services/ # Backend clients (Kimi, GLM, ffmpeg)
231
+ │ └── utils/ # Helpers (temp files, base64)
232
+ ├── .vscode/
233
+ │ └── mcp.json # VS Code MCP configuration
234
+ ├── docs/
235
+ │ └── technical/ # Technical documentation
236
+ └── .github/
237
+ └── copilot-instructions.md # Copilot AI assistant guidelines
238
+ ```
239
+
240
+ ## License
241
+
242
+ MIT
243
+
244
+ ## Credits
245
+
246
+ - [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) by Anthropic
247
+ - [Kimi K2.5](https://github.com/MoonshotAI/Kimi-K2.5) by Moonshot AI
248
+ - [GLM-4.6V](https://docs.z.ai/guides/vlm/glm-4.6v) by Z.AI
249
+ - [ffmpeg](https://ffmpeg.org/) for video processing
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { z } from 'zod';
5
+ // Import tool handlers
6
+ import { analyzeVideoTool } from './tools/analyzeVideo.js';
7
+ import { summarizeVideoTool } from './tools/summarizeVideo.js';
8
+ import { extractFramesTool } from './tools/extractFrames.js';
9
+ import { searchTimestampTool } from './tools/searchTimestamp.js';
10
+ import { getVideoInfoTool } from './tools/getVideoInfo.js';
11
+ /**
12
+ * Main entry point for the Video Context MCP Server
13
+ * Creates an MCP server, registers all video analysis tools, and connects via stdio
14
+ */
15
+ async function main() {
16
+ // Create MCP server with name and version
17
+ const server = new McpServer({
18
+ name: 'video-mcp',
19
+ version: '1.0.0',
20
+ }, {
21
+ capabilities: {
22
+ logging: {}, // Enable logging for progress reporting
23
+ },
24
+ });
25
+ // Register all video analysis tools
26
+ // Tool 1: analyze_video - Ask questions about video content
27
+ server.registerTool('analyze_video', {
28
+ title: 'Analyze Video',
29
+ description: 'Ask questions about video content and get AI-powered answers. Supports both local files and URLs.',
30
+ inputSchema: z.object({
31
+ videoPath: z
32
+ .string()
33
+ .describe('Path to the video file (local path or URL)'),
34
+ question: z
35
+ .string()
36
+ .describe('Question to ask about the video content'),
37
+ provider: z
38
+ .enum(['auto', 'glm', 'kimi'])
39
+ .optional()
40
+ .describe("AI backend to use: 'auto' (default), 'glm' (GLM-4.6V), or 'kimi' (Kimi K2.5)"),
41
+ }),
42
+ }, analyzeVideoTool);
43
+ // Tool 2: summarize_video - Generate structured video summary
44
+ server.registerTool('summarize_video', {
45
+ title: 'Summarize Video',
46
+ description: 'Generate a structured summary of the video including overview, key scenes, and timeline. For long videos (>5 min), extracts keyframes to reduce token usage.',
47
+ inputSchema: z.object({
48
+ videoPath: z
49
+ .string()
50
+ .describe('Path to the video file (local path or URL)'),
51
+ provider: z
52
+ .enum(['auto', 'glm', 'kimi'])
53
+ .optional()
54
+ .describe("AI backend to use: 'auto' (default), 'glm' (GLM-4.6V), or 'kimi' (Kimi K2.5)"),
55
+ }),
56
+ }, summarizeVideoTool);
57
+ // Tool 3: extract_frames - Extract frames from video
58
+ server.registerTool('extract_frames', {
59
+ title: 'Extract Frames',
60
+ description: 'Extract frames from a video at specific timestamps or intervals. This is a local-only operation (no AI backend required).',
61
+ inputSchema: z.object({
62
+ videoPath: z
63
+ .string()
64
+ .describe('Path to the video file (local path only)'),
65
+ mode: z
66
+ .enum(['even', 'interval', 'timestamps'])
67
+ .describe("Extraction mode: 'even' (N evenly-spaced frames), 'interval' (every N seconds), or 'timestamps' (at specific times)"),
68
+ count: z
69
+ .number()
70
+ .int()
71
+ .min(1)
72
+ .max(100)
73
+ .optional()
74
+ .describe("Number of frames to extract (required for 'even' mode)"),
75
+ intervalSec: z
76
+ .number()
77
+ .min(0.1)
78
+ .optional()
79
+ .describe("Interval in seconds between frames (required for 'interval' mode)"),
80
+ timestamps: z
81
+ .array(z.number().min(0))
82
+ .optional()
83
+ .describe("Array of timestamps in seconds (required for 'timestamps' mode)"),
84
+ }),
85
+ }, extractFramesTool);
86
+ // Tool 4: search_timestamp - Find when something happens in video
87
+ server.registerTool('search_timestamp', {
88
+ title: 'Search Timestamp',
89
+ description: 'Find the timestamp when something specific happens in a video. Extracts frames and uses AI to locate the content.',
90
+ inputSchema: z.object({
91
+ videoPath: z
92
+ .string()
93
+ .describe('Path to the video file (local path only)'),
94
+ query: z
95
+ .string()
96
+ .describe("What to search for, e.g., 'person waves', 'dog runs', 'car crash'"),
97
+ provider: z
98
+ .enum(['auto', 'glm', 'kimi'])
99
+ .optional()
100
+ .describe("AI backend to use: 'auto' (default), 'glm' (GLM-4.6V), or 'kimi' (Kimi K2.5)"),
101
+ }),
102
+ }, searchTimestampTool);
103
+ // Tool 5: get_video_info - Get video metadata
104
+ server.registerTool('get_video_info', {
105
+ title: 'Get Video Info',
106
+ description: 'Get video metadata including duration, resolution, fps, codec, file size, and format. This is a local-only operation (no AI backend required).',
107
+ inputSchema: z.object({
108
+ videoPath: z
109
+ .string()
110
+ .describe('Path to the video file (local path only)'),
111
+ }),
112
+ }, getVideoInfoTool);
113
+ // Connect to VS Code via stdio transport
114
+ const transport = new StdioServerTransport();
115
+ await server.connect(transport);
116
+ // Server is now running, listening for tool calls from Copilot
117
+ }
118
+ main().catch((error) => {
119
+ console.error('Fatal error starting video-mcp server:', error);
120
+ process.exit(1);
121
+ });
122
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Video Metadata
3
+ */
4
+ export interface VideoMetadata {
5
+ duration: number;
6
+ width: number;
7
+ height: number;
8
+ fps: number;
9
+ codec: string;
10
+ fileSize: number;
11
+ format: string;
12
+ }
13
+ /**
14
+ * Get video metadata using ffprobe
15
+ * @param videoPath - Path to the video file
16
+ * @returns Video metadata
17
+ */
18
+ export declare function getVideoMetadata(videoPath: string): Promise<VideoMetadata>;
19
+ /**
20
+ * Extract a single frame at a specific timestamp
21
+ * @param videoPath - Path to the video file
22
+ * @param timestampSec - Timestamp in seconds
23
+ * @returns Buffer containing the PNG frame
24
+ */
25
+ export declare function extractFrameAt(videoPath: string, timestampSec: number): Promise<Buffer>;
26
+ /**
27
+ * Extract N evenly-spaced frames from a video
28
+ * @param videoPath - Path to the video file
29
+ * @param count - Number of frames to extract
30
+ * @returns Array of PNG buffers
31
+ */
32
+ export declare function extractFramesEvenly(videoPath: string, count: number): Promise<Buffer[]>;
33
+ /**
34
+ * Extract frames at regular intervals
35
+ * @param videoPath - Path to the video file
36
+ * @param intervalSec - Interval in seconds between frames
37
+ * @returns Array of PNG buffers
38
+ */
39
+ export declare function extractFramesAtInterval(videoPath: string, intervalSec: number): Promise<Buffer[]>;
40
+ /**
41
+ * Extract frames at specific timestamps
42
+ * @param videoPath - Path to the video file
43
+ * @param timestamps - Array of timestamps in seconds
44
+ * @returns Array of PNG buffers (same order as timestamps)
45
+ */
46
+ export declare function extractFramesAtTimestamps(videoPath: string, timestamps: number[]): Promise<Buffer[]>;
47
+ //# sourceMappingURL=ffmpeg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../../src/services/ffmpeg.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CA0BxB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBnB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BnB"}
@@ -0,0 +1,170 @@
1
+ import ffmpeg from 'fluent-ffmpeg';
2
+ import ffmpegInstaller from '@ffmpeg-installer/ffmpeg';
3
+ import ffprobeInstaller from '@ffprobe-installer/ffprobe';
4
+ import * as fs from 'fs/promises';
5
+ import * as path from 'path';
6
+ import { mkdtemp, rm } from 'fs/promises';
7
+ import { tmpdir } from 'os';
8
+ // Set paths to bundled ffmpeg and ffprobe binaries
9
+ ffmpeg.setFfmpegPath(ffmpegInstaller.path);
10
+ ffmpeg.setFfprobePath(ffprobeInstaller.path);
11
+ /**
12
+ * Get video metadata using ffprobe
13
+ * @param videoPath - Path to the video file
14
+ * @returns Video metadata
15
+ */
16
+ export async function getVideoMetadata(videoPath) {
17
+ return new Promise((resolve, reject) => {
18
+ ffmpeg.ffprobe(videoPath, (err, metadata) => {
19
+ if (err) {
20
+ reject(err);
21
+ return;
22
+ }
23
+ const videoStream = metadata.streams.find((s) => s.codec_type === 'video');
24
+ if (!videoStream) {
25
+ reject(new Error('No video stream found in file'));
26
+ return;
27
+ }
28
+ resolve({
29
+ duration: metadata.format.duration || 0,
30
+ width: videoStream.width || 0,
31
+ height: videoStream.height || 0,
32
+ fps: parseFps(videoStream.r_frame_rate),
33
+ codec: videoStream.codec_name || 'unknown',
34
+ fileSize: metadata.format.size || 0,
35
+ format: metadata.format.format_name || 'unknown',
36
+ });
37
+ });
38
+ });
39
+ }
40
+ /**
41
+ * Extract a single frame at a specific timestamp
42
+ * @param videoPath - Path to the video file
43
+ * @param timestampSec - Timestamp in seconds
44
+ * @returns Buffer containing the PNG frame
45
+ */
46
+ export async function extractFrameAt(videoPath, timestampSec) {
47
+ const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
48
+ const outputPath = path.join(tempDir, 'frame.png');
49
+ try {
50
+ await new Promise((resolve, reject) => {
51
+ ffmpeg(videoPath)
52
+ .seekInput(timestampSec)
53
+ .frames(1)
54
+ .output(outputPath)
55
+ .on('end', () => resolve())
56
+ .on('error', reject)
57
+ .run();
58
+ });
59
+ const frameBuffer = await fs.readFile(outputPath);
60
+ return frameBuffer;
61
+ }
62
+ finally {
63
+ await rm(tempDir, { recursive: true, force: true });
64
+ }
65
+ }
66
+ /**
67
+ * Extract N evenly-spaced frames from a video
68
+ * @param videoPath - Path to the video file
69
+ * @param count - Number of frames to extract
70
+ * @returns Array of PNG buffers
71
+ */
72
+ export async function extractFramesEvenly(videoPath, count) {
73
+ const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
74
+ try {
75
+ await new Promise((resolve, reject) => {
76
+ ffmpeg(videoPath)
77
+ .screenshots({
78
+ count,
79
+ folder: tempDir,
80
+ filename: 'frame-%i.png',
81
+ size: '1280x?', // Resize width to 1280, maintain aspect ratio
82
+ })
83
+ .on('end', () => resolve())
84
+ .on('error', reject);
85
+ });
86
+ // Read all generated frame files
87
+ const framePaths = (await fs.readdir(tempDir))
88
+ .filter((f) => f.endsWith('.png'))
89
+ .sort();
90
+ const frames = await Promise.all(framePaths.map((f) => fs.readFile(path.join(tempDir, f))));
91
+ return frames;
92
+ }
93
+ finally {
94
+ await rm(tempDir, { recursive: true, force: true });
95
+ }
96
+ }
97
+ /**
98
+ * Extract frames at regular intervals
99
+ * @param videoPath - Path to the video file
100
+ * @param intervalSec - Interval in seconds between frames
101
+ * @returns Array of PNG buffers
102
+ */
103
+ export async function extractFramesAtInterval(videoPath, intervalSec) {
104
+ const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
105
+ try {
106
+ await new Promise((resolve, reject) => {
107
+ ffmpeg(videoPath)
108
+ .outputOptions([`-vf fps=1/${intervalSec}`])
109
+ .output(path.join(tempDir, 'frame-%04d.png'))
110
+ .on('end', () => resolve())
111
+ .on('error', reject)
112
+ .run();
113
+ });
114
+ const framePaths = (await fs.readdir(tempDir))
115
+ .filter((f) => f.endsWith('.png'))
116
+ .sort();
117
+ const frames = await Promise.all(framePaths.map((f) => fs.readFile(path.join(tempDir, f))));
118
+ return frames;
119
+ }
120
+ finally {
121
+ await rm(tempDir, { recursive: true, force: true });
122
+ }
123
+ }
124
+ /**
125
+ * Extract frames at specific timestamps
126
+ * @param videoPath - Path to the video file
127
+ * @param timestamps - Array of timestamps in seconds
128
+ * @returns Array of PNG buffers (same order as timestamps)
129
+ */
130
+ export async function extractFramesAtTimestamps(videoPath, timestamps) {
131
+ const frames = [];
132
+ const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
133
+ try {
134
+ for (let i = 0; i < timestamps.length; i++) {
135
+ const outputPath = path.join(tempDir, `frame-${i}.png`);
136
+ const timestamp = timestamps[i];
137
+ await new Promise((resolve, reject) => {
138
+ ffmpeg(videoPath)
139
+ .seekInput(timestamp)
140
+ .frames(1)
141
+ .output(outputPath)
142
+ .on('end', () => resolve())
143
+ .on('error', reject)
144
+ .run();
145
+ });
146
+ frames.push(await fs.readFile(outputPath));
147
+ }
148
+ return frames;
149
+ }
150
+ finally {
151
+ await rm(tempDir, { recursive: true, force: true });
152
+ }
153
+ }
154
+ /**
155
+ * Parse fps string (e.g., "24/1" or "30/1") to number
156
+ */
157
+ function parseFps(fpsString) {
158
+ if (!fpsString)
159
+ return 0;
160
+ const parts = fpsString.split('/');
161
+ if (parts.length === 2) {
162
+ const numerator = parseInt(parts[0], 10);
163
+ const denominator = parseInt(parts[1], 10);
164
+ if (denominator !== 0) {
165
+ return numerator / denominator;
166
+ }
167
+ }
168
+ return parseInt(fpsString, 10) || 0;
169
+ }
170
+ //# sourceMappingURL=ffmpeg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../src/services/ffmpeg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * GLM-4.6V Client
3
+ * Handles video analysis using Z.AI's API
4
+ */
5
+ export interface GLMClientOptions {
6
+ apiKey: string;
7
+ baseURL?: string;
8
+ }
9
+ export declare class GLMClient {
10
+ private apiKey;
11
+ private baseURL;
12
+ constructor(options: GLMClientOptions);
13
+ /**
14
+ * Analyze a video using base64-encoded data
15
+ * @param base64Data - Base64-encoded video data
16
+ * @param question - The question to ask about the video
17
+ * @param useFlash - Use the free-tier flash model
18
+ * @returns The AI analysis response
19
+ */
20
+ analyzeVideoBase64(base64Data: string, question: string, useFlash?: boolean): Promise<string>;
21
+ /**
22
+ * Analyze a video from a URL
23
+ * @param url - URL of the video
24
+ * @param question - The question to ask about the video
25
+ * @param useFlash - Use the free-tier flash model
26
+ * @returns The AI analysis response
27
+ */
28
+ analyzeVideoUrl(url: string, question: string, useFlash?: boolean): Promise<string>;
29
+ /**
30
+ * Analyze multiple images (e.g., extracted frames)
31
+ */
32
+ analyzeImages(images: Array<{
33
+ data: string;
34
+ mimeType: string;
35
+ }>, prompt: string, useFlash?: boolean): Promise<string>;
36
+ /**
37
+ * Analyze with thinking mode enabled
38
+ */
39
+ analyzeWithThinking(content: any[], prompt: string, useFlash?: boolean): Promise<{
40
+ reasoning: string;
41
+ answer: string;
42
+ }>;
43
+ private requestChatCompletion;
44
+ private extractTextFromContent;
45
+ }
46
+ /**
47
+ * Create a GLM client instance from environment variables
48
+ */
49
+ export declare function createGLMClient(): GLMClient | null;
50
+ //# sourceMappingURL=glmClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glmClient.d.ts","sourceRoot":"","sources":["../../src/services/glmClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAwBD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,EAAE,gBAAgB;IAKrC;;;;;;OAMG;IACG,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;;;;OAMG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC,MAAM,CAAC;IAoBlB;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EACjD,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC,MAAM,CAAC;IAwBlB;;OAEG;IACG,mBAAmB,CACvB,OAAO,EAAE,GAAG,EAAE,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC;QACT,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;KACf,CAAC;YAqEY,qBAAqB;IA2BnC,OAAO,CAAC,sBAAsB;CAoB/B;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,SAAS,GAAG,IAAI,CAMlD"}