mcp-dart
Provides tools for discovering, downloading, parsing, and searching Korean DART financial reports, enabling AI assistants to access Open DART data through structured tools.
README
AgentLadle MCP DART
English | δΈζ
π¨π³ China A-Share Market β Cloud-hosted MCP for Shanghai & Shenzhen listed companies. Read more | Get API Key
A MCP (Model Context Protocol) server that provides tools for discovering, downloading, parsing, and searching Korean DART financial reports (κΈμ΅κ°λ μ μ μ곡μμμ€ν ).
It enables AI assistants (Claude, Cursor, etc.) to access Korea's Open DART data through 6 structured tools β from resolving a company name to keyword-searching within report pages.
Features
- 6 MCP tools for DART data: resolve company name, list filings, download+parse, get TOC, read pages, keyword search
- Full μ 기곡μ financial report support β A001 μ¬μ
λ³΄κ³ μ (annual), A002 λ°κΈ°λ³΄κ³ μ (semi-annual), A003 λΆκΈ°λ³΄κ³ μ (quarterly), each with a dedicated
toc.yamlsection mapping derived from real DART XML - Auto-detecting multi-format parser β structured SECTION-N XML (A/B/D/E types) routes to the section-tree parser (
toc.yamlwhen available, generic tree extraction otherwise); HTML single-page disclosures (I001 μμ곡μ, I002 곡μ 곡μ/μ μ μ€μ ) route to the HTML extraction parser. Format is detected by file content, not hardcoded by type. - Professional DART document parsing β direct XML path extraction (
./P,./TABLE) and standard TOC alignment (A001: 123 codes / 110 leaves; A002: 53 codes / 43 leaves; A003: 59 codes / 48 leaves) - η« θζ + θε ιι‘΅ pagination model β pages respect DART's standard section tree (precision over fixed 4000-char chunking)
- Korean-aware search β substring matching (no
\bword boundaries), character-count TF normalization, morphological-variant hints - Three-tier local cache β ZIP archives, extracted XML, and parsed JSON stored separately under
~/.agentladle/mcp-dart/data/{zip,xml,json}/ - Idempotent β already-downloaded/parsed filings are automatically skipped
- Pure Python, cross-platform (Windows / macOS / Linux)
Prerequisites
- Python 3.10+ β Download Python
- uv β Install uv
- DART API key (free) β register at https://opendart.fss.or.kr/
Note: After installing uv, restart your terminal and MCP client (e.g. Cherry Studio) to ensure the
uvcommand is recognized.
Quick Start
Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"mcp-dart": {
"command": "uvx",
"args": ["agentladle-mcp-dart"],
"env": {
"DART_API_KEY": "your_dart_api_key_here",
"UV_HTTP_TIMEOUT": "300"
}
}
}
}
That's it. uvx will automatically download the package and its dependencies from PyPI β no clone, no manual install, no path configuration.
Slow network? The first
uvxrun downloads many dependencies (includingdart-fss,pandas, etc.). The default 30s timeout may be too short and cause MCPConnection closed. SetUV_HTTP_TIMEOUTto"300"to avoid download timeouts. If it still fails, use the pip install alternative below.
Alternative: .env file
If you prefer not to inject the key via the MCP client env block, copy .env.example to one of:
./.env(per-project override; git-ignored β never commit a real key)~/.agentladle/mcp-dart/.env(user-global default)
and set:
DART_API_KEY=your_dart_api_key_here
The first existing .env wins; explicit env vars set in the MCP client always override .env. See .env.example for details.
Alternative: pip install
If you prefer managing the environment yourself:
pip install agentladle-mcp-dart
Then configure (no need for uvx):
{
"mcpServers": {
"mcp-dart": {
"command": "agentladle-mcp-dart",
"env": { "DART_API_KEY": "your_dart_api_key_here" }
}
}
}
Alternative: Run from source (local development)
Clone the repository and run directly:
git clone https://github.com/agentladle/mcp-dart.git
Then configure your MCP client:
{
"mcpServers": {
"mcp-dart": {
"command": "uv",
"args": ["run", "--directory", "/path/to/mcp-dart", "agentladle-mcp-dart"],
"env": { "DART_API_KEY": "your_dart_api_key_here" }
}
}
}
Replace /path/to/mcp-dart with the actual path to the cloned repository.
Data Flow
DART OpenAPI Local Files (~/.agentladle/mcp-dart/data/)
ββββββββββββ ββββββββββββββββββββββββββββββββββββββββββ
corp_list (dart-fss) βββ corp_list.csv (CSV cache, ~114k corps)
search_dart_company βββ corp_list.csv lookup (Tool 6: name β stock_code)
β
search_filings API βββ zip/{rcept_no}.zip (Tool 2: download)
β
ZIP extraction βββ xml/{rcept_no}/*.xml (Tool 2: extract)
β
dart_parsers + toc.yaml βββ json/{stock_code}_{rcept_no}.json (Tool 2: parse)
β
Local TF search βββ search results (Tool 5: keyword_search)
TOC (section_tree) βββ section_tree + page ranges (Tool 3: get_report_toc)
Page range read βββ page content (Tool 4: get_report_pages)
Tools
| # | Tool | Description |
|---|---|---|
| 1 | list_dart_filings |
List DART filings for a Korean company by stock code (returns rcept_no) |
| 2 | download_dart_report |
Download a DART filing ZIP and parse it into a section-tree JSON cache |
| 3 | get_report_toc |
Get the section_tree (TOC) with page ranges β derived from toc.yaml, not heuristic |
| 4 | get_report_pages |
Read pages by global page number or by section_code |
| 5 | keyword_search |
Korean substring full-text search with character-count TF + position boost |
| 6 | search_dart_company |
Resolve a company name (Korean/English) to stock_code / corp_code via the local corp_list.csv cache |
Tool 1: list_dart_filings
List available DART filings for a Korean listed company.
| Parameter | Type | Required | Description |
|---|---|---|---|
stock_code |
string | β | 6-digit Korean stock code, e.g. "005930" (Samsung Electronics) |
bgn_de |
string | β | Start date YYYYMMDD (default: 20150101) |
end_de |
string | β | End date YYYYMMDD (default: today) |
report_types |
string[] | β | DART detail types to filter (default: ["A001","A002","A003"] β μ¬μ
/λ°κΈ°/λΆκΈ°λ³΄κ³ μ) |
limit |
int | β | Max filings to return (default 20, max 100) |
Returns each filing's rcept_no, rcept_dt, report_nm, corp_code, report_type, and a parseable flag (true for any valid DART type β the parser auto-detects document format at parse time).
Tool 2: download_dart_report
Download and parse a single DART filing. Fuses the SEC flow's download + parse into one step. Idempotent (skips if cached and valid).
| Parameter | Type | Required | Description |
|---|---|---|---|
rcept_no |
string | β | 14-digit DART receipt number (from list_dart_filings) |
stock_code |
string | β | 6-digit stock code for the JSON filename ({stock_code}_{rcept_no}.json); when omitted, caches as {rcept_no}.json β lookup still works via rcept_no |
rcept_dt |
string | β | Receipt date YYYYMMDD (informational) |
report_type |
string | β | DART detail type, default "A001". Any valid type from types.yaml accepted; parser auto-detects document format (section-tree XML for A/B/D/E, HTML for I001/I002). |
force_parse |
bool | β | Re-parse even if cached JSON exists |
Tool 3: get_report_toc
Retrieve the complete DART section_tree (Table of Contents) for a parsed report. Built directly from toc.yaml aligned with the parsed XML β page ranges are authoritative, not heuristic.
| Parameter | Type | Required | Description |
|---|---|---|---|
rcept_no |
string | β | 14-digit DART receipt number |
stock_code |
string | β | Stock code (improves cache lookup) |
Each node has section_code, title, start_page, end_page, local_pages, matched (bool β whether XML matched this toc entry), and children. Pass any section_code to Tool 4's section_code parameter to read that whole subtree.
Tool 4: get_report_pages
Read full page content by global page range or by section_code.
| Parameter | Type | Required | Description |
|---|---|---|---|
rcept_no |
string | β | 14-digit DART receipt number |
start_page |
int | β | Start page (1-based); default 1; ignored if section_code set |
page_count |
int | β | Pages to return (default 3, max 10). Ignored when end_page is positive. |
end_page |
int | β | Inclusive end page (e.g. start_page=12, end_page=14). 0 = unset. |
section_code |
string | β | DART section code (e.g. "020100"); overrides page-range args, returns whole subtree |
stock_code |
string | β | Stock code (cache lookup aid) |
Tool 5: keyword_search
Korean-friendly full-text search. Scoring:
- TF = substring count / non-whitespace character count (Korean has no whitespace-delimited words)
- Position boost Γ1.2 if first hit is in the top 20% of the page
- ALL match mode applies Γ2.0 bonus when every keyword hits
| Parameter | Type | Required | Description |
|---|---|---|---|
rcept_no |
string | β | 14-digit DART receipt number |
keywords |
string[] | β | 1β5 Korean (or ASCII) keywords; pass morphological variants like ["λ§€μΆ", "λ§€μΆμ‘"] |
match_mode |
string | β | "ANY" (default) or "ALL" |
max_results |
int | β | Max matches (default 5, max 50) |
stock_code |
string | β | Stock code (cache lookup aid) |
Each match returns page_number, score, keyword_hits, snippet (highlighted with **...**), and the section context (section_code/section_title).
Tool 6: search_dart_company
Resolve a company name (Korean or English) to a stock_code / corp_code. Queries the locally cached corp_list.csv (no network call after first preheat). Use this before list_dart_filings / download_dart_report whenever the user mentions a company by name but does not provide a 6-digit stock_code.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | β | Company name (Korean corp_name or English corp_eng_name), e.g. "μΌμ±μ μ" or "Samsung" |
exact |
bool | β | true = exact name match; false (default) = case-insensitive substring contains |
limit |
int | β | Max matches (default 20, max 50) |
include_delisting |
bool | β | true = also return delisted / non-listed companies; false (default) = only listed companies with a 6-digit stock_code |
Each match contains corp_name, corp_eng_name, stock_code, corp_code, modify_date. When multiple matches are returned, pick the correct stock_code and pass it to list_dart_filings.
Configuration
After first run, a default config file is created at ~/.agentladle/mcp-dart/config.yaml:
dart:
api_key: ""
paths:
data_dir: "~/.agentladle/mcp-dart/data"
zip_dir: "~/.agentladle/mcp-dart/data/zip"
xml_dir: "~/.agentladle/mcp-dart/data/xml"
json_dir: "~/.agentladle/mcp-dart/data/json"
parsing:
page_char_limit: 4000
max_pages_per_section: 10 # soft target (precision preserved on overflow)
download:
delay_between_requests: 0.2
DART_API_KEY resolution priority (highest to lowest):
- Real OS environment variable (
DART_API_KEY=xxx uvx agentladle-mcp-dart) .envfile β./.envfirst, then~/.agentladle/mcp-dart/.envdart.api_keyin~/.agentladle/mcp-dart/config.yaml
Data Directory Structure
~/.agentladle/mcp-dart/
βββ .env # Optional user-global API key (git-ignored)
βββ config.yaml # Configuration (auto-created)
βββ data/
βββ corp_list.csv # ~114k Korean companies (CSV cache, dart-fss)
βββ zip/
β βββ {rcept_no}.zip # Original DART archive (retained after download)
βββ xml/
β βββ {rcept_no}/ # Extracted XML per filing
β βββ {rcept_no}.xml # Main DART XML
β βββ {rcept_no}_NNNNN.xml # Optional attachments
βββ json/
βββ {stock_code}_{rcept_no}.json # Parsed section_tree + pages + coverage
File naming convention: {stock_code}_{rcept_no}.json when stock_code is known; {rcept_no}.json when stock_code was omitted at download time. find_json_file also falls back to *_{rcept_no}.json glob and legacy raw/ / xml/ co-located layouts.
Example Usage
The tools follow an EAFP (Easier to Ask for Forgiveness than Permission) approach. AI assistants should attempt to read/search directly and rely on errors to trigger downloads.
Scenario A: File already exists locally (Shortest Path)
User: "Analyze Samsung's latest financial report."
1. keyword_search(rcept_no="<rcept_no>", keywords=["λ§€μΆ", "λ§€μΆμ‘", "μμ
μ΄μ΅"])
β Returns page snippets matching the keywords immediately.
Scenario B: File missing (Fallback triggered)
User: "What does LG Energy Solution's latest annual report say about R&D?"
1. keyword_search(rcept_no="<rcept_no>", keywords=["μ°κ΅¬κ°λ°", "R&D"])
β Error: Parsed report not found.
2. list_dart_filings(stock_code="373220", report_types=["A001"])
β Returns the correct rcept_no.
3. download_dart_report(rcept_no="<rcept_no>")
β Downloads ZIP, extracts XMLs, parses to JSON cache.
4. keyword_search(rcept_no="<rcept_no>", keywords=["μ°κ΅¬κ°λ°", "R&D"])
β Now returns hits with section context.
Scenario C: Latest ad-hoc disclosure (Samsung earnings guidance / μ μ μ€μ )
User: "Analyze Samsung's latest earnings guidance."
1. list_dart_filings(stock_code="005930", report_types=["I002"], limit=1)
β Returns the latest 곡μ 곡μ (e.g. μ μ μ€μ / provisional earnings).
2. download_dart_report(rcept_no="<rcept_no>", stock_code="005930", report_type="I002")
β Parses the HTML single-page disclosure.
3. keyword_search(rcept_no="<rcept_no>", keywords=["λ§€μΆ", "μμ
μ΄μ΅", "μ€μ "])
β AI summarizes revenue, operating profit, and YoY change.
Tech Stack
| Component | Choice | Purpose |
|---|---|---|
| MCP Framework | mcp (FastMCP) |
MCP server with stdio transport |
| API / Download | dart-fss (MIT) |
DART auth, corp list, ZIP download |
| XML Parsing | lxml |
Core parser engine |
| Structured Data | pandas |
corp_list CSV cache (dart-fss dependency) |
| TOC / Format Config | pyyaml |
toc.yaml / types.yaml / formats.yaml loaders |
| Search | Python built-in | Character-count TF + position boost |
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.