Skip to main content
Glama
mkkim2102

finance-mcp-server

by mkkim2102
README.md
# Finance MCP Server

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

[한국어 버전](https://github.com/mkkim2102/finance-mcp-server-ko)

A personal finance research and execution toolkit for LLM agents, built as one
[MCP](https://modelcontextprotocol.io) 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.

## 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 data
```

The 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](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.

```sh
# 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.py
```

### Registering with an MCP client

```json
{
  "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](USAGE.md) — full setup per source, complete tool catalog, worked examples
- [DESIGN.md](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

[MIT](LICENSE)

TDQS

B3.4/5.0

Scored across 46 tools

Disambiguation3/5

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.

Naming Consistency4/5

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.

Tool Count2/5

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.

Completeness4/5

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

ActivitySlowing
ResponsivenessNo issues