Skip to main content

MCP server for US stock Maximum Drawdown analytics

Project description

mdd-stock-mcp

An MCP server for Maximum Drawdown (MDD) analytics across US stocks, Korean stocks (KOSPI/KOSDAQ), and cryptocurrencies. Plug it into Claude Desktop and ask questions like "What was SPY's worst drawdown during COVID?" or "비트코인 2022년 MDD 알려줘" — Claude will fetch the data and discuss it conversationally.

License: MIT Python >=3.11 MCP Compatible

Disclaimer: This project uses yfinance, an unofficial Yahoo Finance scraper. Not affiliated with Yahoo, not for production trading systems, not for financial advice. Data may be inaccurate, delayed, or unavailable. Use at your own risk.


What it does

  • Calculates Maximum Drawdown for any supported asset over a date range
  • Returns OHLCV price history for plotting
  • Returns a daily drawdown (underwater) series
  • Compares MDD across multiple tickers side-by-side

Supported markets (via the market parameter):

market Examples Notes
us (default) AAPL, SPY, QQQ NYSE / NASDAQ
kr 005930005930.KS (Samsung), 035720.KQ (KOSDAQ) 6-digit codes auto-append .KS (KOSPI). Use explicit .KQ for KOSDAQ.
crypto BTCBTC-USD, ETH-USD, BTC-KRW Bare symbols auto-append -USD.

Quickstart (Claude Desktop)

1. Clone the repo:

git clone https://github.com/librarywon/mdd-stock-mcp.git
cd mdd-stock-mcp

2. Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "mdd-stock-mcp": {
      "command": "uvx",
      "args": ["--from", "/absolute/path/to/mdd-stock-mcp", "mdd-stock-mcp"]
    }
  }
}

Replace /absolute/path/to/mdd-stock-mcp with the actual path where you cloned the repo (e.g. /Users/yourname/Documents/mdd-stock-mcp).

3. Restart Claude Desktop.

Ask: "Using mdd-stock-mcp, what was AAPL's MDD between 2020-01-01 and 2020-12-31?"


Alternative install (after PyPI publishing)

uvx mdd-stock-mcp

(Placeholder — not yet published to PyPI.)


Tools

Tool Description Example
calculate_mdd Single-ticker MDD calculate_mdd("SPY", "2020-01-01", "2020-12-31")
get_price_history OHLCV time series get_price_history("005930", "2024-01-01", "2024-06-30", market="kr")
get_drawdown_series Daily drawdown % series get_drawdown_series("BTC", "2022-01-01", "2022-12-31", market="crypto")
compare_mdd Multi-ticker MDD comparison compare_mdd(["SPY","QQQ","DIA"], "2020-01-01", "2020-12-31")

Each tool accepts:

  • price: "adj_close" (default, dividend/split adjusted) or "close" (raw closing price)
  • market: "us" (default), "kr", or "crypto" — see the supported markets table

Output schemas

calculate_mdd — success response
{
  "ticker": "SPY",
  "mdd_pct": -0.338915,
  "peak_date": "2020-02-19",
  "trough_date": "2020-03-23",
  "drawdown_duration_days": 33,
  "recovered": false,
  "recovery_date": null,
  "market": "us",
  "currency": "USD"
}
calculate_mdd — error response
{
  "error": true,
  "error_type": "InvalidTickerError",
  "message": "InvalidTickerError: Ticker 'XYZFAKE' not found or returned no data from Yahoo Finance."
}
get_price_history — success response
{
  "ticker": "AAPL",
  "price_basis": "adj_close",
  "count": 62,
  "data": [
    {
      "date": "2020-01-02",
      "open": 296.239990,
      "high": 300.600006,
      "low": 295.190002,
      "close": 298.829956,
      "volume": 33870100
    }
  ]
}
get_drawdown_series — success response
{
  "ticker": "SPY",
  "price_basis": "adj_close",
  "count": 125,
  "data": [
    {"date": "2020-01-02", "drawdown_pct": 0.0},
    {"date": "2020-01-03", "drawdown_pct": -0.007054},
    {"date": "2020-03-23", "drawdown_pct": -0.338915}
  ]
}
compare_mdd — success response (partial failure shown)
{
  "price_basis": "adj_close",
  "start": "2020-01-01",
  "end": "2020-06-30",
  "results": [
    {
      "ticker": "SPY",
      "mdd_pct": -0.338915,
      "peak_date": "2020-02-19",
      "trough_date": "2020-03-23",
      "drawdown_duration_days": 33,
      "recovered": false,
      "recovery_date": null,
      "error": null
    },
    {
      "ticker": "XYZFAKE",
      "mdd_pct": null,
      "peak_date": null,
      "trough_date": null,
      "drawdown_duration_days": null,
      "recovered": null,
      "recovery_date": null,
      "error": "InvalidTickerError: Ticker 'XYZFAKE' not found or returned no data from Yahoo Finance."
    }
  ]
}

How MDD is calculated

  • Formula: drawdown_t = price_t / max(price_{0..t}) - 1
  • MDD = min(drawdown) over the date range (most negative value)
  • Peak: argmax of price up to and including the trough date
  • Recovery: first date after trough where price >= peak_price
  • Note: recovered=false means "did not recover within the queried window", not "never recovered historically"

All price values use dividend/split-adjusted close by default (price="adj_close"). Pass price="close" for raw unadjusted closing prices.


Example Claude conversation

User: mdd-stock-mcp으로 SPY의 2020년 코로나 폭락 분석해줘

Claude: [calls calculate_mdd] SPY는 2020-02-19 최고점에서 2020-03-23 최저점까지 약 -33.9%의 MDD를 기록했습니다. 회복은 2020-08-18에 완료됐어요. 그래프 그려드릴까요?

User: 응

Claude: [calls get_price_history + get_drawdown_series, draws chart in artifact]


Limitations

  • US stocks, Korean stocks (KOSPI/KOSDAQ), and major cryptocurrencies — limited to what Yahoo Finance exposes. Other international exchanges (Tokyo, London, etc.) aren't wired up.
  • Daily resolution — No intraday (1m, 5m, etc.) data.
  • yfinance is unofficial — Yahoo Finance may rate-limit or change their API without notice. For production use, swap data.py for a paid provider like Polygon.io, Alpha Vantage, or Tiingo.
  • In-memory cache only — Price data is cached for 5 minutes per process. Cache is lost on server restart.
  • No real-time data — All data is end-of-day historical prices.

Development

# Install with dev dependencies
uv pip install -e ".[dev]"

# Run tests
pytest tests/

# Open MCP inspector (interactive tool tester)
fastmcp dev src/stock_mcp/server.py

Project structure:

src/stock_mcp/
  server.py   — FastMCP app + 4 tool definitions
  data.py     — yfinance wrapper + TTL cache + price-column selector
  mdd.py      — Pure MDD math functions
  models.py   — Pydantic input/output models
  errors.py   — Custom error types
tests/
  test_mdd.py — Offline math tests (no network required)

Claude Desktop config reference

{
  "mcpServers": {
    "mdd-stock-mcp": {
      "command": "uvx",
      "args": ["--from", "/Users/jaewon/Documents/mdd-stock-mcp", "mdd-stock-mcp"]
    }
  }
}

After publishing to PyPI, simplify to:

{
  "mcpServers": {
    "mdd-stock-mcp": {
      "command": "uvx",
      "args": ["mdd-stock-mcp"]
    }
  }
}

Deployment

Local (stdio) — default

The default transport is stdio, which is what Claude Desktop expects. Use the uvx config from the Quickstart section above.

Docker

# Build the image
docker build -t mdd-stock-mcp .

# Run with HTTP transport (e.g. for testing or a hosted setup)
docker run -p 8000:8000 mdd-stock-mcp --transport http

Replace 8000 with any port you prefer. The --transport http flag enables the HTTP/SSE transport mode; omit it for the default stdio mode.

Smithery / hosted

Smithery can host MCP servers so you don't need to run them locally. Once the smithery.yaml configuration is present in the repo root, you can register the server through the Smithery dashboard. See the Smithery documentation for registration instructions.


Roadmap

Planned additions (not yet scheduled — PRs welcome):

  • Sharpe / Sortino / CAGR tools — additional risk/return metrics as new MCP tools, following the same patterns as the existing four.
  • Optional Polygon.io / Alpha Vantage providers — drop-in replacements for the yfinance backend in data.py, configurable via environment variable.
  • Shorter date ranges / intraday support — hourly or intraday resolution for ranges under ~7 days, contingent on a stable data provider.

Contributing

This is a small focused project. PRs are welcome — especially for:

  • Additional data providers (Polygon, Alpha Vantage, Tiingo) in data.py
  • Additional metrics (Sharpe ratio, CAGR, Sortino) as new tools
  • Better error messages and edge-case handling

Please open an issue first for significant changes.


License

MIT — see LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mdd_stock_mcp-0.1.0.tar.gz (112.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mdd_stock_mcp-0.1.0-py3-none-any.whl (14.0 kB view details)

Uploaded Python 3

File details

Details for the file mdd_stock_mcp-0.1.0.tar.gz.

File metadata

  • Download URL: mdd_stock_mcp-0.1.0.tar.gz
  • Upload date:
  • Size: 112.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mdd_stock_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e0efcb5d2c67e45f35030a03ae13274050d830807f7d174e856d12519112e2b4
MD5 324017fea70521e5d46fbfa4b596f501
BLAKE2b-256 aea0d674acc4521ec28742ba963b0cc78c7fab50e75a260886d506bc83db0d83

See more details on using hashes here.

Provenance

The following attestation bundles were made for mdd_stock_mcp-0.1.0.tar.gz:

Publisher: publish.yml on librarywon/mdd-stock-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mdd_stock_mcp-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mdd_stock_mcp-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mdd_stock_mcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 621c29ef87d1931ab570aaf6807d580675d93b966c5332d69ca9a79bb59bf478
MD5 a65f2cf1887a68756bf3ebee47926d7d
BLAKE2b-256 f6fc7d5238c29edc16a4d365cd5d51d7c80c577fa841ef8c63dd2024ce539fa0

See more details on using hashes here.

Provenance

The following attestation bundles were made for mdd_stock_mcp-0.1.0-py3-none-any.whl:

Publisher: publish.yml on librarywon/mdd-stock-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page