chart-mcp 组装了一个 FastAPI 后端、一个 MCP(模型上下文协议)服务器、一个基于 Vercel AI 聊天机器人模板的 Next.js 前端以及一个自托管的 SearxNG 实例,以生成一个加密货币分析协作者。该项目通过 SSE 分发技术分析步骤,并提供两个特定的工件。所有测试(后端和前端)都集中在 /tests 下,便于导航和交叉覆盖:
finance — 实时流水线(OHLCV、指标、水平、图表模式和标记化摘要)。search — 来自 SearxNG 的新闻稿和文档聚合。⚠️ Alpha 版:提供的分析仅供教育用途。不提供任何投资建议。
| 组件 | 主要角色 |
|---|---|
| FastAPI (src/chart_mcp) | 由令牌保护的 REST 路由 (/api/v1/*),SSE /stream/analysis,暴露 MCP 标准输入输出。 |
| Python 服务 | CCXT 连接器、指标计算、支撑/阻力检测、图表模式检测、LLM 摘要标记化、SearxNG 客户端。 |
| SSE 工具 | chart_mcp/utils/sse.py 管理金融事件的头部、心跳、取消和序列化。 |
| SearxNG (docker/searxng) | 用于路由 /api/v1/search 和 MCP 工具 web_search 的 Docker 化服务。 |
前端 (frontend/ai-chatbot) | 严格复制 Vercel AI 聊天机器人模板并扩展了 finance 和 search 工件,重用了内部图表组件。 |
| GitHub Actions CI | 顺序管道 lint → typecheck → tests → build → e2e,涵盖 Python 和 Node。 |
FastAPI 后端 + MCP
make setup && make dev
# → API 可在 http://localhost:8000 访问
替代方案:
docker compose -f docker/docker-compose.yml up api用于容器化运行。
SearxNG(聚合搜索引擎)
docker compose -f docker/docker-compose.yml up searxng
# → 界面在 http://localhost:8080
Next.js 前端 / Vercel AI 聊天机器人
cd frontend/ai-chatbot
pnpm install
pnpm dev
# → UI 在 http://localhost:3000(消费本地 API)
公共变量
复制 .env.example(根目录)和 frontend/ai-chatbot/.env.example 到本地文件(.env, .env.local),然后调整 MCP/SearxNG 令牌。
pnpm复制 .env.example 文件(根目录和 frontend/ai-chatbot/),然后调整值。后端关键变量:
| 变量 | 描述 |
|---|---|
API_TOKEN | 所有受保护路由和 SSE 流所需的 Bearer 令牌。 |
ALLOWED_ORIGINS | 允许的 CORS 原点(逗号分隔)。生产中必需。 |
MCP_API_BASE | 后端的基础 URL(例如 http://localhost:8000)。 |
MCP_API_TOKEN | MCP CLI 和前端查询 API 使用的令牌。 |
MCP_SESSION_USER | 后端记录当前用户身份的标识。 |
EXCHANGE | 用于 OHLCV 的 CCXT 交易所(默认为 binance)。 |
OHLC_CACHE_TTL_SECONDS / OHLC_CACHE_MAX_ENTRIES | 内存中 OHLCV 缓存参数。 |
FEATURE_FINANCE | 启用/禁用可选财务路由。 |
SEARXNG_BASE_URL | SearxNG 实例的内部 URL(例如 http://searxng:8080)。 |
SEARXNG_TIMEOUT | SearxNG 请求的超时(秒)。 |
RATE_LIMIT_PER_MINUTE | 应用到限流中间件的配额。 |
前端侧(frontend/ai-chatbot/.env.example)需要相同的 MCP_* 变量以便从浏览器访问 MCP API。还可以添加您的分析/可观测性密钥。PLAYWRIGHT 和 PLAYWRIGHT_TEST_BASE_URL 保持注释状态以加速 E2E 运行:在 pnpm exec playwright test 之前导出它们,同时保留 OPENAI_API_KEY 未定义以使用模拟提供者。
REST 路由通过 Swagger (/docs) 文档化。curl 示例:
# OHLCV
curl -H "Authorization: Bearer $API_TOKEN" \
-H "X-Session-User: regular" \
"http://localhost:8000/api/v1/market/ohlcv?symbol=BTCUSDT&timeframe=1h&limit=500"
# 指标
curl -X POST -H "Authorization: Bearer $API_TOKEN" \
-H "X-Session-User: regular" \
-H "Content-Type: application/json" \
-d '{"symbol":"BTCUSDT","timeframe":"1h","indicator":{"name":"ema","params":{"window":21}},"limit":200}' \
http://localhost:8000/api/v1/indicators/compute
# 支撑/阻力
curl -H "Authorization: Bearer $API_TOKEN" \
-H "X-Session-User: regular" \
"http://localhost:8000/api/v1/levels?symbol=BTCUSDT&timeframe=4h&limit=500&max=5"
# 图表模式
curl -H "Authorization: Bearer $API_TOKEN" \
-H "X-Session-User: regular" \
"http://localhost:8000/api/v1/patterns?symbol=BTC/USDT&timeframe=1h&limit=500"
# 聚合摘要
curl -X POST -H "Authorization: Bearer $API_TOKEN" \
-H "X-Session-User: regular" \
-H "Content-Type: application/json" \
-d '{"symbol":"BTCUSDT","timeframe":"1h","include_levels":true,"include_patterns":true}' \
http://localhost:8000/api/v1/analysis/summary
# SearxNG 搜索
curl -H "Authorization: Bearer $API_TOKEN" \
-H "X-Session-User: regular" \
"http://localhost:8000/api/v1/search?q=bitcoin%20etf&categories=news,science"
# Prometheus 指标
curl http://localhost:8000/metrics
import { fetchEventSource } from "@microsoft/fetch-event-source";
/** Node.js/TypeScript 示例,用于解析金融 SSE 流。 */
async function streamFinanceAnalysis() {
const controller = new AbortController();
await fetchEventSource(
"http://localhost:8000/stream/analysis?symbol=BTCUSDT&timeframe=1h",
{
headers: {
Authorization: `Bearer ${process.env.MCP_API_TOKEN}`,
"X-Session-User": process.env.MCP_SESSION_USER ?? "regular",
},
signal: controller.signal,
async onmessage(message) {
if (!message.event || !message.data) {
return;
}
const payload = JSON.parse(message.data);
switch (message.event) {
case "token":
console.log("部分摘要:", payload.payload?.text ?? payload.text);
break;
case "metric":
console.log("指标:", payload.payload);
break;
case "done":
controller.abort();
break;
default:
console.log(`[${message.event}]`, payload.payload ?? payload);
}
},
},
);
}
streamFinanceAnalysis().catch((error) => {
console.error("流中断", error);
});
后端发送的头部确保没有缓冲:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no
所有作业都在 .github/workflows/ci.yml 中声明,并按顺序执行。
| 步骤 | 本地命令 |
|---|---|
| Python 代码检查 | ruff check ., black --check src tests, isort --check-only src tests |
| Python 类型检查 | mypy src |
| 后端测试 | pytest -q(生成覆盖率报告在 coverage.xml) |
| Docker 构建 | docker build -f docker/Dockerfile .(内置健康检查) |
| 前端类型检查 | cd frontend/ai-chatbot && pnpm exec tsc --noEmit |
| 前端测试 | pnpm --filter ai-chatbot exec vitest run + pnpm exec playwright test |
CI 发布 JUnit 和覆盖率工件以方便跟踪。
在运行 Playwright 之前,请导出:
export PLAYWRIGHT=1
export PLAYWRIGHT_TEST_BASE_URL=http://127.0.0.1:3000
export MCP_API_BASE=http://127.0.0.1:8000
export MCP_API_TOKEN=playwright-token
export MCP_SESSION_USER=regular
对于这些测试,保留 OPENAI_API_KEY 未定义以强制使用模拟提供者(不应有任何实际请求发送到 OpenAI)。对于生产运行,请在您的环境秘密中设置该密钥。
.env 或秘密 —— 只有 .env.example 文件被版本控制。ALLOWED_ORIGINS;如果列表为空且非 Playwright 模式,应用程序将拒绝启动。Authorization: Bearer <API_TOKEN> 和 X-Session-User。python -m chart_mcp.mcp_main) 注册工具 create_finance_artifact, create_search_artifact, web_search, market 等,以与前端对称集成。/metrics)。docker compose -f docker/docker-compose.yml up --build
# -> 启动 FastAPI API(端口 8000)和 SearxNG(端口 8080)
Dockerfile 包含一个调用 docker/healthcheck.py 的 HEALTHCHECK,允许 Kubernetes、Docker Compose 或 CI 验证 API 的可用性。要部署 Next.js 前端,请遵循 Vercel 指南(或以标准 Node.js 模式部署应用),并将 MCP_API_BASE 指向您的安全 API。
配置 NEXT_PUBLIC_API_BASE_URL 和 NEXT_PUBLIC_API_TOKEN 以指向您的 FastAPI 实例(默认情况下:与本地令牌相同源)。Vitest 测试覆盖 components/chart,而 Playwright 通过模拟路由检查 /chart。
ℹ️ Playwright 配置会自动启动
pnpm dev并在每次测试活动前生成会话状态(cookie)。无需手动启动前端。
前端额外有用脚本:
# Next.js 静态分析(ESLint)
pnpm lint
# 检查 TypeScript 类型而不生成文件
pnpm typecheck
# 启动 Vitest 监视测试
pnpm test:watch
# 启动本地 e2e Playwright 套件(Next.js 服务器会自动启动)
pnpm test:e2e
make setup
ALLOWED_ORIGINS=http://localhost:3000 make dev
make setup 安装 Python 依赖并注册项目为可编辑模式。ALLOWED_ORIGINS 至少应包含一个授权原点;本地可以重复使用 Next.js 前端的 URL (http://localhost:3000)。pip install -r requirements.txt 安装 fastmcp。python -m chart_mcp.mcp_main 启动 MCP 服务器(标准输入输出)。chart_mcp/schemas/mcp.py 中,规范 https://modelcontextprotocol.io。| 工具 | 主要输入 | 输出 |
|---|---|---|
get_crypto_data | symbol, timeframe, limit, start, end | 由 Pydantic 验证的 OHLCV 列表 {ts,o,h,l,c,v} |
compute_indicator | symbol, timeframe, indicator, params, limit | 不含 NaN 的列表 {ts, 值...} |
identify_support_resistance | symbol, timeframe, limit, params | 水平 {price, kind, strength, strength_label, ts_range} |
detect_chart_patterns | symbol, timeframe, limit, params | 图形 {name, score, confidence, points, metadata} |
generate_analysis_summary | payload (symbol, timeframe, 选项) | 教育性文本 + 免责声明 |
web_search | query, categories, time_range | SearxNG 结果 {title, url, snippet, source, score} |
fastmcp call python -m chart_mcp.mcp_main compute_indicator \
'{"symbol": "BTCUSDT", "timeframe": "1h", "indicator": "ema", "limit": 100}'
仓库包含一个现成的 SearxNG 服务:
docker/docker-compose.yml, docker/docker-compose.dev.yml, docker/searxng/settings.yml。SEARXNG_BASE_URL, SEARXNG_SECRET(未提交),SEARXNG_TIMEOUT(可选)。docker compose -f docker/docker-compose.dev.yml up --build searxng
当 SEARXNG_BASE_URL 指向 http://searxng:8080 时,FastAPI API 将公开 /api/v1/search。MCP 工具 web_search 使用相同的配置。
make docker-build
make docker-run
docker/healthcheck.py(执行 GET /health 请求)的 HEALTHCHECK。docker-compose.dev.yml 启动 api 和 searxng 以形成完整的堆栈。本地命令:
make lint # ruff
make typecheck # mypy
make test # pytest(单元测试 + 集成测试 + SSE)
CI 管道(定义在 .github/workflows/ci.yml,需创建):ruff → mypy → pytest → 构建 Docker 镜像 → 前端测试(Vitest/Playwright)→ 工件。
Authorization: Bearer <API_TOKEN> + X-Session-User: regular。ALLOWED_ORIGINS 定义原点。生产中无回退。.env 不提交,敏感变量通过环境/Docker 密钥注入。| 语言 | 支持的版本 |
|---|---|
| Python | 3.11, 3.12 |
| Node.js(即将推出的前端) | 20.x |
MIT