Skip to main content

MCP server for Korean DART financial report download, parsing and search

Project description

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.yaml section 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.yaml when 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 \b word 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

Note: After installing uv, restart your terminal and MCP client (e.g. Cherry Studio) to ensure the uv command 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"
      }
    }
  }
}

That's it. uvx will automatically download the package and its dependencies from PyPI โ€” no clone, no manual install, no path configuration.

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):

  1. Real OS environment variable (DART_API_KEY=xxx uvx agentladle-mcp-dart)
  2. .env file โ€” ./.env first, then ~/.agentladle/mcp-dart/.env
  3. dart.api_key in ~/.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.

Scenario D: Company name only (no stock code)

User: "What does Samsung Electronics' latest annual report say about revenue?"

1. search_dart_company(query="์‚ผ์„ฑ์ „์ž", exact=True)
   โ†’ Returns stock_code "005930".
2. list_dart_filings(stock_code="005930", report_types=["A001"], limit=1)
   โ†’ Returns the latest rcept_no.
3. download_dart_report(rcept_no="<rcept_no>", stock_code="005930")
   โ†’ Downloads ZIP โ†’ xml/, parses to json/.
4. keyword_search(rcept_no="<rcept_no>", keywords=["๋งค์ถœ", "๋งค์ถœ์•ก"])
   โ†’ Returns revenue-related snippets.

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentladle_mcp_dart-1.0.0-py3-none-any.whl (66.5 kB view details)

Uploaded Python 3

File details

Details for the file agentladle_mcp_dart-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for agentladle_mcp_dart-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 88936168665c7c3dedab55a77de45873e1cd016700f8cd5b84e2355d901f9b8f
MD5 6a111ae451c2250c2fa728db1deb8ec9
BLAKE2b-256 600c722031993992d2325f2fd41e004aced8bbb875bb1861b45dd6f9d1457fff

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page