
Finance MCP
io.github.Blahaj-gifPublished by GitHub account Blahaj-gifv0.5.0Updated Nov 6, 2026
Market data, SEC filings and risk tools for Webull, Saxo and IBKR. Only you can send an order.
The publisher's own server: Finance Foundation
Overview
Local MCP server giving an assistant read access to brokerage accounts, market data, SEC filings and macro releases, with order submission kept to a human-run…
- What you can do
- Fetch prices and bars from the configured broker with a Yahoo fallback, each labelled with its bar and age
- Compute technical indicators, volume profile, options greeks, backtests, position sizing and portfolio risk
- Parse SEC EDGAR filings such as Form 4, 8-K, 13F, 13D/G and 144 into answers
- Read economic calendar rows from BLS, the Fed and BEA, plus earnings data
- Read account balance, positions and open orders, and draft or preview orders into a local queue
- Cancel a resting order and log journal entries
- When to use it
- Useful for research on a real brokerage account: asking about a ticker's technicals, checking insider filings or macro releases, or reviewing positions and drafting an order for later manual approval. A broker-free install still exposes the 28 market, filing and macro tools.
- Requirements
- Local Python install (3.10 or 3.12) via uv, run over stdio; a Streamlit dashboard is a separate app. SEC_USER_AGENT with a real contact address is required for filings tools; BLS_API_KEY is optional. Broker access is optional and set through FINANCE_BROKER (webull, saxo or ibkr) with WEBULL_APP_KEY and WEBULL_APP_SECRET, SAXO_ACCESS_TOKEN, or a running IBKR Client Portal Gateway. Network access to the data sources is needed.
Installation
In SourceWeft
- Open Finance MCP in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
Finance MCP
An MCP server that gives an AI assistant read access to your real brokerage account and the market around it — and gives you, not the assistant, the only button that sends an order.
38 tools over Webull, Saxo, IBKR, Yahoo Finance, SEC EDGAR, BLS, the Federal Reserve and the BEA, plus a Streamlit dashboard that is the sole path to execution. The list is filtered to what your broker can actually serve, so a given account sees 36 or 37 of them — and 28 with no broker at all, which is a working install, not a broken one.
The assistant can draft an order. It cannot place one. Drafts go to a local queue; sending requires a broker preview and your click in the dashboard. That path does not exist on the tool side, so no prompt can reach it.
Every tool declares this to the client rather than only to the reader: 32 of
36 are annotated read-only, one is destructive (cancel_order, which pulls a
resting order). A client that respects MCP annotations can wave through a price
lookup and stop on the one call that reaches the market.
What this can and cannot do with your account
Asking an unknown repository for brokerage credentials is the hardest trust ask in software, so the answer is here rather than forty paragraphs down.
- There is no execution path on the tool side. Not gated, not guarded —
absent.
draft_orderwrites to a local queue. Sending needs a broker preview and your click in the dashboard, which no prompt can reach. - Twenty-eight of the 38 tools never touch a broker. SEC filings, macro, indicators, options maths, earnings. With no credentials at all you get those twenty-eight, and that is a working install rather than a degraded one.
- Two of the three adapters have never been run. Saxo and Interactive Brokers are built from published API references and have not been executed against a live or paper account. They say so in every tool output that uses them. Only Webull has been run against a real account.
- The dashboard's submit button is Webull-only. The MCP tools route through the broker protocol; that one button does not, yet.
- Use a read-scoped key where your broker offers one. Nothing outside the dashboard needs write access.
1,431 tests across 32 files, and CI runs them on every push.
Those all stub the network, which is correct — a suite that goes red because SEC
returned a 503 overnight is a suite nobody reads. It is also why two defects
survived every one of them: a euro-area series that had stopped publishing eight
months earlier and was reported as current, and a filing watcher that answered
403 to every request and called itself healthy. Both needed the real internet to
see. tests/test_live_sources.py asks every external source for real and checks
that this tool's account of the answer is true — in particular that a series
marked fresh actually is. It is opt-in and skipped by default:
It also runs weekly in CI, because a check that depends on somebody remembering
is a check that eventually stops happening — and discontinued series and broken
scrapers are exactly the failures that arrive quietly over weeks. That workflow
is inert until FRED_API_KEY and SEC_USER_AGENT exist as repository secrets,
and when they do not it says so in the job summary rather than reporting a green
tick that verified nothing.
Candles with overlays, a volume pane and the forecast cone. Weekends and market holidays are collapsed, so there are no blank stretches.
What it does
What you need
Installation guide → — fifteen minutes, most of it waiting for free API keys.
This places real orders against a real account. The consensus score is a fixed-weight heuristic that underperformed buy-and-hold in backtest and is labelled as such throughout. Not financial advice — see NOTICE.md for the full disclaimers and the third-party data terms.
Brokers
Both unverified adapters say so in every tool output that uses them, and refuse rather than guess on the paths the docs did not pin down.
dashboard/broker_protocol.py is the interface; tests/test_broker_conformance.py
runs the same suite against every adapter. FINANCE_BROKER=ibkr selects which
adapter the protocol and the MCP tools report through.
What works with which broker
28 of the 38 tools are broker-agnostic — indicators, options, SEC filings, insider and institutional data, earnings, macro. They work the same whoever you clear through, though the prices underneath them now come from your broker where it serves bars (see below).
Eight are account and order tools, and they go through
broker_protocol.py, so they work with any adapter that declares the capability
they need:
A tool is only registered when the configured broker can serve it. Start with
FINANCE_BROKER=saxo and cancel_order is not in tools/list at all — Saxo
cancels by its own order id and documents no mapping from ours, so a cancel tool
would be a tool that can only refuse. An unusable tool costs a model context on every
request and is one more wrong choice available to it.
The same rule covers having no broker. Every adapter constructs lazily, so that
listing tools never opens a socket — which meant an empty .env built a broker
object quite happily and all eight account tools were offered to someone who
could not call a single one of them. They now check for their credentials
offline and register only if they have them, so a broker-free install lists 28
tools that all work rather than 36 of which eight cannot. Where the answer is
genuinely unknowable offline — IBKR's Client Portal Gateway holds the session
after a browser login and wants no token at all — the tools stay registered,
because hiding a tool that would have worked leaves nobody a way to find out why.
Two more exist only for the broker that has them: saxo_corporate_actions
(dividends, splits, tenders and their election deadlines — Saxo is the only one
of the three with them) and ibkr_market_scanner (the exchange-side scan,
rather than inferring rotation from eleven ETF price pulls).
Capability is resolved per account, not per broker name, because three different things have to line up:
Webull alone runs twelve independent regional entities on separate hosts, and
market-data entitlements are bought per account on top of that — an order book
that returns one level means an L1 subscription, not a missing endpoint.
dashboard/capabilities.py keeps a cache keyed on broker × entity × account, a
probe can only ever withdraw a capability and never invent one, and it records
what a call did rather than why. Inferring a cause from an error message is
how this file previously came to blame a region for a parameter mistake.
Macro releases
CPI prints at 08:30:00 ET. The calendar carries the print that happened or the prior one, never a forecast — there is no consensus feed here, street estimates are a licensed product, so a "surprise" against a prior reading is not a surprise.
Near a scheduled release the macro cache collapses from six hours to three
seconds, so the answer is the freshest available whenever you ask. Set
FINANCE_MACRO_WATCH=1 and a background thread also fetches the print as it
publishes, so it is already in hand.
Neither bursts. BLS documents 50 requests per 10 seconds; the fast cadence uses ten. Polling faster does not make BLS publish sooner — a burst of identical requests fired at the instant all return the same stale payload, because the wait is on an external event rather than on throughput.
Prices come from your broker
fetch_data tries the configured broker first and Yahoo second, so a Saxo user
gets Saxo's /chart/v1/charts and an IBKR user gets
/iserver/marketdata/history — for every price in the server, not just the
account tools. Before this, supplying Saxo or IBKR credentials still left the
whole price feed on the public fallback, which was invisible because the tools
still worked. The fallback always announces itself when it is used.
Both broker feeds sort ascending before returning. Webull returned newest-first and nothing sorted it, so every indicator ran on a reversed series and the sector heatmap ranked the worst performers as leaders; that is not a mistake worth making twice.
contract_rules() fetches real tick and lot sizes, and rule_violations() uses
them when supplied — the check that catches an order preview prices cleanly and
placement then refuses.
The dashboard's submit button is still Webull-only. The MCP tools route through the protocol; the Streamlit approve-and-submit path does not yet, and moving it means putting two adapters nobody has run on the one code path that has been exercised for real. Verification comes first — which is what HELP-WANTED.md is asking for.
IBKR is the Client Portal Web API — plain request/response JSON — not the TWS socket API. That distinction is why it is an adapter and not a rewrite. It also brought the one broker behaviour the protocol did not already have: IBKR can answer a placement with warnings instead of an order, each needing confirmation before anything is transmitted. Client libraries normally answer those from a table of canned replies. This one raises them to the person who approved the order, which is the whole point of the tool.
Help wanted → — an hour with a Saxo simulation token or an IBKR paper account would close the verification gap. The scripts that do it read only; they never place an order.
Works with any MCP client
Nothing in the server is specific to one assistant. It speaks MCP over stdio, so anything that speaks MCP can run it. The installer registers it with every client it finds on the machine; to wire one up by hand, add this to that client's MCP config:
The dashboard is a separate Streamlit app and does not care which client you use. Order approval happens there regardless.
Macro Calendar & Real-Time Filings
Four public sources sit alongside the broker feed, so Claude can see the events that move price as well as the price itself.
Filings are parsed, not forwarded. Most of what an analyst wants from a filing is already a machine-readable field. "Was that sale pre-scheduled?" is <aff10b5One> in the Form 4 XML — a boolean. So the server extracts and answers rather than handing over a document: one Form 4 is ~6,600 tokens of raw XML, and a single 10-K is ~610,000 tokens, which is three times a 200k context window. get_insider_activity also separates real decisions (codes P/S) from compensation mechanics — grants, option exercises, and shares withheld for tax — which are routinely misreported as "insiders sold $X".
On latency. EDGAR acceptance timestamps are exact to the second, so an earnings 8-K (item 2.02) is visible as soon as it is accepted. The delay you experience is your own polling interval, not the feed. get_earnings uses that same item code to confirm which quarters were actually released, and flags an upcoming date that Yahoo is only estimating — Yahoo publishes an unset date as a window and a set one as a single day, and the two are indistinguishable once formatted.
No consensus, and it says so. Street forecasts are a licensed product with no free source, so every comparison in the calendar is against the previous print and is labelled that way. A "surprise" measured against a prior reading is not a surprise: the market trades the gap to expectations, and expectations are the one thing not available here.
Rate and quota handling. BLS allows 25 API queries a day unregistered; the release-schedule pages are ordinary web fetches and deliberately do not draw on that budget. Results are cached (6h for macro series, 24h for schedules, 2min for filings), so a repeated calendar call costs nothing. The SEC's 10 req/s ceiling is enforced at the client.
Normalization. Filer names and release text arrive in mixed scripts and number conventions. A dedicated layer folds Unicode to a canonical form, expands atomic Latin letters that have no decomposition (Ærø → AEro, not r), converts non-ASCII digits, and parses numbers written US, European, Swiss or Indian style — including accounting negatives like (1,234.56).
Getting a BLS key (optional, free, ~2 minutes)
Unregistered access is capped at 25 API queries a day. To lift it to 500:
- Register at data.bls.gov/registrationEngine — the key arrives by return email.
- Add
BLS_API_KEY=<your key>to.envand restart the server. - Run the
validate_bls_keytool to confirm it was accepted.
That last step matters: a mistyped key does not raise an error, it silently drops you back to the 25/day tier, which only shows up days later as an exhausted quota. Registered access also extends history from 10 to 20 years and returns BLS's own computed percentage changes, which the server checks its own arithmetic against.
Use get_data_sources at any time to see every source's configuration and remaining quota.
Help wanted
Three things where an hour from someone else is worth more than a day from me:
- Verify the Saxo adapter. Written from Saxo's published reference, never run
against their API. A 24-hour simulation token is free and needs no approval,
and
tests/verify_saxo.pyanswers the six open questions without placing an order. - Verify the IBKR adapter. Same situation, and a paper account is enough.
Run the Client Portal Gateway, log in through a browser, then
python -m tests.verify_ibkr. It submits nothing — it reads, and it calls IBKR's own non-bindingwhatif. → HELP-WANTED.md - Install it on a clean machine.
install.batandinstall.share covered by unit tests and inspection, never by a fresh OS — the first thing every new user touches is the least proven path here.
Also open: IG Markets (REST, similar shape to Saxo).
dashboard/broker_protocol.py is the interface;
tests/test_broker_conformance.py runs against anything that implements it.
Where the numbers come from
Not all data carries the same weight, and the tools say which is which.
get_company_financials returns the filed figures directly. Where Yahoo and the filing disagree, the filing wins and the tool says so.
IV rank is the one measure that cannot be sourced authoritatively for free: no public feed publishes implied-volatility history. Rather than pretend otherwise, the server records one ATM IV observation per symbol per day as options are queried, and reports a true IV rank once a symbol has 30 days of its own history. Until then it shows a realised-volatility proxy, explicitly labelled, with a count of how many more observations are needed.
Data Integrity
Market data is the foundation everything else rests on, so it is checked rather than trusted. Every price frame — from either source — passes a single gate before any tool sees it:
- Bar ordering is enforced. The Webull API returns bars newest-first. Frames are sorted ascending and the invariant is asserted, so
.iloc[-1]is always the most recent bar. (Without this, tools reported the oldest bar of the window as the current price and computed every indicator on a time-reversed series.) - Staleness is measured in trading sessions, using a built-in NYSE calendar — not calendar days, which cannot tell a holiday weekend from an outage.
- Sanity checks reject NaN prices and impossible OHLC bars.
- Failures are errors, not text. Tools raise real MCP errors rather than returning
"Error: ..."as content, so a failure can never be mistaken for a finding. - Source substitution is announced. When the Webull feed fails and Yahoo serves the request, every affected tool says so.
Run the suite with pytest. It is entirely offline — no credentials, no network, no orders.
Installation
Path A — the installer (Windows, no Python required)
- Unzip this package anywhere (e.g. your Desktop).
- Double-click
install.bat. - It installs the
uvPython engine if missing, registers the server in%APPDATA%\Claude\claude_desktop_config.jsonunder the namefinance, writes a.envtemplate, and drops a Finance MCP Dashboard shortcut on your Desktop. - Fill in
.env(see Authentication). - Restart Claude Desktop. The server is only read at startup.
The installer prints an ACTION NEEDED block if WEBULL_APP_KEY or
SEC_USER_AGENT are still at their placeholder values, so a half-configured
install does not look like a finished one.
Nothing is installed system-wide beyond uv; dependencies are resolved into a
cache the first time the server or dashboard runs, so the first launch is
slower than the rest.
Path B — clone the repo
No installer, no shortcut. You wire up the two entry points yourself.
The MCP server (what Claude talks to). Add this to
%APPDATA%\Claude\claude_desktop_config.json on Windows, or
~/Library/Application Support/Claude/claude_desktop_config.json on macOS, and
restart Claude Desktop:
Use an absolute path, and forward slashes even on Windows. Claude Code users
can instead run claude mcp add finance -- uv run /absolute/path/to/finance_mcp.py.
The dashboard (what you look at). Run it from the repo root, not from
Module boundaries. dashboard/webull_client.py is the market-data client and
the shared signed-request plumbing; dashboard/broker.py is the trading surface
(accounts, buying power, positions, the order lifecycle). They are separate
because they fail differently: a price feed degrades to a fallback and says so,
while an order path must refuse rather than substitute.
dashboard/barcache.py is a small on-disk cache of validated bar frames shared
between the MCP server and the dashboard — a hit skips the download, never the
integrity gate. Disable it with FINMCP_BAR_CACHE=0.
dashboard/ — app.py resolves its sibling modules and .streamlit/config.toml
relative to the working directory, and launching from elsewhere loses the theme:
It opens on http://localhost:8501. Add --server.port 8899 to move it.
It binds loopback only. Streamlit leaves server.address unset by default,
and unset does not mean localhost — it listens on every interface, which for
this app means a live brokerage account, its positions and a working submit
button reachable by anyone on the same network. .streamlit/config.toml pins
127.0.0.1, and finance-mcp-dashboard passes the same flag for an installed
copy that may not have that file beside it. It is a default rather than a lock:
pass --server.address yourself if you genuinely mean to serve it elsewhere,
and put something in front of it if you do, because there is no authentication
here.
The alert manager (optional, Windows toast notifications). The dashboard starts it automatically in a background thread; to run it standalone:
Verify the install — pytest runs the whole suite offline, with no
credentials and no network:
Then ask Claude to run get_data_sources — it reports which credentials are
configured, which feeds are reachable and what quota is left, without touching
your account. check_connection confirms the Webull session specifically.
Authentication
- Open the newly generated
.envfile located in this folder. - Paste your Webull
WEBULL_APP_KEYandWEBULL_APP_SECRET. - Save the file.
.env and conf/token.txt are gitignored, and SDK logs are credential-redacted at write time — the Webull SDK dumps the full signed request (key, HMAC signature, access token) at ERROR level, which routine rate-limit responses would otherwise write straight to disk.
Optional settings
Using it
From the assistant
Restart your MCP client so it picks up the server, then ask for what you want: "How does NVDA look on the daily?", "What's due on the economic calendar this week?", "Draft a limit buy for 10 AAPL at 300." The last one writes a draft to the queue and stops there.
In the dashboard
Double-click the Finance MCP Dashboard shortcut, or run
streamlit run dashboard/app.py from the repo root. Nine tabs:
The Events tab: the economic calendar with each row's actual or prior print, earnings dates flagged as confirmed, disputed or estimated, and watchlist filings with a hover preview.
The Execution tab — the only path to the market. Preview with the broker, then approve.
DISPLAY in the top right switches the visual theme (Terminal, the default; Research; Slate), the chart overlay palette and row density.
The Execution tab is the only place an order can be submitted. Submission is two-step by design: 1 — Preview with Webull asks the broker to price the order (non-binding), and only then does 2 — Approve and submit unlock. An order the broker will not preview is never sent, and a failed submission leaves the draft pending rather than marking it executed.
3. What Claude can and cannot do
There is no configuration flag that grants Claude submission rights. Removing the human from that step would require editing the source.
Disclaimer: This is an open-source project for educational and experimental quantitative research. Algorithmic trading carries significant financial risk.
mcp-name: io.github.Blahaj-gif/hitl-finance-mcp
Source: README.md at commit ff2169e
Tools
0Version history
2- v0.5.0LatestNov 6, 2026
- v0.3.1Sep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts
Other Finance integrations
Finance Foundation
foundation.financeOfficial publisher
A remote MCP server for open financial reference data: look up companies, markets, funds and assets, resolve identifiers, traverse a knowledge graph and read a
FYN
fyi.fynOfficial publisher
Read-only personal finance for AI agents: budgets, receipts, net worth, bills. OAuth 2.1.

Korea Finance Factcheck
Published by GitHub account hs85-newbie
Fact-checks numbers in Korean finance writing against DART, Bank of Korea ECOS and US Treasury

Apizie Finance
Published by GitHub account nafadza14
Remote MCP server giving assistants cited financial data from SEC EDGAR, FRED, ECB, U.S. Treasury, GLEIF and market feeds.

Finance MCP
Published by GitHub account aowang-ai
Hosted MCP server that lets an assistant discover, inspect and run finance data tools covering US stocks, SEC filings, macro series, crypto and prediction…