Skip to main content
Glama
bse-mcp

bse-mcp

bse-mcp

An MCP server that gives Claude live data from BSE India (Bombay Stock Exchange) by scrip code: price and ratios, market depth, peers, a year of daily prices, quarterly P&L with derived EBITDA and margins, corporate announcements with PDF links, and a security search. On top of the data it computes fundamentals, technical indicators and position sizes with Indian trading costs, and it ships nine trading-analysis skills that put those tools to work. Ask Claude "what did ABB India report last quarter?" or "how many ABB shares can I buy with a 1% risk?" and it looks it up.

Unofficial. Not affiliated with BSE. It reads the same public endpoints the bseindia.com pages use; they can change without notice, and the data is BSE's (see Data and terms).

Tools

Tool

What it returns

search_scrips(query)

Scrip codes matching a name, symbol, ISIN or code fragment. Start here.

get_quote(scripcode)

LTP and change, day / 52-week ranges, price band, volume, delivery %, market cap, EPS / PE / PB / ROE / margins (standalone and consolidated), group, sector, flags (ASM/GSM).

get_market_depth(scripcode)

Top-5 bids and asks with totals.

get_session_status(scripcode)

Whether the scrip's price is from today's session (live, closed_after_session, pre_open, awaiting_open, market_closed, stock_not_trading, unknown), judged from the price's own timestamp, since BSE quotes every scrip at all times. get_quote, analyze_fundamentals and analyze_prices(scripcode) carry the same session block.

get_peers(scripcode)

BSE's peer table: price, PE, PB, revenue, PAT, margins, 52-week range.

get_price_history(scripcode)

BSE's daily closes and traded quantity for the last 12 months, oldest first (no daily highs and lows).

get_financials(scripcode, quarters=5, upto=None)

Quarterly P&L as filed, newest first, each quarter labelled by its months (Apr–Jun 2026) and by Indian FY (Q1 FY27); derived EBITDA, EBITDA / PBT / PAT margins and tax rate. The latest filed quarter is detected automatically.

analyze_fundamentals(scripcode, quarters=8)

Computed from the filings: YoY and QoQ growth (matched by period), margins and margin change, cost structure, interest coverage, tax rate, other income as % of PBT, TTM totals and TTM growth, TTM P/E and price/sales. The filing unit is checked against BSE's Rs-crore results card instead of assumed. Banks (kind: "bank") get NII, PPOP, cost-to-income, provisions, gross / net NPA %, NPA coverage, RoA and CET1 instead.

analyze_prices(scripcode=None, closes=None, dates, highs, lows, volumes, timeframe="daily", entry_date=None, side="long")

Technical indicators, either on BSE's last 12 months of daily closes (scripcode) or on daily candles you pass in (e.g. from NSE's nse-bhavcopy MCP server): returns, CAGR, volatility, drawdown, SMA 20/50/200, EMA 12/26/50, MACD, RSI(14), Bollinger(20,2), 52-week position, SMA50/200 trend, swing highs and lows with RSI, Fibonacci levels and pullback targets, RSI divergence, volume vs its average, and price_jumps (possible unadjusted splits). With highs and lows also ATR(14), ADX/DI, stochastic, chandelier exit and pivots. timeframe="weekly" builds weekly bars; entry_date adds trailing-stop levels since the entry.

position_size(capital, entry, stop or atr, risk_pct=1, target, ...)

Shares for a trade by fixed-fractional risk, capped by capital (with leverage) and a single-stock limit, saying which limit decided; loss at stop and gain at target net of STT, exchange and SEBI charges, stamp duty, GST and your brokerage; reward:risk, breakeven move, expected value and Kelly fractions.

record_analysis(scripcode, skill, action, entry, stop, target, horizon_days=20, ...)

Saves a skill's verdict (buy / sell / hold / avoid) to the local journal with the live price and session status, for scoring later (Python server only; see Judging the skills).

get_announcements(scripcode, months=12, category="all", page=1)

Filings from BSE's announcements feed with PDF links; category="results" for financial results only.

download_announcement_pdf(attachment, save_dir, filename=None)

Saves a filing's PDF (Python server only).

list_scrips(segment, status, group, name_contains, scripcode, limit)

BSE's List of Securities, filtered.

call_bse_api(endpoint, params, scripcode, quarter)

Any of the 23 documented endpoints, raw, for whatever the tools above don't shape.

Related MCP server: MyFinancial Market Data MCP

Trading skills

Skills are instructions Claude follows for a kind of task. bse-mcp ships nine, adapted from Bhala Srinivash's nse-trading-skills (MIT; the licence travels in each skill folder) so that every number comes from the tools above:

Skill

For questions like

bse-mcp-trading-toolkit

"Analyze ABB", "should I buy X?": runs the others as one workflow

bse-mcp-technical-analysis

Trend, support and resistance, indicator dashboard, scenarios

bse-mcp-multi-timeframe-analysis

Weekly bias, daily setup, entry trigger

bse-mcp-rsi-divergence

Regular and hidden RSI divergences

bse-mcp-fibonacci-trading

Retracement zones and extension targets

bse-mcp-stop-loss-strategies

Where to put the initial stop

bse-mcp-trailing-stops

Trailing an open position from its entry date

bse-mcp-position-sizing

How many shares, within portfolio limits

bse-mcp-risk-reward-ratio

Whether a trade's R:R and expected value justify it

They are read-only: they end in a plan for you to decide on and never place orders. Changes from the originals: the Groww and yfinance steps are replaced by this server's tools; order placement is gone; the hourly screen becomes a daily trigger (no free intraday data); and a few errors are fixed (a delivery round trip costs more than the "~0.1%" quoted, since STT alone is 0.2%; the sizing example put 36% of an account in one stock against its own 20% limit; ADX was labelled a volatility measure; leverage was said to multiply the loss at the stop; the chandelier exit was called tighter than a 2× ATR trail; a "trades needed to recover a loss" column didn't add up).

Getting them:

  • Claude Code: bse-mcp setup (which the installers below run) copies them into ~/.claude/skills/, replacing older copies of the same skills. --no-skills skips that.

  • Claude app (claude.ai and the desktop app): download the zips from skill-zips/ and add each one under Customize → Skills → + → Create skill → Upload a skill. Skills need "Code execution and file creation" turned on in Settings → Capabilities. Skills you enable there also reach Claude Code when you're signed in to the same account, so you can then run bse-mcp setup --no-skills.

ATR, ADX, stochastic and the ATR-based stops need daily highs and lows, which BSE's price chart doesn't give. Connect NSE's free end-of-day server for those: in Claude Code claude mcp add --transport http nse-bhavcopy https://mcp.nseindia.in/bhavcopy/cm/mcp; in the Claude app, Settings → Connectors → Add custom connector with the same URL. Without it the skills use BSE's closes and say which levels they couldn't compute.

Judging the skills

The Python server keeps a journal in ~/.bse-mcp/journal.db (SQLite; BSE_MCP_JOURNAL moves it) so you can see which skills' calls work out:

  • The skills end an analysis by calling record_analysis with their verdict, entry, stop, target and horizon. The live price, session status, skill version (a hash of the skill's files) and model are saved with it.

  • bse-mcp snapshot [500112:SBIN ...] records get_quote and analyze_prices for each scrip (or for the lines of ~/.bse-mcp/watchlist.txt, scripcode [NSE symbol] each) and keeps NSE daily candles locally, because BSE and NSE only serve recent history. Run it a few times a day, e.g. with cron: 30 9,13 * * 1-5 bse-mcp snapshot and 0 16 * * 1-5 bse-mcp snapshot (cron needs the full path that which bse-mcp prints).

  • bse-mcp score scores each verdict once horizon_days trading days have closed after the day it was made, on NSE candles: return from the entry, return in the call's direction, best and worst move, and whether the stop or the target was hit first (ambiguous when one daily bar spans both). Days after the verdict only; nothing before it is used.

  • bse-mcp report summarises per skill and skill version: calls, scored, average return in the call's direction, hit rate, and target / stop / ambiguous counts.

A few weeks of calls on a handful of stocks says little: let it run over many scrips for a few months before comparing skills.

Install

BSE blocks most datacenter IPs, so the server runs where BSE will answer: on your own computer, or in your own Cloudflare Worker. Pick one.

Claude Desktop or Claude Code, on your computer (most reliable)

One command installs everything and registers the server with Claude Desktop (and Claude Code, if you have it):

# macOS / Linux
curl -LsSf https://raw.githubusercontent.com/goransh-gattani/bse-mcp/main/install.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/goransh-gattani/bse-mcp/main/install.ps1 | iex"

It installs uv if needed (uv brings its own Python, so an old system Python doesn't matter), installs bse-mcp, checks that BSE answers from your network, adds a bse entry to Claude Desktop's config without touching your other servers (the previous file is kept as .bak), and, if you have Claude Code, registers the server there and copies in the trading skills. Then quit Claude Desktop completely and reopen it. Re-run the same command to upgrade.

Prefer double-clicking? Download Connect-BSE-to-Claude.zip, unzip it, and double-click Connect BSE to Claude (.command on Mac, .bat on Windows). It runs the same installer and then restarts Claude Desktop for you. The first time, macOS asks you to right-click → Open, and Windows SmartScreen may need "More info → Run anyway", because the files aren't code-signed.

Already installed bse-mcp another way? bse-mcp setup does just the registration and skills step (--no-desktop, --no-code and --no-skills leave out parts).

By hand, if you prefer:

Needs Python 3.10+. macOS's built-in Python is 3.9, so the simplest route is uv, which fetches a recent Python just for this tool:

curl -LsSf https://astral.sh/uv/install.sh | sh                 # once; then reopen the terminal
uv tool install --python 3.12 "bse-mcp[chrome] @ git+https://github.com/goransh-gattani/bse-mcp"
bse-mcp --diag                                                  # should show HTTP 200
which bse-mcp                                                   # full path, for the config below

With Python 3.10+ already installed, pip install "bse-mcp[chrome] @ git+https://github.com/goransh-gattani/bse-mcp" works too (pip install "bse-mcp[chrome]" once it is on PyPI). [chrome] adds curl_cffi, which makes BSE far less likely to refuse.

Claude Code:

claude mcp add bse -- bse-mcp

Claude Desktop: Settings → Developer → Edit Config, add the server with the full path from which bse-mcp (the app doesn't see your terminal's PATH), then quit (⌘Q) and reopen the app:

{ "mcpServers": { "bse": { "command": "/Users/you/.local/bin/bse-mcp" } } }

uvx works too: "command": "uvx", "args": ["--from", "bse-mcp[chrome]", "bse-mcp"].

claude.ai, through your own Cloudflare Worker

Deploy to Cloudflare

Or from a checkout: cd worker && npx wrangler login && npx wrangler deploy. Either way you get a URL like https://bse-mcp.<you>.workers.dev. Then in claude.ai: Settings → Connectors → Add custom connector, URL https://bse-mcp.<you>.workers.dev/mcp, no authentication. Enable it in a chat.

Anyone who knows the URL can call it (the data is public; the cost is your Worker's free quota, 100k requests a day). To restrict it set a MCP_TOKEN variable on the Worker; the server then requires Authorization: Bearer <token>. Claude Code can send that (claude mcp add --transport http bse <url> --header "Authorization: Bearer <token>"); claude.ai's custom connectors expect OAuth rather than a fixed token, so leave it unset for claude.ai.

The Worker has the same tools except download_announcement_pdf; get_announcements gives a pdf_download_url on the Worker instead. BSE sometimes blocks Cloudflare's IP ranges; when it does the tools say so, and the Python server from a home network is the fallback.

Just trying it

A demo instance runs at https://bse-proxy.goransh-gattani.workers.dev/mcp (add it as a custom connector). It is shared, unmonitored and on a free quota, so don't build on it: deploy your own.

If BSE refuses

The tools answer with the cause: BSE refused ... (HTTP 403). From a computer run bse-mcp --diag; it tries each HTTP client (curl_cffi with Chrome's TLS fingerprint, urllib, curl) against BSE and prints what came back. Installing curl_cffi fixes most refusals. From a Worker, BSE is blocking Cloudflare at the moment; retry later or use the Python server.

How the calculations are done

Each analysis result carries a definitions block saying exactly what every figure is, so answers can be checked. In brief: EBITDA is revenue less materials, stock-in-trade purchases, inventory change, employee and other expenses; EBIT is PBT plus finance costs; TTM is the latest four consecutive quarters; YoY compares with the quarter ending 12 months earlier, found by date rather than by position; growth off a zero or negative base is left blank rather than reported as a meaningless percentage. RSI is Wilder's (checked against StockCharts' published worked example), EMAs are SMA-seeded, Bollinger bands use the population standard deviation. EV/EBITDA, P/B, ROCE and debt ratios are not computed: BSE's results endpoints give the P&L only, and the tool says so instead of estimating.

get_price_history and analyze_prices(scripcode=...) read the 12-month view of BSE's price chart: one close and BSE-only traded quantity per day, no open, high or low. Exchange histories aren't always adjusted for splits and bonuses (NSE's bhavcopy isn't), so analyze_prices lists any one-day move of 25% or more as price_jumps, to be checked against the company's announcements.

position_size uses the fixed-fractional rule: shares = the smallest of risk ÷ stop distance, capital × leverage ÷ entry, and the single-stock cap ÷ entry. Costs use the statutory rates for cash equity as Upstox published them in October 2026: STT 0.1% on each side for delivery and 0.025% on the sell side intraday, NSE's transaction charge 0.00307% (revised from 1 March 2026), SEBI's ₹10 a crore, stamp duty 0.015% (delivery) or 0.003% (intraday) on the buy side, and GST at 18% on brokerage and exchange and SEBI charges. BSE's transaction charge varies by scrip group, so NSE's rate stands in unless you pass exchange_txn_rate. Brokerage and DP charges depend on your broker: pass yours, or they count as zero and the result says so.

The formulas are the standard ones. For background on what they mean and how analysts use them, see Zerodha Varsity's Fundamental Analysis and Technical Analysis modules (Varsity's text is Zerodha's copyright and is not reproduced here).

Data and terms

  • Figures are what BSE publishes: quotes are delayed as BSE delays them; financials are as originally filed (later restatements are not applied) and labelled Rs million by BSE for most companies; derived rows (EBITDA, margins) are computed here and marked as such.

  • The quarter-id scheme (126 = Jun-25, one step per quarter) was verified on one company's filings; quarter names in results are taken from BSE's own period dates, so they stay right even if the scheme drifts. quarter names the Indian April–March FY quarter; for companies with another financial year (ABB India reports January–December) use period, which gives the months.

  • Indicators and ratios describe past figures. They are not forecasts or investment advice.

  • The data belongs to BSE and its use is governed by BSE's terms. This project only fetches it for you, the way your browser would; it grants no rights to redistribute it. Not investment advice.

Development

pip install -e ".[test]" && pytest            # Python tools and MCP wiring, against recorded BSE responses
node --test worker/test/worker.test.mjs        # the Worker, same fixtures
python scripts/build_skill_zips.py             # after editing anything in src/bse_mcp/skills/

The tests use responses recorded from BSE (shapes and values, ABB India, Oct 2026) and never call BSE, so they prove parsing and the protocol, not that BSE still answers. A release is a tag vX.Y.Z matching pyproject.toml; publish.yml builds and uploads to PyPI via trusted publishing.

The tool logic is in src/bse_mcp/tools.py (plain functions), the calculations in analysis.py and sizing.py, BSE access in bse.py, MCP wiring in server.py, the skills in src/bse_mcp/skills/ (zipped copies in skill-zips/, checked by the tests), and the same tools in JavaScript in worker/worker.js. Companion project: bse-automation (a browser UI for the same endpoints and a Postman collection documenting them).

License

MIT. The skills are adapted from nse-trading-skills, MIT, © 2026 Bhala Srinivash.

Available Tools

9 tools
call_bse_apiB

Call any documented BSE endpoint and return its raw decoded JSON. endpoint is one of: getScripHeaderData, ComHeadernew_par, MarketDepth, StockTrading, HighLow, PriceBand, SecurityPosition, StockReachGraphCas, EQPeerGp, TabResults_PAR_NEWS, TabResults_PAR_RESULTS, ScripwiseCautionaryMsg, LeftMenunew, Corp_detailedResult_Transpose_ng, Corp_BSEDnBResults_SEBI_Consolidated_Res_ng, Corp_SEGMENTS_QUART_COMP_ng, Corp_Segments_Total_p_ng, Corp_GET_BSEDnBResultNotes_ng, AnnSubCategoryGetData, GetQuoteAllSearchDatabeta, ListofScripData_new, ddlGroup, Mkt_GetTicker_ng. Default params are filled from scripcode and quarter (a BSE quarter id like '130.00', or 'Q1 FY27'); anything in params overrides them.

Inputs: endpoint (required), params, quarter, scripcode.

download_announcement_pdfA

Save an announcement's PDF (the 'attachment' from get_announcements) into save_dir, optionally under filename, and return the file path.

Inputs: save_dir (required), attachment (required), filename. Returns: result

get_announcementsA

Corporate announcements and filings for a scrip from BSE's announcements feed, newest first, with PDF links. months: look back 1-12 months (BSE returns nothing for longer spans). category: 'all' or 'results' (financial results only). page: 1-based, about 50 rows per page; 'total' says how many exist.

Inputs: scripcode (required), page, months, category.

get_financialsA

Quarterly P&L from BSE's results filings, newest first, with derived EBITDA, margins and tax rate. quarters: how many to return (1-16). upto: the newest quarter to include, like 'Q1 FY27'; by default the latest quarter BSE has results for is detected. Values are as originally filed; expenses are negative; BSE labels the amounts Rs million for most companies.

Inputs: scripcode (required), upto, quarters.

get_market_depthB

Top-5 bids and asks (price and quantity) with totals for one BSE scrip.

Inputs: scripcode (required).

get_peersC

BSE's peer group for a scrip: each peer's code, LTP, change %, PE, PB, EPS, revenue and PAT (Rs Cr), OPM, NPM, 52-week range and the quarter those results are from.

Inputs: scripcode (required). Returns: result

get_quoteA

Live price and key facts for one BSE scrip: LTP, change, day/52-week range, volume, delivery %, market cap, EPS/PE/PB/ROE/margins (standalone and consolidated), group, sector/industry, ISIN, flags (ASM/GSM etc.). scripcode: the 5-6 digit BSE code.

Inputs: scripcode (required).

list_scripsA

List BSE securities from the List of Securities page, filtered by segment (Equity, EQT0, MF, HS, MB, 'Preference Shares', 'Debentures and Bonds', 'Equity - Institutional Series', 'Commercial Papers', 'Government Securities', 'Certificate of Deposit', 'Treasury Bills'), status (Active/Suspended/Delisted/''), group code (A, B, T, ...), a name fragment, or one exact code. Returns up to limit rows and the total count. Big segments without a name filter are several MB on BSE's side; add a filter when you can.

Inputs: group, limit, status, segment, +2 more.

search_scripsA

Find BSE scrip codes by company name, symbol, ISIN or code fragment (e.g. 'reliance', 'ABB', 'INE117A01022'). Returns up to 20 matches: scripcode, symbol, name, isin, market. Use the scripcode in the other tools.

Inputs: query (required). Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 9 tools

    Disambiguation4/5

    Most tools target distinct resources and actions (quote, depth, peers, financials, announcements, PDF download, raw API). The only real overlap is between search_scrips and list_scrips, both of which can filter by name/code, but their descriptions clarify search is for finding a scripcode while list is for browsing/filtering segment listings. call_bse_api is a deliberate catch-all that could overlap with everything, but it is clearly framed as an escape hatch.

    Naming Consistency5/5

    All nine tools use a consistent snake_case verb_noun pattern: get_peers, search_scrips, get_market_depth, get_quote, get_financials, get_announcements, download_announcement_pdf, list_scrips, call_bse_api. The verbs are standard and predictable, with no mixing of camelCase or inconsistent conventions.

    Tool Count5/5

    Nine tools is well-scoped for a read-only BSE market-data server. Each tool covers a meaningful, non-redundant slice of functionality (search, quote, depth, peers, financials, announcements, PDF retrieval, listing, raw API access). No tool feels like filler or a trivial wrapper.

    Completeness4/5

    The set covers core needs: scrip discovery, live quotes, market depth, peer comparison, quarterly financials, corporate announcements, and PDF downloads. Minor gaps exist, such as a dedicated historical price/time-series tool and explicit index data, but call_bse_api provides a documented raw-endpoint escape hatch for those cases. The surface is nearly complete for a read-only BSE data server.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Provides real-time and historical Indian stock market data from NSE and BSE exchanges with 66 tools covering quotes, options chains, corporate actions, IPOs, and market analytics for LLM-powered financial analysis.
      42 npm
      13
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables Claude to fetch live Pakistan Stock Exchange data from the PSX Data Portal, including quotes, market summaries, top movers, fundamentals, price history with indicators, dividends, announcements, index constituents, sectors, and portfolio valuation. It also supports screening and comparing listed stocks by valuation, technical, sector, index, and Shariah criteria.
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Connects AI assistants over the Model Context Protocol to live NSE and BSE data, enabling research on Indian listed companies — quotes and price history, quarterly and annual fundamentals, valuation and peer comparison, shareholding, FII/DII flows, F&O and index options, screening, IPOs, corporate actions, filings and market news. Read-only, with no local setup required.
      MIT