MCPcopy Index your code
hub / github.com/axuitomo/CF-EMBY-PROXY-UI

github.com/axuitomo/CF-EMBY-PROXY-UI @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
286 symbols 617 edges 1 files 4 documented · 1%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

# CF-EMBY-PROXY-UI

基于 Cloudflare Workers 的 Emby/Jellyfin 代理、分流与可视化管理面板

version platform storage ui

一个单文件 worker.js 项目:统一多台 Emby 节点入口、隐藏源站 IP、支持直连/反代混合策略、提供 ADMIN_PATH(默认 /admin)可视化后台,并集成日志、Cloudflare 统计、Telegram 日报与控制面 / 数据面分层优化。

当前版本的全局设置页已支持新手 / 高手模式切换、设置变更快照、全局设置专用迁移,以及“系统 UI / 代理与网络 / 静态资源策略 / 安全防护 / 日志设置 / 监控告警 / 账号设置 / 备份与恢复”分区导航;同时继续保留控制面 / 数据面分层、缓存键清洗、转码 m3u8 禁缓存、Geo 白/黑名单模式切换等优化。

img

  • 讨论群:https://t.me/+NhDf7qMxH4ZlODY9
  • 教程文档:https://wiki.8081666.xyz
  • 这是一个面向个人的Worker 代理方案,对于家庭来说免费版worker请求数可能不够用
  • 建议每次新增多个节点后导出 JSON 做本地备份
  • ⚠️提示:本工具仅供学习,请遵守当地法律法规,造成的一切后果自负。

目录


项目简介

CF-EMBY-PROXY-UI 是一个运行在 Cloudflare Workers 上的媒体代理系统,适用于:

  • 多台 Emby / Jellyfin 服务器统一入口
  • 隐藏源站真实 IP
  • 为海外源站提供 Cloudflare 边缘加速
  • 提供带 UI 的管理后台,而不是纯手改配置
  • 实现“反代 + 直连”混合路由

项目当前版本在单文件内集成了以下模块:认证、KV/D1 数据管理、代理主链路、日志、可视化控制台、定时任务入口。代码头部也明确将其定义为单文件部署架构。


核心能力

1) 可视化管理

  • 后台地址:ADMIN_PATH(默认 /admin
  • 支持节点新增、编辑、删除、导入、导出
  • 支持全局 Ping / 健康检查
  • 支持仪表盘展示请求量、运行状态、流量趋势、资源分类徽章
  • 支持 DNS 编辑双模式:CNAME模式 / A模式 可切换,保存时自动处理互斥关系
  • 支持推荐优选域名卡片、DNS 历史卡片回填,以及 DNS 实用链接快捷跳转
  • 支持全局设置新手 / 高手模式切换,默认新手模式隐藏高风险高级项
  • 支持冷启动初始化自检,缺少 JWT_SECRET / ADMIN_PASS 时直接在控制台与页面提示
  • 支持“一键整理 KV 数据”,用于修复旧版本升级后 sys:theme 脏值、sys:nodes_index 错乱与遗留缓存键
  • 支持设置变更快照、全局设置专用迁移与完整备份

2) 智能代理与分流

  • 默认由 Worker 透明中继请求与响应
  • 支持同源 30x 继续代理
  • 支持显式“源站直连节点”名单
  • 支持外链强制反代或直接下发 Location
  • 内置 wangpandirect 关键词匹配,可识别网盘 / 对象存储链接并直连

3) 媒体场景优化

  • 静态资源、封面、字幕与视频流分开处理
  • 大视频流不在 Worker 内做对象缓存,响应缓存头尽量沿用源站 / Cloudflare 数据面策略
  • 支持轻量级元数据预热(海报 / 白名单 .m3u8 / 字幕),不在 Worker 内做视频 Range 旁路预取或大对象缓存
  • 轻量级元数据预热自带快速熔断,源站 3 秒内无响应就直接放弃预热
  • Worker 元数据缓存键会自动清洗 Token、设备号、播放会话等噪声参数,提升跨用户命中率
  • 转码 m3u8 与非白名单播放列表不会写入 Worker 缓存
  • 视频主字节流尽量交给 Cloudflare 原生网关、Range 断点续传与 Cache Rules 处理
  • 支持 WebSocket 透明转发
  • 支持 Emby / Jellyfin 媒体授权头兼容与安全同步,并可按节点显式指定上游类型
  • 支持节点级真实客户端 IP 透传控制,便于兼容按来源 IP 风控的特殊上游

4) 安全与可观测性

  • 登录失败次数限制,达到阈值自动锁定 15 分钟
  • 支持自定义管理路径 ADMIN_PATH,降低固定 /admin 扫描命中率
  • 国家/地区白名单 / 黑名单模式切换
  • IP 黑名单
  • 单 IP 请求限速(按分钟)
  • 日志写入 D1、运行状态优先写入 D1 sys_status(KV 兜底)、定时清理、Telegram 每日报表
  • DNS 修改属于敏感操作,管理 API 需要显式确认头;当前 UI 主链路按“站点级草稿 -> 保存时统一同步”执行
  • 支持 Cloudflare GraphQL 仪表盘统计与本地 D1 兜底统计

架构总览

flowchart LR
    U[客户端 / 播放器] --> W[Worker 控制面]
    W --> A["管理面板 (ADMIN_PATH)"]
    W --> C["鉴权 / 路由 / UI / 元数据预热"]
    C --> KV[(Cloudflare KV)]
    C --> D1[(Cloudflare D1)]
    C --> G["CF 原生数据面 / Cache Rules"]
    G --> E[Emby / Jellyfin 源站]
    G --> X[外部直链 / 网盘 / 对象存储]
    S[scheduled 定时任务] --> D1
    S --> TG[Telegram 日报]
    A --> CF[Cloudflare GraphQL Analytics]

功能矩阵

模块 说明
后台认证 JWT 登录态,密码错误累计锁定
节点管理 节点增删改查、导入导出、备注/标签/密钥
路由模式 透明反代、同源跳转继续代理、源站直连节点
外链策略 强制反代外部链接 / 直接下发 Location
网盘直连 wangpandirect 关键词模糊匹配
缓存 静态资源缓存、视频透传、字幕边缘缓存、预热微缓存
安全 Geo 白名单/黑名单模式、IP 黑名单、单 IP 限速、真实客户端 IP 透传模式
兼容补丁 Authorization / X-Emby-Authorization / X-MediaBrowser-Authorization 兼容
协议优化 H1/H2/H3 开关、晚高峰自动降级、403 重试
日志监控 D1 请求日志、清理任务、Telegram 日报
仪表盘 Cloudflare GraphQL 聚合 + D1 本地兜底
设置中心 新手/高手模式、分区导航、设置快照、专用迁移
连接能力 HTTP(S) + WebSocket

工作原理

请求转发原理

客户端请求先到 Worker,Worker 根据 URL 中的节点名读取 KV 中的节点配置,再构造回源请求发送到 Emby 源站;源站响应由 Worker 流式回传给客户端。对普通 API、静态资源、视频流、重定向、WebSocket,会分别走不同的处理分支。

IP 隐藏原理

Worker 作为公网入口,外部只能看到 Cloudflare 边缘节点,而不是你的 Emby 源站真实 IP。需要注意的是,这种“隐藏”是网络入口层面的隐藏,不等于完全匿名:Cloudflare 仍会追加自身请求头,源站 TCP 层看到的也仍然是 Cloudflare 网络。

默认情况下,项目在回源时会先清洗 X-Real-IP / X-Forwarded-For / Forwarded 以及 Connection / Upgrade 等易伪造或可能影响协议升级的请求头,再由 Worker 注入真实内容,方便上游日志审计与访问控制。

这里的“真实 IP”指的是客户端与 Cloudflare 建立连接时被 Cloudflare 识别到的来源 IP。它可以是用户本机的公网出口 IP,也可以是用户前置代理的出口 IP。默认情况下,节点会透传 X-Real-IPX-Forwarded-For;项目注入的这两个请求头传达的是同一个真实 IP,其中 X-Forwarded-For 不是完整代理链。并且注入发生在节点自定义请求头之后,因此节点里新增同名请求头也不能覆盖这两个值。如果个别上游会按真实出口 IP、地区或 ASN 做风控,也可以在节点级改为仅保留 X-Real-IP、强制不透传【慎用】。

直连 / 反代混合原理

本项目不是“全量一刀切反代”。它支持:

  • 节点默认走 Worker 中继
  • 同源 30x 跳转继续代理
  • 某些节点被显式标记为“源站直连节点”后,源站 2xx 可直接下发给客户端
  • 命中网盘关键词或外链策略时,可直接把目标地址返回给客户端

这意味着它既能保留 Worker 统一入口,也能在带宽敏感场景下降低 Worker 中继成本。

控制面 / 数据面分离原理

这次架构调整的核心,是让 Worker 只做自己擅长的轻逻辑:

  • 控制面(Worker):鉴权、路由、UI 渲染、元数据处理、轻量级预热、轻量缓存键清洗
  • 数据面(Cloudflare 原生网关):视频主字节流、Range 断点续传、边缘缓存、Cache Rules 脱敏共享

对应到实现上,项目已经移除了 Worker 里对视频流的“黑洞式 drain”和大对象缓存倾向。海报、字幕、白名单播放列表继续在 Worker 层用 caches.default 做轻缓存;而视频本体则尽量保持薄透传,更依赖 Cloudflare 底层转发与 Cache Rules 配置,尤其建议为视频路径启用 Ignore query string 来实现跨用户共享缓存。


部署前须知

适合什么场景

  • Emby 源站在海外,直连线路差
  • 多台服务器希望统一访问域名
  • 不想暴露源站真实 IP
  • 需要可视化后台维护节点

不太适合什么场景

  • 局域网 / 内网直连环境
  • 源站本身就在国内优质线路(如 CN2)
  • 大规模公共分享、超大带宽分发

使用风险提醒

  • 腐竹如果明确禁止 CF 反代,使用该方案可能导致账号受限
  • Cloudflare 可能识别高流量滥用,建议仅用于个人或家庭分享
  • Worker 并不能抹除所有 CF 痕迹,请求头和源 IP 识别仍有暴露反代特征的可能

环境变量与绑定

⚙️ 环境变量与绑定配置指南

在部署本项目时,你需要配置相应的环境变量与服务绑定。为了方便管理,我们将配置项分为 Worker 核心配置(在 Cloudflare 控制台设置)和 SaaS 面板进阶配置(在部署后的管理后台设置)。

一、 Worker 核心配置(控制台填写)

在 Cloudflare Worker 的 设置 -> 变量和机密 或 绑定页面 中进行配置。建议首次部署时对照下表直接填写:

[必需项]

这些是系统正常运行的基础,必须配置

变量名 / 绑定名称 类型 作用说明 配置示例 / 建议
ENI_KV KV 绑定 核心数据存储。用于持久化保存项目主配置、节点信息、失败计数统计以及登录锁定状态等。 绑定你创建的 KV 命名空间(例如:EMBY_DATA)。
ADMIN_PASS 加密变量 (Secret) 后台登录密码。用于验证管理面板的访问权限。 MyStrongPassword123
JWT_SECRET 加密变量 (Secret) 安全会话密钥。用于生成和校验后台登录状态 (JWT),防止越权访问。 建议填入一段高强度的随机长字符串。

[可选项]

按需配置,用于开启日志统计或自定义系统行为。

变量名 / 绑定名称 类型 作用说明 配置示例 / 建议
DB D1 绑定 日志数据库。绑定后可开启请求日志审计、流量统计及自动化日报功能。 绑定你创建的 D1 数据库。
ADMIN_PATH 文本变量 (Var) 自定义管理入口。用于修改默认的 /admin 路径,有效防范自动化扫描工具的嗅探。 /secret_portal_99

> ⚠️ 注意:不能以 /api 开头。 |

💡 命名兼容性提示: 核心代码已向下兼容多种旧版命名(如 KV / EMBY_KV / EMBY_PROXY 会自动映射为 ENI_KVD1 / PROXY_LOGS 会映射为 DB)。但强烈建议在新部署时统一使用 ENI_KVDB,以确保与后续的更新、README 说明及自动化脚本保持一致。


二、 SaaS 面板进阶配置(后台 UI 填写)

项目部署成功并登录管理后台后,可在**“全局设置”**中配置以下进阶参数。这些参数最终会安全地加密存储在 ENI_KV 中。

参数分类 参数名 作用说明
Cloudflare 联动(推荐配置) cfApiToken Cloudflare API 令牌:用于实现一键清理缓存、GraphQL 流量高级统计等深度联动功能。
cfZoneId 区域 ID:对应你当前代理域名所在的 Zone ID。
cfAccountId 账户 ID:对应你的 Cloudflare 账户 ID。
Telegram 通知(按需配置) tgBotToken 机器人 Token:用于发送每日数据报表及系统告警。
tgChatId 会话 ID:接收通知的个人或群组 Chat ID。

💡 节点级补充: “媒体认证头模式”和“真实客户端 IP 透传”都支持在 节点编辑面板 单独配置。 适合按节点对个别 Emby / Jellyfin 源站或特殊风控上游做差异化处理。


三、 Cloudflare API Token 权限建议

如果你希望在后台配置 cfApiToken 以启用完整的增强能力(如仪表盘高级统计、一键清缓存),请确保生成的 API Token 至少包含以下权限:

  • Account (账户级)
    • Account Analytics -> Read (读取)
    • Workers Scripts -> Read (读取)
  • Zone (区域级)
    • Workers Routes -> Read (读取)
    • Analytics -> Read (读取)
    • Cache Purge -> Purge (清除)
    • DNS -> Edit (编辑)

📝 提示:如果你仅需要基础的代理分发与节点管理,不需要仪表盘数据增强或缓存控制,可以暂不配置此 Token。


四、 定时触发器 (Cron Triggers)

为实现自动化运维,本项目依赖 Cloudflare Worker 的定时触发器功能。

  • 功能作用:驱动定时清理过期日志、发送 Telegram 每日报表以及执行节点异常告警检查。
  • 配置方式:请前往 Worker 控制台的 Triggers (触发器) 选项卡中手动添加。(注:社区交流时常有人误拼成 corn,请确认拼写为 cron)
  • 生效时间:根据 Cloudflare 官方说明,Cron 表达式基于 UTC 时区 运行。配置变更后,最多可能需要约 15 分钟才能传播到全球边缘节点生效。

部署步骤

第一步:创建 KV

  1. 打开 Cloudflare Dashboard
  2. 进入左侧导航栏>储存与数据库 > Workers KV
  3. 创建一个 命名空间,例如:EMBY_DATA

第二步:创建 Worker

你可以任选以下三种方式:

方式 A:Cloudflare 控制台直接粘贴

  1. 进入 Workers 和 Pages -> 创建应用 -> 从helloworld开始->设置名称创建
  2. 创建后进入 Edit code
  3. worker.js 全量替换进去并部署

方式 B:通过 Cloudflare 连接 GitHub 自动部署

  1. 先将当前项目Fork到你自己的 GitHub 仓库
  2. 先打开仓库根目录的 wrangler.toml
  3. 如果你希望修改 Worker 名称,先把 name 改成你要使用的名称
  4. 点击Cloudflare Dashboard左侧导航栏的 存储和数据库
  5. 获取 KV ID
  6. 在下拉菜单或页面中选择 KV
  7. 在列表中找到并点击你为项目创建的 KV 命名空间
  8. 进入详情页后,在右侧面板找到并复制 命名空间 ID (Namespace ID) 对应id
  9. 如果你准备启用 D1 日志功能,再获取 D1 名称和 ID
  10. 同样在 存储和数据库 下,选择 D1 SQL 数据库
  11. 如果还没有数据库,可以先按下方“第四步”创建一个,再回来继续
  12. 点击你的数据库名称进入概览页面
  13. 记下这里的数据库名称对应database_name,并复制页面上显示的 数据库 ID (Database ID)对应database_id
  14. 将上面获取到的值填入仓库根目录 wrangler.toml 中的 iddatabase_namedatabase_id
  15. 如果你暂时不使用 D1,请先删除 wrangler.toml 中的 [[d1_databases]] 配置段,再进行首次部署
  16. 把修改后的 wrangler.toml 提交并推送到你自己的 GitHub 仓库
  17. 在 Cloudflare 中进入 Workers 和 Pages,选择连接 GitHub 仓库创建 Worker
  18. 选择本仓库后,保持仓库根目录为部署根目录,然后执行首次部署
  19. Cloudflare 会读取仓库内的 wrangler.toml,并以 worker.js 作为入口文件
  20. 首次部署完成后,后续只要你向已绑定分支 push 新提交,Cloudflare 就会自动拉取最新代码并重新部署

仓库中的 wrangler.toml 现在同时声明 Worker 入口、兼容日期以及 KV / D1 绑定信息;部署前请先把占位符替换成你自己的实际值。

完成方式 B 部署后,可以继续跳转到 第五步:设置环境变量

方式 C:通过 GitHub Actions 自动部署

  1. 先将当前项目Fork到你自己的 GitHub 仓库
  2. 打开仓库根目录的 wrangler.toml
  3. 如果你希望修改 Worker 名称,先把 name 改成你要使用的名称
  4. 点击Cloudflare Dashboard左侧导航栏的 存储和数据库
  5. 获取 KV ID
  6. 在下拉菜单或页面中选择 KV
  7. 在列表中找到并点击你为项目创建的 KV 命名空间
  8. 进入详情页后,在右侧面板找到并复制 命名空间 ID (Namespace ID)
  9. 如果你准备启用 D1 日志功能,再获取 D1 名称和 ID
  10. 同样在 存储和数据库 下,选择 D1 SQL 数据库
  11. 如果还没有数据库,可以先按下方“第四步”创建一个,再回来继续
  12. 点击你的数据库名称进入概览页面
  13. 记下这里的数据库名称,并复制页面上显示的 数据库 ID (Database ID)
  14. 将上面获取到的值填入仓库根目录 wrangler.toml 中的 iddatabase_namedatabase_id
  15. 如果你暂时不使用 D1,请先删除 wrangler.toml 中的 [[d1_databases]] 配置段
  16. 在 GitHub 仓库的 Settings -> Secrets and variables -> Actions 中新增以下 Secrets
  17. CLOUDFLARE_ACCOUNT_ID:你的 Cloudflare Account ID
  18. CLOUDFLARE_API_TOKEN:使用 Edit Cloudflare Workers 模板创建的 API Token
  19. 将仓库中的 deploy-worker.yml 提交并推送到 mainmaster 分支
  20. 对于当前这种纯 worker.js + wrangler.toml 结构,GitHub Actions 会直接调用 Wrangler 部署到 Cloudflare Workers
  21. 如果你的默认部署分支不是 mainmaster,请先修改 .github/workflows/deploy-worker.yml 里的 branches 配置
  22. 首次部署后,后续每次向已配置分支 push 新提交,GitHub Actions 都会自动重新部署

方式 C 不依赖 Cloudflare 的 Git 仓库集成,而是由 GitHub Actions 直接读取仓库根目录的 worker.jswrangler.toml 完成部署;如果你更希望把部署权限收敛在 GitHub Secrets 中,这种方式会更合适。

完成方式 C 部署后,可以继续跳转到 第五步:设置环境变量

第三步:绑定 KV(方式 A 必做)

  1. 如果你使用的是方式 A,打开 Worker 的绑定页
  2. 添加绑定选择KV 命名空间
  3. 变量名填:ENI_KV
  4. 绑定到你刚创建的 KV

第四步:创建并绑定 D1(可选但推荐)

  1. 打开 左侧导航栏->储存与数据库 -> D1SQL数据库
  2. 创建数据库,例如:emby_proxy_logs
  3. 如果你使用的是方式 A,回到 Worker 绑定页,添加绑定选择D1 数据库
  4. 变量名填:DB
  5. 如果你使用的是方式 B 或方式 C,请把数据库名称和数据库 ID 填入 wrangler.toml,然后重新推送到已绑定分支触发自动部署
  6. 后续在后台“日志记录”页面执行初始化 DB

如果你使用“方式 A:控制台直接粘贴”,KV / D1 仍然需要在 Cloudflare Dashboard 中手动绑定;如果你使用“方式 B / 方式 C”,则优先以 wrangler.toml 中填写的绑定信息为准。

第五步:设置环境变量

在 Worker 的 变量与机密 中新增:

  • ADMIN_PASS:后台密码
  • JWT_SECRET:随机高强度字符串
  • ADMIN_PATH:可选,自定义管理后台入口,默认 /admin

如果首次请求时缺少 ADMIN_PASSJWT_SECRET,Worker 会在控制台打印一次初始化警告,首页和管理页也会显示“系统未初始化”提示。

第六步:按需添加 Cron Trigger

如果你需要自动清理日志、发送 Telegram 日报或定时异常告警,再补这一步:

  1. 打开 Worker 的 Triggers
  2. 添加一个 Cron Trigger
  3. 例如可先使用每天一次的表达式:0 1 * * *
  4. 保存后等待 Cloudflare 全球传播生效

Cloudflare 官方文档说明:注意Cron Trigger 使用 UTC,而中国时区是UTC+8,免费计划最多 5 个、付费计划最多 250 个;单次 Cron 执行最长 15 分钟。

第七步:自定义域绑定与优选域名路由教程

Cloudflare Dashboard->左侧导航栏->域注册->管理域

点击要绑定的域名,在仪表盘右侧DNS模块,点击DNS记录

添加DNS记录

类型选择CNAME ,名称自定义,目标为优选域名 可以从https://cf.090227.xyz/ 中选

优选域名推荐:saas.sin.fan mfa.gov.ua www.shopify.com

格外注意:关闭代理状态[关闭小黄云],然后点击保存即可 img

配置路由

在你的域名管理页面左侧菜单栏,点击 Workers 路由 (Workers Routes)-在HTTP 路由-点击添加路由

举例:我的域名是 xyz9923.qzz.io ,我上面设置的名称为emby

路由填写为 emby.xyz9923.qzz.io/ 必须在域名的后边携带/**

Worker选择:Worker 一栏选择你第一步创建的那个Worker

img

域名推荐设置:

  • SSL/TLS:Full
  • 开启 Always Use HTTPS
  • 开启 TLS 1.3
  • 开启 WebSockets
  • 可按需开启 Tiered Cache

反代访问端口需使用 Cloudflare 支持的 HTTPS 端口,例如 443 / 2053 / 2083 / 2087 / 2096 / 8443

第八步Cloudflare Cache Rules 教程[违反TOS慎重开启]


文档导航

如果你想快速理解当前版本里最容易看花眼的部分,建议按下面顺序阅读:

  • 全局设置功能文档:面向小白解释后台“全局设置”每一栏是干什么的、什么时候该改、什么时候别乱动
  • 设置绑定词典:记录设置字段与界面输入框、默认值、加载/保存规则的对应关系
  • 主流程图:从 fetch / scheduled 入口看整条请求链路怎么分发

后台功能说明

后台路径:

https://你的域名/admin

如果设置了自定义环境变量:

ADMIN_PATH=/secret_portal_99
https://你的域名/secret_portal_99

后台主要页面

  • 仪表盘:展示请求量、流量趋势、资源类别、运行状态、定时任务状态,按需手动刷新
  • 节点管理:搜索节点、导入/导出配置、全局 Ping
  • 日志记录:按日期范围查询请求记录、初始化 DB、手动清理
  • DNS 编辑:当前站点 DNS 草稿编辑、推荐优选域名、历史记录回填、实用链接
  • 设置页:系统 UI、代理与网络、静态资源策略、安全防护、日志设置、监控告警、账号设置、备份与恢复

DNS 编辑页说明

  • 后台 DNS 编辑页内置 推荐优选域名 卡片,点击后会自动回填当前站点的 CNAME 草稿,但仍需要再点一次“保存 DNS”才会真正写入 Cloudflare
  • CNAME模式:只保留 1 条 CNAME;保存时会自动删除当前站点下的 A / AAAA
  • A模式:可混合多条 A / AAAA,最少保留 1 条;切换到该模式时只会先改后台草稿,不会立刻改 Cloudflare
  • A模式 切回 CNAME模式 时,如果当前没有有效 CNAME 草稿,会默认回填 saas.sin.fan
  • DNS 历史记录只保留 CNAME 修改历史,点击历

Core symbols most depended-on inside this repo

jsonError
called by 48
worker.js
nowMs
called by 29
worker.js
jsonResponse
called by 20
worker.js
clampIntegerConfig
called by 18
worker.js
getRuntimeConfig
called by 17
worker.js
normalizeHostnameText
called by 15
worker.js
sanitizeRuntimeConfig
called by 15
worker.js
fetchCloudflareApiJson
called by 11
worker.js

Shape

Function 286

Languages

TypeScript100%

Modules by API surface

worker.js286 symbols

For agents

$ claude mcp add CF-EMBY-PROXY-UI \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact