{"id":"8601ccf5-ceee-4261-a4f5-7221cb8be068","slug":"ashare-mcp","kind":"mcp","name":"ashare-mcp","summary":"MCP server for Chinese A-share financial statements. 把 A 股财报变成 LLM 可调的工具。","owner":"yli769227-jpg","repoUrl":"https://github.com/yli769227-jpg/ashare-mcp","license":"MIT","licenseTier":"permissive","trust":"community","stars":6,"match":null,"fewStars":false,"format":"mcp","createdAt":"2026-04-27T08:40:26.000Z","addedAt":"2026-10-21T04:30:01.609Z","logoUrl":"https://avatars.githubusercontent.com/u/227625760?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["cloud-infra","data-analytics","memory-knowledge"],"tags":["a-share","agent","akshare","anthropic","finance","financial-analysis","llm"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-21T04:30:23.102Z","sample":false,"url":"https://conduits.dev/tools/ashare-mcp","language":"Python","transports":["stdio"],"install":{"pypi":"ashare-mcp"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# ashare-mcp\n\n[![CI](https://github.com/yli769227-jpg/ashare-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/yli769227-jpg/ashare-mcp/actions/workflows/ci.yml)\n[![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue.svg)](https://www.python.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n\n> **Turn Chinese A-share (沪深京) financial statements into tools your LLM can call.**\n> 把 A 股财报变成 LLM 可调的工具 —— 一句\"平安银行 2024 年报怎么样?\"直接拿到结构化三大表。\n\n<p align=\"center\">\n  <img src=\"assets/demo.gif\" width=\"720\" alt=\"Ask Claude about Ping An Bank's 2024 financials via ashare-mcp, get a structured table back\">\n</p>\n\n让 Claude(或任何 MCP 客户端)用一句\"平安银行 2024 年报怎么样?\"直接拿到结构化的资产负债表 / 利润表 / 现金流量表,字段经过精选、单位明确、缓存友好。\n\n数据来源东方财富,通过 [akshare](https://github.com/akfamily/akshare),全部免费、无需 token。\n\n---\n\n## 为什么再做一个\n\nGitHub 上\"金融 LLM\"项目大多卷在 **trading agent** 和 **SEC 10-K RAG**——前者同质化严重,后者只服务美股。**A 股 + 中文 + MCP 协议层** 的组合几乎空白。\n\n`ashare-mcp` 的定位很窄:**做 A 股财报这一件事,做到能被任何 LLM 客户端十秒接入**。它不预测股价、不写研报、不替你做决策——它只把数据从东方财富搬到 LLM 的工具调用里,字段干净、单位清楚、错误明确。\n\n## 快速开始\n\n```bash\ngit clone https://github.com/yli769227-jpg/ashare-mcp.git\ncd ashare-mcp\npython3 -m venv .venv && source .venv/bin/activate\npip install -e .\n```\n\n跑一次冒烟测试:\n\n```bash\npython -c \"from ashare_mcp.data_source import get_annual_statements; \\\n  r = get_annual_statements('SZ000001', 2024); \\\n  print(r['company_name'], r['balance_sheet']['TOTAL_ASSETS'])\"\n# -> 平安银行 5769270000000.0\n```\n\n## 接入 Claude Desktop\n\n编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`(Mac):\n\n```json\n{\n  \"mcpServers\": {\n    \"ashare\": {\n      \"command\": \"/absolute/path/to/ashare-mcp/.venv/bin/python\",\n      \"args\": [\"-m\", \"ashare_mcp.server\"]\n    }\n  }\n}\n```\n\n重启 Claude Desktop,就能直接问:\n\n> 帮我看一下平安银行 2024 年报,总资产、总负债、净利润、经营性现金流分别多少?\n\n## 工具列表\n\n| 工具 | 输入 | 输出 |\n|---|---|---|\n| `get_three_statements` | `stock_code`, `year` | 年报三大表(精选 ~150 字段)|\n| `cross_check_balance` | `stock_code`, `year` | 4 条勾稽校验(3 条通用 + 1 条行业感知)+ 误差 |\n| `compare_peers` | `stock_codes[]`, `year`, `metrics?` | 同业 N 家横向对比 + 排名 / max-min-avg-std + ROE |\n| `track_company_history` | `stock_code`, `years`, `metrics?` | 跨年时间序列 + YoY / CAGR / trend / anomalies |\n| `parse_document` *(需 `[pdf]` extra)* | `file_path`, `output_format?`, `lang?` | PDF / DOCX / PPTX / 图片 → LLM-ready markdown(MinerU)|\n\n代码归一化支持 `000001` / `SZ000001` / `sz.000001` / `000001.SZ` 多种格式。\n\n`cross_check_balance` 当前包含 4 条勾稽(前 3 条行业通用,第 4 条行业感知):\n\n1. **资产负债平衡** — `TOTAL_ASSETS = TOTAL_LIABILITIES + TOTAL_EQUITY`\n2. **现金流恒等式** — `NETCASH_OPERATE + NETCASH_INVEST + NETCASH_FINANCE + RATE_CHANGE_EFFECT = CCE_ADD`\n3. **期末/期初现金对账** — `END_CCE − BEGIN_CCE = CCE_ADD`\n4. **营业利润分解(行业感知)**\n   - **银行**:`OPERATE_PROFIT = OPERATE_INCOME − OPERATE_EXPENSE`\n   - **工商企业**:`OPERATE_PROFIT = TOTAL_OPERATE_INCOME − TOTAL_OPERATE_COST + OTHER_INCOME + INVEST_INCOME + FAIRVALUE_CHANGE_INCOME + ASSET_IMPAIRMENT_INCOME + CREDIT_IMPAIRMENT_INCOME + ASSET_DISPOSAL_INCOME [+ EXCHANGE_INCOME]`\n   - **行业自动识别**:有 `ACCEPT_DEPOSIT > 10 亿` 走银行公式,有 `TOTAL_OPERATE_INCOME` + `TOTAL_OPERATE_COST` 走工商公式,否则 `skipped`(保险等暂不支持)\n\n容忍度:前 3 条 1 万元(单项舍入),第 4 条 1000 万元(多项加总舍入累积)。字段缺失或行业无法识别时该条 `skipped`,不影响其它校验。实测 3 行业(银行 / 白酒 / 电池)4 家公司 2024 年报全过 4/4。\n\n走 lru cache 联动:**先调 `get_three_statements` 后调 `cross_check_balance`,后者 < 1ms 秒回**(同一只股票数据已在内存)。\n\n`compare_peers` 默认 metrics:`TOTAL_ASSETS / TOTAL_OPERATE_INCOME / PARENT_NETPROFIT / NETCASH_OPERATE / TOTAL_EQUITY`,自动派生 **`ROE = PARENT_NETPROFIT / 平均权益`**(本年期末权益 + 去年期末权益的均值,去年数据走 lru cache 几乎无成本;去年数据缺失时降级为期末权益,在 `roe_method` 字段标 `ending_equity_fallback`)。**自动 fallback**:银行业 `TOTAL_OPERATE_INCOME` 缺失时退到 `OPERATE_INCOME` 并在 `fallbacks` 字段标注。**并发实现**:ThreadPoolExecutor(max_workers=8),N 家公司并行拉(单家失败不挂整体,记入 `errors`)。实测 4 大银行 2024 年报对比 ~38s 跑完;招行 ROE 12.85%(零售之王长期领跑)。\n\n## HTTP API 模式\n\n除了 MCP stdio 协议,项目还提供一个 FastAPI HTTP wrapper,**供 Web 前端、curl、Postman 等任意 HTTP 客户端调用**——这是给 Web demo 用的:\n\n```bash\npip install -e .\nashare-mcp-http\n# Uvicorn running on http://0.0.0.0:8000\n```\n\n5 个 endpoint(完整 schema 见 `/docs` FastAPI 自动生成的 OpenAPI 页面):\n\n| 方法 | 路径 | 对应 MCP tool |\n|---|---|---|\n| `GET` | `/healthz` | (健康检查 + 版本号)|\n| `GET` | `/api/statements?stock_code&year` | `get_three_statements` |\n| `GET` | `/api/cross-check?stock_code&year` | `cross_check_balance` |\n| `POST` | `/api/compare-peers`(body JSON) | `compare_peers` |\n| `GET` | `/api/history?stock_code&years` | `track_company_history` |\n\n错误统一格式:`{\"error\": \"...\", \"code\": \"INVALID_INPUT\" | \"UPSTREAM_ERROR\"}`(HTTP 422 / 502)。CORS 默认 `*`,生产部署前应收紧到具体域名。`/api/compare-peers` 单次最多 20 个代码(防请求放大);公开部署建议在反向代理层(Nginx / Cloudflare 等)再加限流。\n\n冒烟测试:\n\n```bash\ncurl 'http://localhost:8000/api/statements?stock_code=000001&year=2024' | jq '.company_name, .balance_sheet.TOTAL_ASSETS'\n# \"平安银行\"\n# 5769270000000\n```\n\n## Web 前端 demo\n\n`web/` 子目录是一个 React + Vite + TypeScript + Tailwind 写的 4-tab 前端,直接调上面的 HTTP API,**给非技术用户也能用浏览器试一下**:\n\n```bash\ncd web\nnpm install\ncp .env.example .env.local  # 默认 VITE_API_BASE=http://localhost:8000\nnpm run dev           # 开发预览 → http://localhost:5173\nnpm run build         # 生产构建到 dist/\n```\n\n4 个 tab 对应 4 个核心工具:**三大报表 / 勾稽校验 / 同业对比 / 历史趋势**。需要后端 `ashare-mcp-http` 同时跑在 :8000。详见 [`web/README.md`](./web/README.md)。\n\n## PDF 文档解析(可选)\n\n`parse_document` 工具用 [opendatalab/MinerU](https://github.com/opendatalab/MinerU) 把 PDF / DOCX / PPTX / 图片(招股书、研报、年报扫描件等)解析成 LLM-ready 的 markdown。由于 MinerU pipeline 后端需要 torch + transformers 等几 GB 依赖,**单独走 extra 安装**:\n\n```bash\npip install -e \".[pdf]\"        # 装 mineru\n# 若要解析 PDF / 图片,还需 pipeline extras:\npip install \"mineru[pipeline]\"\n```\n\n不装也不影响其它 4 个工具——只是调用 `parse_document` 时会以 `RuntimeError(\"mineru not installed\")` 友好失败。\n\n## 架构\n\n```mermaid\nflowchart LR\n    LLM[Claude / 任意 MCP 客户端] -->|JSON-RPC over stdio| Server[ashare-mcp<br/>FastMCP server]\n    Web[Web 前端<br/>React + Vite] -->|HTTP / JSON| HTTP[ashare-mcp-http<br/>FastAPI wrapper]\n    Curl[curl / Postman / 其它] -->|HTTP / JSON| HTTP\n    Server -->|共享业务层| Core[业务模块<br/>checks / peer_compare / history]\n    HTTP -->|共享业务层| Core\n    Core -->|代码归一化| Norm[股票代码归一化<br/>SZ/SH/BJ 自动判断]\n    Core -->|拉取三表| DS[数据源封装<br/>akshare 包装层]\n    DS -->|缓存命中| Cache[(进程内存缓存<br/>lru_cache)]\n    DS -->|缓存未命中| YearlyEM[akshare<br/>by_yearly_em]\n    YearlyEM -->|HTTP| EM[东方财富<br/>财报数据接口]\n    DS -->|字段过滤| Filter[剔除元数据列<br/>剔除同比列<br/>剔除空/零字段]\n```\n\n**关键设计**:\n\n- **字段名保留东方财富原始英文**(`TOTAL_ASSETS` / `LOAN_ADVANCE` / `NETPROFIT`)。LLM 直接能理解,且银行 / 工商企业 / 保险等不同行业字段都在同一份字典里,无需做行业判断。\n- **进程内存缓存**让\"同一公司多年份对比\"几乎零成本——冷启动一次拉全量,后续年份切换 < 1ms。\n- **日志走 stderr**,不污染 MCP stdio 协议通道。\n\n## 部署\n\n仓库已内置三份部署配置,前后端分开部署:\n\n| 文件 | 平台 | 部署对象 | 关键配置 |\n|---|---|---|---|\n| `railway.json` + `nixpacks.toml` | [Railway](https://railway.app/) | 后端 `ashare-mcp-http` | Nixpacks 构建(Python 3.11),启动 `ashare-mcp-http`,健康检查 `/healthz`,失败重启最多 3 次 |\n| `vercel.json` | [Vercel](https://vercel.com/) | 前端 `web/`(Vite 静态站) | 构建 `cd web && npm run build`,产物 `web/dist`,SPA rewrites 到 `index.html` |\n\n**后端(Railway)**:连接仓库后 Railway 自动读 `nixpacks.toml` 构建(锁 Python 3.11,不装 `[pdf]` extra),`$PORT` 由平台注入(见 `http_app.py`)。健康检查打 `/healthz`。\n\n**前端(Vercel)**:框架识别为 Vite,构建 `web/` 子目录输出到 `web/dist`。部署前在 Vercel 环境变量里设置 `VITE_API_BASE` 指向你的 Railway 后端地址。\n\n> 公开部署提醒:`http_app.py` 的 CORS 默认 `*`,生产应收紧到具体前端域名;`/api/compare-peers` 单请求上限 20 个代码,建议反向代理层再加限流。\n\n## 路线图\n\n| 版本 | 工具 | 状态 |\n|---|---|---|\n| v0 | `get_three_statements` | ✅ |\n| v1 | `cross_check_balance`(3 条行业通用勾稽) | ✅ |\n| v1 | `compare_peers`(同业横向对比 + ROE 派生) | ✅ |\n| v1.5 | `cross_check_balance` + 营业利润分解(行业感知:银行 / 工商企业) | ✅ |\n| v1.5 | `compare_peers` 升级到 ROE_avg(平均权益) | ✅ |\n| v2 | 跨年趋势工具 `track_company_history`(单公司多年 + CAGR) | ✅ |\n| v2 | `parse_document` PDF/DOCX → markdown(MinerU,optional) | ✅ |\n| v2(当前) | FastAPI HTTP wrapper + Web 前端 demo + pytest + CI | ✅ |\n| v3 | 季度数据 + 同比/环比派生指标 | 待定 |\n| v3 | 公开 demo 站部署配置(Vercel 前端 + Railway 后端) | ✅(`railway.json` / `nixpacks.toml` / `vercel.json` 已落仓,见「部署」一节)|\n| v3 | MCP 官方 registry 发布 | 待定 |\n\n## 本地开发\n\n```bash\n# 装 dev 依赖(包含 pytest / httpx)\npip install -e \".[dev]\"\n\n# 跑测试套件(全部离线,akshare 走 mock,~1.5s)\npytest tests/ -v\n\n# 增量验证(每次改完跑一遍)\npython -c \"from ashare_mcp.server import mcp; \\\n  import asyncio; print([t.name for t in asyncio.run(mcp.list_tools())])\"\n\n# 起 HTTP server 本地预览\nashare-mcp-http\n# 另一终端:\ncurl http://localhost:8000/healthz\n```\n\n### CI\n\n`.github/workflows/ci.yml` 跑两个 job:\n\n- **Backend** matrix:Python 3.10 / 3.11 / 3.12 — `pip install -e \".[dev]\"` + `pytest tests/ -v` + 验证 MCP & HTTP 入口都能 import\n- **Frontend**(Node 20)— `cd web && npm ci` + `tsc --noEmit` + `npm run build`\n\nPDF 路径(`parse_document`)默认 skip(mineru 是 optional);要本地跑这部分:`pip install -e \".[dev,pdf]\" && pytest tests/test_parse_document.py -v`。\n\n## 数据声明\n\n- 数据源:东方财富,通过 [akshare](https://github.com/akfamily/akshare)。\n- 数据延迟、口径、准确性以东方财富为准,**不构成投资建议**。\n- 仅用于教育与研究目的。\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n"}