helibeiqi
dsh-quant-data-mcp
Zero-dependency MCP stdio server template + ready-to-use A-share data tools for DeepSeek Harness (dsh). No API key, all env-var paths, standard NDJSON protocol.
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 16, 2026
- Updated
- Aug 16, 2026
Introduction
dsh-quant-data-mcp
零依赖 MCP stdio server 通用模板 + A 股数据开箱示例,可直接作为 DeepSeek Harness (dsh) 的 bundle 安装。
- 零依赖:只用 Node 内置模块(
fetch需要 Node ≥ 18)。无需pnpm、无需npm install、无需构建。 - 无 API key:所有数据源都是公开免密钥端点(东方财富 / 腾讯)。开箱即用。
- 路径全环境变量化:
cordis.patch.yml不写死任何绝对路径,全部通过!!js process.env.X在 dsh 启动时解析。 - 真实协议:严格按 MCP 官方的 NDJSON 帧格式实现,能被 dsh 的
dsh-mcp-client正常注册。
设计意图:它既是「A 股数据工具箱」,也是「手搓 MCP server 的模板」。把
TOOLS数组与handleCall里的工具换成你自己的零密钥本地数据源,即可复用到任意场景。
文件结构
dsh-quant-data-mcp/
├── README.md # 本文档
├── package.json # dsh bundle 声明(dsh.bundle.patch)
├── cordis.patch.yml # dsh 插件注册(全环境变量化,canonical 格式)
├── env.example.cmd # dsh 启动前需 set 的环境变量示例(Windows)
├── setup.ps1 # 一键安装脚本:拷贝 bundle + 注册 + 打印环境变量
└── lib/
└── quant-mcp-server.mjs # 零依赖 MCP server(核心代码)
兼容性(Compatibility)
- 支持的 DSH 版本:v0.1.0-rc.6 及以上(使用
dsh.bundlemanifest +cordis.patch.yml机制)。 - 运行时:Node.js >= 18(仅用内置模块,无需
npm install)。 - 最后验证日期:2026-08-16。
安装
方式 A:一键脚本(Windows / PowerShell)
pwsh -File setup.ps1
# 可选参数:-DshHome X:\path\to\.dsh -Node X:\path\to\node.exe
脚本会:① 把本 bundle 拷贝到 <DshHome>\profiles\node_modules\dsh-quant-data-mcp\;
② 把 dsh-quant-data-mcp 追加进 web profile 的 dsh.profile.bundles(先备份 package.json);
③ 打印你需要在 dsh 启动前设置的环境变量。
方式 B:手动
- 把整个
dsh-quant-data-mcp/文件夹拷到<DshHome>\profiles\node_modules\dsh-quant-data-mcp\。 - 编辑
<DshHome>\profiles\web\package.json,在dsh.profile.bundles数组里加"dsh-quant-data-mcp"(若无该字段则新建)。 - 在启动 dsh 前设置下面三个环境变量(参考
env.example.cmd)。 - 重启 dsh。
环境变量
| 变量 | 用途 | 默认值 |
|---|---|---|
QUANT_MCP_NODE | 要 spawn 的 Node 可执行文件绝对路径 | 必填,无默认 |
QUANT_MCP_SERVER | lib/quant-mcp-server.mjs 的绝对路径 | 必填,无默认 |
QUANT_MCP_CWD | server 子进程的工作目录 | 必填,无默认 |
QUANT_MCP_LOG | 可选,server 端日志文件路径;不设则禁用日志 | 未设置 = 不写日志 |
示例(放进你的 dsh-web-dual.cmd,在启动看门狗/dsh 之前):
REM ⚠️ 下面的路径是示例(原作者机器),请改成你自己的路径
set "QUANT_MCP_NODE=C:\Users\YOUR_USER\.workbuddy\binaries\node\versions\22.22.2\node.exe"
set "QUANT_MCP_SERVER=C:\Users\YOUR_USER\.dsh\profiles\node_modules\dsh-quant-data-mcp\lib\quant-mcp-server.mjs"
set "QUANT_MCP_CWD=C:\Users\YOUR_USER\quant-workspace"
REM 可选:set "QUANT_MCP_LOG=C:\Users\YOUR_USER\dsh-mcp-quant-server.log"
验证(三步)
dsh 重启后,确认:
- 端口在监听:
netstat -ano | findstr 8787出现LISTENING。 - server 子进程被拉起:任务管理器可见
node ...\quant-mcp-server.mjs。 - 工具真注册:若设置了
QUANT_MCP_LOG,日志里应出现sent tools/list with 6 tools: a_share_daily,quote_snapshot,quote_batch,financials,northbound,sectors。 在 dsh Web UI 里,模型可见mcp__quant_data__*前缀的 6 个工具。
想脱离 dsh 单独验证 server 协议正确性?用任意 MCP SDK 客户端(
StdioClientTransport+Client)连它,跑connect → listTools → callTool三步即可。协议是标准 NDJSON,官方 SDK 必能连。
工具列表(mcp__quant_data__* 命名空间)
| 工具 | 说明 | 数据源 |
|---|---|---|
a_share_daily | A 股日频 OHLCV(支持 qfq/hfq/raw 复权) | 东方财富 push2his,失败时回退腾讯 proxy.finance.qq.com fqkline(结果含 source 字段) |
quote_snapshot | 单只 A 股实时快照(价/昨收/开/高/低/涨跌%) | 腾讯 qt.gtimg.cn |
quote_batch | 多只 A 股实时快照(一次最多 50) | 腾讯 qt.gtimg.cn |
financials | 主要财务指标(EPS/ROE/营收/净利/毛利率…) | 东方财富 RPT_LICO_FN_CPD |
northbound | 沪深港通资金流快照(日/月/年/累计净买入) | 东方财富 kamt |
sectors | 行业/概念/地域板块列表 + 主力净流入 | 东方财富 clist (m:90) |
网络韧性(重要)
本 server 的 a_share_daily 已实现多源回退:主源东方财富 push2his,在其被网络封锁时自动回退腾讯 proxy.finance.qq.com fqkline(返回结果含 source 字段标明实际命中源,amount/amplitude 在回退源下为 null)。其余工具的单源情况:
quote_snapshot/quote_batch→ 腾讯qt.gtimg.cnfinancials→ 东方财富datacenter-webnorthbound→ 东方财富push2kamtsectors→ 东方财富push2clist
⚠️ 实测部分网络(如本测试机)会按端点封锁
push2*.eastmoney.com:kamt(北向)可达,而clist(板块)/push2his(日线)被拒。这种封锁是部署环境的出网策略,换数据库/付费源救不了「本机出不去」;但换用可达主机即可解决——a_share_daily已内置该回退。northbound/sectors在你的 QMT 交易机上通常可达(push2 本就是最稳的行情主机之一);若需在受限网络下也跑通sectors,请联系我为其接一个可达镜像源。
踩坑笔记(社区里最容易被坑的地方)
1. MCP 帧格式是 NDJSON,不是 Content-Length
官方 MCP SDK(以及 dsh-mcp-client)发送端 JSON.stringify(msg)+'\n',接收端按 \n 切分并 strip 行尾 \r,没有 Content-Length 头。如果你用 Content-Length 帧:
- 真 SDK 写 NDJSON,你的
drain()永远匹配不到\r\n\r\n→ 收不到initialize/tools/list; - 你自己手搓的同款帧测试客户端会「假阳性通过」,但 dsh 真机注册不上。
正确实现见 lib/quant-mcp-server.mjs 的 drain():按 \n 切分、strip 行尾 \r。
2. cordis patch 的 MCP 条目必须 name + config: 包裹
光写 id + 扁平的 serverName/transport/... 会导致 dsh 启动即崩(code=1 死循环,Edge 显示拒绝连接),且 dump-config 还能通过——极具迷惑性。原因:Include.import(name) 执行 name.startsWith("cordis:"),当 options.name 为 undefined 时抛 Cannot read properties of undefined (reading 'startsWith')。
canonical 写法(本 bundle 即此格式):
- insert:
- id: mcp-quant-data
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: quant_data
transport: stdio
command: !!js process.env.QUANT_MCP_NODE
# ⚠️ 关键:args 里的 !!js 元素必须「不引号」写成 block list(见下方坑 4)。
# 写成 args: ['!!js process.env.QUANT_MCP_SERVER'](单引号 flow 元素)会被当成
# 字面量字符串,node 找不到该文件 → ENOENT → server 静默 spawn 失败、工具永久注销。
args:
- !!js process.env.QUANT_MCP_SERVER
cwd: !!js process.env.QUANT_MCP_CWD
...
- patch 层是 override-only:裸
- id: mcp-quant会报patch: entry "mcp-quant" not found,必须用- insert:。 !!js process.env.X是 cordis YAML 解析器支持的标签,能在加载时读取环境变量——这就是「路径全环境变量化」的实现方式,无需 install 脚本硬填路径。id/serverName必须全局唯一:dsh-mcp-client基础包自带一个id: mcp-quant/serverName: quant的示例条目。若你的 bundle 复用同名id,cordis 合并 patch 树时会抛duplicate loader entry id: mcp-quant并启动即崩(code=1 死循环)。本 bundle 用mcp-quant-data/quant_data规避;给你的 bundle 命名请加专属前缀(如mcp-<yourbundle>)。
3. dump-config 通过 ≠ 能启动
dsh --profile web --dump-config 仅验证配置能解析;boot 时插件树加载失败(如坑 2)不会体现在 dump 里。硬闸门是真能启动 + 工具真注册(见上「验证」三步)。
4. ⚠️ YAML 引号陷阱:!!js 标签只在「未引号」的 scalar 上被解析
这是本 bundle 最隐蔽、也最致命的坑,曾导致 server 静默 spawn 失败、工具全部注销而 dsh 毫无报错。
cordis 的 YAML 解析器只在未加引号的 scalar 上展开 !!js 标签;一旦用单引号包裹 flow 元素,它就退化成字面量字符串,!!js 不再解析:
# ❌ 错误(曾用写法):单引号 flow 元素 → args 变成字面量字符串
# ["!!js process.env.QUANT_MCP_SERVER"],node 找不到该文件 → ENOENT → spawn 瞬间退出
args: ['!!js process.env.QUANT_MCP_SERVER']
# ✅ 正确:未引号的 block list → cordis 逐元素展开 !!js
args:
- !!js process.env.QUANT_MCP_SERVER
同理,command: / cwd: 也必须直接写 !!js process.env.X,不要写成 '!!js process.env.X'。
如何自查是否踩中:dsh 起来后若某个 mcp__quant_data__* 工具根本不存在(或 dsh 日志/进程树里看不到 quant-mcp-server.mjs 子进程),第一时间检查 cordis.patch.yml 的 args 是否用了单引号 flow 写法。现象特征:dsh 进程树里只有默认的 quant + 因子 2 个 node 子进程,没有你的 server;server 日志文件(QUANT_MCP_LOG)不会被创建(因为 server 根本没被 spawn)。这不是 server 代码问题——server 单独 node quant-mcp-server.mjs 直跑完全正常。
数据源禁忌(请勿调用,已实测踩雷)
以下端点会 403 / 重定向到 HTML / 结构性失效,切勿复用:
emweb.securities.eastmoney.com/...(老 emweb 站点) → 已停用f10.eastmoney.com/.../zycwzbAjax.json→ 403 Forbiddenweb.ifzq.gtimg.cn/...json→ "No dispatch info found"(已下线)- 东方财富报表名不是直观的
RPT_F10_FN_INCOME/BALANCE/CASHFLOW/MAININDICATOR(均返回「报表配置不存在」);实测可用的只有RPT_LICO_FN_CPD(财报汇总)、RPT_F10_FINANCE_GINCOME、RPT_DMSK_FN_INCOME。
金额口径:东方财富原始多为「元」,本 server 统一 /1e8 转「亿元」再 toFixed(2)。
升级 / 重装注意
- dsh 升级会清空
node_modules补丁:bundle 目录、其package.json的 bundle 声明、web profile 的bundles列表都会被重置。升级后重跑setup.ps1即可恢复。 QUANT_MCP_*环境变量位于启动脚本 / shell 层,不受 dsh 升级影响(env.example.cmd拷进你的启动脚本即可)。
卸载(Uninstall)
本插件为纯本地 stdio 进程,不写入系统目录、不注册系统服务,删除即彻底移除。
# 1) 编辑 <DshHome>\profiles\web\package.json,从 dsh.profile.bundles 数组删除 "dsh-quant-data-mcp"
# 2) 删除 bundle 目录
Remove-Item -Recurse -Force "<DshHome>\profiles\node_modules\dsh-quant-data-mcp"
# 3) (可选)清理启动脚本里的 QUANT_MCP_* 环境变量,然后重启 dsh
- 环境变量(
QUANT_MCP_*)只存在于你自己的env.example.cmd/ shell 中,按需清理即可,不随 bundle 删除而自动清除。 - 不残留任何系统级痕迹。
局限与声明
- 这是模板 + 示例,不是一站式量化平台。因子研究、回测、本地复权面板等请在本机 Anaconda 环境完成。
- 所有数据经公开端点抓取,可能随时因对方反爬 / 接口调整而失效;server 对失败返回
isError,不会伪造结果。 - 不含任何 API key、不含任何硬编码绝对路径(
env.example.cmd与本文档示例里的路径均用YOUR_USER占位,照抄时改成你自己的即可)。 - 适用场景:dsh 内让模型直接取 A 股行情 / 财务 / 资金流做快速论证;严肃因子研究仍以本地复权面板为准。
如何扩展成你自己的数据源
- 在
TOOLS数组里加一条工具 schema(名称、描述、inputSchema)。 - 在
handleCall里加一个else if (name === 'your_tool') result = await yourHandler(args)。 - 在文件底部实现
yourHandler(用fetch调你的免密钥端点即可)。 - 重新启动 dsh,看日志
sent tools/list with N tools数量是否 +1。
无需改 cordis.patch.yml、无需重新注册 bundle。