Skip to main content
Glama
Vaskka

ak-mcp

by Vaskka
README.md
# ak-mcp:AKShare 金融数据 MCP Server

`ak-mcp` 是一个基于 [Model Context Protocol](https://modelcontextprotocol.io)(MCP)的金融数据查询服务,
以 [AKShare](https://akshare.akfamily.xyz/) 为数据源,把官方数据字典中收录的 **1000+ 个数据接口**自动注册为
MCP 工具,供 Claude、Codex、Cursor 等 Agent 直接发现和调用。查询结果默认写入 **MySQL 本地缓存**,
缓存命中时不再访问远程数据源,显著降低网络依赖与延迟。

## 特性

- **遵循最新 MCP 协议**:基于官方 Python SDK v2(`mcp>=2.0`),实现 **2026-07-28** 修订版协议,并自动兼容
  2025-11-25 及更早版本的客户端;同一服务同时支持 **stdio** 与 **Streamable HTTP** 两种传输。
- **全量接口覆盖**:接口清单直接由官方文档(https://akshare.akfamily.xyz/data/ )生成,当前收录
  **1019 个接口**,覆盖股票、期货、债券、期权、外汇、货币、现货、利率、私募/公募基金、指数、宏观、
  加密货币、银行、能源、另类数据、工具箱、指标计算等全部大类。
- **缓存优先**:MySQL 缓存命中即返回;未命中才回源 AKShare 并写回缓存;回源失败时自动返回过期数据并标记
  `stale: true`。
- **按分类 TTL**:实时行情、日频历史、宏观指标、静态字典分别使用不同缓存有效期,支持按函数覆盖。
- **原生参数 Schema**:每个工具的参数由 AKShare 函数签名自动生成(必填/可选、类型、默认值),Agent
  可直接按文档参数调用,无需额外学习封装格式。
- **运维友好**:内置接口检索、缓存统计、缓存清理、健康检查、绕过缓存直查等元工具。

## 架构

```mermaid
flowchart LR
    A[Agent 客户端<br/>Claude / Codex / Cursor] -->|stdio 或 Streamable HTTP| M[MCP Server<br/>mcp>=2, 2026-07-28]
    M --> T[1000+ 个数据工具<br/>工具名 = AKShare 函数名]
    T --> E[执行器<br/>超时 / 参数过滤 / 结果规范化]
    E --> C{MySQL 缓存<br/>ak_cache}
    C -->|命中且未过期| R[返回 JSON]
    C -->|未命中或过期| K[AKShare]
    K --> C
    K --> D[新浪 / 东财 / 交易所等数据源]
    M --> Meta[元工具<br/>检索 / 统计 / 清理 / 健康]
```

## 目录结构

```text
ak-mcp/
├── src/ak_mcp/               # 服务端核心代码
│   ├── server.py             # MCP 服务装配与工具注册
│   ├── registry.py           # 文档接口清单加载与安装包匹配
│   ├── schema.py             # 函数签名 -> JSON Schema
│   ├── executor.py           # 线程池调用、超时、参数过滤
│   ├── normalize.py          # DataFrame -> JSON 规范化
│   ├── cache.py              # MySQL 缓存(SQLAlchemy)
│   ├── ttl.py                # TTL 规则引擎
│   ├── config.py             # 环境变量配置
│   └── cli.py                # 命令行入口
├── scripts/
│   ├── build_registry.py     # 抓取官方文档生成接口清单
│   └── init_db.sql           # MySQL 初始化 SQL
├── config/
│   ├── akshare_registry.json # 官方文档接口清单(已生成,1019 个)
│   └── ttl_rules.yaml        # 缓存 TTL 规则
├── tests/                    # 单元与集成测试
├── docker-compose.yml        # MySQL 8 本地环境
├── pyproject.toml
└── Makefile
```

## 环境要求

- Python 3.11+(建议 3.11/3.12/3.13)
- MySQL 8.0+(可用项目自带 Docker Compose)
- AKShare 官方要求 64 位操作系统

## 快速开始

### 1. 安装

```bash
make install          # 创建 .venv 并安装依赖(等价于 pip install -e ".[dev]")
```

### 2. 启动 MySQL

方式一(推荐):使用项目自带 Docker Compose:

```bash
make mysql-up         # docker compose up -d mysql,映射标准 3306 端口
```

方式二:使用已有 MySQL,手动执行初始化:

```bash
mysql -uroot -p < scripts/init_db.sql
```

### 3. 配置

```bash
cp .env.example .env
```

按需修改 `.env`。默认配置对应项目自带的 MySQL 容器:

```dotenv
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=ak_mcp
MYSQL_PASSWORD=ak_mcp_password
MYSQL_DB=ak_mcp
```

所有配置项见 [.env.example](.env.example)。

### 4. 生成接口清单(可选)

仓库已提交 `config/akshare_registry.json`(对应官方文档 1.18.94),通常无需重新生成。如需同步最新文档:

```bash
make registry
```

### 5. 启动服务

stdio 模式(供桌面客户端本地调用):

```bash
ak-mcp
# 或 .venv/bin/ak-mcp
```

Streamable HTTP 模式(供远程/多客户端调用):

```bash
ak-mcp --transport http --host 127.0.0.1 --port 8765
```

其他命令:

```bash
ak-mcp --list-functions          # 打印全部文档接口
ak-mcp --refresh-registry        # 重新抓取官方文档并更新清单
ak-mcp --verbose                 # 调试日志
```

## QuickStart:Agent 接入

### Claude Desktop

编辑 `claude_desktop_config.json`(Claude Desktop 的 MCP 配置):

```json
{
  "mcpServers": {
    "ak-mcp": {
      "command": "/absolute/path/to/ak-mcp/.venv/bin/ak-mcp",
      "env": {
        "MYSQL_HOST": "127.0.0.1",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "ak_mcp",
        "MYSQL_PASSWORD": "ak_mcp_password",
        "MYSQL_DB": "ak_mcp"
      }
    }
  }
}
```

保存后重启 Claude Desktop,即可在对话中直接使用 `stock_zh_a_hist`、`fund_open_fund_info_em`、
`macro_china_cpi_yearly` 等全部数据工具。

### Codex

在 `~/.codex/config.toml` 中追加:

```toml
[mcp_servers.ak-mcp]
command = "/absolute/path/to/ak-mcp/.venv/bin/ak-mcp"
env = { MYSQL_HOST = "127.0.0.1", MYSQL_PORT = "3306", MYSQL_USER = "ak_mcp", MYSQL_PASSWORD = "ak_mcp_password", MYSQL_DB = "ak_mcp" }
```

也可以使用 Codex CLI 的 MCP 添加命令(具体语法以当前 Codex 版本 `codex mcp --help` 为准)。

### 通用 MCP 客户端(HTTP)

先启动 HTTP 模式:

```bash
ak-mcp --transport http --host 127.0.0.1 --port 8765
```

然后在支持 URL 的 MCP 客户端中配置:

```json
{
  "mcpServers": {
    "ak-mcp": {
      "url": "http://127.0.0.1:8765/mcp"
    }
  }
}
```

## 使用示例

### 查询 A 股历史行情

Agent 直接调用工具 `stock_zh_a_hist`,参数与 AKShare 官方文档一致:

```text
stock_zh_a_hist(symbol="000001", period="daily", start_date="20260801", end_date="20260826", adjust="")
```

返回 JSON:

```json
{
  "data": [
    {
      "日期": "2026-08-03",
      "开盘": 10.38,
      "收盘": 10.47,
      "最高": 10.59,
      "最低": 10.32,
      "成交量": 886273
    }
  ],
  "meta": {
    "function": "stock_zh_a_hist",
    "params": { "symbol": "000001", "period": "daily" },
    "cached": true,
    "stale": false,
    "rows": 18,
    "elapsed_ms": 2,
    "truncated": false
  }
}
```

### 定位接口

不确定接口名时,先调用 `ak_search_functions`:

```text
ak_search_functions(query="可转债 实时行情")
ak_search_functions(category="macro")
```

### 运维元工具

| 工具 | 说明 |
| --- | --- |
| `ak_search_functions` | 按关键词/分类检索接口清单 |
| `ak_cache_stats` | 缓存统计:条数、过期数、行数、字节数、Top 函数 |
| `ak_cache_clear` | 清理指定函数/参数或全部缓存 |
| `ak_health` | 服务健康、协议版本、接口数、缓存状态 |
| `ak_execute_raw` | 绕过缓存直查 AKShare(用于强制刷新) |

## 接口清单机制

1. `scripts/build_registry.py` 抓取官方文档 `data/` 目录下所有页面的 Markdown 源文件,解析
   `接口:xxx`、`描述:xxx` 与输入参数表,生成 `config/akshare_registry.json`。
2. 服务启动时以该清单为唯一来源:清单中收录、且已安装 akshare 中存在的接口,逐一注册为 MCP 工具。
3. 清单有而安装包缺失的接口会跳过并告警(例如文档先于版本发布时);可用
   `AKSHARE_REQUIRE_VERSION_MATCH=true` 强制版本一致。

## 缓存机制

### 缓存优先流程

1. 按 `函数名 + 规范化参数 + akshare 版本` 计算 SHA-256 缓存键。
2. 命中且未过期:直接返回缓存 JSON(`meta.cached = true`)。
3. 未命中或过期:调用 AKShare 回源,规范化后写回 MySQL。
4. 回源失败:若存在过期数据,返回旧数据并标记 `meta.stale = true`;否则返回错误文本。

### 表结构(`ak_cache`)

服务启动时通过 SQLAlchemy 自动建表,也可参考 [scripts/init_db.sql](scripts/init_db.sql) 手工创建:

| 字段 | 说明 |
| --- | --- |
| `cache_key` | SHA-256 缓存键(唯一) |
| `function_name` | AKShare 函数名 |
| `params_json` | 规范化参数 |
| `result_json` | 结果数据(LONGTEXT) |
| `row_count` | 数据行数 |
| `ttl_seconds` | 本次缓存有效期 |
| `created_at` / `expires_at` / `last_fetched_at` | 时间戳 |
| `fetch_ms` | 回源耗时 |
| `akshare_version` | 数据版本 |

### TTL 规则

规则定义在 `config/ttl_rules.yaml`,按顺序匹配、先命中先生效:

| 规则 | 匹配 | 默认 TTL |
| --- | --- | --- |
| 实时行情 | `spot/realtime/minute/分时/实时` 等 | 60s |
| 日频历史 | `hist/history/kline/daily/财务/净值` 等 | 6h |
| 宏观利率 | 分类 `macro/interest_rate` | 12h |
| 静态字典 | `list/calendar/info/简介/日历` 等 | 7d |
| 其他 | 兜底 | 1h(可用 `AK_CACHE_TTL_DEFAULT` 修改) |

## 配置项

| 环境变量 | 默认值 | 说明 |
| --- | --- | --- |
| `AK_MYSQL_DSN` | 由拆分变量拼装 | 完整 SQLAlchemy DSN,优先级最高 |
| `MYSQL_HOST/PORT/USER/PASSWORD/DB` | 见 `.env.example` | MySQL 连接拆分变量 |
| `AK_CACHE_ENABLED` | `true` | 关闭后直连 AKShare 不缓存 |
| `AK_CACHE_ALLOW_DEGRADED` | `false` | MySQL 不可用时降级为无缓存运行 |
| `AK_CACHE_TTL_DEFAULT` | `3600` | 兜底 TTL(秒) |
| `AK_CACHE_TTL_RULES` | `config/ttl_rules.yaml` | TTL 规则文件 |
| `AK_MAX_ROWS` | `100000` | 单次返回最大行数,超出截断 |
| `AK_CALL_TIMEOUT` | `60` | 单次 AKShare 调用超时(秒) |
| `AKSHARE_REGISTRY` | `config/akshare_registry.json` | 接口清单路径 |
| `AKSHARE_REQUIRE_VERSION_MATCH` | `false` | 版本不匹配时启动失败 |
| `AKSHARE_FUNCTION_EXCLUDE` | 空 | 排除的接口名正则(逗号分隔) |

## 开发与测试

```bash
make test          # 运行全部测试(单元 + MCP 内存集成)
make lint          # ruff 检查
make fmt           # ruff 格式化
```

测试覆盖:文档解析、Schema 生成、TTL 分类、参数规范化、缓存键、SQLite 缓存行为、MCP 内存模式下的
工具注册/调用/错误处理。真实网络与 MySQL 的集成验证可通过本地 Docker Compose 手动执行
(参见上文“端到端验证”)。

## 常见问题

**启动时提示某接口未找到**:`Registry function not found in installed akshare: xxx`
表示官方文档先于当前安装的 akshare 版本发布,该接口会被跳过,不影响其他接口;升级 akshare
或重新生成清单即可。

**MySQL 连接失败**:确认 `.env` 端口与 `docker compose ps` 显示的一致(本项目容器直接映射
标准端口 `3306`);也可以设置 `AK_CACHE_ALLOW_DEGRADED=true` 临时以无缓存模式启动。

**数据源接口报错**:AKShare 部分接口依赖第三方网站(新浪、东财等),可能受网络、风控或字段变更影响;
可通过 `ak_execute_raw` 绕过缓存复现,或升级 akshare 版本。

**时区与编码**:缓存时间统一为 UTC;数据写入与读取使用 UTF-8/utf8mb4,中文列名可直接返回。

## 安全与生产建议

- v1 面向本地与内网,未内置鉴权与限流;生产环境建议置于网关之后(OAuth/API Key、速率限制)。
- 缓存为所有 Agent 共享,不区分用户;涉及敏感场景请自行增加隔离。
- HTTP 模式对外暴露时,建议仅监听内网地址,或通过反向代理添加 TLS。

## License

MIT