← 返回列表
未验证
DeepSeek Harness dsh MCP 插件:按问题检索 B 站视频并定位到具体片段带时间戳、可回跳
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/2 · 已提供中文文档
DeepSeek Harness (dsh) MCP 插件:按问题检索 B 站视频并定位到具体片段(带时间戳、可回跳)
综合分
28
GitHub 分
28
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add wjxn13/dsh-video-evidence该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
信任档位:仅索引本站尚未对其实装验证,仅收录元数据
- 是什么
- dsh 原生插件 · platform
- 装得上吗
- 本站尚未做安装检查
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 24 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
数据截至 2026/9/20(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成dsh-video-evidence
兼容的 Harness 版本
- 已验证支持:DeepSeek Harness 0.1.0-rc.6(通过 @deepseek-ai/dsh-mcp-client,跨 profile 可用)。
- 最新版 0.1.2-alpha.3:适配计划进行中,暂无确切完成时间。升级前请先备份你的 DSH 安装。
给 DeepSeek Harness (dsh) 的 MCP 插件:按问题检索 B 站视频,并定位到真正讲到该内容的片段(带时间戳、可直接回跳)。
不是"搜到视频"就结束,而是回答"这个问题的答案在视频的第几分钟"。
用户:Spring Boot 项目怎么创建?
→ 1. https://www.bilibili.com/video/BV17m411d7Ny?t=0
环境准备、JDK 版本选择 …
→ 2. https://www.bilibili.com/video/BV17m411d7Ny?t=60
打开 IDEA,新建 Project,选择 Spring Initializr …
→ 3. https://www.bilibili.com/video/BV17m411d7Ny?t=90
填写 Group / Artifact,勾选依赖,Finish …
为什么做这个
市面上的"跨模态检索 / 智能搜索"插件,绝大多数做的是网页和文本这一层:给一段查询,返回一堆链接和摘要。这一层已经很挤了,重复造轮子没有意义。
真正还没有被好好解决的,是视频内部的片段级定位:
- 搜索引擎只能告诉你"这个视频可能相关",不会告诉你相关的是哪 30 秒;
- 视频平台自带的字幕搜索依赖 UP 主上传字幕,覆盖率和质量都靠运气;
- 对教程、课程录像、会议发言这类内容,用户真正要的从来不是"整片",而是"讲到 X 的那一小段"。
本插件补的就是这一段:公开视频 → 本地转写 → 片段级检索 → 可回跳的时间戳证据。全部本地完成,不依赖任何付费 API 或第三方检索服务。
工作流程
┌──────────────────────── dsh (MCP client) ────────────────────────┐
│ mcp__video_evidence__video_search / __video_cache_stats │
└───────────────────────────────┬──────────────────────────────────┘
│ stdio / JSON-RPC
┌───────────────────────────────▼──────────────────────────────────┐
│ server.js (Node 常驻进程,只做协议转发) │
│ · 双分帧解析:NDJSON ⇄ Content-Length │
│ · 收到 tools/call 才 spawn Python worker │
└───────────────────────────────┬──────────────────────────────────┘
│ spawn(按需,用完即退)
┌───────────────────────────────▼──────────────────────────────────┐
│ worker.py → server.py │
│ 1. bili.py B 站 wbi 签名搜索 → 取 cid → 取 360P 流地址 │
│ 2. asr.py ffmpeg 拉流转 16k 单声道 wav │
│ faster-whisper (base/int8, CPU) 转写 │
│ 3. cache.py SQLite 按 BV 号缓存转写结果(TTL 30 天) │
│ 4. evidence.py 中文 BM25(单字 + 二元组)打分 │
│ 45s 滑窗 / 30s 步长切块 → 排序取 top-k │
└──────────────────────────────────────────────────────────────────┘
为什么是 Node 常驻 + Python worker: dsh 的 dsh-mcp-client spawn 之后会立刻发 initialize,跟 Python 常驻进程握手不稳定(实测 4 次启动、0 条消息收到)。Node 冷启动足够快,而真正的检索/ASR 留在 Python 侧,只在工具被真正调用时才拉起,空闲时不占资源。
安装
前置依赖
| 依赖 | 说明 |
| --- | --- |
| Node.js | 18+,只用到内置模块,无需 npm install |
| Python | 3.9+ |
| ffmpeg | 必须在 PATH 中,或用 FFMPEG_BIN 指定绝对路径 |
| faster-whisper | pip install -r requirements.txt |
git clone https://github.com/wjxn13/dsh-video-evidence.git
cd dsh-video-evidence
Windows
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt
macOS / Linux
python3 -m venv .venv
注意:server.js 里写死了 .venv/Scripts/python.exe(Windows 布局)。
非 Windows 需要把 server.js 中 PY 的路径改成 .venv/bin/python。
.venv/bin/pip install -r requirements.txt
首次调用 video_search 时,faster-whisper 会自动下载 base 模型到 models/base/(约 145MB)。也可以手动放置,或用 ASR_MODEL_DIR 指向已有模型目录。
接入 dsh
在用户级 ~/.dsh/cordis.patch.yml 里追加(路径改成你自己的):
- insert:
- id: mcp-video-evidence
name: "@deepseek-ai/dsh-mcp-client"
config:
serverName: video_evidence # ← 决定工具名前缀:mcp__video_evidence__*
transport: stdio
command: "C:/path/to/node.exe"
args:
- "C:/path/to/dsh-video-evidence/server.js"
cwd: "C:/path/to/dsh-video-evidence"
env:
PYTHONIOENCODING: "utf-8"
PYTHONUNBUFFERED: "1"
toolCallTimeoutMs: 240000
几个关键点:
- name 要填 @deepseek-ai/dsh-mcp-client,这是 dsh 的 MCP loader 包名,不是随便起的名字。
- serverName 决定工具名前缀:mcp____,所以这里是 mcp__video_evidence__video_search。
- command 用 node 的绝对路径。dsh 会清理子进程环境,不能依赖 PATH。
- cwd 要指向插件目录,server.js 依赖它定位 .venv 和 worker.py。
- toolCallTimeoutMs 给足(这里 240 秒)。首次查询要拉流 + 转写,默认的短超时会让工具在结果出来前被判失败。
然后重启 dsh——配置只在启动时加载。用 dsh --dump-config --profile web 可以确认条目有没有被正确合并进去。
⚠️ id 不能和已有条目重复。 cordis loader 不允许同 id 覆盖,重复会直接让 dsh 启动崩溃(报 duplicate loader entry)。改配置前先备份 cordis.patch.yml。
工具
video_search
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| query | string | 必填 | 要检索的问题或关键词 |
| max_videos | integer | 3 | 最多处理几个候选视频(1–5) |
| max_clips | integer | 5 | 返回几个最相关片段(1–10) |
| audio_seconds | integer | 300 | 每个视频最多转写前多少秒(60–1800) |
| budget_seconds | integer | 170 | 总时间预算,超时就返回已经拿到的结果 |
video_cache_stats
无参数。返回已缓存转写的视频数量。
性能实测
本机环境:Windows 11 / Ryzen 7 6800H / RTX 3050 Ti(纯 CPU 推理,不用显卡),faster-whisper base + int8:
| 项目 | 实测 |
| --- | --- |
| 转写速度 | 45 秒音频 ≈ 2.3 秒(约 20 倍实时) |
| 10 分钟视频 | ≈ 30 秒 |
| 命中缓存后 | 几乎瞬时(只查 SQLite + BM25) |
也就是说,一次交互式提问(转写前 90–180 秒)通常在几秒内返回。
环境变量
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| FFMPEG_BIN | PATH 里的 ffmpeg | ffmpeg 可执行文件路径。不设则自动从 PATH 查找,找不到才需要显式指定 |
| ASR_MODEL_DIR | /models/base | faster-whisper 模型目录 |
| BILI_SESSDATA | 空 | B 站 SESSDATA Cookie。不填也能用(搜索/取流正常),填了可以尝试走官方字幕通道 |
| VDB_CACHE | /cache.sqlite3 | 转写缓存数据库路径 |
| VDB_CACHE_TTL | 2592000(30 天) | 缓存有效期(秒) |
| VDB_AUDIO_SEC | 300 | 默认单视频转写时长上限 |
| VDB_BUDGET_SEC | 170 | 默认总时间预算 |
| VDB_MAX_VIDEOS | 3 | 默认候选视频数 |
| VDB_WINDOW / VDB_STRIDE | 45 / 30 | 滑窗切块的窗口长度与步长(秒) |
| VDB_WORKER_TIMEOUT | 220000 | Python worker 超时(毫秒) |
已知限制
- 只覆盖 B 站公开视频,且只转写前 audio_seconds 秒(默认 5 分钟)。长视频靠后的内容需要调大该参数,耗时线性增长。
- 匿名状态下拿不到官方字幕(subtitles 接口返回 0 条),所以一律走本地 ASR,不依赖 UP 主有没有上传字幕。
- BM25 是词面匹配,不做语义向量检索。换个说法提问可能命中不到,这是有意的取舍——本地 CPU 上跑 embedding 模型会显著拖慢交互式响应。
- server.js 里 Python 路径写死为 .venv/Scripts/python.exe(Windows 布局),非 Windows 需要手动改一处。
排错
工具注册不上去(dsh 里看不到 mcp__video_evidence__*)
这是最坑的一类问题,现象是:配置明明正确(dsh --dump-config --profile web 能看到条目),重启也没用,日志里反复刷 server ready → stdin closed → server ready。
根因:同一个 dsh 实例里存在两套 MCP 分帧格式。
- dsh 自带的 dsh-mcp-client 发的是 NDJSON(裸 JSON + \n,没有 Content-Length 头)
- argo / memorix 这类用标准 MCP SDK 的走的是 Content-Length: N\r\n\r\n{json}
只认 Content-Length 的解析器收 NDJSON 时永远凑不出一条完整消息 → 不回 initialize → dsh 超时关 stdin → 重拉,死循环。
本插件的 server.js 已经用 clientFraming 闩锁 + nextMessage() 做了双格式兼容,响应按客户端格式对称回写。如果你要 fork 改写协议层,这两段不要动。
配套的两个必要细节:
1. initialize 必须回显客户端发来的 protocolVersion,不能硬编码。MCP SDK 会校验服务端返回的版本是否在自身支持列表内,硬编码新版会让较老 SDK 判定协商失败并直接关闭 stdin。
2. ping / resources/list / prompts/list 要返回空结果而不是 -32601。 客户端探测能力时收到 method not found 会判定连接不健康,进而断连重连。
怎么定位: 在 stdin 的 data 回调里打第一条原始数据:
if (!gotAny) {
gotAny = true;
log("FIRST stdin data: raw=" + JSON.stringify(d.toString("utf8").slice(0, 400)));
}
看到 {"method":"initialize",...} 后面直接跟 \n、没有 Content-Length,就确认是 NDJSON。
B 站搜索返回空(HTTP 200、code:0、但结果为空)
wbi 签名的坑:urllib.parse.urlencode 默认用 quote_plus,空格编码成 +;B 站服务端按 %20 重算签名,校验不通过就静默拒绝。
必须用 quote(空格 -> %20),不能用默认的 quote_plus(空格 -> +)
q = urllib.parse.urlencode(p, quote_via=urllib.parse.quote)
bili.py 里已经修好,并且加了非 wbi 的 legacy 接口作为兜底。
目录结构
dsh-video-evidence/
├── server.js # Node 常驻 MCP server(协议层:双分帧 + 方法分发)
├── worker.py # Python worker 入口(CLI,读 JSON 参数、打 JSON 结果)
├── server.py # 业务编排:搜索 → 取流 → 转写 → 检索
├── bili.py # B 站 API 客户端(wbi 签名、搜索、cid、playurl)
├── asr.py # ffmpeg 拉流 + faster-whisper 转写
├── evidence.py # 中文 BM25 打分 + 滑窗切块
├── cache.py # SQLite 转写缓存(按 BV 号,TTL 30 天)
└── requirements.txt
License
MIT