Async screener.in scraper with MCP server and CLI for NSE/BSE stock data
Project description
screener-ai-tool
An async Python toolkit for fetching and analyzing Indian (NSE/BSE) stock data
from screener.in — fundamentals, price history,
technical indicators, peer comparisons, shareholding patterns, and corporate
documents/announcements. Ships as a CLI (screener), a library
(screener_ai), and an MCP server for use with Claude and other LLM clients.
Disclaimer: This is a personal-use tool for analyzing publicly visible data on screener.in. It is not affiliated with or endorsed by screener.in. Be polite: respect screener.in's Terms of Service, keep request rates low (defaults are conservative), prefer an authenticated session for heavier usage, and do not use this tool to circumvent rate limits or scrape at scale. You are responsible for how you use this tool.
Architecture
┌───────────────────────────┐
│ screener.in │
│ (HTML pages + JSON APIs) │
└──────────────┬─────────────┘
│ httpx (rate-limited, retried)
▼
┌───────────────────────────┐
│ client.py │
│ ScreenerClient │
│ - RateLimiter (token bkt) │
│ - retries + backoff │
│ - cookie jar / session │
└──────────────┬─────────────┘
│
┌────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ parsers.py │ │ auth.py │ │ indicators.py │
│ HTML/JSON → │ │ login/session │ │ SMA/EMA/RSI/ │
│ pydantic │ │ persistence │ │ MACD/Bollinger│
│ models │ │ │ │ /Stochastic │
└──────┬────────┘ └───────┬────────┘ └──────┬────────┘
│ │ │
└────────────┬─────────────┴────────────┬────────────┘
▼ ▼
┌───────────────────────────────────────┐
│ service.py │
│ ScreenerService │
│ high-level facade (search, overview, │
│ price_history, financials, peers, │
│ shareholding, documents, technical, │
│ snapshot) — page-cache(8) per instance │
└───────┬───────────────────┬─────────────┘
│ │
┌──────────────▼───┐ ┌─────────▼──────────┐
│ bulk.py │ │ export.py │
│ bulk_fetch over │ │ JSON/CSV/Parquet │
│ many symbols │ │ export │
│ (semaphore-bound) │ │ │
└──────────────┬─────┘ └─────────┬───────────┘
│ │
┌──────────────▼───────────────────────▼───────────┐
│ Interfaces │
│ ┌────────────────────┐ ┌──────────────────────┐│
│ │ cli.py │ │ mcp_server.py ││
│ │ `screener ...` │ │ FastMCP server ││
│ │ typer + rich │ │ `screener_*` tools ││
│ └────────────────────┘ └──────────────────────┘│
└─────────────────────────────────────────────────────┘
Installation
Have your agent install it (recommended)
This repo ships an llms.txt written for AI coding agents. Paste
this into your agent (Claude Code, Cursor, Codex, etc.):
Fetch and follow the instructions at
https://raw.githubusercontent.com/singhvedant/screener-ai-tool/main/llms.txt
to install screener-ai-tool, register its MCP server, and install its skill.
The agent will: install the package (pip/uv), register the screener MCP
server, copy skills/screener-ai-tool/SKILL.md into its own skills directory
(so the skill can be toggled on/off independently later), and verify
everything works end-to-end.
Manual installation
Requires Python 3.11+.
pip install screener-ai-tool
# or
uv pip install screener-ai-tool
Or from source, with uv:
git clone https://github.com/singhvedant/screener-ai-tool.git
cd screener-ai-tool
# create a virtual environment and install in editable mode with dev deps
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
After installation the screener CLI entry point is available (or run via
uv run screener ... / python -m screener_ai ...).
Authentication & session persistence
screener.in allows limited anonymous browsing (~50 page views/day) before showing rate-limit prompts. Logging in with your screener.in account raises those limits significantly.
# interactive (prompts for password, hidden input)
screener login --email you@example.com
# or via environment variables (useful for CI / scripts)
export SCREENER_EMAIL=you@example.com
export SCREENER_PASSWORD=your-password
screener login
# check status
screener auth-status
# log out (clears saved session)
screener logout
On success, the session cookie (sessionid) is written to
~/.screener-ai/session.json (mode 0600, JSON of cookie name → value). All
subsequent CLI/MCP/library calls reuse this session automatically until it
expires or screener logout is run. Credentials and cookies are never
logged.
CLI usage
All commands support --json for raw JSON output (useful for piping into
jq or other tools), and most accept --days / --consolidated/--standalone
where relevant. Async commands wrap asyncio.run; errors print a message to
stderr and exit with code 1 (authentication errors suggest screener login).
screener search QUERY
Search for companies by name or symbol.
screener search reliance
screener search tata --json
screener price SYMBOL [--days 365] [--limit 30]
Show recent price history (rich table of the latest --limit rows).
screener price RELIANCE
screener price RELIANCE --days 90 --limit 10
screener price TCS --json > tcs_prices.json
screener overview SYMBOL
Company overview: name, sector/industry, key ratios, pros/cons.
screener overview RELIANCE
screener overview INFY --json
screener fundamentals SYMBOL [--statement profit-loss|quarters|balance-sheet|cash-flow|ratios]
Fetch a financial statement table.
screener fundamentals RELIANCE --statement quarters
screener fundamentals RELIANCE --statement balance-sheet --json
screener technical SYMBOL [--days 365] [--series]
Technical analysis snapshot (SMA/EMA/RSI/MACD/Bollinger + signals). Pass
--series to include full indicator time series.
screener technical RELIANCE
screener technical RELIANCE --days 180 --series --json
screener events SYMBOL / screener news SYMBOL
events shows announcements + corporate documents; news is an alias view
focused on announcements, credit ratings, and concall material.
screener events RELIANCE
screener news RELIANCE --json
screener peers SYMBOL
Peer comparison table (with median row).
screener peers RELIANCE
screener shareholding SYMBOL
Quarterly and yearly shareholding pattern tables.
screener shareholding RELIANCE
screener snapshot SYMBOL
Aggregated "everything we know" snapshot — overview, financial tables, shareholding, peers, documents, and technical analysis, fetched concurrently.
screener snapshot RELIANCE --json
screener bulk SYMBOLS... [--dataset price] [--concurrency 8] [--out FILE]
Fetch a dataset for many symbols concurrently. Per-symbol failures are
captured (never raised) as {"error": "..."} entries.
screener bulk RELIANCE TCS INFY HDFCBANK --dataset overview
screener bulk RELIANCE TCS INFY --dataset price --days 90 --concurrency 16 --out prices.json
screener export SYMBOL [--what price|fundamentals|snapshot] [--fmt json|csv|parquet] [--out FILE]
Export data to JSON, CSV, or Parquet (CSV/Parquet for tabular data such as price history and financial tables via pandas).
screener export RELIANCE --what price --fmt csv --out reliance_price.csv
screener export RELIANCE --what snapshot --fmt json --out reliance_snapshot.json
screener serve [--transport stdio|http] [--host 127.0.0.1] [--port 8631]
Run the MCP server (see below).
MCP setup
stdio transport (recommended for Claude Code / Claude Desktop)
# if installed via pip/uv (entry point on PATH)
claude mcp add screener -- screener serve
# if running from a cloned repo
claude mcp add screener -- uv run --directory ~/Development/screener-ai-tool screener serve
This registers a screener MCP server that Claude launches on demand via
stdio.
HTTP transport
To run the server over streamable HTTP (e.g. for remote access or shared deployments):
uv run --directory ~/Development/screener-ai-tool screener serve --transport http --host 127.0.0.1 --port 8631
Then point an MCP-compatible client at http://127.0.0.1:8631.
MCP tool list
All tools return JSON-serializable dicts (model_dump).
| Tool | Description |
|---|---|
screener_login(email, password) |
Authenticate and persist a session (use when rate-limited as anonymous) |
screener_auth_status() |
Current authentication status |
screener_search(query, limit=10) |
Search for companies |
screener_price(symbol, days=365, limit=0) |
Price history (optionally truncated to last limit points) |
screener_overview(symbol) |
Company overview + key ratios |
screener_fundamentals(symbol, statement="profit-loss") |
Financial statement table |
screener_technical(symbol, days=365, include_series=False) |
Technical indicators + signals |
screener_peers(symbol) |
Peer comparison table |
screener_shareholding(symbol) |
Shareholding pattern (quarterly/yearly) |
screener_events(symbol) |
Announcements + corporate documents |
screener_news(symbol) |
Announcements + credit ratings + concalls |
screener_snapshot(symbol, days=365) |
Full aggregated snapshot |
screener_bulk(symbols, dataset="price", days=365, concurrency=8) |
Bulk fetch over many symbols |
screener_export(symbol, what="snapshot", fmt="json", out_path="") |
Export data to a file |
Data models
Defined with pydantic v2 in screener_ai.models:
SearchResult— id, name, url, symbol (parsed from url)CompanyRef— symbol, name, company_id, warehouse_id, consolidatedPricePoint/PriceHistory— date, close, dma50, dma200, volume, delivery_pctKeyRatios— market_cap, current_price, high_52w, low_52w, pe, book_value, dividend_yield, roce, roe, face_value, extrasCompanyOverview— ref, about, website, bse_code, nse_code, sector, industry, ratios, pros, consFinancialTable— kind, columns, rows (raw strings) +.numeric()helperShareholdingPattern— quarterly / yearlyFinancialTablePeerRow/PeerComparison— peer metrics + median rowDocumentLink/CorporateDocs— announcements, annual reports, credit ratings, concallsIndicatorSeries,MACDResult,BollingerResult— technical indicator seriesTechnicalSnapshot/TechnicalAnalysis— latest indicator values + signalsFullSnapshot— everything aggregated for one symbol
Rate limiting & politeness
- Default: 2 requests/second, burst of 5 (token-bucket
RateLimiter). - On HTTP 429, the client backs off exponentially (with jitter) and honors
Retry-After; if retries are exhausted,RateLimitErroris raised. - Connection pooling is bounded (
max_connections=20,keepalive=10). - Anonymous browsing is heavily throttled by screener.in (~50 page views/day).
Log in (
screener login) for a much higher effective limit, and consider lowering--concurrencyforbulk/snapshotoperations. bulk_fetch/screener bulkisolate per-symbol errors — one bad symbol never aborts the whole batch.
Testing
# unit tests only (no network) — the default safe subset
pytest -m "not integration and not load"
# live integration tests (hits screener.in; skips gracefully on network errors)
pytest -m integration
# heavy load test (500+ symbols; requires network and takes a while)
pytest -m load
Unit tests use captured fixtures in tests/fixtures/ (real screener.in HTML
and JSON responses) plus respx to mock httpx for client-level tests — no
network access is required for pytest -m "not integration and not load".
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file screener_ai_tool-0.1.0.tar.gz.
File metadata
- Download URL: screener_ai_tool-0.1.0.tar.gz
- Upload date:
- Size: 158.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee739cd3153608792a7c462c8cd107d1380864fba3c89dbab0403905078a86b7
|
|
| MD5 |
bad149d02cd3627c5f1408aa9c8cb713
|
|
| BLAKE2b-256 |
ed4439efd54f05eb8d5f44ea73d74a94b5bbe3d364ece227c3d54d849927cace
|
Provenance
The following attestation bundles were made for screener_ai_tool-0.1.0.tar.gz:
Publisher:
publish.yml on singhvedant/screener-ai-tool
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
screener_ai_tool-0.1.0.tar.gz -
Subject digest:
ee739cd3153608792a7c462c8cd107d1380864fba3c89dbab0403905078a86b7 - Sigstore transparency entry: 1825131482
- Sigstore integration time:
-
Permalink:
singhvedant/screener-ai-tool@c39d3a68365bd9c94cf604bc46b2371f29839595 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/singhvedant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c39d3a68365bd9c94cf604bc46b2371f29839595 -
Trigger Event:
release
-
Statement type:
File details
Details for the file screener_ai_tool-0.1.0-py3-none-any.whl.
File metadata
- Download URL: screener_ai_tool-0.1.0-py3-none-any.whl
- Upload date:
- Size: 41.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3e53d59517cb1b3850bb3da0ea043a05a69c25bf6468023496255d07825e805
|
|
| MD5 |
72253cf8be1ec3f27b13e36b9665b9e1
|
|
| BLAKE2b-256 |
89409a779d2af3fe158206f29bc65a15c50535f034c269110585cdfd6ba6d562
|
Provenance
The following attestation bundles were made for screener_ai_tool-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on singhvedant/screener-ai-tool
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
screener_ai_tool-0.1.0-py3-none-any.whl -
Subject digest:
c3e53d59517cb1b3850bb3da0ea043a05a69c25bf6468023496255d07825e805 - Sigstore transparency entry: 1825131541
- Sigstore integration time:
-
Permalink:
singhvedant/screener-ai-tool@c39d3a68365bd9c94cf604bc46b2371f29839595 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/singhvedant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c39d3a68365bd9c94cf604bc46b2371f29839595 -
Trigger Event:
release
-
Statement type: