npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

screener-mcp

v0.1.0

Published

MCP server exposing Screener.in Indian-stock fundamentals, financials, peers, and price/EPS trends.

Readme

screener-mcp

An MCP server exposing Screener.in data for Indian stocks (NSE/BSE) — fundamentals, financial statements, peers, and price/EPS time-series — as tools any MCP client (Claude, etc.) can call.

Screener.in is server-rendered (Django), so most data comes from a single HTML GET; the chart tool uses Screener's JSON chart API.

Tools

| Tool | Args | Returns | |---|---|---| | get_fundamentals | symbol | Key ratio cards (P/E, P/B, ROE, ROCE, Market Cap, Book Value, Dividend Yield, etc.), pros/cons, about | | get_financials | symbol | Statement tables: Quarterly Results, P&L, Balance Sheet, Cash Flow, Ratios, Shareholding | | get_peers | symbol | Sector peer comparison table (CMP, P/E, Market Cap, Div Yield, NP, ROCE, sales growth) + sector median | | get_chart | symbol, metric?, days? | Time-series from the chart API. metric e.g. Price-DMA50-Volume, Price, Quarter Sales, EPS | | get_ratios | symbol | The same fundamentals as typed numbers (pe, pb, roe, roce, debtEquity, salesGrowth3yPct, promoterHoldingPct, …) rather than display strings | | get_quarterly_results | symbol | Per-quarter Sales / Net Profit / EPS / OPM keyed by ISO quarter-end date | | run_screen | query, maxPages?, sort?, order? | Stocks matching a Screener DSL query. Needs sign-in | | screener_auth_status | — | Whether a signed-in Screener session is present and still valid (see Signing in) |

get_fundamentals returns what Screener displays ("₹ 17,60,650 Cr."); get_ratios returns what you can compute with (marketCapCr: 1760650). Reach for get_ratios when comparing or grading stocks, get_fundamentals when showing a human the page as-is.

Banks and NBFCs get null for debtEquity and salesGrowth3yPct on purpose — their "Borrowings" are customer deposits and their "Sales" is interest income, so those ratios don't mean what they mean elsewhere. isFinancialCompany and caveats say when this applied.

Screens

run_screen takes Screener's own filter DSL and pages through the results (50 per page):

Return on capital employed > 15 AND Debt to equity < 1
  AND Piotroski score >= 7 AND Market Capitalization > 5000

This is the one tool that requires sign-in — Screener redirects anonymous callers to /register/. It's dramatically cheaper than calling get_ratios over a whole universe: one paged request replaces hundreds of per-stock fetches.

symbol is the NSE/BSE trading symbol, e.g. TCS, RELIANCE, MTARTECH.

Use it (no setup)

Requires Node 18+. Nothing to clone or build — add this to your MCP config (.mcp.json in a project, or ~/.claude.json globally):

{
  "mcpServers": {
    "screener": {
      "command": "npx",
      "args": ["-y", "screener-mcp"]
    }
  }
}

Or, from Claude Code:

claude mcp add screener -- npx -y screener-mcp

Then an agent can call get_fundamentals, get_financials, get_peers, get_chart.

To pin a version, use [email protected]. To run straight from git without npm: npx -y github:ashu017/screener-mcp (builds on install via the prepare script).

Signing in (optional)

Screener serves more to logged-in accounts. Screener has no OAuth or API keys — it's a Django app, so being "signed in" means holding a sessionid cookie. To get one:

npx screener-mcp login     # prompts for email + password, no echo
npx screener-mcp status    # is my session still valid?
npx screener-mcp logout    # delete it

login posts once to Screener's own login form and keeps only the returned cookie, in ~/.config/screener-mcp/session.json at mode 0600. Your password is never written to disk, never logged, and never placed in an MCP config file. All four data tools work anonymously; sign-in only adds account-gated data.

The session outlives the server process, so you log in once, not per MCP session. When the cookie expires, tools return an instruction to re-run login instead of failing obscurely — and agents can call screener_auth_status to check deliberately.

If Screener ever puts a captcha in front of login, fall back to copying the cookie by hand: sign in with a browser, take the sessionid value from DevTools → Application → Cookies, and pass it as an env var (this takes precedence over the stored file):

{
  "mcpServers": {
    "screener": {
      "command": "npx",
      "args": ["-y", "screener-mcp"],
      "env": { "SCREENER_SESSION_ID": "your-sessionid-cookie" }
    }
  }
}

| Env var | Purpose | |---|---| | SCREENER_SESSION_ID | Use this cookie instead of the stored session | | SCREENER_MCP_CONFIG_DIR | Override where the session is stored | | SCREENER_USERNAME / SCREENER_PASSWORD | Non-interactive login, for CI/headless |

Use your own account only, and note that automated access to account-gated pages is subject to Screener's terms.

Local development

npm install        # runs tsc via the prepare script
npm run build      # tsc
npm start          # node dist/index.js  (stdio transport)
npm run dev        # tsx src/index.ts
npm test           # vitest (needs Node 20+)

Point an MCP client at a local checkout with:

{
  "mcpServers": {
    "screener": {
      "command": "node",
      "args": ["/absolute/path/to/screener-mcp/dist/index.js"]
    }
  }
}

How peers works

Screener lazy-loads the peer table from GET /api/company/{warehouseId}/peers/ — note this uses a separate warehouse id (from data-warehouse-id on the page), not the company id, and requires the X-Requested-With: XMLHttpRequest header. get_peers resolves the warehouse id from the company page, fetches that fragment, and parses the comparison table plus the sector-median row.

Testing

npm test

Tests run the parsers against a captured Screener HTML fixture (test/tcs.fixture.html), so they are deterministic and don't hit the network.

Notes / etiquette

  • Data is scraped from Screener.in for personal use. Respect their terms and don't hammer the site; cache results and rate-limit in your client.
  • Selectors target Screener's current DOM; if Screener changes markup, the parsers (src/screener.ts) may need updating. The fixture test will catch regressions.

License

MIT