logo
0
0
WeChat Login
Ivan Li<ivanli2048@gmail.com>
feat(release): require channel labels stable/rc

Tavily Hikari

Release CI Pipeline Rust Frontend

Tavily Hikari 是一个面向 MCP (Model Context Protocol) 的 Tavily 代理层,基于 Rust + Axum 构建,具备多密钥轮询、匿名透传与细粒度审计能力。后端通过 SQLite 维护密钥状态与请求日志,前端使用 React + Vite 提供实时的可视化运维界面,可直接查看 Key 健康、告警与历史流量。

功能亮点

  • 多密钥轮询 + 亲和:SQLite 记录每个 Key 的最近使用时间,并为访问令牌(access token)维护一个短期“亲和”关系——在一段时间窗口内,同一 token 会优先命中同一把 Tavily API key;亲和关系失效或 Key 状态变化(耗尽/禁用)时,再通过全局“最久未使用”策略在健康 Key 间重新分配,以尽量均衡磨损。
  • 短 ID 与密钥密级隔离:每个 Tavily Key 会生成 4 位 nanoid,对外只暴露短 ID;真实 Key 仅管理员 API/Web 控制台可读取。
  • 健康巡检:一旦收到 Tavily 432(额度耗尽)会把 Key 标记为 exhausted,并在下一个 UTC 月初或管理员恢复后重新上阵。
  • 高匿透传:仅透传 /mcp 与静态资源,自动清洗 X-Forwarded-* 等敏感头并重写 Origin/Referer,细节见 docs/high-anonymity-proxy.md
  • 可视化运维web/ 单页应用展示实时统计、请求日志、管理员操作入口,支持复制真实 Key、软删除/恢复等动作。
  • 完整审计request_logs 表保留 method/path/query、状态码、错误信息、透传/丢弃头部等字段,方便回溯配额损耗与异常请求。
  • 生产级 CI/CD:GitHub Actions 对代码格式、lint、单元测试把关;发版由 PR intent label 驱动(打 tag + GitHub Release + 推送 ghcr.io 镜像)。

组件与数据流

Client → Tavily Hikari (Axum) ──┬─> Tavily upstream (/mcp) ├─> SQLite (api_keys, request_logs) └─> Web SPA (React/Vite, served via /)
  • 后端:Rust 2024 edition、Axum、SQLx、Tokio;负责 CLI、Key 生命周期、请求透传/审计、静态资源托管。
  • 数据层:SQLite 单文件库,包含 api_keys(状态、短 ID、配额字段)与 request_logs(请求/响应/错误)。
  • 前端:React 18 + TanStack Router + Tailwind CSS + DaisyUI + Vite 5;构建后输出 web/dist,由后端静态挂载或通过 Vite Dev Server 代理到 http://127.0.0.1:58087

快速开始

本地运行

# 1. 启动代理(示例绑定高位端口) cargo run -- --bind 127.0.0.1 --port 58087 # 2. (可选)启动前端 Dev Server cd web && npm ci && npm run dev -- --host 127.0.0.1 --port 55173 # 3. 通过管理员接口注册 Tavily key(ForwardAuth 头视部署而定) curl -X POST http://127.0.0.1:58087/api/keys \ -H "X-Forwarded-User: admin@example.com" \ -H "X-Forwarded-Admin: true" \ -H "Content-Type: application/json" \ -d '{"api_key":"key_a"}'

服务启动后可访问 http://127.0.0.1:58087/health 验证状态,或在浏览器打开 http://127.0.0.1:55173 使用控制台。所有 Tavily key 建议通过管理员 API 或 Web 控制台录入,避免把敏感密钥写入环境变量。

Docker 部署

CI 在发布时会产出 ghcr.io/ivanli-cn/tavily-hikari:<tag> 镜像,可直接运行:

docker run --rm \ -p 8787:8787 \ -v $(pwd)/data:/srv/app/data \ ghcr.io/ivanli-cn/tavily-hikari:latest

镜像已包含 web/dist,默认监听 0.0.0.0:8787 并把 SQLite 数据写入 /srv/app/data/tavily_proxy.db(可通过挂载卷持久化)。容器启动后同样需通过管理员接口或前端控制台为代理注册 Tavily key。

Docker Compose

仓库内提供了一个最小化的 docker-compose.yml,用于长期运行或一次性 POC:

docker compose up -d # 以管理员身份注入首批 Tavily key curl -X POST http://127.0.0.1:8787/api/keys \ -H "X-Forwarded-User: admin@example.com" \ -H "X-Forwarded-Admin: true" \ -H "Content-Type: application/json" \ -d '{"api_key":"key_a"}'
  • 服务会自动使用 ghcr.io/ivanli-cn/tavily-hikari:latest,将 8787 端口暴露到宿主机。
  • 通过 tavily-hikari-data 卷持久化 /srv/app/data/tavily_proxy.db,容器重启不会丢数据。
  • 其他 CLI 参数可通过 compose 文件的 environment 字段覆写(例如自定义 upstream 或端口)。

若需要运行自定义镜像,可在 compose 文件里将 image 替换为 build: . 并在本地构建 web/dist 后执行 docker compose up --build

CLI / 环境变量

Flag / Env说明
--keys / TAVILY_API_KEYSTavily API key 列表(可选),支持逗号分隔或多次传参,仅用于一次性导入或开发场景;生产环境推荐通过管理员 API/前端控制台录入。
--upstream / TAVILY_UPSTREAMTavily MCP 上游地址,默认 https://mcp.tavily.com/mcp
--bind / PROXY_BIND监听地址,默认 127.0.0.1
--port / PROXY_PORT监听端口,默认 8787。建议开发期使用高位端口(如 58087)。
--db-path / PROXY_DB_PATHSQLite 文件路径,默认 tavily_proxy.db
--static-dir / WEB_STATIC_DIRWeb 静态目录,若缺省且存在 web/dist 会自动挂载。
--forward-auth-header / FORWARD_AUTH_HEADER指定 ForwardAuth 注入的“用户标识”请求头(如 Remote-Email)。
--forward-auth-admin-value / FORWARD_AUTH_ADMIN_VALUE匹配到该值时视为管理员,可访问 /api/keys/* 接口。
--forward-auth-nickname-header / FORWARD_AUTH_NICKNAME_HEADER可选,提供 UI 展示的昵称头(如 Remote-Name)。
--admin-mode-name / ADMIN_MODE_NAME当缺少昵称头时用于覆盖前端显示的管理员名称。
--admin-auth-forward-enabled / ADMIN_AUTH_FORWARD_ENABLED是否启用 ForwardAuth 管理员校验(默认 true)。
--admin-auth-builtin-enabled / ADMIN_AUTH_BUILTIN_ENABLED是否启用内置管理员登录(cookie 会话)(默认 false)。
--admin-auth-builtin-password-hash / ADMIN_AUTH_BUILTIN_PASSWORD_HASH内置管理员口令哈希(PHC 字符串,推荐)。
--admin-auth-builtin-password / ADMIN_AUTH_BUILTIN_PASSWORD内置管理员登录口令(不推荐,优先使用口令哈希)。
--dev-open-admin / DEV_OPEN_ADMIN仅限本地调试的开关,跳过管理员校验(默认 false)。

首次运行会自动建表。若在 CLI/环境变量里显式传入 --keysTAVILY_API_KEYS,会同步 api_keys 表:在列表中的 Key 会被新增或恢复为 active不在列表中的 Key 会被标记为 deleted。默认推荐通过管理员 API/前端控制台维护 Key 集合。

HTTP API 速览

MethodPath说明认证
GET/health健康检查,返回 200 代表代理可用。
GET/api/summary汇总成功/失败次数、活跃 Key 数、最近活跃时间。
GET/api/keys列出 4 位短 ID、状态、请求统计。管理员
GET/api/logs?page=1最近请求日志(分页返回,默认每页 20 条),包含状态码与错误。管理员
POST/api/tavily/searchTavily /search 的代理入口,供 Cherry Studio 等 HTTP 客户端使用。Hikari Token
POST/api/keys管理员接口,新增或“反删除”一个 Key。Body: { "api_key": "..." }管理员
DELETE/api/keys/:id管理员接口,软删除指定短 ID。管理员
GET/api/keys/:id/secret管理员接口,返回真实 Tavily Key。管理员

管理员身份由外层 ForwardAuth 注入的请求头判断;控制台仅在管理员会话下显示“复制原始 Key”按钮。

Cherry Studio 接入示例

Tavily Hikari 通过 /api/tavily/search 为 Tavily HTTP API 提供代理与密钥池能力,Cherry Studio 这类直接调用 Tavily HTTP 的客户端只需要改动 Base URL 与 API 密钥来源即可迁移到 Hikari。

  • Base URL:https://<你的 Hikari 域名>/api/tavily
  • API 密钥:在 Tavily Hikari 控制台为当前用户生成的访问令牌 th-<id>-<secret>

以 Cherry Studio 为例,可按以下步骤配置:

  1. 在 Tavily Hikari 用户总览页中创建访问令牌(例如 th-xxxx-xxxxxxxxxxxx),复制该 token。
  2. 打开 Cherry Studio → 设置 → 网络搜索(Web Search)
  3. 将搜索服务商设置为 Tavily (API key)
  4. API 地址 / API URL 设置为 https://<你的 Hikari 域名>/api/tavily,本地开发时通常为 http://127.0.0.1:58087/api/tavily
  5. API 密钥 / API key 填写为步骤 1 中复制的 Hikari 访问令牌(完整的 th-xxxx-xxxxxxxxxxxx),而不是 Tavily 官方 API key。
  6. 可按需在 Cherry 中调整结果数、是否附带答案/日期等选项。

安全提醒:不要在 Cherry Studio 中直接填写 Tavily 官方 API key,推荐始终通过 Hikari 颁发的访问令牌间接访问 Tavily。

更完整的 HTTP 代理设计、字段说明与验收标准见 docs/tavily-http-api-proxy.md

密钥生命周期 & 审计

  • 额度感知:当 Tavily 返回 432 时会自动将 Key 标记为 exhausted,轮询器将跳过该 Key,直到 UTC 月初或手动恢复。
  • 调度算法:优先选择最久未使用的 active Key;若全部被禁用则按照禁用时间回退,避免请求被直接拒绝。
  • 日志字段request_logs 记录 method/path/query、上游响应体、状态码、错误堆栈、透传/丢弃头部,便于配额排障。
  • 匿名策略:详见 docs/high-anonymity-proxy.md,包括允许/丢弃的头部列表、主机名改写策略等。

ForwardAuth 配置

代理本身通过 ForwardAuth 提供的请求头判断操作者身份,可通过环境变量/CLI 配置:

export ADMIN_AUTH_FORWARD_ENABLED=true export FORWARD_AUTH_HEADER=Remote-Email export FORWARD_AUTH_ADMIN_VALUE=xxx@example.com export FORWARD_AUTH_NICKNAME_HEADER=Remote-Name
  • FORWARD_AUTH_HEADER 指定哪一个请求头携带用户邮箱或 ID。
  • 当该头的值等于 FORWARD_AUTH_ADMIN_VALUE 时,会授予管理员权限,从而允许访问 /api/keys 相关接口。
  • FORWARD_AUTH_NICKNAME_HEADER(可选)会透传到前端,用于显示操作员昵称;缺省时可在 ADMIN_MODE_NAME 中设置固定昵称。
  • 本地快速验证可以临时设置 DEV_OPEN_ADMIN=true,生产环境务必保持默认的安全策略。

内置管理员登录

如果你不想(或暂时无法)部署 ForwardAuth 网关,Hikari 也可以开启内置管理员登录页,并通过 HttpOnly cookie 会话保护管理接口:

export ADMIN_AUTH_BUILTIN_ENABLED=true echo -n 'change-me' | cargo run --quiet --bin admin_password_hash export ADMIN_AUTH_BUILTIN_PASSWORD_HASH='<phc-string>' # 不使用 ForwardAuth 时可关闭它: export ADMIN_AUTH_FORWARD_ENABLED=false
  • 开启内置登录且浏览器未登录时,首页会出现“管理员登录”按钮。
  • 登录成功会设置 HttpOnly cookie(hikari_admin_session),并解锁 /admin 与所有管理员接口。
  • 生产环境仍推荐使用 ForwardAuth;内置登录更适合自托管/小规模部署。
    • 不要在环境变量里存放明文口令;优先使用 ADMIN_AUTH_BUILTIN_PASSWORD_HASH(PHC 字符串)并设置强口令。

部署示例(Caddy 作为网关):见 examples/forwardauth-caddy/

前端控制台

  • 构建产物位于 web/dist,可由后端直接托管或独立静态站点部署。
  • 通过 React + TanStack Router 实现实时仪表盘:Key 列表、状态筛选、请求日志流式刷新。
  • DaisyUI + Tailwind 提供深浅色主题,Iconify 提供图标,自带版本号展示(scripts/write-version.mjs 会把版本写入构建结果)。
  • 开发期 npm run dev 会把 /api/mcp/health 请求代理到后端,减少 CORS 与鉴权配置成本。

界面截图

面向用户与管理员的主要界面截图如下:

MCP 客户端配置(Codex CLI)

在 Codex CLI 中配置 MCP 客户端的示例

管理后台(中文)

管理后台总览:访客令牌、统计卡片与 API Keys 表格

用户仪表盘(User Dashboard)

用户仪表盘:月成功数、今日请求、密钥池状态与近期请求

MCP 客户端

Tavily Hikari 实现了标准的 MCP(HTTP 传输 + Bearer Token 认证),可与主流客户端配合使用:

示例(Codex CLI — ~/.codex/config.toml):

experimental_use_rmcp_client = true [mcp_servers.tavily_hikari] url = "https://<your-host>/mcp" bearer_token_env_var = "TAVILY_HIKARI_TOKEN"

设置环境变量并验证:

export TAVILY_HIKARI_TOKEN="<token>" codex mcp list | grep tavily_hikari

开发与测试

  • Rust:固定使用 1.91.0(见 rust-toolchain.toml)。
    • cargo fmt / cargo clippy -- -D warnings / cargo test --locked --all-features
    • cargo run -- --help 查看完整 CLI。
  • 前端:Node 20 + pnpm/npm 均可,推荐 npm cinpm run build 会串行执行 tsc -bvite build
  • Git Hooks:运行 lefthook install 后,每次提交会自动执行 cargo fmtcargo clippynpx dprint fmtnpx commitlint --edit,确保遵循 Conventional Commits(英文)。
  • CI.github/workflows/ci.yml 负责 lint、测试、PR 构建与集成 smoke。
  • Label Gate.github/workflows/label-gate.yml 强制 PR 必须且只能有 1 个 intent label(type:*)与 1 个 channel label(channel:*)。
  • Release.github/workflows/release.yml 在 main CI 通过后触发,负责打 tag / 创建 Release / 推送 GHCR 镜像。

发版(PR Label)

本仓库使用 PR label 决定“是否发版 + bump 级别”:

  • 每个 PR 必须且只能有 1 个 intent label:type:patch / type:minor / type:major / type:docs / type:skip
  • 每个 PR 必须且只能有 1 个 channel label:channel:stable / channel:rc
  • PR 合并到 main 且 CI 通过后:
    • type:patch|minor|major:计算下一版本并发布 tag(稳定:vX.Y.Z;预发布:vX.Y.Z-rc.<sha7>),同时创建 GitHub Release 与推送 GHCR 镜像(稳定:latestvX.Y.Z;预发布:仅 vX.Y.Z-rc.<sha7>,不推进 latest)。
    • type:docs|skip:不发版(不打 tag / 不推镜像)。
  • 如果某个 commit 无法映射到“恰好一个 PR”,则会保守跳过发版(避免误发)。

生产部署提示

  1. 仅开放 /mcp/api/*、静态资源;其余路径默认 404,若前面挂有 Nginx/Cloudflare,确保不要把 /mcp 之外的入口暴露到上游。
  2. 结合 ForwardAuth 或其他零信任代理限制管理接口;普通用户不应看见真实 Key。
  3. 若需更强匿名性,请按照 docs/high-anonymity-proxy.md 的头部清洗策略部署,并确认 Origin/Referer 已被改写。
  4. 建议把 SQLite 放在持久卷或外部存储中,并定期导出 request_logs 以满足审计合规。

附加资料

  • docs/high-anonymity-proxy.md:高匿名场景下的头部处理策略。
  • Dockerfile:多阶段构建示例,可参考自定义镜像流程。
  • web/README(如存在):更细的前端说明。

License

Distributed under the MIT License。在使用、复制或分发时请保留许可声明。