Skip to main content
Glama
bd-finance-mcp

bd-finance-mcp

by Claudefarid

bd-finance-mcp

Bangladesh's financial markets, available to your AI assistant. Both stock exchanges, every listed share, and what the taka is worth today.

An MCP server built with FastMCP.

⚠️ Not investment advice. This reports publicly published prices. It does not analyse, recommend, or predict. Figures are last-traded values and may lag the live market.

Unofficial. Not affiliated with DSE, CSE, or Bangladesh Bank.

Tools

Tool

What it does

compare_exchanges(code)

The same share priced on both exchanges, with the spread between them.

market_summary(exchange)

Breadth — how many shares rose, fell, held flat or never traded.

top_movers(direction, exchange, limit)

gainers, losers, volume or value.

get_stock(codes, exchange)

Prices for specific trading codes.

search_stock(query, exchange)

Find codes by substring, e.g. "BANK".

sector_performance(sector)

How a whole sector traded — did banks rise while textiles fell?

list_sectors()

The 22 DSE sectors you can ask about.

company_profile(code)

Sector, market cap, P/E ratio, paid-up capital, shares outstanding.

exchange_rate(currencies)

Taka per USD, EUR, GBP, SAR, AED, MYR and 160 more.

finance_news(keyword, sources, business_only)

Latest business and financial headlines.

list_news_sources()

Which papers are covered, and which could not be.

company_profile turns a bare price into something you can reason about — GP trades at a P/E of 11.44 in Telecommunication with a 326,907mn taka market cap, BRAC Bank at 6.14 in Banking. Prices alone don't tell you that.

compare_exchanges is the one you can't easily do yourself — most Bangladeshi companies list on both markets, and the prices genuinely differ. GP was trading at 240.60 on Dhaka and 241.50 on Chittagong while this was being written.

sector_performance answers the question a price list can't: how did banks do today? It aggregates every share in a sector — advancers, decliners, average move, best and worst — from one query. Partial names work, so "pharma" finds "Pharmaceuticals & Chemicals".

Prices tell you a share moved; finance_news tells you why.

Every market response carries a market block saying whether DSE is currently trading (Sunday–Thursday, 10:00–14:30 Asia/Dhaka) and whether the figures are live or the last completed session. Outside session hours, "today's gainers" means the previous close — the response says so rather than leaving you to assume.

Related MCP server: Financial Modeling Prep MCP Server

Sources

Source

Provides

dsebd.org

Dhaka Stock Exchange — ~395 instruments, company fundamentals

cse.com.bd

Chittagong Stock Exchange — ~387 instruments

open.er-api.com

Currency reference rates, 166 currencies

dsebd.org sector pages

22 sectors and their constituents

The Daily Star — Business

Bangladeshi business news

The Business Standard — Economy

Bangladeshi business news

Dhaka Tribune

General newsroom (see note below)

Financial Times — Companies

International business news

Dhaka Tribune publishes no business-only feed, so its articles are general newsroom output. finance_news leaves it out by default (business_only=True) rather than passing student politics off as market coverage — name it in sources, or set business_only=False, to include it.

Bonik Barta is not available. It is a single-page app: every path, including /api/v1/, returns the same HTML shell with HTTP 200. There is no feed or API behind it. A status code alone is not proof a source works.

New Age is not available. No working RSS feed exists at any conventional path.

Financial Times links are paywalled. Headlines and summaries come through the public feed; the articles themselves require a subscription.

No API key, login, or paid data feed.

Not included: Bangladesh Bank. Its econdata pages sit behind a CAPTCHA challenge. That is an explicit request not to automate, and this project respects it rather than working around it. Use exchange_rate for reference rates instead — but note those are mid-market, not BB's official rate, and not what a bank will actually pay you.

Not included: gold prices. BAJUS renders them client-side; nothing is in the HTML to parse.

Not included: the DSEX index. It appears only in DSE's navigation menus — the live value is injected by JavaScript, so there is nothing to read from the served HTML. market_summary gives you breadth and turnover instead, which describes the session without pretending to quote an index it cannot see.

Install

Requires uv and Python 3.12+.

git clone https://github.com/Claudefarid/bd-finance-mcp.git
cd bd-finance-mcp
uv sync
uv run fastmcp install claude-code server.py:mcp

Restart your client, then ask "Compare GP's price on both Bangladeshi exchanges" or "What's the taka doing against the riyal?"

Verify with uv run python test_server.py.

Six things that will bite you if you build this yourself

Each of these produces wrong answers rather than errors — the dangerous kind of bug.

1. The two exchanges disagree about untraded shares.

DSE reports a share that did not trade with price 0. CSE carries yesterday's price forward. Compute percent change naively and DSE hands you a list of −100% "crashes" that are really just shares nobody bought. Trade count is the only signal that works on both, so it decides whether a percentage is meaningful here.

This matters more on CSE than you would guess: 187 of its 387 listed shares did not trade on the day this was written. Nearly half the market. Get this wrong and CSE data is worthless.

2. dsebd.org serves an incomplete TLS certificate chain.

Its leaf certificate is signed by a Sectigo intermediate the server never sends. Browsers and curl recover by fetching it via AIA; Python's certifi bundle cannot, so httpx fails with CERTIFICATE_VERIFY_FAILED.

The fix is not verify=False — that disables verification altogether, which is a bad trade anywhere and a worse one for financial data. Verify against the OS trust store instead:

import ssl, truststore
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
httpx.AsyncClient(verify=ctx)

3. DSE's P/E table is one column per trading day, and the newest is last.

The ratio table sits under a Particulars header whose columns are dates. Read the first column — the obvious choice — and you report a P/E from a week ago as today's. company_profile takes the last populated column and returns the date alongside it, so the figure is always checkable.

There is a second trap in the same table: the page carries several Particulars headers, and the first one reads "Unaudited / Audited" rather than dates. Matching on width picks the right one.

A missing P/E is not a parsing failure, either. DSE prints - across the row for companies without meaningful earnings — BEXIMCO, for one — so None there is the honest answer.

4. The Daily Star's feed puts HTML inside its <title> tags.

Its headlines arrive wrapped in an unescaped anchor:

<title><a href="/business/news/...">7,896 customers withdraw Tk 327 crore</a></title>

ElementTree parses that anchor as a child element, so findtext("title") returns an empty string — not an error, just nothing. Every Daily Star headline came back blank, and because an empty headline matches no keyword, the paper looked like it was ignoring every topic when it was simply never being read. "".join(element.itertext()) collects descendant text and fixes it.

5. Substring matching puts the IT sector inside "Financial Institutions".

The obvious way to resolve a sector name is query in name.lower(). Ask for "IT" and you match both IT Sector and Financial Inst**it**utions — so the most natural query for the sector fails as ambiguous. Matching runs in tiers instead: exact, then prefix, then word-boundary, then substring, taking the first tier that resolves to one sector.

6. Mid-market rates are not remittance rates.

exchange_rate returns reference rates. Banks and exchange houses apply their own spread, so what actually lands in a recipient's account is lower. The tool says so in its own description, so a model relying on it does not quietly present these as the rate you'd receive.

Please be considerate

Each call is a single page fetch, and requests identify themselves by User-Agent. Don't poll in a tight loop.

License

MIT — see LICENSE. Covers this code only, not the exchanges' data.

Available Tools

11 tools
company_profileCompany ProfileA

Fundamentals for one DSE-listed company: sector, market cap, P/E, capital.

This is the context a price alone cannot give you — what business the company is in, how large it is, and what the market is paying per taka of earnings. DSE-listed companies only.

Inputs: code (required). Returns: object

compare_exchangesCompare ExchangesB

Price the same share on both Dhaka and Chittagong exchanges.

Most Bangladeshi companies are listed on both. Prices can differ, and the gap is the kind of thing you cannot see without checking two sites.

Inputs: code (required). Returns: object

exchange_rateExchange RateA

What one unit of foreign currency is worth in taka.

Defaults to the currencies that matter most for Bangladeshi remittances. Rates are mid-market reference rates — banks and exchange houses apply their own spread, so what you actually receive will be lower.

Inputs: currencies. Returns: object

finance_newsFinance NewsA

Latest business and financial news, newest first.

Use this to explain what the market is doing — prices tell you a share moved, the news tells you why. Pass keyword to keep only articles mentioning a company, sector or topic.

sources limits the scan: 'dailystar', 'tbsnews', 'dhakatribune' or 'ft' (international, paywalled links). Naming a source always includes it.

Dhaka Tribune publishes no business-only feed, so its articles are general newsroom output. business_only keeps it out of the default mix — set it False for wider coverage, or name it in sources to read it directly.

Inputs: limit, keyword, sources, business_only. Returns: object

get_stockGet StockA

Current prices for specific trading codes on one exchange.

Codes are short symbols like ['GP', 'BRACBANK']. Use compare_exchanges to see one share priced on both markets at once.

Inputs: codes (required), exchange. Returns: object

list_news_sourcesList News SourcesA

Which news feeds are covered, and which financial papers are not.

Inputs: no named parameters. Returns: object

list_sectorsList SectorsA

List the DSE sectors you can ask about, e.g. Bank, Textile, Pharmaceuticals.

Inputs: no named parameters. Returns: object

market_summaryMarket SummaryC

Market breadth — how many shares rose, fell, held flat or never traded.

Inputs: exchange. Returns: object

search_stockSearch StockC

Find trading codes containing a substring, e.g. 'BANK' or 'PHARMA'.

Inputs: query (required), exchange. Returns: object

sector_performanceSector PerformanceA

How one DSE sector traded today — did banks rise while textiles fell?

Aggregates every share in the sector: how many advanced, declined or never traded, the average move, and the best and worst performers. Partial names match, so "pharma" finds "Pharmaceuticals & Chemicals".

Inputs: sector (required). Returns: object

top_moversTop MoversA

Biggest movers of the session on one exchange.

direction is 'gainers', 'losers', 'volume' or 'value'. Gainers and losers rank by percent change, so cheap and expensive shares compare fairly. Shares that did not trade are excluded rather than shown as total losses.

Inputs: limit, exchange, direction. Returns: object

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 11 tools

    Disambiguation4/5

    Each tool targets a distinct slice of the market: movers, breadth, quotes, sectors, news, FX, and cross-exchange comparison. The only mild ambiguity is between get_stock and compare_exchanges, but the descriptions explicitly point from one to the other.

    Naming Consistency3/5

    Names are all snake_case, but the set mixes verb-led actions (search_stock, list_sectors, get_stock, compare_exchanges) with noun-only snapshots (top_movers, market_summary, exchange_rate, company_profile, finance_news, sector_performance). There is no single predictable pattern, though each name is still readable.

    Tool Count5/5

    11 tools is well within the ideal range, and each tool covers a meaningful part of the domain: quotes, movers, sectors, fundamentals, news, FX, and exchange comparison. No obvious redundancy that would justify trimming.

    Completeness4/5

    The server covers the main read-only market data needs: current prices, movers, breadth, sector aggregates, company fundamentals, news, FX, and dual-exchange quotes. Missing historical price/performance and index-level data are notable but workable gaps for an agent doing day-of analysis.

    Maintenance

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Enables AI assistants to retrieve live Dhaka Stock Exchange data, including prices for all listed shares, top gainers/losers, and market summary, through natural language queries.
      4
      1
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI assistants to access and analyze financial data, stock information, company fundamentals, and market insights through 250+ tools covering stocks, ETFs, crypto, forex, commodities, and economics.
      624 npm
      Apache 2.0
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI assistants to access and analyze financial data, stock information, company fundamentals, and market insights through 250+ tools covering stocks, ETFs, crypto, forex, commodities, and economics.
      624 npm
      Apache 2.0
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI assistants to access and analyze financial data, stock information, company fundamentals, and market insights through 250+ tools spanning stocks, ETFs, crypto, forex, commodities, economics, and more.
      624 npm
      Apache 2.0