You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two new MCP tools (analyze_audio, analyze_audio_video) on qwen3.5-omni-plus,
separate from qwen3.7-plus video/image. Reuse the non-streaming analyze path:
live testing shows the doc's 'stream=True mandatory' claim is stale -- omni
non-stream returns 200 for text/audio/video.
Audio uses input_audio{data,format} where data must be data:;base64,<b64>
(raw base64 rejected). Local files validated by ext + magic-byte before
encoding; 25MB guardrail reused (8.8MB / 11.7MB base64 verified on omni).
New QWEN_OMNI_MODEL env, default qwen3.5-omni-plus.
Copy file name to clipboardExpand all lines: AGENTS.md
+9-5Lines changed: 9 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,20 +33,21 @@ CI runs the same on Node 20 and 22. Local green ≠ CI green if you skip a step.
33
33
34
34
-**TypeScript strict.** No `any` in `src/` (allowed sparingly in `test/` for fixture typing). No `@ts-ignore`. No non-null assertions in `src/`.
35
35
- Prefer narrow types and `unknown` over `any` when parsing external JSON (see `src/bailian.ts`).
36
-
- The DashScope payload builder (`buildPayload`) is intentionally injectable — if the `video_url`/`image_url` content block shape changes, change it in one place.
36
+
- The DashScope payload builder (`buildPayload`) is intentionally injectable — if the `video_url`/`image_url`/`input_audio` content block shape changes, change it in one place (`contentBlock` / `audioBlock` in `src/bailian.ts`).
37
37
- Do not add a new runtime, language, or heavy dependency without explicit maintainer approval.
38
38
- Match existing style; let `prettier` and `eslint --fix` handle formatting.
39
39
40
40
## Tool surface
41
41
42
-
The server exposes 3 MCP tools (see `src/server.ts`): `analyze_video`, `analyze_image`, `check_endpoint_status`. Do not silently change a tool's name or argument schema — that breaks MCP clients. Add new tools rather than renaming.
42
+
The server exposes 5 MCP tools (see `src/server.ts`): `analyze_video`, `analyze_image`, `analyze_audio`, `analyze_audio_video`, `check_endpoint_status`. Do not silently change a tool's name or argument schema — that breaks MCP clients. Add new tools rather than renaming.
43
43
44
44
`check_endpoint_status` must redact the API key (`redactKey`). There is a test asserting no key leaks — keep it passing.
- Model: `qwen3.7-plus` (multimodal, native video — **no client-side frame extraction**) for `analyze_video`/`analyze_image`.
50
+
- Omni model: `qwen3.5-omni-plus` (native audio + audio-video understanding) for `analyze_audio`/`analyze_audio_video`, configured via `QWEN_OMNI_MODEL`. Omni calls send `modalities: ["text"]` to force text-only output (no voice blob).
50
51
- The Anthropic-compatible `/apps/anthropic` endpoint does NOT support video input. Do not switch to it for multimodal tools.
51
52
- Video frame sampling is server-side (fixed 0.5s/frame on OpenAI-compatible mode). Do not add frame extraction logic.
52
53
@@ -64,5 +65,8 @@ The server exposes 3 MCP tools (see `src/server.ts`): `analyze_video`, `analyze_
64
65
## Fragile assumptions (verify before relying on)
65
66
66
67
1. The OpenAI-compatible endpoint accepts a `video_url` content block for `qwen3.7-plus`. If a live call rejects it, the fallback is the native DashScope `video` content type or switching to `qwen-vl-max-latest`. Change `contentBlock()` in `src/bailian.ts`.
67
-
2. The exact model id string `qwen3.7-plus`. Verify against the Bailian model list if a call returns a model-not-found error.
68
-
3. Local files up to the 25MB guardrail in `src/media.ts` can be sent as base64 data URLs — verified live (14MB video / ~18MB body, HTTP 200 on `qwen3.7-plus` OpenAI-compatible mode). Larger files must be hosted at a public URL. Local input is validated by extension + magic-byte signature before encoding (see `toDataUrl`).
68
+
2. The exact model id strings `qwen3.7-plus` and `qwen3.5-omni-plus`. Verify against the Bailian model list if a call returns a model-not-found error.
69
+
3. Local files up to the 25MB guardrail in `src/media.ts` can be sent as base64 data URLs — verified live (14MB video / ~18MB body, HTTP 200 on `qwen3.7-plus` OpenAI-compatible mode; 8.8MB video / ~11.7MB base64 body, HTTP 200 on `qwen3.5-omni-plus`). Larger files must be hosted at a public URL. Local input is validated by extension + magic-byte signature before encoding (see `toDataUrl` / `toAudioData`).
70
+
4.**Qwen-Omni `stream=True` is NOT mandatory.** The official doc claims all Qwen-Omni requests must set `stream=True`, but live testing shows non-streaming calls succeed (text/audio/video, HTTP 200 + JSON). The omni tools therefore reuse the same non-streaming `analyze` path as `qwen3.7-plus`. If a future endpoint revision starts rejecting non-stream omni calls, add a streaming variant in `src/bailian.ts` and route omni tools through it.
71
+
5.**`input_audio.data` must be `data:;base64,<b64>` + `format`, not raw base64.** Raw base64 is rejected with `"The provided URL does not appear to be valid"`. Verified live for mp3/wav. If other formats (flac/ogg/m4a/aac) are rejected, change `toAudioData()` in `src/media.ts` (e.g. to a full `data:audio/<fmt>;base64,` data URL) — single point of change, no tool-schema impact.
72
+
6. The default `dashscope.aliyuncs.com/compatible-mode/v1` endpoint serves `qwen3.5-omni-plus` (verified live). No workspace-specific MaaS URL is needed. If a future key/region rejects omni, add an optional `QWEN_OMNI_BASE_URL` env and route omni calls through it.
Copy file name to clipboardExpand all lines: README.md
+22-16Lines changed: 22 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,16 @@
1
1
# qwen-omni-mcp
2
2
3
-
An [MCP](https://modelcontextprotocol.io) server that gives Claude Code and other AI agents **videoand image understanding** via [Bailian (DashScope)](https://bailian.console.aliyun.com/) using the multimodal **Qwen3.7-Plus**model.
3
+
An [MCP](https://modelcontextprotocol.io) server that gives Claude Code and other AI agents **video, image, audio, and audio-video understanding** via [Bailian (DashScope)](https://bailian.console.aliyun.com/) using the multimodal **Qwen3.7-Plus**and **Qwen3.5-Omni** models.
4
4
5
-
Qwen3.7-Plus reads video natively — **no client-side frame extraction**. Pass a public media URL **or a local file path**; the model does the rest.
5
+
Qwen3.7-Plus reads video natively — **no client-side frame extraction**. Qwen3.5-Omni adds native **audio** understanding (and audio-track awareness for video). Pass a public media URL **or a local file path**; the model does the rest.
6
6
7
7
## Highlights
8
8
9
9
-**Native video understanding** — send a video URL or local file, get grounded analysis
10
10
-**Image understanding** — describe, Q&A, OCR
11
-
-**Local file support** — pass a local path; files are sent inline as base64 data URLs (25MB guardrail)
12
-
-**Convenience tools** — summarize, text extraction, frame comparison, Q&A
|`analyze_video`| Analyze a video (URL or local file) with a custom prompt |
87
+
|`analyze_image`| Analyze an image (URL or local file) with a custom prompt |
88
+
|`analyze_audio`| Analyze an audio file (URL or local) with a custom prompt (Omni) |
89
+
|`analyze_audio_video`| Analyze a video's visuals + sound (URL or local) with a prompt (Omni) |
90
+
|`check_endpoint_status`| Show configured endpoint/model (key redacted) |
87
91
88
-
Each media tool accepts a public `http`/`https` URL **or a local file path**. Local files are read and sent inline as base64 data URLs, with a 25MB guardrail (verified up to a 14MB video / ~18MB body, HTTP 200). Files larger than 25MB must be hosted at a public URL instead. Local input is validated by extension + magic-byte signature before encoding, so non-media files are rejected.
92
+
Each media tool accepts a public `http`/`https` URL **or a local file path**. Local files are read and sent inline as base64, with a 25MB guardrail (verified up to a 14MB video / ~18MB body on Qwen3.7-Plus, and an 8.8MB video / ~11.7MB base64 body on Qwen3.5-Omni, both HTTP 200). Files larger than 25MB must be hosted at a public URL instead. Local input is validated by extension + magic-byte signature before encoding, so non-media files are rejected.
93
+
94
+
`analyze_audio` / `analyze_audio_video` use the omni model (`QWEN_OMNI_MODEL`, default `qwen3.5-omni-plus`) and force text-only output. Audio is sent as an `input_audio` block in the `data:;base64,<b64>` form with a `format` field (mp3/wav/flac/ogg/m4a/aac).
0 commit comments