Skip to main content
Glama
54dabang

Kylin Offline MCP ECharts

by 54dabang
README.md
# Kylin Offline MCP ECharts

离线图表 MCP 服务,面向 Kylin ARM64 + 64KB `PAGE_SIZE`。它使用 Apache ECharts 的纯 JS SVG SSR 能力,再调用系统 `rsvg-convert` 生成 PNG,不走 `@napi-rs/canvas` / `canvas` PNG 渲染路径。

## 渲染链路

```text
MCP SSE tool call
  -> ECharts option
  -> echarts.init(null, theme, { renderer: "svg", ssr: true, width, height })
  -> chart.renderToSVGString()
  -> rsvg-convert --zoom 2 -f png -o chart.png chart.svg
  -> /charts/chart_xxx.png
  -> JSON text with chartUrl/imageFile/imageFormat/size
```

## 本机 Docker 测试

```bash
docker build -t kylin-offline-mcp-echarts:local .
docker run --rm -p 7003:7003 -v "$PWD/charts:/app/charts" kylin-offline-mcp-echarts:local
curl http://127.0.0.1:7003/health
```

SSE 地址:

```text
http://127.0.0.1:7003/sse
```

同一端口提供:

```text
/sse
/messages
/health
/charts
/api/tools/:toolName
```

## curl 直连 HTTP 测试

除了 MCP SSE 外,也支持直接通过 HTTP 调用图表工具,适合 `curl`、脚本和容器冒烟测试。

先检查服务:

```bash
curl http://127.0.0.1:7003/health
```

生成柱状图:

```bash
curl -X POST http://127.0.0.1:7003/api/tools/generate_bar_chart \
  -H 'Content-Type: application/json' \
  -d '{
    "data": [
      { "category": "人员A", "value": 9.70 },
      { "category": "人员B", "value": 8.52 },
      { "category": "人员C", "value": 7.37 },
      { "category": "人员D", "value": 6.97 },
      { "category": "人员E", "value": 6.41 },
      { "category": "人员F", "value": 5.01 }
    ],
    "title": "示例金额排名前六名人员",
    "axisXTitle": "人员姓名",
    "axisYTitle": "报销金额(万元)"
  }'
```

成功时会直接返回:

```json
{
  "status": "success",
  "chartUrl": "/charts/generate_bar_chart_1780000000000_abcd1234ef.png",
  "imageFile": "/app/charts/generate_bar_chart_1780000000000_abcd1234ef.png",
  "imageFormat": "png",
  "size": {
    "width": 800,
    "height": 600,
    "bytes": 30000,
    "zoom": 2
  }
}
```

然后就可以直接访问图片:

```bash
curl -O http://127.0.0.1:7003/charts/<上一步返回的png文件名>
```

## 测试用例

工具:`generate_bar_chart`

```json
{
  "data": "[{\"category\": \"人员A\", \"value\": 9.70}, {\"category\": \"人员B\", \"value\": 8.52}, {\"category\": \"人员C\", \"value\": 7.37}, {\"category\": \"人员D\", \"value\": 6.97}, {\"category\": \"人员E\", \"value\": 6.41}, {\"category\": \"人员F\", \"value\": 5.01}]",
  "title": "示例金额排名前六名人员",
  "axisXTitle": "人员姓名",
  "axisYTitle": "报销金额(万元)"
}
```

`data` 既支持数组,也支持上面这种 JSON 字符串。

成功返回文本内容类似:

```json
{
  "status": "success",
  "chartUrl": "/charts/generate_bar_chart_1780000000000_abcd1234ef.png",
  "imageFile": "/app/charts/generate_bar_chart_1780000000000_abcd1234ef.png",
  "imageFormat": "png",
  "size": {
    "width": 800,
    "height": 600,
    "bytes": 30000,
    "zoom": 2
  }
}
```

## Kylin ARM64 Release tar

GitHub Actions 工作流:

```text
.github/workflows/release-kylin-arm64.yml
.github/workflows/release-kylin-arm64-page64k.yml
```

`release-kylin-arm64.yml` 使用 GitHub 托管 `ubuntu-24.04-arm` runner 生成 `linux/arm64` tar。GitHub 官方文档列出的 ARM64 runner label 包括 `ubuntu-24.04-arm`,但托管 runner 不能指定 64K page-size 内核。

`release-kylin-arm64-page64k.yml` 用 `[self-hosted, Linux, ARM64, page64k]`,会先检查:

```bash
test "$(uname -m)" = "aarch64"
test "$(getconf PAGE_SIZE)" = "65536"
```

面向 Kylin ARM64 + 64KB `PAGE_SIZE` 的最终发布,推荐使用 self-hosted 64K runner workflow。

Kylin 打包默认参考 `54dabang/gpt-vis-mcp` 的 Kylin 基础镜像:

```dockerfile
ARG KYLIN_BASE_IMAGE=macrosan/kylin:v10-sp3-2403
FROM ${KYLIN_BASE_IMAGE}
```

GitHub Actions 的 `kylin_base_image` 输入可以覆盖为 `kylin-server-arm64:v10`。无论使用哪个 Kylin/vendor 基础镜像,都必须先通过 `yum` 安装 `nodejs`、`npm`、`gcc`、`gcc-c++`、`make`、`pkgconfig`、`cairo-devel`、`libjpeg-turbo-devel`、`libpng-devel`、`pango-devel`、`giflib-devel`、`librsvg2-devel`、`librsvg2-tools` 等系统依赖,再执行 `npm ci`。

手动运行时输入 tag,例如 `v0.1.0`。成功后 Release asset 名称:

```text
kylin-offline-mcp-echarts-v0.1.0-linux-arm64.tar.gz
```

下载链接模板:

```text
https://github.com/<owner>/<repo>/releases/download/v0.1.0/kylin-offline-mcp-echarts-v0.1.0-linux-arm64.tar.gz
https://gh.llkk.cc/https://github.com/<owner>/<repo>/releases/download/v0.1.0/kylin-offline-mcp-echarts-v0.1.0-linux-arm64.tar.gz
```

64K 自托管 runner 产物模板:

```text
https://github.com/<owner>/<repo>/releases/download/v0.1.0-page64k/kylin-offline-mcp-echarts-v0.1.0-page64k-linux-arm64-page64k.tar.gz
https://gh.llkk.cc/https://github.com/<owner>/<repo>/releases/download/v0.1.0-page64k/kylin-offline-mcp-echarts-v0.1.0-page64k-linux-arm64-page64k.tar.gz
```

目标机加载:

```bash
docker load -i kylin-offline-mcp-echarts-v0.1.0-linux-arm64.tar.gz
docker image inspect kylin-offline-mcp-echarts:v0.1.0-arm64 --format '{{.Os}}/{{.Architecture}}'
docker run -d --name kylin-offline-mcp-echarts -p 7003:7003 -v "$PWD/charts:/app/charts" kylin-offline-mcp-echarts:v0.1.0-arm64
```

64KB 页面大小最终仍建议在真实 Kylin ARM64 目标机上确认:

```bash
getconf PAGE_SIZE
docker exec kylin-offline-mcp-echarts rsvg-convert --version
curl http://127.0.0.1:7003/health
```

## 关键约束

本项目没有运行时依赖 `mcp-echarts` npm 包,因为 `mcp-echarts@0.7.1` 直接依赖 `@napi-rs/canvas`。这里保留兼容的工具定义和 ECharts option 生成方式,但渲染路径完全替换为 SVG SSR + 系统 `rsvg-convert`。

`Dockerfile.kylin` 仍设置 64K 链接和 npm 源码编译约束:

```dockerfile
ENV LDFLAGS="-Wl,-z,max-page-size=65536"
ENV npm_config_build_from_source=true
ENV npm_config_canvas_build_from_source=true
```

当前业务路径不调用 canvas,这两个环境变量是为了防止未来依赖变化时误拉 4KB page-size 预编译原生包。