
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
search2chart-mcp
Advanced tools
跨客户端 ECharts 图表 MCP server:数据 → 自包含可交互 HTML + 对话框内联图片(data URI / localhost http / GitHub+jsDelivr CDN 公网 https)
A cross-agent ECharts chart MCP server. Feed it data (from web search or a CSV/XLSX file), get back an interactive chart as a self-contained HTML file. Works with DeepSeek Harness (DSH), Codex, WorkBuddy, and Trae.
把「数据 → 图表」做成一次开发、多端通用的 MCP server。agent 用自带搜索 / 本地文件取数后调用本服务,即可在对话里出图。零运行时依赖(纯 Node 手写 MCP stdio 协议)。
npm run fetch-echarts 把 echarts 落到 vendor/,沙箱禁外网也能渲染。chart_from_data)+ 文件流(chart_from_file)。npm i xlsx 后支持 .xlsx/.xls;不装也能跑 CSV。| 工具 | 作用 |
|---|---|
chart_from_data | 结构化数据 → 写入图表 HTML 文件,返回绝对路径 + 数据概要(完整 ECharts option 默认省略,includeOption: true 恢复) |
chart_from_file | CSV/XLSX 路径 → 解析后写入图表 HTML,返回路径 + 概要(首列类别轴,其余列数值序列) |
list_chart_types | 列出支持的类型 / 配色与字段约定 |
字段约定:第一列 = 类别轴;其余列 = 数值序列(多列即多序列);chartType: auto 按数据自动选 饼/柱。
MCP 工具结果在多数宿主里走文本通道:宿主(如 DSH 的 mcp-client)会把非文本块折叠成纯文本,直接把 HTML 吐回去只会在工具结果里显示成一长段 / 调试视图,不会被当成网页内联渲染。
因此本 server 统一把图表写成 .html 文件并返回绝对路径,各宿主用自己擅长的方式呈现:
想让宿主直接拿到 HTML(而不是走文件链接),把工具参数
returnHtml: true即可额外返回 HTML 原文——前提是宿主能渲染 HTML(如 Trae 的预览、装了 genui 的 DSH)。
图表文件默认写入 os.tmpdir()/echarts-charts/,可用环境变量 ECHARTS_CHARTS_DIR 覆盖(例如设成你的工作区 charts/ 目录,产物就落在该目录)。产物自动清理:超过 3 天或目录内超过 500 个文件时删除最旧者,无需手动维护。
不同客户端对「工具结果里的图片」处理方式不一致:有的把 image content block 当多模态输入(纯文本模型会过滤掉),有的不渲染 file:// 图片。为此采用模型回写策略:
.svg,并在返回的文本里给出  这一行 + 一句「请在最终回复中原样写回该行」的指示。image content block(base64 SVG),供 Claude Desktop / Cursor 等支持 image block 的客户端直接渲染。.html 路径文本(可点击打开交互式图表)。通过环境变量 ECHARTS_INLINE_MODE 控制内联行为:
| 模式 | 行为 | 适用客户端 |
|---|---|---|
inline(默认) | data URI → localhost http → file:// 自动 fallback | OpenCode / DSH / 通用 |
file | 只输出 file:// 本地路径 | ZCode |
cdn | 上传 GitHub+jsDelivr,输出公网 https(见下方隐私说明) | WorkBuddy |
all | 测试模式:一次返回所有格式,让用户判断哪个能显示 | 首次接入时测试 |
none | 纯文本(.html 路径 + 数据),无内联 | 纯文本模型 / 终端 |
隐私说明(cdn 模式):图表含你的数据,上传到公网 GitHub 仓库后经 jsDelivr 可被任何人访问。因此 CDN 仅在显式设置
ECHARTS_INLINE_MODE=cdn时启用,不会自动兜底上传;敏感数据请勿使用 cdn 模式。
| 变量 | 默认值 | 说明 |
|---|---|---|
ECHARTS_INLINE_MODE | inline | 内联模式(inline / file / cdn / all / none) |
ECHARTS_RETURN_IMAGE | true | 是否返回 MCP image content block |
ECHARTS_RETURN_DATA | true | 是否附带清洗后完整数据 |
ECHARTS_RETURN_OPTION | false | 是否附带完整 ECharts option JSON(体积较大,默认省略;工具参数 includeOption 可单次覆盖) |
ECHARTS_DATA_MAX_ROWS | 60 | 返回数据的最大行数 |
ECHARTS_DATA_URI_MAX | 49152 | data URI 最大字节数 |
SEARCH2CHART_PORT | 18765 | 本地 HTTP 服务端口 |
ECHARTS_CHARTS_DIR | os.tmpdir()/echarts-charts | 图表输出目录 |
ECHARTS_CDN_TOKEN | — | GitHub PAT(cdn 模式必填) |
ECHARTS_CDN_REPO | iqingyoung/search2chart-cdn | GitHub 仓库(cdn 模式) |
ECHARTS_CDN_RETENTION_DAYS | 3 | CDN 图片保留天数(自动清理) |
ECHARTS_CDN_BRANCH | main | GitHub 分支 |
先用 all 模式一次性测试所有格式:
临时配置:
{ "env": { "ECHARTS_INLINE_MODE": "all" } }
发给 Agent:
用 chart_from_data 生成一个简单柱状图。
数据:[["城市","销量"],["北京",120],["上海",200],["广州",150]]
标题:城市销量对比
chartType:bar
Agent 返回 3-4 行图片,分别标记为 【1·data URI】【2·localhost http】【3·file://】【4·CDN 公网 https】。哪个在对话框里真正渲染成了图片,你的客户端就支持哪种。然后把 ECHARTS_INLINE_MODE 固定为对应值。
工具结果里已内置 Agent 自动检测指令,告诉模型如何根据用户反馈自动设置模式:
| 用户反馈 | Agent 动作 |
|---|---|
| "1正常" | 提示设置 ECHARTS_INLINE_MODE=inline |
| "2正常" | 提示设置 ECHARTS_INLINE_MODE=inline |
| "3正常" | 提示设置 ECHARTS_INLINE_MODE=file |
| "4正常" | 提示设置 ECHARTS_INLINE_MODE=cdn |
| "都行" | 提示设置 ECHARTS_INLINE_MODE=inline(data URI 优先) |
| "都不行" | 提示设置 ECHARTS_INLINE_MODE=none |
已知实测:ZCode →
file,OpenCode →inline(data URI),WorkBuddy →cdn,DSH →inline(localhost http),Claude/Cursor →inline+returnImage:true。
视觉与数据:
#fafaf7:SVG 与 HTML 都用米白底,避免透明背景在深色/灰白客户端不可见。returnData: false 或环境变量 ECHARTS_RETURN_DATA=false 可关;超 60 行(ECHARTS_DATA_MAX_ROWS 可调)自动截断。ZCode 实测:MCP 客户端把工具结果的 image block 当模型输入过滤掉,但模型回复里的
file://markdown 图片能被渲染器直接显示——因此走「模型回写」通路。
各客户端表现:
| 客户端 | image block 内联 | 模型回写 file:// 图片 | 路径文本兜底 |
|---|---|---|---|
| ZCode | ❌(过滤) | ✅(实测) | ✅ |
| Claude Desktop / Cursor | ✅ | 取决于客户端 | ✅ |
| Codex CLI / Claude Code(终端) | ❌(终端不渲染像素) | ❌ | ✅ 落盘 .html |
| DSH(MCP 通道) | ❌ | ❌(sanitizeUrl 拦截 file:) | ✅ 路径变可点击链接;或改用 dsh/ 原生插件 |
node server.js # 由 MCP 客户端以 stdio 拉起,无需手动运行
npm run fetch-echarts # 可选:下载 echarts 到 vendor/,支持离线/沙箱渲染
npm test # 可选:端到端自检(initialize / tools/list / 两路出图)
所有客户端统一用 stdio 拉起。推荐用 npx(无需 clone):npx search2chart-mcp。或手动指定路径 node <绝对路径>/mcp/server.js(注意 mcp/ 子目录,server.js 在 mcp/ 下,不在仓库根)。
路径坑:本仓库根有
mcp/和dsh/两个子目录。MCP server 入口是mcp/server.js,不是根目录的server.js。所有接入配置里的 args 都要写完整路径.../search2chart-mcp/mcp/server.js。
ZCode 的 MCP 配置在 .zcode 体系下,分 workspace 和 user 两个 scope。
在 <repo>/.zcode/config.json(workspace scope,仅当前项目生效)或 ~/.zcode/cli/config.json(user scope,全局生效)的 mcp.servers 下新增:
{
"mcp": {
"servers": {
"echarts-chart-mcp": {
"type": "stdio",
"command": "node",
"args": ["/abs/path/to/search2chart-mcp/mcp/server.js"],
"enabled": true
}
}
}
}
接入踩坑(实测):
node 依赖 PATH:若启动失败(设置 → MCP 显示 failed / spawn node ENOENT),用 which node 查绝对路径(如 /usr/local/bin/node、~/.nvm/versions/node/v20.x.x/bin/node),填进 command 字段。type / command / args / enabled / cwd / env / timeoutMs。image content block 当作多模态模型输入处理,纯文本模型(如 GLM-5.2)会过滤掉。本 server 采用「模型回写」策略——工具结果里给出  字面量并指示模型在最终回复中原样写回,走 ZCode 的 markdown 渲染通路(展示给人看),绕开 MCP 输入过滤。重启后调用工具,模型回复里会直接显示图表。echarts-chart-mcp 显示为「已连接」。工具名形如 mcp__echarts-chart-mcp__chart_from_data。DSH 用 Cordis 加载插件(不是 harness.yaml)。在 profile 的 patch 层新增一个 mcp-client 实例即可(每个实例只连一个 server)。
编辑 ~/.dsh/profiles/<profile>/cordis.patch.yml(如 web profile):
- insert:
- id: mcp-client-echarts-chart
name: '@deepseek-ai/dsh-mcp-client' # 随 dsh 包预装
config:
transport: stdio
serverName: echarts-chart
command: 'C:/abs/path/to/node.exe'
args:
- 'C:/abs/path/to/search2chart-mcp/mcp/server.js'
cwd: 'C:/abs/path/to/search2chart-mcp'
failOnStartupError: false # 务必 false,否则 server 启动失败会让 DSH 整体启动失败
reconnect: { enabled: true, initialDelayMs: 500, maxDelayMs: 30000, maxAttempts: 10 }
- insert: 包裹:写成顶层 - id: 会被 DSH 当成「覆盖已有插件」,因 id 在 bundle 层不存在而静默 skip,表现就是重启后找不到、且不报错。id 全局唯一;serverName 须匹配 [A-Za-z0-9_-]{1,32},决定工具前缀 mcp__echarts-chart__*。C:/... 正斜杠(Windows 下 Node 接受),避免重启后相对/PATH 丢失。extractText 丢弃),且 markdown 渲染器只放行 http(s) 协议(sanitizeUrl 拦截 file:/data:)。因此在 DSH 里只能走 .html 路径文本通路——终回复里用反引号包路径成可点击链接,浏览器打开即交互式图表。若要真正内联出图,改用本仓库 dsh/ 目录下的原生 DSH 插件(走 localhost HTTP 服务 + http URL markdown 图片),见仓库根 README。mcp__echarts-chart__chart_from_data 等工具。完整示例见 examples/dsh-cordis.patch.yml。
写入 ~/.workbuddy/mcp.json 的 mcpServers:
{ "mcpServers": { "echarts-chart-mcp": { "command": "node", "args": ["/abs/path/to/search2chart-mcp/mcp/server.js"] } } }
工具返回 HTML 文件路径后,助手用 HTML 预览 / Visualizer 内联展示。
在 Trae 的 MCP 设置中加入同上的 stdio 配置(命令 node,参数指向 mcp/server.js 的绝对路径),Web IDE 直接预览返回的 HTML(亦可设 returnHtml: true 直接拿到 HTML)。
claude mcp add echarts -- node /abs/path/to/search2chart-mcp/mcp/server.js
终端无内联渲染:工具会落盘 .html,用浏览器打开即可。Codex 会把 image block 透传给支持图像的模型(模型不支持则降级为占位文本)。
搜索流(agent 搜完把数据喂入):
{ "data": [["品牌","市占率"],["A",32.5],["B",27.8],["C",18.2]], "chartType": "pie", "title": "品牌市占率" }
文件流:
{ "filePath": "/data/sales.csv", "chartType": "bar", "title": "月度销量" }
echarts-chart-mcp/
├── server.js # MCP stdio 协议 + 工具入口
├── lib/
│ ├── chart.js # 数据归一化 + 选图推断 + ECharts option
│ ├── html.js # 自包含可交互 HTML(类型/配色/宽高控件)
│ ├── svg.js # 零依赖 SVG 渲染器(bar/line/pie)→ image content block
│ └── parse.js # CSV 零依赖解析;XLSX 走可选 xlsx
├── scripts/
│ ├── fetch-echarts.js # 下载 echarts 到 vendor/(离线用)
│ └── selftest.js # 端到端自检
├── examples/
│ └── dsh-cordis.patch.yml # DSH 接入示例
├── sample.csv # 自测用样例
├── package.json
├── README.md
├── LICENSE
└── .gitignore
「写文件 + 可点击链接」是零 UI 改动的通用方案,四端都能用。若要在 DSH 对话流里直接内联(不点链接),可按 DSH「一切皆插件」的官方扩展路径,加一对「原生 dsh 插件 + 配对 UI 插件」:生成逻辑复用 lib/chart.js / lib/html.js,只是出口从 MCP 文本换成 Cordis 结构化事件 + ECharts UI 组件(参照 dsh-client-ui-tool 的 searchBody/card 渲染分支)。此方式不碰 DSH 本体。
MIT
FAQs
跨客户端 ECharts 图表 MCP server:数据 → 自包含可交互 HTML + 对话框内联图片(data URI / localhost http / GitHub+jsDelivr CDN 公网 https)
We found that search2chart-mcp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.