finance-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@finance-mcp-server Any DART filings or Telegram chatter on Naver today?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Finance MCP Server
A personal finance research and execution toolkit for LLM agents, built as one MCP server that composes three purpose-built sources: DART, Telegram, and Toss Securities.
Why these three
Most "AI + finance" setups reach for one thing: a market data API, or a news feed, or a broker connection. This project is built around the idea that useful financial reasoning needs three different kinds of input, each doing the job it's actually good at:
DART — structured data. Korea's official disclosure system (filings, financial statements, shareholder structure, dividends). This is ground truth: audited, dated, and unambiguous. It's slow-moving and backward-looking by nature — a company's last quarterly filing, not what's happening right now.
Telegram — unstructured data. Chosen deliberately, not as a generic "news" source. Analysts and everyday investors post their actual research and opinions on Telegram every day — it's where a lot of pre-publication and off-the-record commentary in Korean stock investing circles actually happens. Reading it isn't about ingesting news headlines; it's about seeing what people who are actively trading are paying attention to right now, which is a different signal than what any news wire reports.
Toss Securities — the execution layer. Prices, order books, candles, account holdings — and, increasingly, the ability to actually act: placing, modifying, and canceling live orders, and managing a portfolio. This is the layer that turns research into a position.
Put together: DART tells you what's true, Telegram tells you what people are paying attention to, and Toss is how you act on either.
Related MCP server: DART 공시 브리핑 MCP 서버
Architecture
Each source is a complete, independent MCP server that also runs on its own:
finance-mcp-server/
├── server.py # composes the three below into one MCP server
├── dart/ # structured data
├── toss/ # execution layer
└── telegram/ # unstructured dataThe root server.py doesn't fork or reimplement any of the three servers'
logic. At import time, it loads each <source>/server.py as an isolated
module and copies its registered tools onto one shared MCP server instance.
Editing a tool's behavior means editing it inside its own source folder —
the root file only wires things together, and picks up any change made
inside a source automatically on the next restart.
The only name collision across all three is test_connection (each ships
one); those are renamed to dart_test_connection, toss_test_connection,
and telegram_test_connection. Everything else keeps its original name.
There's also a finance_test_connection tool that checks all three sources'
credentials/connectivity in one call.
Quick start
Each source needs its own credentials — see USAGE.md for the full setup walkthrough per source (including Toss's IP allow-list requirement and Telegram's one-time login), the complete tool catalog, and worked examples.
# in each of dart/, toss/, telegram/ you want to use:
cp .env.example .env # then fill in the real values
# from the repo root:
uv sync
uv run server.pyRegistering with an MCP client
{
"mcpServers": {
"finance-mcp": {
"command": "/absolute/path/to/finance-mcp-server/.venv/bin/python",
"args": ["/absolute/path/to/finance-mcp-server/server.py"]
}
}
}Order placement is live (Toss)
place_order and modify_order submit real orders against a real account
and require an explicit confirm=True argument — calling without it raises
an error instead of submitting anything — with orders above a size threshold
additionally requiring confirm_high_value_order=True. cancel_order is
intentionally not gated behind confirm=True, since canceling is the safe
direction. None of this is a substitute for a human-in-the-loop check: an
autonomous agent can supply confirm=True on its own, so treat it as
recording caller intent, not as proof a human approved the trade. There is
no simulation/dry-run mode. Read toss/README.md before connecting this to
anything that can call tools autonomously.
Documentation
USAGE.md — full setup per source, complete tool catalog, worked examples
DESIGN.md — the rationale behind each source's guardrails: the different kinds of limits in DART/Telegram (bounding data volume) versus Toss (bounding irreversible intent), and what changed as a result of a security review before this was made public
Status
This is an evolving personal project, not a polished product. The three sources were each built and hardened independently before being composed here; expect rough edges, and expect the tool set to keep growing (especially on the Toss side).
License
Available Tools
46 toolscancel_orderB
Cancel a pending live order; cancellation does not require confirmation.
Inputs: order_id (required), account_seq (required). Returns: object
check_dart_api_keyA
Check whether the DART API key was loaded without exposing it.
Inputs: no named parameters. Returns: object
check_toss_api_credentialsA
Check whether TOSS_CLIENT_ID / TOSS_CLIENT_SECRET were loaded, without exposing them.
Inputs: no named parameters. Returns: object
dart_test_connectionB
Return a message to verify that the MCP server is working.
Inputs: message (required). Returns: object
download_fileA
Download the file attached to one message to local disk and return its path.
Saves under this project's downloads/ folder by default; dest_dir selects a
subdirectory within that downloads/ folder (relative paths, .., and absolute
paths that resolve outside it are rejected). The filename is sanitized and
de-duplicated against existing files in the target directory.
Inputs: chat (required), message_id (required), dest_dir. Returns: object
finance_test_connectionA
Check DART, Toss, and Telegram credentials/connectivity in one call.
Inputs: no named parameters. Returns: object
get_accountsA
List your Toss Securities accounts (계좌 목록 조회).
Returns each account's accountSeq, which the other account tools (get_holdings, get_buying_power, get_commissions, get_sellable_quantity) require as their account_seq argument.
Inputs: no named parameters. Returns: object
get_buying_powerA
Get cash buying power for one account. (매수가능금액 조회, read-only)
Args: account_seq: The numeric accountSeq returned by get_accounts(). currency: 'KRW' or 'USD'.
Inputs: account_seq (required), currency. Returns: object
get_candlesA
Get OHLCV candle-chart data for a single symbol. (캔들 차트 조회)
Args: symbol: A single ticker symbol, no market prefix, e.g. '005930' (KRX) or 'AAPL' (US). Only one symbol is accepted per call. interval: Candle interval: '1m' (1-minute) or '1d' (daily). count: Number of candles to return, between 1 and 200. before: Optional cursor (from a previous response's 'nextBefore') to page further back in time. Omit for the most recent candles. adjusted: Whether prices should be adjusted for splits/dividends.
Inputs: symbol (required), count, before, adjusted, +1 more. Returns: object
get_channel_infoA
Get title, description/about, member count, type, and username for a chat.
chat may be a @username, a numeric/marked (-100...) chat ID from list_dialogs,
or (best-effort) a chat title. If resolution by ID fails on a fresh session, call
list_dialogs first to warm the client's entity cache, then retry.
Inputs: chat (required). Returns: object
get_commissionsA
Get your brokerage commission rates by market. (매매 수수료 조회, read-only)
Args: account_seq: The numeric accountSeq returned by get_accounts().
Inputs: account_seq (required). Returns: object
get_company_profileB
Get official company information from Open DART.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380.
Inputs: corp_code (required). Returns: object
get_company_profile_by_queryA
Find a listed company and return its DART company profile.
Args: query: Exact company name, six-digit stock code, or eight-digit DART corporation code.
Inputs: query (required). Returns: object
get_current_priceA
Get the current (last-traded) price for one or more symbols. (현재가 조회)
Args: symbols: Comma-separated ticker symbols, up to 200. No market prefix. Examples: '005930,000660' (KRX) or 'AAPL,MSFT' (US).
Inputs: symbols (required). Returns: object
get_disclosure_document_textA
Get the plain-text content of one DART disclosure document.
Downloads the original filing (원문) for a receipt number and strips HTML markup, so the content can be read directly. Useful for reading the details of any filing found via search_disclosures.
Args: rcept_no: The 14-digit disclosure receipt number (접수번호), as returned by search_disclosures or other DART tools.
Inputs: rcept_no (required). Returns: object
get_dividend_infoA
Get dividend-related figures (배당에 관한 사항) across a range of years.
Uses Open DART's 배당에 관한 사항 endpoint, which reports per-share face value, net income, earnings per share, total cash/stock dividend amounts, dividend payout ratio, dividend yield, and dividend per share for the current period and the two prior periods.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380. start_year: First business year to fetch (four digits), e.g. 2021. end_year: Last business year to fetch (four digits), e.g. 2023. report_type: "annual" (사업보고서), "half" (반기보고서), "q1" (1분기보고서), "q3" (3분기보고서), or "all" to fetch all four report types for each year.
Inputs: end_year (required), corp_code (required), start_year (required), report_type. Returns: object
get_exchange_rateA
Get the exchange rate between two currencies. (환율 조회)
Args: base_currency: 'KRW' or 'USD'. quote_currency: 'KRW' or 'USD'. date_time: Optional ISO 8601 timestamp for a historical rate. Omit for the latest rate.
Inputs: date_time, base_currency, quote_currency. Returns: object
get_executive_ownership_reportsA
Get executive/major-shareholder stock ownership reports (임원ㆍ주요주주 소유보고).
Uses Open DART's 임원ㆍ주요주주 소유보고 endpoint, which lists ownership reports filed by company executives and major (10%+) shareholders whenever their holdings change. DART returns this endpoint's full filing history in one call with no date parameter of its own, so date filtering and the result limit are both applied here after fetching. Active large-cap companies can have thousands of these filings, so the default limit keeps a call without a date range from returning all of them at once.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380. start_date: Optional start of a filing-date range, as YYYYMMDD or YYYY-MM-DD. When omitted, defaults to roughly the last 3 months (90 days), since this endpoint covers frequent, routine insider-ownership filings. end_date: Optional end of a filing-date range, as YYYYMMDD or YYYY-MM-DD. When omitted, defaults to today (or completes a roughly three-month window when only end_date is supplied). limit: Maximum number of filings to return, most recent first (default 50, max 200). Narrow the date range to see more than the most recent filings.
Inputs: corp_code (required), limit, end_date, start_date. Returns: object
get_financial_statementsA
Get key financial-statement accounts for a company across a range of years.
Uses Open DART's key-accounts endpoint (주요계정), which returns core figures such as total assets, total liabilities, total equity, revenue, operating profit, and net income, for both consolidated (CFS) and separate (OFS) financial statements.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380. start_year: First business year to fetch (four digits), e.g. 2021. end_year: Last business year to fetch (four digits), e.g. 2023. report_type: "annual" (사업보고서), "half" (반기보고서), "q1" (1분기보고서), "q3" (3분기보고서), or "all" to fetch all four report types for each year.
Inputs: end_year (required), corp_code (required), start_year (required), report_type. Returns: object
get_full_financial_statementA
Get the complete financial statement (every line item) for one period.
Uses Open DART's full-statement endpoint (전체 재무제표), which returns every line item in the balance sheet, income statement, and other statements for a single business year and report type.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380. year: Business year to fetch (four digits), e.g. 2023. report_type: "annual" (사업보고서), "half" (반기보고서), "q1" (1분기보고서), or "q3" (3분기보고서). fs_div: "CFS" for consolidated financial statements (연결재무제표, default) or "OFS" for separate financial statements (별도/개별 재무제표).
Inputs: year (required), corp_code (required), fs_div, report_type. Returns: object
get_holdingsA
Get portfolio summary and per-symbol positions for one account. (보유자산 조회, read-only)
Args: account_seq: The numeric accountSeq returned by get_accounts().
Inputs: account_seq (required). Returns: object
get_major_holding_reportsA
Get 5%-rule major shareholding disclosure reports (대량보유 상황보고).
Uses Open DART's 대량보유 상황보고 endpoint, which lists every report filed under the "5% rule" whenever an investor's holding in the company crosses a disclosure threshold. DART returns this endpoint's full filing history in one call with no date parameter of its own, so date filtering and the result limit are both applied here after fetching.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380. start_date: Optional start of a filing-date range, as YYYYMMDD or YYYY-MM-DD. When omitted, defaults to roughly the last year (365 days), since 대량보유 filings are relatively infrequent 5%-rule events. end_date: Optional end of a filing-date range, as YYYYMMDD or YYYY-MM-DD. When omitted, defaults to today (or completes a roughly one-year window when only end_date is supplied). limit: Maximum number of filings to return, most recent first (default 50, max 200). Without start_date/end_date, this is what keeps a very active filer from returning thousands of rows in one call — narrow the date range to see more.
Inputs: corp_code (required), limit, end_date, start_date. Returns: object
get_market_calendarA
Get market session times (pre/regular/after-market) around a given date. (장 운영 정보 조회)
Args: market: 'KR' (Korean exchanges) or 'US' (US exchanges). date: Optional date (YYYY-MM-DD) to center the lookup on. Omit for today.
Inputs: date, market. Returns: object
get_messagesA
Get up to 200 recent messages from one chat, newest first.
chat: @username, numeric/marked chat ID (see get_channel_info for resolution
notes), or title. since_date: optional cutoff, ISO 8601 (e.g. "2026-08-01" or
"2026-08-01T00:00:00+09:00"); results default to the last 7 days when it is
omitted. Pass an explicit date to look further back; a very old date effectively
means all history. A value with no timezone is treated as UTC.
offset_id: only return messages with an ID strictly below this one, useful for
paging backward through history. Returns each message's id, ISO date, sender
name/id, text, has_media, and media_type.
Inputs: chat (required), limit, offset_id, since_date. Returns: result
get_orderB
Get all available details for one order, including execution information.
Inputs: order_id (required), account_seq (required). Returns: object
get_orderbookA
Get the current bid/ask order book for a single symbol. (호가 조회)
Args: symbol: A single ticker symbol, no market prefix, e.g. '005930' (KRX) or 'AAPL' (US). Only one symbol is accepted per call.
Inputs: symbol (required). Returns: object
get_ordersC
List orders using the spec's status, symbol, from, to, cursor and limit filters.
Inputs: status (required), account_seq (required), limit, cursor, +3 more. Returns: object
get_price_limitsA
Get today's upper/lower price limits for a single symbol. (상한가/하한가 조회)
Args: symbol: A single ticker symbol, no market prefix, e.g. '005930'.
Inputs: symbol (required). Returns: object
get_recent_tradesA
Get the most recent executed trades (체결) for a single symbol.
Args: symbol: A single ticker symbol, no market prefix, e.g. '005930' (KRX) or 'AAPL' (US). Only one symbol is accepted per call. count: Number of recent trades to return, between 1 and 50.
Inputs: symbol (required), count. Returns: object
get_sales_contract_disclosuresA
Get single sale/supply contract disclosures (단일판매ㆍ공급계약체결).
Finds every 단일판매ㆍ공급계약체결 filing for a company in a date range and reads each one to extract the contract amount, the contract period (start/end dates), the counterparty, and related details — useful for tracking order backlog (수주잔고) from disclosed sales contracts. This disclosure type has no structured JSON API in Open DART, so each filing's original document is downloaded and parsed.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380. start_date: Start of the search range (filing date), as YYYYMMDD or YYYY-MM-DD. end_date: End of the search range (filing date), as YYYYMMDD or YYYY-MM-DD.
Inputs: end_date (required), corp_code (required), start_date (required). Returns: object
get_sellable_quantityA
Get how many shares of a symbol can currently be sold from one account. (판매가능수량 조회, read-only)
Args: account_seq: The numeric accountSeq returned by get_accounts(). symbol: A single ticker symbol, no market prefix, e.g. '005930'.
Inputs: symbol (required), account_seq (required). Returns: object
get_stock_infoA
Look up basic info (name, market, currency, status, shares outstanding...) for symbols.
Args: symbols: Comma-separated ticker symbols, up to 200. No market prefix. Examples: '005930' (Samsung Electronics, KRX), '005930,AAPL'.
Inputs: symbols (required). Returns: object
get_stock_warningsA
Get investment-caution flags for a single KRX symbol (매수 유의사항, e.g. 관리종목/VI 등).
Args: symbol: A single ticker symbol, no market prefix, e.g. '005930'.
Inputs: symbol (required). Returns: object
list_dialogsA
List Telegram dialogs. chat_type filters to all, channel, group (including supergroups), or user.
Inputs: chat_type. Returns: result
modify_orderA
Modify a live pending order; requires confirm=True before submission.
symbol is required to determine the market. US-market modifications
support changing price only; changing quantity requires canceling and
placing a new order instead.
Toss appears to allow KR-market modifications to decrease or keep the same quantity, but not increase it; increasing quantity requires canceling the order and placing a new one instead.
A modification does not edit an order in place. Toss replaces it with a
new live order under a new ID, and the original order_id becomes
inactive with status REPLACED immediately after a successful
modification. The caller MUST use the returned new_order_id for any
further operations on this order, including checking status, canceling,
or modifying it again. Reusing the original order_id fails with HTTP
409 already-modified.
Inputs: symbol (required), order_id (required), order_type (required), account_seq (required), +4 more. Returns: object
place_orderB
Submit a live quantity- or amount-based stock order.
The API wire fields are symbol, side, orderType, timeInForce, quantity, price, orderAmount, clientOrderId, and confirmHighValueOrder. Quantity and orderAmount are mutually exclusive; orderAmount is for US MARKET orders.
Inputs: side (required), symbol (required), order_type (required), account_seq (required), +7 more. Returns: object
search_companyA
Search DART companies by company name, stock code, or corp code.
Args: query: A company name, six-digit stock code, or eight-digit DART corporation code. Examples: 삼성전자, 005930, 00126380. listed_only: When true, return only companies with a stock code. limit: Maximum number of results, between 1 and 50.
Inputs: query (required), limit, listed_only. Returns: object
search_disclosuresA
Search DART disclosure filings (공시검색) within a date range.
Uses Open DART's general disclosure search endpoint. Returns filing metadata (title, date, receipt number) only; use get_disclosure_document_text with a result's receipt_no to read a specific filing's content.
Args: corp_code: The company's eight-digit Open DART corporation code. Samsung Electronics is 00126380. start_date: Start of the search range, as YYYYMMDD or YYYY-MM-DD. end_date: End of the search range, as YYYYMMDD or YYYY-MM-DD. pblntf_ty: Optional disclosure category to filter by: "A" (정기공시), "B" (주요사항보고), "C" (발행공시), "D" (지분공시), "E" (기타공시), "F" (외부감사관련), "G" (펀드공시), "H" (자산유동화), "I" (거래소공시), or "J" (공정위공시). keyword: Optional substring to match against each filing's report title (report_nm), applied after fetching from DART since the API itself has no title-search parameter.
Inputs: end_date (required), corp_code (required), start_date (required), keyword, +1 more. Returns: object
search_filesA
Find messages carrying files, globally or in one chat.
file_type: "document" (general files/PDFs), "photo", "video", "audio" (Telegram
music/audio files only — voice notes and video notes are excluded), or "any".
since_date: optional ISO 8601 cutoff (e.g. "2026-01-01"). Results default to
the last 7 days when omitted. Pass an explicit date to look further back; a very
old date effectively means all history. A value with no timezone is treated as UTC.
Same global-search caveat as search_messages: results are scanned dialog-by-dialog,
not ranked account-wide. Returns per match: message id, chat id/title, date,
filename, mime_type, size_bytes, caption, sender_name, media_type.
Inputs: chat, limit, query, file_type, +1 more. Returns: result
search_messagesA
Search message text globally or in one chat; omit chat for a global search.
since_date: optional ISO 8601 cutoff (e.g. "2026-01-01"). Results default to
the last 7 days when omitted. Pass an explicit date to look further back; a very
old date effectively means all history. A value with no timezone is treated as UTC.
Global search (no chat) scans dialogs one at a time and stops once limit
results are collected, so results favor whichever dialogs are scanned first
rather than being ranked by relevance or recency across the whole account.
Inputs: query (required), chat, limit, since_date. Returns: result
telegram_test_connectionA
Check that Telegram credentials are present, the StringSession connects, and the account is authorized.
Inputs: no named parameters. Returns: object
toss_test_connectionC
Return a message to verify that the MCP server process is working.
Inputs: message (required). Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 46 tools
Most tools have distinct purposes, but several overlaps create ambiguity: multiple connection/credential checks (dart_test_connection, check_dart_api_key, finance_test_connection), two company-profile tools (get_company_profile vs get_company_profile_by_query), and two financial-statement tools (get_financial_statements vs get_full_financial_statement). Detailed descriptions help, but an agent could easily pick the wrong one based on name alone.
Most tools follow a readable get_/search_/check_/place_/cancel_/modify_ pattern, but there are minor inconsistencies: connection checks mix test_connection, check_*_api_key, and check_*_credentials; get_financial_statements vs get_full_financial_statement uses awkward singular/plural variation; Telegram tools use list_dialogs instead of get_dialogs.
46 tools is far beyond the 3-15 well-scoped range, and the count is inflated by redundant health-check/credential tools and by bundling three unrelated integrations (DART, Toss, Telegram) into one server. It is not an extreme 50+ count, but it is too heavy for a coherent single-purpose surface.
Within each bundled domain, coverage is reasonably complete: DART covers company search, financials, shareholder data, and disclosures; Toss covers quotes, orders, and accounts; Telegram covers listing chats, reading/searching messages, and downloading files. Minor gaps like no send_message and no broader historical order report exist, but agents can work around them.
Maintenance
Related MCP Connectors
Trading MCP server for AI agents, with live market data, account reads and controlled execution.
Research-only MCP server: your AI as a quant research desk. 90 tools, no trades, no brokers.
The Octagon MCP server provides specialized AI-powered financial research and analysis by integrating with the Octagon Market Intelligence API. It enables users to analyze public market data (SEC filings, earnings transcripts, financial metrics, and stock data for 8000+ companies), private market data (3M+ companies, 500k+ funding rounds, 2M+ M&A/IPO transactions), and conduct deep research including web scraping capabilities. The server also features autonomous research agents that search hundreds of sources and return fully cited reports in approximately one minute.
Official Intrinio MCP server. US stock prices, options and fundamentals for AI agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server wrapping Toss Securities Open API, enabling stock price queries and trading for Korean and US stocks via natural language.3649 npmMIT
- FlicenseNot gradedqualityDmaintenanceMCP server that searches and filters DART electronic disclosures for Korean companies, enabling AI agents to create investor briefing summaries.-
- AlicenseNot gradedqualityBmaintenanceRead-only MCP server that connects LLMs to personal investment accounts (Toss Securities, KIS), market data, SEC filings, and Binance futures for context-aware investment responses.1MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that retrieves Korean stock fundamentals and financial data from OpenDART, enabling LLMs to access corporate disclosures, financial statements, and dividend information.Apache 2.0