asian-etf-mcp
by ivyyy0601
README.md
# asian-etf-mcp
An [MCP](https://modelcontextprotocol.io) server that exposes **thematic ETF data
across 5 Asian markets + the US** (Hong Kong, China A-Share, Taiwan, South Korea,
US) as tools an LLM agent — or Claude Code / Claude Desktop — can call.
It fetches public OHLCV data from Yahoo Finance, computes industry returns /
momentum / rankings, and serves them through a small set of well-described tools.
Every result carries its **source files and `as_of` date**, so answers built on it
are auditable.
## Tools
| tool | args | returns |
|------|------|---------|
| `list_markets` | — | every market → industries → ETFs (call first to discover) |
| `get_etf_performance` | `market, industry, start?, end?` | each ETF's total return vs the benchmark |
| `get_industry_momentum` | `market, end_date?` | per-industry 5d / 21d / 63d / YTD return, absolute + relative |
| `get_industry_ranking` | `market, start?, end?` | industries ranked by return |
| `get_etf_ohlcv` | `code, market, start?, end?` | raw daily OHLCV bars |
`market` accepts `hk` / `cn` / `tw` / `sk` / `us` (or full names). Dates are ISO
strings like `2025-06-01`.
## Quick start
```bash
git clone https://github.com/ivyyy0601/etf-mcp.git
cd etf-mcp # (or the asian-etf-mcp directory)
python3.10+ -m venv .venv
./.venv/bin/pip install -r requirements.txt
# Build the data cache once (fetches ~55 symbols from Yahoo Finance, ~2-3 min)
./.venv/bin/python build_cache.py
```
That's it — the server is self-contained. The market/industry/ETF definitions
ship in `configs/`, and the data comes from public Yahoo Finance, so **you don't
need any account, API key, or access to anyone's server.**
## Use with Claude Code
```bash
claude mcp add asian-etf -- /abs/path/to/.venv/bin/python /abs/path/to/src/server.py
```
Then ask, e.g. *“use asian-etf to show which US sector has the strongest momentum.”*
## How it works
Two layers, kept separate on purpose:
```
src/server.py the "menu": thin FastMCP wrapper, one @mcp.tool() per function
│ calls
src/data_access.py the "kitchen": reads CSVs, computes returns/momentum/rankings
```
`data_access.py` has **no MCP dependency** — it returns plain Python objects and
can be imported by anything (tests, a notebook, a LangGraph agent). `server.py`
only adds the protocol + tool descriptions.
**Caching (fast reads).** `build_cache.py` precomputes every standard view into
`cache.json` once. Default-parameter tool calls are served from that cache
(instant); only custom date ranges are computed on the fly.
**Refresh-on-use (always current, zero babysitting).** When a tool is called and
the cache is older than the latest trading day, the server rebuilds it first
(fetches the latest data), then answers. So you never have to run a cron or open
anything — it self-maintains.
## Configuration
| env var | default | meaning |
|---------|---------|---------|
| `ASIAN_ETF_ROOT` | `./data` | where OHLCV CSVs are stored (generated) |
| `ASIAN_ETF_CONFIG_DIR` | `./configs` | market/industry/ETF definitions (shipped) |
To add a market or ETF, edit the JSON files in `configs/` — no code changes.
## Keeping it fresh
- **Anyone:** nothing to do — refresh-on-use fetches the latest from Yahoo Finance
when needed. Or run `python build_cache.py` whenever you want.
- **Maintainer fast-path (optional):** if you run the companion data collector on a
server, `sync_data.sh` can pull its daily CSVs and `build_cache.py --no-live`
recomputes from them in seconds. Requires SSH access to that server; everyone
else simply uses the live Yahoo Finance path.
## Project layout
```
src/server.py MCP server (5 tools)
src/data_access.py Streamlit-free data + cache layer
build_cache.py refresh job: fetch + precompute → cache.json
configs/ market definitions (committed)
sync_data.sh maintainer fast-path (optional)
test_data_access.py smoke test for the data layer (no MCP needed)
```
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues