An MCP server that gives AI assistants Pakistan Stock Exchange data. It runs locally in Docker: the assistant loads PSX data (prices, screener, index constituents, sectors, filings, debt market, margin-eligible scrips) into a private in-memory DuckDB and answers your questions with SQL. It's built on psxdata.
Requires: Docker, except for the Claude Desktop one-click bundle (see below), which needs uv instead.
Claude Code (plugin, recommended):
claude plugin marketplace add psxdata/psxdata-mcp
claude plugin install psxdata@psxdata-mcpClaude Code (plugin, hosted server: invite-only, no Docker, adds warehouse marts):
claude plugin marketplace add psxdata/psxdata-mcp
claude plugin install psxdata-hosted@psxdata-mcpClaude Code asks for the server URL when the plugin is enabled; use the one from your invitation.
Then run /mcp and sign in to psxdata. Install one of the two plugins, not both.
Claude Code (server only):
claude mcp add --transport stdio --scope user psxdata -- docker run -i --rm -v psxdata-cache:/home/app/.psxdata mtauha/psxdata-mcp:latestCursor: open this link:
cursor://anysphere.cursor-deeplink/mcp/install?name=psxdata&config=eyJjb21tYW5kIjoiZG9ja2VyIiwiYXJncyI6WyJydW4iLCItaSIsIi0tcm0iLCItdiIsInBzeGRhdGEtY2FjaGU6L2hvbWUvYXBwLy5wc3hkYXRhIiwibXRhdWhhL3BzeGRhdGEtbWNwOmxhdGVzdCJdfQ==
Claude Desktop (one-click): download psxdata-mcp-<version>.mcpb from the
latest release and open it (or drag it
into Settings → Extensions). This route needs no Docker, but it runs on uv,
which it uses to fetch Python and the dependencies on first launch; install uv first if Claude
Desktop reports it missing. The first launch takes a few seconds longer than later ones.
Any other client: add to its MCP config (Claude Desktop's is
claude_desktop_config.json):
{
"mcpServers": {
"psxdata": {
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "psxdata-cache:/home/app/.psxdata", "mtauha/psxdata-mcp:latest"]
}
}
}| Tool | What it does |
|---|---|
load_prices(symbols, start?, end?) |
Daily OHLCV for up to 50 symbols → prices |
load_screener() |
All ~729 symbols with price, P/E, dividend yield, market cap → screener |
load_index(name) |
Constituents and weights of KSE100, KSE30, KMI30, … → index_constituents |
load_sectors() |
37-sector summary → sectors |
load_fundamentals(symbols?) |
Filed financial reports list → fundamentals |
load_symbols() |
All listed symbols with name and sector → symbols |
load_debt_market() |
TFCs, Sukuks, government securities → debt_market |
load_eligible_scrips() |
Margin-eligible scrips by market → eligible_scrips |
query(sql) |
DuckDB SQL over loaded tables (≤200 rows, 30 s, no file/network access) |
list_tables() |
What's loaded, row counts, load time |
quote(symbol) |
Latest snapshot for one symbol |
Ask things like "How has OGDC done against KSE-100 constituents this year?" or "Which cement stocks have a P/E under 6?"
Ready-made analysis workflows, served as MCP prompts (pick them from your client's prompt
menu, e.g. /mcp__psxdata__tearsheet in Claude Code) and shipped as skills in the Claude Code
plugin, which Claude loads on its own when a request matches.
| Skill | What it does |
|---|---|
psx-playbook |
The rules every analysis follows: data traps, SQL patterns, web cross-checks |
tearsheet(symbol) |
One-page report on a stock: performance, risk, valuation vs. sector, filings, news |
screen(criteria?) |
Value, dividend or momentum presets, or your own conditions, with red flags |
shariah-screen(screen?) |
The same screens limited to KMI All-Share members, with purification notes |
compare(symbols, period?) |
2–10 stocks side by side: returns, risk, correlation, valuation, price path |
market-wrap(period?) |
Daily or weekly summary: KSE-100 drivers, breadth, sectors, movers, news |
Sources live in src/psxdata_mcp/skills/*.md; skills/ is generated from them with
uv run python scripts/sync_skills.py (a test fails if the two drift).
- Prices are PKR and not adjusted for splits, bonus issues or dividends.
- Historical data is cached in the
psxdata-cacheDocker volume, so each symbol is downloaded once. Live data (screener, sectors, quotes) refreshes every 15 minutes. - Loaded tables live in memory and reset when the assistant session ends.
- Data is scraped from the public PSX website; it isn't an official feed.
uv sync
uv run pytest # unit + server tests
uv run pytest -m live # hits real PSX
docker build -t psxdata-mcp:dev . && uv run pytest -m container
uv run python scripts/stage_mcpb.py build/mcpb # stage the Claude Desktop bundle
npx @anthropic-ai/mcpb pack build/mcpb build/psxdata-mcp.mcpb
PSXDATA_MCP_BUNDLE=build/psxdata-mcp.mcpb uv run pytest -m bundle
npx @modelcontextprotocol/inspector docker run -i --rm psxdata-mcp:devMIT