video-context-mcp-server 0.40.0-beta → 0.41.0-beta

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 (38) hide show
  1. package/README.md +114 -30
  2. package/dist/generated/version.d.ts +1 -1
  3. package/dist/generated/version.js +1 -1
  4. package/dist/index.js +4 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/services/providerRouter.d.ts +6 -5
  7. package/dist/services/providerRouter.d.ts.map +1 -1
  8. package/dist/services/providerRouter.js +36 -15
  9. package/dist/services/providerRouter.js.map +1 -1
  10. package/dist/services/qwenClient.d.ts +59 -0
  11. package/dist/services/qwenClient.d.ts.map +1 -0
  12. package/dist/services/qwenClient.js +174 -0
  13. package/dist/services/qwenClient.js.map +1 -0
  14. package/dist/services/s3Relay.d.ts +48 -0
  15. package/dist/services/s3Relay.d.ts.map +1 -0
  16. package/dist/services/s3Relay.js +117 -0
  17. package/dist/services/s3Relay.js.map +1 -0
  18. package/dist/tools/analyzeVideo.d.ts.map +1 -1
  19. package/dist/tools/analyzeVideo.js +15 -3
  20. package/dist/tools/analyzeVideo.js.map +1 -1
  21. package/dist/tools/orchestrator.d.ts +4 -2
  22. package/dist/tools/orchestrator.d.ts.map +1 -1
  23. package/dist/tools/orchestrator.js +49 -15
  24. package/dist/tools/orchestrator.js.map +1 -1
  25. package/dist/tools/schemas.d.ts +10 -10
  26. package/dist/tools/schemas.d.ts.map +1 -1
  27. package/dist/tools/schemas.js +4 -4
  28. package/dist/tools/schemas.js.map +1 -1
  29. package/dist/tools/searchTimestamp.d.ts.map +1 -1
  30. package/dist/tools/searchTimestamp.js +22 -15
  31. package/dist/tools/searchTimestamp.js.map +1 -1
  32. package/dist/tools/summarizeVideo.d.ts.map +1 -1
  33. package/dist/tools/summarizeVideo.js +43 -8
  34. package/dist/tools/summarizeVideo.js.map +1 -1
  35. package/dist/utils/videoUtils.d.ts.map +1 -1
  36. package/dist/utils/videoUtils.js +5 -0
  37. package/dist/utils/videoUtils.js.map +1 -1
  38. package/package.json +4 -2
package/README.md CHANGED
@@ -14,8 +14,8 @@ An MCP server that gives coding assistants (GitHub Copilot, Cursor, Claude Code)
14
14
  - 📊 **Video Metadata** — Get duration, resolution, fps, codec, and other technical details
15
15
  - 🎙️ **Audio Transcription** — Transcribe speech with paragraph-level timestamps (`[MM:SS]`) using Deepgram, AssemblyAI, Groq/Whisper, or Gemini
16
16
  - 🔊 **Speaker Diarization** — Identify who said what (Deepgram and AssemblyAI)
17
- - 🔊 **Audio-Enhanced Analysis** — Auto-transcribes audio and injects transcripts into AI prompts for richer results (GLM/Kimi only)
18
- - 🔄 **Multi-Provider Support** — Choose between GLM-4.6V, Kimi K2.5, or Gemini
17
+ - 🔊 **Audio-Enhanced Analysis** — Auto-transcribes audio and injects transcripts into AI prompts for richer results (GLM/Kimi/Qwen)
18
+ - 🔄 **Multi-Provider Support** — Choose between GLM-4.6V, Qwen3.5, Kimi K2.5, or Gemini
19
19
  - 🎯 **Smart Video Handling** — Extracts keyframes from long videos to reduce token usage
20
20
  - ⭐ **Pro tier** — Extended frame extraction, multi-platform downloads, higher resolution. [Learn more ↓](#pro)
21
21
 
@@ -62,6 +62,7 @@ Create or update `.vscode/mcp.json` in your workspace:
62
62
  "command": "video-context-mcp",
63
63
  "env": {
64
64
  "Z_AI_API_KEY": "your-zai-key",
65
+ "DASHSCOPE_API_KEY": "your-dashscope-key",
65
66
  "MOONSHOT_API_KEY": "your-moonshot-key",
66
67
  "GEMINI_API_KEY": "your-gemini-key",
67
68
  "DEEPGRAM_API_KEY": "your-deepgram-key",
@@ -89,6 +90,7 @@ Add to your Cursor MCP configuration (global or project-level):
89
90
  "command": "video-context-mcp",
90
91
  "env": {
91
92
  "Z_AI_API_KEY": "your-zai-key",
93
+ "DASHSCOPE_API_KEY": "your-dashscope-key",
92
94
  "MOONSHOT_API_KEY": "your-moonshot-key",
93
95
  "GEMINI_API_KEY": "your-gemini-key",
94
96
  "DEEPGRAM_API_KEY": "your-deepgram-key",
@@ -110,6 +112,7 @@ Add to your Cursor MCP configuration (global or project-level):
110
112
  ```bash
111
113
  claude mcp add \
112
114
  --env Z_AI_API_KEY=your-zai-key \
115
+ --env DASHSCOPE_API_KEY=your-dashscope-key \
113
116
  --env MOONSHOT_API_KEY=your-moonshot-key \
114
117
  --env GEMINI_API_KEY=your-gemini-key \
115
118
  --env DEEPGRAM_API_KEY=your-deepgram-key \
@@ -133,6 +136,7 @@ Create `.mcp.json` in your project root:
133
136
  "command": "video-context-mcp",
134
137
  "env": {
135
138
  "Z_AI_API_KEY": "your-zai-key",
139
+ "DASHSCOPE_API_KEY": "your-dashscope-key",
136
140
  "MOONSHOT_API_KEY": "your-moonshot-key",
137
141
  "GEMINI_API_KEY": "your-gemini-key",
138
142
  "DEEPGRAM_API_KEY": "your-deepgram-key",
@@ -162,6 +166,7 @@ Use `npx -y video-context-mcp-server@latest` as the command instead of `video-co
162
166
  "args": ["-y", "video-context-mcp-server@latest"],
163
167
  "env": {
164
168
  "Z_AI_API_KEY": "your-zai-key",
169
+ "DASHSCOPE_API_KEY": "your-dashscope-key",
165
170
  "MOONSHOT_API_KEY": "your-moonshot-key",
166
171
  "GEMINI_API_KEY": "your-gemini-key",
167
172
  "DEEPGRAM_API_KEY": "your-deepgram-key",
@@ -178,6 +183,7 @@ Use `npx -y video-context-mcp-server@latest` as the command instead of `video-co
178
183
  ```bash
179
184
  claude mcp add \
180
185
  --env Z_AI_API_KEY=your-zai-key \
186
+ --env DASHSCOPE_API_KEY=your-dashscope-key \
181
187
  --env MOONSHOT_API_KEY=your-moonshot-key \
182
188
  --env GEMINI_API_KEY=your-gemini-key \
183
189
  --env DEEPGRAM_API_KEY=your-deepgram-key \
@@ -241,19 +247,21 @@ All tools accept local file paths, `file://` URIs, and remote `http(s)` URLs. Re
241
247
 
242
248
  ### Video Providers
243
249
 
244
- Set all three keys to get the full fallback chain. The server will try GLM first, then Kimi, then Gemini, so having all keys ensures it never gets stuck without a working provider:
250
+ Set all keys to get the full fallback chain. The server will try GLM first, then Qwen, then Kimi, then Gemini, so having all keys ensures it never gets stuck without a working provider:
245
251
 
246
- | Provider | Key | Link |
247
- | -------------------------------------- | ------------------ | ------------------------------------------------- |
248
- | **GLM-4.6V** (default, free-tier) | `Z_AI_API_KEY` | [Get key](https://z.ai/manage-apikey/apikey-list) |
249
- | **Kimi K2.5** | `MOONSHOT_API_KEY` | [Get key](https://platform.moonshot.ai) |
250
- | **Gemini 3 Flash Preview** (free-tier) | `GEMINI_API_KEY` | [Get key](https://aistudio.google.com/app/apikey) |
252
+ | Provider | Key | Link |
253
+ | -------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------- |
254
+ | **GLM-4.6V** (default, free-tier) | `Z_AI_API_KEY` | [Get key](https://z.ai/manage-apikey/apikey-list) |
255
+ | **Qwen3.5** (free credits) | `DASHSCOPE_API_KEY` | [Get key](https://modelstudio.console.alibabacloud.com/ap-southeast-1?tab=dashboard#/api-key) |
256
+ | **Kimi K2.5** | `MOONSHOT_API_KEY` | [Get key](https://platform.moonshot.ai) |
257
+ | **Gemini 3 Flash Preview** (free-tier) | `GEMINI_API_KEY` | [Get key](https://aistudio.google.com/app/apikey) |
251
258
 
252
259
  When a provider's API key is missing or its API call fails at runtime, tools automatically fall back through the remaining providers in priority order, starting from the configured default:
253
260
 
254
- - GLM default (standard): **GLM → Kimi → Gemini**
255
- - Kimi default: **Kimi → GLM → Gemini**
256
- - Gemini default: **Gemini → GLM → Kimi**
261
+ - GLM default (standard): **GLM → Qwen → Kimi → Gemini**
262
+ - Qwen default: **Qwen → GLM → Kimi → Gemini**
263
+ - Kimi default: **Kimi → GLM → Qwen → Gemini**
264
+ - Gemini default: **Gemini → GLM → Qwen → Kimi**
257
265
 
258
266
  ### Audio Providers
259
267
 
@@ -274,17 +282,72 @@ When an audio key is missing or an audio API call fails at runtime, tools automa
274
282
 
275
283
  ### Video Providers
276
284
 
277
- | Feature | GLM-4.6V (default) | Kimi K2.5 | Gemini 3 Flash Preview |
278
- | -------------- | ------------------------------------ | ---------------------------------------------- | ---------------------------------------------- |
279
- | Price | Free tier available (GLM-4.6V-Flash) | $0.60 input / $3.00 output per 1M tokens | Free tier available |
280
- | Video formats | mp4, avi, mov, wmv, webm, m4v | mp4, mpeg, mov, avi, flv, mpg, webm, wmv, 3gpp | mp4, mpeg, mov, avi, flv, mpg, webm, wmv, 3gpp |
281
- | Context window | 128K tokens | 256K tokens | 1M tokens |
282
- | Max file size | ~20 MB (base64) | 100 MB | 2 GB |
283
- | Best for | **Default** — free, good accuracy | Broader format support | Last-resort fallback only |
285
+ | Feature | GLM-4.6V (default) | Qwen3.5 | Kimi K2.5 | Gemini 3 Flash Preview |
286
+ | -------------- | ------------------------------------ | --------------------------------- | ---------------------------------------------- | ---------------------------------------------- |
287
+ | Price | Free tier available (GLM-4.6V-Flash) | Free credits (1M tokens, 90 days) | $0.60 input / $3.00 output per 1M tokens | Free tier available |
288
+ | Video formats | mp4, avi, mov, wmv, webm, m4v | mp4, avi, mov, wmv, webm, m4v | mp4, mpeg, mov, avi, flv, mpg, webm, wmv, 3gpp | mp4, mpeg, mov, avi, flv, mpg, webm, wmv, 3gpp |
289
+ | Context window | 128K tokens | 128K tokens | 256K tokens | 1M tokens |
290
+ | Max file size | ~12 MB (base64) | ~10 MB (base64) | 100 MB | 2 GB |
291
+ | Best for | **Default** — free, good accuracy | Free alternative to GLM | Broader format support | Last-resort fallback only |
284
292
 
285
- **GLM-4.6V** is the default — it offers a free tier, making it a good zero-cost starting point. **Kimi K2.5** is a paid alternative with broader format support. **Gemini** is also free and used as a last-resort fallback — despite superior technical specs, it has proven inaccurate for video analysis in practice.
293
+ **GLM-4.6V** is the default — it offers a free tier, making it a good zero-cost starting point. **Qwen3.5** offers free credits (1M tokens for 90 days) with a similar feature set. **Kimi K2.5** is a paid alternative with broader format support. **Gemini** is also free and used as a last-resort fallback — despite superior technical specs, it has proven inaccurate for video analysis in practice.
286
294
 
287
- Set `VIDEO_MCP_DEFAULT_PROVIDER=kimi` or `gemini` to change the default.
295
+ Set `VIDEO_MCP_DEFAULT_PROVIDER=qwen`, `kimi`, or `gemini` to change the default.
296
+
297
+ <details>
298
+ <summary><strong>Automatic S3 relay: bypass the 10 MB local file limit with Qwen and GLM</strong></summary>
299
+
300
+ **GLM-4.6V** and **Qwen3.5** both accept direct video URLs, but base64-encoding a local file caps out at **10–12 MB**. Set `AWS_S3_BUCKET` to have the server automatically upload local videos (and platform downloads from YouTube, Bilibili, etc.) to S3 and pass a presigned URL to GLM/Qwen — no manual upload step needed.
301
+
302
+ **Why it works**: Qwen and GLM require the server to serve `Content-Length` and `Content-Type` headers alongside the video. AWS S3 provides these automatically.
303
+
304
+ **One-time setup**
305
+
306
+ ```bash
307
+ # 1. Create a bucket
308
+ aws s3 mb s3://my-video-analysis
309
+
310
+ # 2. Add AWS_S3_BUCKET to your .vscode/mcp.json env block
311
+ ```
312
+
313
+ AWS credentials are resolved automatically in this order:
314
+
315
+ 1. **Environment variables** — add these to your `mcp.json` env block (no AWS CLI required):
316
+ ```jsonc
317
+ // .vscode/mcp.json — env section
318
+ {
319
+ "AWS_S3_BUCKET": "my-video-analysis",
320
+ "AWS_ACCESS_KEY_ID": "AKIA...",
321
+ "AWS_SECRET_ACCESS_KEY": "your-secret-key",
322
+ "AWS_REGION": "us-east-1",
323
+ }
324
+ ```
325
+ 2. **`~/.aws/credentials`** — if you have the AWS CLI configured, credentials are picked up automatically; only `AWS_S3_BUCKET` is needed:
326
+ ```jsonc
327
+ // .vscode/mcp.json — env section
328
+ {
329
+ "AWS_S3_BUCKET": "my-video-analysis",
330
+ }
331
+ ```
332
+ 3. **IAM instance role / ECS task role** — for AWS-hosted environments.
333
+
334
+ That's it. Every time you analyze a local video (or a YouTube/Bilibili download) with GLM or Qwen, the server uploads it to S3, uses the presigned URL, and leaves the object in the bucket for reuse.
335
+
336
+ **Optional:** Set `AWS_S3_RELAY_CLEANUP=true` to delete all relayed objects when the MCP server session ends. Objects uploaded during a session are reused across multiple tool calls before being cleaned up at exit.
337
+
338
+ **Cost**: AWS S3 free tier covers 5 GB storage + 20K GET requests/month for 12 months. After the free tier, storage is roughly $0.023/GB/month.
339
+
340
+ **Still want direct URLs?** Pass a presigned URL manually:
341
+
342
+ ```bash
343
+ aws s3 cp my-video.mp4 s3://my-video-analysis/my-video.mp4
344
+ aws s3 presign s3://my-video-analysis/my-video.mp4 --expires-in 3600
345
+ # returns: https://my-video-analysis.s3.amazonaws.com/my-video.mp4?X-Amz-...
346
+ ```
347
+
348
+ Then pass the URL directly to `analyze_video` or `summarize_video`.
349
+
350
+ </details>
288
351
 
289
352
  ### Audio Providers
290
353
 
@@ -305,12 +368,23 @@ Set `AUDIO_MCP_DEFAULT_PROVIDER` to change the default.
305
368
 
306
369
  ### Core
307
370
 
308
- | Variable | Description | Default |
309
- | ---------------------------- | -------------------------------------------------- | ------- |
310
- | `Z_AI_API_KEY` | Z.AI API key for GLM-4.6V | — |
311
- | `MOONSHOT_API_KEY` | Moonshot AI API key for Kimi K2.5 | — |
312
- | `GEMINI_API_KEY` | Google API key for Gemini | — |
313
- | `VIDEO_MCP_DEFAULT_PROVIDER` | Default video provider: `glm`, `kimi`, or `gemini` | `glm` |
371
+ | Variable | Description | Default |
372
+ | ---------------------------- | ---------------------------------------------------------- | ------- |
373
+ | `Z_AI_API_KEY` | Z.AI API key for GLM-4.6V | — |
374
+ | `DASHSCOPE_API_KEY` | Alibaba Cloud API key for Qwen3.5 | — |
375
+ | `MOONSHOT_API_KEY` | Moonshot AI API key for Kimi K2.5 | — |
376
+ | `GEMINI_API_KEY` | Google API key for Gemini | |
377
+ | `VIDEO_MCP_DEFAULT_PROVIDER` | Default video provider: `glm`, `qwen`, `kimi`, or `gemini` | `glm` |
378
+
379
+ ### S3 Relay
380
+
381
+ | Variable | Description | Default |
382
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
383
+ | `AWS_S3_BUCKET` | S3 bucket name for automatic video relay. When set, local videos (and platform downloads) are uploaded to S3 and GLM/Qwen receive a presigned URL — bypassing the 10–12 MB base64 limit. | — |
384
+ | `AWS_ACCESS_KEY_ID` | AWS access key ID. Required if you are not using `~/.aws/credentials` or an IAM role. | — |
385
+ | `AWS_SECRET_ACCESS_KEY` | AWS secret access key. Required alongside `AWS_ACCESS_KEY_ID`. | — |
386
+ | `AWS_REGION` | AWS region for the S3 bucket (e.g. `us-east-1`). Required if not set in `~/.aws/config`. | — |
387
+ | `AWS_S3_RELAY_CLEANUP` | When `true`, delete all relayed S3 objects when the MCP server session ends (process exit). Default: objects are kept in the bucket for reuse across sessions. | — |
314
388
 
315
389
  ### Audio
316
390
 
@@ -320,7 +394,7 @@ Set `AUDIO_MCP_DEFAULT_PROVIDER` to change the default.
320
394
  | `ASSEMBLYAI_API_KEY` | AssemblyAI API key | — |
321
395
  | `GROQ_API_KEY` | Groq API key for Whisper transcription | — |
322
396
  | `AUDIO_MCP_DEFAULT_PROVIDER` | Default audio provider: `deepgram`, `assemblyai`, `groq`, or `gemini`. Falls back in that order when the selected key is missing. | `deepgram` |
323
- | `AUDIO_ENHANCE_VIDEO_ANALYSIS` | Inject audio transcripts into `analyze_video`/`summarize_video` prompts (GLM/Kimi only). `auto` = transcribe when audio track detected; `true` = always; `false` = disabled. | `auto` |
397
+ | `AUDIO_ENHANCE_VIDEO_ANALYSIS` | Inject audio transcripts into `analyze_video`/`summarize_video` prompts (GLM/Kimi/Qwen). `auto` = transcribe when audio track detected; `true` = always; `false` = disabled. | `auto` |
324
398
 
325
399
  ### Caching
326
400
 
@@ -393,9 +467,15 @@ vmcp cache clear:all --yes # skip confirmation
393
467
 
394
468
  ### Video Summarization
395
469
 
396
- | Variable | Description | Default |
397
- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
398
- | `VIDEO_MCP_MAX_FRAMES` | Max keyframes for `summarize_video` (GLM/Kimi only; Gemini uploads full video). **Free**: clamped 5–50. **Pro**: default 100; set `0` for uncapped. Either way, trailing frames are automatically dropped if the total payload exceeds the provider's size limit (12 MB for GLM, 80 MB for Kimi). | `50` free / `100` pro |
470
+ | Variable | Description | Default |
471
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
472
+ | `VIDEO_MCP_MAX_FRAMES` | Max keyframes for `summarize_video` (GLM/Kimi/Qwen only; Gemini uploads full video). **Free**: clamped 5–50. **Pro**: default 100; set `0` for uncapped. Either way, trailing frames are automatically dropped if the total payload exceeds the provider's size limit (12 MB for GLM, 10 MB for Qwen, 80 MB for Kimi). | `50` free / `100` pro |
473
+
474
+ ### Qwen
475
+
476
+ | Variable | Description | Default |
477
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
478
+ | `QWEN_BASE_URL` | Override the DashScope API endpoint. Use for regional routing: Singapore (default), Virginia (`https://dashscope-us.aliyuncs.com/compatible-mode/v1/chat/completions`), or Beijing (`https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions`). | `https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions` |
399
479
 
400
480
  ### yt-dlp (Platform Downloads)
401
481
 
@@ -424,6 +504,7 @@ vmcp cache clear:all --yes # skip confirmation
424
504
  "command": "video-context-mcp",
425
505
  "env": {
426
506
  "Z_AI_API_KEY": "your-zai-key",
507
+ "DASHSCOPE_API_KEY": "your-dashscope-key",
427
508
  "MOONSHOT_API_KEY": "your-moonshot-key",
428
509
  "GEMINI_API_KEY": "your-gemini-key",
429
510
  "DEEPGRAM_API_KEY": "your-deepgram-key",
@@ -439,6 +520,7 @@ vmcp cache clear:all --yes # skip confirmation
439
520
  "YT_DLP_PATH": "/usr/local/bin/yt-dlp",
440
521
  "YT_DLP_COOKIES_FILE": "/path/to/cookies.txt",
441
522
  "YT_DLP_IMPERSONATE": "chrome",
523
+ "AWS_S3_BUCKET": "my-video-analysis",
442
524
  "VIDEO_MCP_LICENSE_KEY": "your-license-key"
443
525
  }
444
526
  }
@@ -559,6 +641,7 @@ Use this `.vscode/mcp.json` to run the local build (never commit this file):
559
641
  "args": ["${workspaceFolder}/dist/index.js"],
560
642
  "env": {
561
643
  "Z_AI_API_KEY": "your-zai-key",
644
+ "DASHSCOPE_API_KEY": "your-dashscope-key",
562
645
  "MOONSHOT_API_KEY": "your-moonshot-key",
563
646
  "GEMINI_API_KEY": "your-gemini-key",
564
647
  "VIDEO_MCP_DEFAULT_PROVIDER": "glm",
@@ -605,6 +688,7 @@ Proprietary — All Rights Reserved. No part of this software may be copied, mod
605
688
  - [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) by Anthropic
606
689
  - [Kimi K2.5](https://github.com/MoonshotAI/Kimi-K2.5) by Moonshot AI
607
690
  - [GLM-4.6V](https://docs.z.ai/guides/vlm/glm-4.6v) by Z.AI
691
+ - [Qwen3.5](https://bailian.console.alibabacloud.com/ap-southeast-1/) by Alibaba Cloud
608
692
  - [Deepgram](https://www.deepgram.com/) for audio transcription
609
693
  - [AssemblyAI](https://www.assemblyai.com/) for audio transcription
610
694
  - [Groq/Whisper](https://console.groq.com/) for audio transcription
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.40.0-beta";
1
+ export declare const VERSION = "0.41.0-beta";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/sync-version.ts — do not edit
2
- export const VERSION = '0.40.0-beta';
2
+ export const VERSION = '0.41.0-beta';
3
3
  //# sourceMappingURL=version.js.map
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ import { setLoggerServer } from './utils/logger.js';
12
12
  import { initLicenseValidation } from './utils/license.js';
13
13
  import { sweepStaleTempDirs } from './utils/tempFiles.js';
14
14
  import { sweepExpiredCacheDirs } from './utils/artifactCache.js';
15
+ import { registerSessionCleanup } from './services/s3Relay.js';
15
16
  import { triggerUpdateCheck, waitForUpdateCheck, wrapWithUpdateNotice, } from './utils/updateCheck.js';
16
17
  import { VERSION } from './generated/version.js';
17
18
  import { analyzeVideoSchema, summarizeVideoSchema, extractFramesSchema, searchTimestampSchema, getVideoInfoSchema, transcribeVideoSchema, } from './tools/schemas.js';
@@ -31,6 +32,8 @@ async function main() {
31
32
  });
32
33
  // Wire up the logger so tools can emit progress notifications
33
34
  setLoggerServer(server);
35
+ // Register S3 relay session-end cleanup (no-op unless AWS_S3_RELAY_CLEANUP=true)
36
+ registerSessionCleanup();
34
37
  // Clean up orphaned temp directories from previous runs that were killed mid-call
35
38
  sweepStaleTempDirs().catch(() => { }); // fire-and-forget
36
39
  // Remove expired per-video artifact directories from the persistent cache
@@ -58,7 +61,7 @@ async function main() {
58
61
  // Tool 2: summarize_video - Generate structured video summary
59
62
  server.registerTool('summarize_video', {
60
63
  title: 'Summarize Video',
61
- 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 (unless using Gemini, which processes natively).',
64
+ 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 (unless using Gemini, which processes natively). Provider options: 'glm' (default), 'qwen', 'kimi', 'gemini'.",
62
65
  inputSchema: summarizeVideoSchema,
63
66
  }, withUpdateCheck(summarizeVideoTool));
64
67
  // Tool 3: extract_frames - Extract frames from video
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -2,16 +2,17 @@
2
2
  * Provider Selection
3
3
  * Determines which AI backend to use based on user preference
4
4
  */
5
- export type VideoProvider = 'glm' | 'kimi' | 'gemini';
5
+ export type VideoProvider = 'glm' | 'kimi' | 'gemini' | 'qwen';
6
6
  /**
7
7
  * Validate that the selected provider has a configured API key
8
- * @param provider - User-specified provider ('glm', 'kimi', or 'gemini')
8
+ * @param provider - User-specified provider ('glm', 'kimi', 'gemini', or 'qwen')
9
9
  * @param hasKimiKey - Whether Kimi API key is available
10
10
  * @param hasGLMKey - Whether GLM API key is available
11
11
  * @param hasGeminiKey - Whether Gemini API key is available
12
+ * @param hasQwenKey - Whether Qwen API key is available
12
13
  * @returns The validated provider
13
14
  */
14
- export declare function selectProvider(provider: VideoProvider, hasKimiKey: boolean, hasGLMKey: boolean, hasGeminiKey?: boolean): VideoProvider;
15
+ export declare function selectProvider(provider: VideoProvider, hasKimiKey: boolean, hasGLMKey: boolean, hasGeminiKey?: boolean, hasQwenKey?: boolean): VideoProvider;
15
16
  /**
16
17
  * Result type returned by resolveProviderWithFallback.
17
18
  * When `fallbackFrom` is set, the caller should notify the user that the
@@ -33,7 +34,7 @@ export type ProviderResult = {
33
34
  * Returns a ProviderResult with `fallbackFrom` set if a fallback occurred.
34
35
  * Throws only when no provider API key is available at all.
35
36
  */
36
- export declare function resolveProviderWithFallback(provider: VideoProvider, hasKimiKey: boolean, hasGLMKey: boolean, hasGeminiKey?: boolean): ProviderResult;
37
+ export declare function resolveProviderWithFallback(provider: VideoProvider, hasKimiKey: boolean, hasGLMKey: boolean, hasGeminiKey?: boolean, hasQwenKey?: boolean): ProviderResult;
37
38
  /**
38
39
  * Get the default provider from environment variable
39
40
  */
@@ -52,7 +53,7 @@ export declare function getDefaultProvider(): VideoProvider;
52
53
  * This is used for runtime error-based fallback: if the first provider's API call
53
54
  * throws (overloaded, timeout, 5xx, etc.), the caller retries with the next entry.
54
55
  */
55
- export declare function getRuntimeFallbackChain(provider: VideoProvider, hasKimiKey: boolean, hasGLMKey: boolean, hasGeminiKey?: boolean): VideoProvider[];
56
+ export declare function getRuntimeFallbackChain(provider: VideoProvider, hasKimiKey: boolean, hasGLMKey: boolean, hasGeminiKey?: boolean, hasQwenKey?: boolean): VideoProvider[];
56
57
  /**
57
58
  * Get the maximum number of frames to extract for summarization.
58
59
  *
@@ -1 +1 @@
1
- {"version":3,"file":"providerRouter.d.ts","sourceRoot":"","sources":["../../src/services/providerRouter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAA;AAErD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,EAClB,YAAY,GAAE,OAAe,GAC5B,aAAa,CAiBf;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,aAAa,CAAA;IACvB,YAAY,CAAC,EAAE,aAAa,CAAA;CAC7B,CAAA;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,EAClB,YAAY,GAAE,OAAe,GAC5B,cAAc,CAqBhB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAUlD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,EAClB,YAAY,GAAE,OAAe,GAC5B,aAAa,EAAE,CAcjB;AAQD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAerC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAQzC"}
1
+ {"version":3,"file":"providerRouter.d.ts","sourceRoot":"","sources":["../../src/services/providerRouter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAE9D;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,EAClB,YAAY,GAAE,OAAe,EAC7B,UAAU,GAAE,OAAe,GAC1B,aAAa,CAyBf;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,aAAa,CAAA;IACvB,YAAY,CAAC,EAAE,aAAa,CAAA;CAC7B,CAAA;AAUD;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,EAClB,YAAY,GAAE,OAAe,EAC7B,UAAU,GAAE,OAAe,GAC1B,cAAc,CAsBhB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAWlD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,EAClB,YAAY,GAAE,OAAe,EAC7B,UAAU,GAAE,OAAe,GAC1B,aAAa,EAAE,CAejB;AAQD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAerC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAQzC"}
@@ -5,26 +5,44 @@
5
5
  import { isPro } from '../utils/license.js';
6
6
  /**
7
7
  * Validate that the selected provider has a configured API key
8
- * @param provider - User-specified provider ('glm', 'kimi', or 'gemini')
8
+ * @param provider - User-specified provider ('glm', 'kimi', 'gemini', or 'qwen')
9
9
  * @param hasKimiKey - Whether Kimi API key is available
10
10
  * @param hasGLMKey - Whether GLM API key is available
11
11
  * @param hasGeminiKey - Whether Gemini API key is available
12
+ * @param hasQwenKey - Whether Qwen API key is available
12
13
  * @returns The validated provider
13
14
  */
14
- export function selectProvider(provider, hasKimiKey, hasGLMKey, hasGeminiKey = false) {
15
- if (provider === 'gemini' && !hasGeminiKey) {
16
- throw new Error('Gemini provider selected but GEMINI_API_KEY is not configured');
17
- }
18
- if (provider === 'kimi' && !hasKimiKey) {
19
- throw new Error('Kimi K2.5 provider selected but MOONSHOT_API_KEY is not configured');
20
- }
21
- if (provider === 'glm' && !hasGLMKey) {
22
- throw new Error('GLM-4.6V provider selected but Z_AI_API_KEY is not configured');
15
+ export function selectProvider(provider, hasKimiKey, hasGLMKey, hasGeminiKey = false, hasQwenKey = false) {
16
+ const keyAvailable = {
17
+ glm: hasGLMKey,
18
+ kimi: hasKimiKey,
19
+ gemini: hasGeminiKey,
20
+ qwen: hasQwenKey,
21
+ };
22
+ const displayName = {
23
+ glm: 'GLM-4.6V',
24
+ kimi: 'Kimi K2.5',
25
+ gemini: 'Gemini',
26
+ qwen: 'Qwen3.5',
27
+ };
28
+ const envVar = {
29
+ glm: 'Z_AI_API_KEY',
30
+ kimi: 'MOONSHOT_API_KEY',
31
+ gemini: 'GEMINI_API_KEY',
32
+ qwen: 'DASHSCOPE_API_KEY',
33
+ };
34
+ if (!keyAvailable[provider]) {
35
+ throw new Error(`${displayName[provider]} provider selected but ${envVar[provider]} is not configured`);
23
36
  }
24
37
  return provider;
25
38
  }
26
39
  /** Canonical priority order for all video providers. */
27
- const VIDEO_PROVIDER_PRIORITY = ['glm', 'kimi', 'gemini'];
40
+ const VIDEO_PROVIDER_PRIORITY = [
41
+ 'glm',
42
+ 'qwen',
43
+ 'kimi',
44
+ 'gemini',
45
+ ];
28
46
  /**
29
47
  * Resolve the provider, with optional fallback behavior.
30
48
  * If the requested provider's key is missing, falls back in canonical priority
@@ -37,11 +55,12 @@ const VIDEO_PROVIDER_PRIORITY = ['glm', 'kimi', 'gemini'];
37
55
  * Returns a ProviderResult with `fallbackFrom` set if a fallback occurred.
38
56
  * Throws only when no provider API key is available at all.
39
57
  */
40
- export function resolveProviderWithFallback(provider, hasKimiKey, hasGLMKey, hasGeminiKey = false) {
58
+ export function resolveProviderWithFallback(provider, hasKimiKey, hasGLMKey, hasGeminiKey = false, hasQwenKey = false) {
41
59
  const keyMap = {
42
60
  glm: hasGLMKey,
43
61
  kimi: hasKimiKey,
44
62
  gemini: hasGeminiKey,
63
+ qwen: hasQwenKey,
45
64
  };
46
65
  if (keyMap[provider]) {
47
66
  return { provider };
@@ -52,7 +71,7 @@ export function resolveProviderWithFallback(provider, hasKimiKey, hasGLMKey, has
52
71
  return { provider: candidate, fallbackFrom: provider };
53
72
  }
54
73
  }
55
- throw new Error('No video provider API key found. Please set at least one of: Z_AI_API_KEY, MOONSHOT_API_KEY, or GEMINI_API_KEY');
74
+ throw new Error('No video provider API key found. Please set at least one of: Z_AI_API_KEY, DASHSCOPE_API_KEY, MOONSHOT_API_KEY, or GEMINI_API_KEY');
56
75
  }
57
76
  /**
58
77
  * Get the default provider from environment variable
@@ -61,7 +80,8 @@ export function getDefaultProvider() {
61
80
  const envProvider = process.env.VIDEO_MCP_DEFAULT_PROVIDER;
62
81
  if (envProvider === 'glm' ||
63
82
  envProvider === 'kimi' ||
64
- envProvider === 'gemini') {
83
+ envProvider === 'gemini' ||
84
+ envProvider === 'qwen') {
65
85
  return envProvider;
66
86
  }
67
87
  return 'glm';
@@ -80,7 +100,7 @@ export function getDefaultProvider() {
80
100
  * This is used for runtime error-based fallback: if the first provider's API call
81
101
  * throws (overloaded, timeout, 5xx, etc.), the caller retries with the next entry.
82
102
  */
83
- export function getRuntimeFallbackChain(provider, hasKimiKey, hasGLMKey, hasGeminiKey = false) {
103
+ export function getRuntimeFallbackChain(provider, hasKimiKey, hasGLMKey, hasGeminiKey = false, hasQwenKey = false) {
84
104
  // Start with the requested provider, then remaining in canonical priority order
85
105
  const candidates = [
86
106
  provider,
@@ -90,6 +110,7 @@ export function getRuntimeFallbackChain(provider, hasKimiKey, hasGLMKey, hasGemi
90
110
  glm: hasGLMKey,
91
111
  kimi: hasKimiKey,
92
112
  gemini: hasGeminiKey,
113
+ qwen: hasQwenKey,
93
114
  };
94
115
  return candidates.filter((p) => keyMap[p]);
95
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"providerRouter.js","sourceRoot":"","sources":["../../src/services/providerRouter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"providerRouter.js","sourceRoot":"","sources":["../../src/services/providerRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Qwen3.5 Client
3
+ * Handles video analysis using Alibaba Cloud's DashScope API (OpenAI-compatible)
4
+ */
5
+ type QwenContentPart = {
6
+ type: 'text';
7
+ text: string;
8
+ } | {
9
+ type: 'video_url';
10
+ video_url: {
11
+ url: string;
12
+ fps?: number;
13
+ };
14
+ } | {
15
+ type: 'image_url';
16
+ image_url: {
17
+ url: string;
18
+ };
19
+ };
20
+ export declare class QwenClient {
21
+ private apiKey;
22
+ private baseURL;
23
+ constructor(apiKey: string, baseURL?: string);
24
+ /**
25
+ * Analyze a video from a URL.
26
+ * Qwen processes the video server-side using the `fps` parameter.
27
+ */
28
+ analyzeVideoUrl(url: string, prompt: string, fps?: number): Promise<string>;
29
+ /**
30
+ * Analyze a video using base64-encoded data.
31
+ * Subject to a 10 MB encoded string limit per Qwen docs.
32
+ */
33
+ analyzeVideoBase64(base64Data: string, prompt: string, mimeType?: string): Promise<string>;
34
+ /**
35
+ * Analyze multiple images (e.g., extracted video frames).
36
+ * Used for the long-video frame-based strategy.
37
+ */
38
+ analyzeImages(images: Array<{
39
+ data: string;
40
+ mimeType: string;
41
+ }>, prompt: string): Promise<string>;
42
+ /**
43
+ * Analyze with thinking mode enabled (enable_thinking: true).
44
+ * Returns both the chain-of-thought reasoning and the final answer.
45
+ */
46
+ analyzeWithThinking(content: QwenContentPart[], prompt: string): Promise<{
47
+ reasoning: string;
48
+ answer: string;
49
+ }>;
50
+ private requestChatCompletion;
51
+ private requestCompletion;
52
+ private extractTextFromContent;
53
+ }
54
+ /**
55
+ * Create a Qwen client instance from environment variables
56
+ */
57
+ export declare function createQwenClient(): QwenClient | null;
58
+ export {};
59
+ //# sourceMappingURL=qwenClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qwenClient.d.ts","sourceRoot":"","sources":["../../src/services/qwenClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,KAAK,eAAe,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAA;AAoBrD,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAK5C;;;OAGG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,GAAG,GAAE,MAAyB,GAC7B,OAAO,CAAC,MAAM,CAAC;IAoBlB;;;OAGG;IACG,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;OAGG;IACG,aAAa,CACjB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EACjD,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC;IAwBlB;;;OAGG;IACG,mBAAmB,CACvB,OAAO,EAAE,eAAe,EAAE,EAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QACT,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;KACf,CAAC;YAmCY,qBAAqB;YAmBrB,iBAAiB;IAiB/B,OAAO,CAAC,sBAAsB;CAoB/B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,GAAG,IAAI,CAOpD"}