Metadata-Version: 2.4
Name: agentladle-mcp-akshare
Version: 1.0.0
Summary: AKShare MCP Server — 46 financial data tools for LLMs
Project-URL: Homepage, https://github.com/agentladle/mcp-akshare
Project-URL: Repository, https://github.com/agentladle/mcp-akshare
Project-URL: Issues, https://github.com/agentladle/mcp-akshare/issues
Author: AgentLadle
License-Expression: MIT
License-File: LICENSE
Keywords: ai,akshare,finance,llm,mcp,stock
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.10
Requires-Dist: akshare<1.19,>=1.18.40
Requires-Dist: mcp[cli]>=1.0.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Description-Content-Type: text/markdown

# AgentLadle MCP AKShare

**English** | [中文](README_zh.md)

> 🇨🇳 **China A-Share Market** — Cloud-hosted MCP for annual financial reports (2023-2025). [Read more](Chinese-A-share-MCP-README.md) | [Get API Key](https://agentladle.com/register)

> A [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that provides **46 financial data tools** for AI assistants, covering A-share, HK, US markets, macroeconomics, funds, and derivatives — powered by [AKShare](https://akshare.akfamily.xyz/).

It enables AI assistants (Claude, Cursor, etc.) to access financial market data through 46 semantic tools — from candlestick history to macro indicators, with unified symbol format, normalized output, and built-in caching/rate-limiting.

## Features

- **46 MCP tools** across 11 scopes: market, quote, flow, fundamentals, shareholders, content, sector, sentiment, IPO, macro, derivatives
- **Unified symbol format**: `<code>.<market>` (e.g. `000001.SZ`, `00700.HK`, `AAPL.US`) — automatically converted to each AKShare function's required format
- **Normalized output**: Chinese column names → English snake_case with unit conversion (万元→元, 亿股→股)
- **Built-in infrastructure**: TTL cache (history 24h / realtime 10s), token-bucket rate limiter (10 QPS global), retry with fallback sources, `asyncio.to_thread` async wrapping
- **outputSchema**: Each tool returns a typed `ToolResponse` dataclass with structured output schema
- **Tool annotations**: `readOnlyHint`, `idempotentHint`, `openWorldHint` on all tools
- **Scope-based loading**: Load a subset of tools via `AKSHARE_MCP_SCOPES` env var (e.g. `market,quote`)
- **AI workflow hints**: Each response includes a `hint` field guiding the next logical step
- **Chinese keyword handling**: AKShare's Chinese enum parameters (e.g. `北向资金`) mapped to English (`direction=north`)
- **Zero-config install** — one line to add to your MCP client, no clone or manual setup needed
- **Pure Python**, cross-platform (Windows / macOS / Linux)

## Prerequisites

- **Python 3.10+** — [Download Python](https://www.python.org/downloads/)
- **uv** — [Install uv](https://docs.astral.sh/uv/getting-started/installation/)

> **Note:** After installing uv, restart your terminal and MCP client (e.g. Claude Desktop, Cursor) to ensure the `uv` command is recognized.

## Quick Start

Add to your MCP client configuration (Claude Desktop, Cursor, etc.):

```json
{
  "mcpServers": {
    "mcp-akshare": {
      "command": "uvx",
      "args": ["agentladle-mcp-akshare"]
    }
  }
}
```

That's it. `uvx` will automatically download the package and its dependencies from PyPI — no clone, no manual install, no path configuration.

### Optional: Scope filtering

To load only specific scopes (useful for clients with tool count limits):

```json
{
  "mcpServers": {
    "mcp-akshare": {
      "command": "uvx",
      "args": ["agentladle-mcp-akshare"],
      "env": {
        "AKSHARE_MCP_SCOPES": "market,quote,fundamentals"
      }
    }
  }
}
```

### Alternative: pip install

If you prefer managing the environment yourself:

```bash
pip install agentladle-mcp-akshare
```

Then configure:

```json
{
  "mcpServers": {
    "mcp-akshare": {
      "command": "agentladle-mcp-akshare"
    }
  }
}
```

### Alternative: Run from source (local development)

Clone the repository and run directly:

```bash
git clone https://github.com/agentladle/mcp-akshare.git
```

Then configure your MCP client:

```json
{
  "mcpServers": {
    "mcp-akshare": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/mcp-akshare", "agentladle-mcp-akshare"]
    }
  }
}
```

Replace `/path/to/mcp-akshare` with the actual path to the cloned repository.

## Data Flow

```
AKShare Library (1.18.40)           MCP AKShare Server
──────────────────────              ──────────────────────────────────
stock_zh_a_hist()          ──→     get_candlesticks()
stock_zh_a_spot_em()       ──→     get_quote()
stock_financial_*()        ──→     get_financial_statement/metrics()
stock_hsgt_hist_em()       ──→     get_northbound_flow()
stock_zt_pool_em()         ──→     get_limit_up_pool()
macro_china_gdp()          ──→     get_macro_data()
fund_etf_hist_em()         ──→     get_fund_nav_history()
                                    │
                                    ├── Symbol Normalizer (<code>.<market> → func-specific format)
                                    ├── Param Normalizer (period/adjust/date/keyword enums)
                                    ├── Field Mapper (中文列名 → English snake_case + unit conversion)
                                    ├── TTL Cache (history 24h / realtime 10s / fundamental 1h)
                                    ├── Rate Limiter (10 QPS global, 2 QPS per-interface)
                                    └── Retry + Fallback (primary → backup source)
                                    │
                                    ▼
                              ToolResponse { status, data, hint, cached, source, updated_at }
```

## Tools

46 tools across 11 scopes. All tools are read-only with `readOnlyHint=true`.

### Scope: `market` (4 tools)

#### Tool 1: `get_trading_days`

Get trading days for a market between dates.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `market` | string | ✅ | `CN` / `HK` / `US` |
| `start` | string | ✅ | Start date `YYYY-MM-DD` |
| `end` | string | ✅ | End date `YYYY-MM-DD` |

#### Tool 2: `get_market_status`

Get current trading status for all markets (CN/HK/US). No parameters.

#### Tool 3: `get_security_list`

List securities for a market.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `market` | string | ✅ | `CN` / `HK` / `US` |
| `board` | string | ❌ | A-share board: `main`/`chinext`/`star`/`bse` (default: all) |
| `count` | int | ❌ | Max results (default 100, max 1000) |
| `offset` | int | ❌ | Pagination offset (default 0) |

#### Tool 4: `get_exchange_rate`

Get major currency exchange rates.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `base` | string | ❌ | Base currency (default `CNY`) |

### Scope: `quote` (5 tools)

#### Tool 5: `get_candlesticks`

Get candlestick (OHLCV) data for any asset class — routes to the correct AKShare function based on `asset_class` × `period`.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbol` | string | ✅ | Security symbol (e.g. `000001.SZ`, `AAPL.US`, `000300.INDEX`) |
| `asset_class` | string | ❌ | `stock`/`index`/`fund`/`futures` (inferred from suffix if omitted) |
| `period` | string | ❌ | `1m`/`5m`/`15m`/`30m`/`60m`/`day`/`week`/`month` (default `day`) |
| `start` | string | ❌ | Start date `YYYY-MM-DD` |
| `end` | string | ❌ | End date `YYYY-MM-DD` |
| `adjust` | string | ❌ | `none`/`qfq`/`hfq` (default `none`) |
| `count` | int | ❌ | Recent N bars (default 100, max 1000) |

#### Tool 6: `get_quote`

Get latest quote snapshot for one or more symbols.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbols` | string[] | ✅ | List of security symbols |

#### Tool 7: `get_intraday`

Get intraday time-share data.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbol` | string | ✅ | Security symbol |
| `date` | string | ❌ | Date `YYYY-MM-DD` (default: today) |

#### Tool 8: `get_depth`

Get order book (bid/ask depth).

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbol` | string | ✅ | Security symbol |

#### Tool 9: `get_trades`

Get recent trade ticks.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbol` | string | ✅ | Security symbol |
| `count` | int | ❌ | Number of trades (default 100, max 1000) |

### Scope: `flow` (4 tools)

#### Tool 10: `get_capital_flow`

Get capital flow time series for a stock.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbol` | string | ✅ | Stock symbol |
| `period` | string | ❌ | `1d`/`3d`/`5d`/`10d` (default `1d`) |

#### Tool 11: `get_northbound_flow`

Get northbound/southbound capital flow (Stock Connect).

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `direction` | string | ❌ | `north`/`south` (default `north`) |
| `scope` | string | ❌ | `market`/`stock` (default `market`) |
| `symbol` | string | ❌ | Individual stock (when `scope=stock`) |
| `start` | string | ❌ | Start date `YYYY-MM-DD` |
| `end` | string | ❌ | End date `YYYY-MM-DD` |

#### Tool 12: `get_margin_trading`

Get margin trading data (financing + short selling).

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbol` | string | ❌ | Stock symbol (empty = market aggregate) |
| `start` | string | ❌ | Start date `YYYY-MM-DD` |
| `end` | string | ❌ | End date `YYYY-MM-DD` |

#### Tool 13: `get_block_trade`

Get block trade (大宗交易) records.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `symbol` | string | ❌ | Stock symbol (empty = all market) |
| `start` | string | ❌ | Start date `YYYY-MM-DD` |
| `end` | string | ❌ | End date `YYYY-MM-DD` |

### Scope: `fundamentals` (8 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 14 | `get_company` | `symbol` |
| 15 | `get_financial_statement` | `symbol`, `kind` (IS/BS/CF/ALL), `report`, `count` |
| 16 | `get_financial_report_latest` | `symbol` |
| 17 | `get_financial_metrics` | `symbol`, `count` |
| 18 | `get_valuation` | `symbol` |
| 19 | `get_valuation_history` | `symbol`, `metric` (pe/pb/ps), `start`, `end` |
| 20 | `get_dividend` | `symbol` |
| 21 | `get_business_segments` | `symbol`, `by` (product/region) |

### Scope: `shareholders` (5 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 22 | `get_shareholder_top` | `symbol`, `holder_type`, `count` |
| 23 | `get_shareholder_count` | `symbol` |
| 24 | `get_institutional_holding` | `symbol`, `report_date` |
| 25 | `get_insider_trading` | `symbol` |
| 26 | `get_restricted_release` | `symbol`, `start`, `end` |

### Scope: `content` (4 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 27 | `get_news` | `symbol`, `count` |
| 28 | `get_news_search` | `keyword`, `count` |
| 29 | `get_filings` | `symbol`, `count` |
| 30 | `get_research_report` | `symbol`, `count` |

### Scope: `sector` (4 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 31 | `get_index_constituent` | `symbol` (e.g. `000300.INDEX`) |
| 32 | `get_sector_quote` | `sector_type` (industry/concept), `sector_name` |
| 33 | `get_sector_constituent` | `sector_type`, `sector_name` (Chinese) |
| 34 | `get_industry_rank` | `sector_type`, `count` |

### Scope: `sentiment` (6 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 35 | `get_limit_up_pool` | `date` |
| 36 | `get_limit_down_pool` | `date` |
| 37 | `get_dragon_tiger_list` | `start`, `end`, `symbol` |
| 38 | `get_hot_rank` | `market`, `rank_type`, `count` |
| 39 | `get_market_anomaly` | `anomaly_type` (rocket/dive/large_buy/large_sell), `count` |
| 40 | `get_market_summary` | `market` |

### Scope: `ipo` (2 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 41 | `get_ipo_calendar` | `market` (CN/HK) |
| 42 | `get_ipo_detail` | `symbol` |

### Scope: `macro` (4 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 43 | `list_macro_indicators` | `keyword`, `country`, `count` |
| 44 | `get_macro_data` | `indicator_code`, `start`, `end` |
| 45 | `get_interest_rate` | `rate_type` (lpr/shibor/libor), `start`, `end` |
| 46 | `get_bond_yield_curve` | `country` (CN/US), `date` |

### Scope: `derivatives` (8 tools)

| # | Tool | Key Parameters |
|---|------|---------------|
| 47* | `get_fund_quote` | `symbols`, `fund_type` (etf/open) |
| 48* | `get_fund_nav_history` | `symbol`, `start`, `end`, `count` |
| 49* | `get_fund_holding` | `symbol`, `report_date` |
| 50 | `get_futures_quote` | `exchange` (SHFE/DCE/CZCE/CFFEX/INE) |
| 51 | `get_option_quote` | `exchange` (SSE/SZSE) |
| 52 | `get_convertible_bond_value` | `symbol` |
| 53 | `get_forex_quote` | `pairs` |
| 54 | `get_reits_quote` | `symbol` |

> *Tools 47-49 cover fund data within the derivatives scope.

## Configuration

On first run, a default config file is created at `~/.agentladle/mcp-akshare/config.yaml`:

```yaml
# MCP AKShare Server Configuration
cache:
  ttl_history: 86400       # 24h — historical daily data
  ttl_realtime: 10          # 10s — real-time quotes
  ttl_fundamental: 3600     # 1h — financial statements
  ttl_calendar: 604800      # 7d — trading calendar
  ttl_company: 86400        # 1d — company basic info
  ttl_news: 300             # 5m — news
  max_size: 200             # max cached entries

ratelimit:
  global_qps: 10            # global 10 QPS
  per_interface_qps: 2      # per-interface 2 QPS

retry:
  max_retries: 1
  timeout: 30.0
  retry_delay: 1.0

# Comma-separated scope list (empty = all scopes)
# Available: market,quote,flow,fundamentals,shareholders,content,sector,sentiment,ipo,macro,derivatives
scopes: []
```

### Environment Variables

Configuration can be overridden via environment variables (highest priority):

| Variable | Description | Default |
|----------|-------------|---------|
| `AKSHARE_MCP_SCOPES` | Comma-separated scopes to load (empty = all) | `""` (all) |
| `AKSHARE_MCP_GLOBAL_QPS` | Global QPS limit | `10` |
| `AKSHARE_MCP_PER_IF_QPS` | Per-interface QPS limit | `2` |
| `AKSHARE_MCP_TIMEOUT` | Request timeout (seconds) | `30` |
| `AKSHARE_MCP_MAX_RETRIES` | Max retry attempts | `1` |
| `AKSHARE_MCP_TTL_HISTORY` | Cache TTL for historical data (seconds) | `86400` |
| `AKSHARE_MCP_TTL_REALTIME` | Cache TTL for real-time data (seconds) | `10` |

### Data Directory Structure

```
~/.agentladle/mcp-akshare/
├── config.yaml                        # Configuration (auto-created)
└── data/                              # Data directory
```

## Example Usage

The tools are designed with an **EAFP (Easier to Ask for Forgiveness than Permission)** approach. AI assistants should directly invoke data retrieval tools and rely on the `hint` field for workflow guidance.

**Scenario A: Get stock price history**

```
User: "What's Apple's stock price trend over the last 30 days?"

1. get_candlesticks(symbol="AAPL.US", period="day", count=30)
   → Returns 30 daily OHLCV bars.
   → hint: "Use get_quote for real-time price, or get_financial_metrics for fundamentals."
```

**Scenario B: Fundamental analysis workflow**

```
User: "Analyze Ping An Bank's fundamentals"

1. get_company(symbol="000001.SZ")
   → Returns company overview (industry, listing date, shares).

2. get_financial_metrics(symbol="000001.SZ", count=8)
   → Returns ROE, ROA, margins, debt ratio for 8 periods.

3. get_valuation(symbol="000001.SZ")
   → Returns current PE, PB, PS, dividend yield.
   → hint: "Use get_valuation_history for PE/PB trend."
```

**Scenario C: Discover valid symbols**

```
User: "What stocks are in the CSI 300 index?"

1. get_index_constituent(symbol="000300.INDEX")
   → Returns 300 constituent stocks with weights.

2. get_candlesticks(symbol="600519.SH", count=10)
   → Get candlestick data for a specific constituent.
```

**Scenario D: Market sentiment**

```
User: "How's the A-share market doing today?"

1. get_market_summary(market="CN")
   → Returns up/down/flat counts, limit-up/down counts, total turnover.

2. get_limit_up_pool()
   → Returns today's limit-up stocks with reasons.
   → hint: "Check consecutive_days for multi-day limit-ups."
```

## Tech Stack

| Component | Choice | Purpose |
|-----------|--------|---------|
| MCP Framework | `mcp[cli]` (FastMCP) | MCP server with stdio/streamable-http transport |
| Data Source | `akshare>=1.18.40` | 1086+ financial data interfaces (A-share, HK, US, macro, funds) |
| Config | `pyyaml` | YAML configuration file |
| Async | `asyncio.to_thread` | Wrap sync akshare calls in async MCP handlers |
| Cache | Built-in TTLCache | TTL + LRU eviction, per-category TTL |
| Rate Limit | Built-in TokenBucket | Token bucket algorithm, global + per-interface |
| Output Types | `dataclasses` | Structured outputSchema (no pydantic dependency) |
| Build | `hatchling` | PEP 621 standard build backend |
| Package Manager | `uv` | Fast dependency resolution + `uv.lock` |

## Project Structure

```
src/akshare_mcp/
├── __init__.py                # Package version
├── __main__.py               # python -m entry point
├── server.py                 # FastMCP init + tool registration + logging (stderr)
├── config.py                 # Config loading (~/.agentladle/mcp-akshare/config.yaml, singleton)
├── instances.py              # Service singletons (lazy-loaded)
├── models.py                 # Internal data models (dataclass)
├── response.py               # Response builders (success/error/skipped + hint)
├── scopes.py                 # 11 scope definitions + tool mapping
├── tools/                    # Tool layer (thin: parameter validation + response wrapping)
│   ├── market.py             #   scope: market (4 tools)
│   ├── quote.py              #   scope: quote (5 tools)
│   ├── flow.py               #   scope: flow (4 tools)
│   ├── fundamental.py        #   scope: fundamentals (8 tools)
│   ├── shareholder.py        #   scope: shareholders (5 tools)
│   ├── news.py               #   scope: content (4 tools)
│   ├── sector.py             #   scope: sector (4 tools)
│   ├── sentiment.py          #   scope: sentiment (6 tools)
│   ├── ipo.py                #   scope: ipo (2 tools)
│   ├── macro.py              #   scope: macro (4 tools)
│   └── derivative.py         #   scope: derivatives (8 tools)
├── services/                 # Business layer (thick: core logic)
│   ├── base_service.py       #   Base class with config/retry accessors
│   ├── market_service.py     #   Trading days, candlesticks, quotes, depth
│   ├── fundamental_service.py # Financials, valuation, shareholders, IPO
│   ├── flow_service.py       # Capital flow, northbound, margin, block trade
│   ├── news_service.py       # News, filings, research reports
│   ├── sentiment_service.py  # Limit pools, dragon tiger, anomaly, summary
│   ├── macro_service.py      # Macro indicators, interest rates, bond yields
│   ├── sector_service.py     # Index constituents, sector quotes/rank
│   ├── fund_service.py       # Fund quote, NAV, holdings
│   ├── derivative_service.py # Futures, options, bonds, forex, REITs
│   ├── symbol_normalizer.py  # Unified <code>.<market> → function-specific format
│   ├── param_normalizer.py   # Period/adjust/date/keyword enum mapping
│   └── field_mapper.py       # Chinese column → English snake_case + unit conversion
├── output/                   # OutputSchema types (Longbridge-style)
│   ├── common.py             #   ToolResponse wrapper
│   ├── market.py             #   TradingDayItem, SecurityItem, ...
│   ├── quote.py              #   CandlestickItem, QuoteItem, DepthOutput, ...
│   ├── flow.py               #   CapitalFlowItem, NorthboundFlowItem, ...
│   ├── fundamental.py        #   CompanyInfo, FinancialMetricItem, ValuationData, ...
│   ├── shareholder.py        #   ShareholderItem, InsiderTradeItem, ...
│   ├── content.py            #   NewsItem, FilingItem, ResearchReportItem
│   ├── sector.py             #   IndexConstituentItem, SectorQuoteItem, ...
│   ├── sentiment.py          #   LimitPoolItem, DragonTigerItem, MarketSummary, ...
│   ├── ipo.py                #   IPOCalendarItem, IPODetail
│   ├── macro.py              #   MacroIndicatorItem, InterestRateItem, ...
│   └── derivatives.py        #   FundQuoteItem, FuturesQuoteItem, OptionQuoteItem, ...
└── infra/                    # Infrastructure
    ├── cache.py              #   TTL cache with LRU eviction
    ├── ratelimit.py          #   Token bucket (global + per-interface)
    ├── retry.py              #   Retry with exponential backoff
    └── async_wrap.py         #   asyncio.to_thread wrapper for sync calls
```

## License

MIT
