Skip to content
Korean Law MCP logo

Korean Law MCP

By chrisryugj·2,726

Korean law: statutes, precedents, ordinances, treaties and citation verification (법제처 API).

Korean Law MCP

42 APIs compressed into 10 tools. Search, retrieve, and analyze Korean law — statutes, precedents, ordinances, treaties + LLM hallucination guard for legal citations (statutes and precedents, existence + content) + precedent citator (cite_check) + point-in-time law resolution (applicable_law) + ordinance revision radar (ordinance_radar) + successor lookup for repealed statutes.

npm version
MCP 1.27
License: MIT
TypeScript

조코헌트 주간 1등 Top 1 위너

MCP server + CLI for Korea's official legal database (법제처 Open API). Works with Claude Desktop, Cursor, Windsurf, Zed, and any MCP-compatible client.

한국어

Start in one line: add https://mcp.gomdori.app/law?oc=YOUR_KEY as a custom connector in Claude.ai, or run npx --ignore-scripts --omit=optional korean-law-mcp setup → Quick Start

If this saves you time, a GitHub ⭐ helps others find it.

Korean Law MCP — watch the demo

▶ Click to play on YouTube. Narration is in Korean.

Connect it to your AI

Connect to Claude Connect to ChatGPT
Connect to Claude Connect to ChatGPT

v4.15.9: Labor administration decisions

  • search_decisions and get_decision_text add Ministry of Employment and Labor interpretations (moel), Industrial Accident Compensation Insurance review decisions (iaciac) and Employment Insurance review decisions (eiac). Contributed by @adfakdjk332 (#175). Changelog

v4.15.8: Addenda lookup

  • get_law_text(mst, jo="부칙") returns the addenda (effective dates, transitional provisions), newest first — e.g. the Constitution's addendum Articles 1–6. The table of contents and full text now end with the addenda count. Changelog

v4.15.7: Month-end dates and eight-digit case numbers

  • Fixed 지난달, N개월 전, and 최근 N개월 selecting the wrong month at month end (on March 30, "지난달" now means February)
  • Fixed eight-digit case serials being dropped from citation verification and nine-digit serials being truncated into a different case. Changelog, issues #169 and #170

v4.15.6: Precedent body-search option

  • Added search="both" for precedent search: runs title and full-text search together, dedupes by precedent ID, and labels which search matched each hit. search_decisions(domain="precedent", options={search:"both"})
  • When a title search ends with 3 or fewer hits, the output suggests a full-text re-search (measured: "학원강사 근로자" 1 title hit vs 70 full-text hits)
  • Fixed string search:"2" passed via options being treated as a title search. Default behavior unchanged. Changelog, issue #167

v4.15.5: Retrieval and verification boundaries

  • Fixed missing precedent bodies, cancelled cache reads, and statute/branch boundaries in article ranges
  • Included spaced case numbers in citation verification and corrected article-code handoffs and keyword extraction
  • Fixed decision compaction/legal grounds, law hierarchy/sample labels, and daily-law/term rendering
  • Prevented historical-slice substitution and strengthened MCP/CLI key masking and CLI argument limits
  • Reviewed all features again. No new features or dependency changes. Changelog, review evidence

v4.15.4: Full feature review and fixes

  • Corrected case-number matching, summary boundaries, article/annex selection, and citation-mode three-tier responses
  • Preserved decision, treaty and English-law fields; marked skipped citations and failed scenario lookups
  • Corrected ordinance dates and parent-law references, and restored risk detection beyond truncated article excerpts
  • Fixed HTTP cancellation/key forwarding, competition research routing, official links and CLI inputs
  • Reviewed all 99 internal tools and 10 exposed tools. No new features or dependency changes. Changelog, review evidence

v4.15.3: Retrieval correctness and performance

  • Exact case-number searches, per-case fallback validation, and explicit unconfirmed status when treatment scanning is disabled
  • A bounded cache of 20 parsed precedent records shared by text retrieval and citation tracking
  • Shared in-progress statute reads within a batch of article requests
  • Total deadlines and cancellation through body reads; corrected annex/article selection and effective-date slice comparisons
  • Patch release with no added features. Changelog, review evidence

v4.15.2: Audit fixes for recent releases

An audit of 4.14.0 to 4.15.1 turned up places that gave silently wrong answers or ran slow. Exposed tools and arguments are unchanged.

  • Next-step hints in tool output now point only at exposed tools (22 hints named tools that are not in the tool list)
  • Precedent text no longer carries raw <br/> tags, and the condensed body no longer cuts in the middle of a date
  • History lookups: admin-rule version on a reference date, the pre-1997 history of laws re-enacted under the same name, and repeal/current labels when a reference date is resolved
  • Chains keep what they received when they hit the time limit; document_review and law statistics now have a time limit too
  • kordoc pinned to 4.18.2, automatic PDF OCR turned off

v4.15.1: Annexes as they look in the original

The annex parser (kordoc 4.17.0) now reads annexes the way they look in the original HWP. 103 of 272 annexes lay out the whole page with
invisible-border frame tables, which used to come out as one giant table. Borderless frames are now plain text, only ruled parts stay tables,
and fractions built from two cells and a rule become $\frac{…}{…}$.

  • Exact-match tables against what the original shows (346 tables): HWP 66 → 346, law.go.kr PDF 56 → 335
  • The get_law_text efYd description now says a reference date (building permit, incident date) resolves to the version in force that day

v4.15.0: Point-in-time lookups that survive law renames

Korean statutes are often renamed (the fire-safety act changed its title three times since 2004). History used to be matched by title, so every version before a rename vanished and applicable_law answered "not yet in force" for a 2015 date. Versions are now chained by the statute ID (eflaw search with LID), in effective-date slices. Still 10 tools; only optional parameters were added.

  • applicable_law resolves former titles (e.g. the 2015 fire-safety decree, 9 → 79 versions in the history list) and warns when a full revision renumbered the articles in between
  • get_annexes takes date and returns the annex of the version in force that day (e.g. installation criteria at building-permit time)
  • applicable_law also handles administrative rules (notices) such as the sprinkler fire-safety standard (NFSC 103 → NFPC 103, one lineage since 2004); NFTC-style section numbers (jo: "2.7.3") work in get_admin_rule
  • get_law_text treats a non-effective efYd (today, an incident date) as a reference date instead of failing
  • verify_citations reports a renamed statute as renamed, not repealed; get_article_history no longer drops changes beyond the first page
  • Default upstream body limits raised to 8/24 MiB (matching the hosted server); repeat annex lookups 2.4s → 0.8s. See CHANGELOG

v4.13.0 — Compliance-register monitoring: 98 calls down to 1-2

Three field reports from running an ISO compliance register (108 laws across 8 domains) against this server:
#157 · #158 · #159 (@thkim660207-cmd). Tests 738 → 758.

  • search_law_bulk: takes an array of law names and returns one compact line each — law_id · MST · effective_date · upcoming.
    Pass previous={law_id: previous_MST} for diff mode: only laws whose MST changed come back, so a full register sweep
    costs one or two calls. The response ends with a snapshot JSON you feed straight into the next run. Amendments that are
    promulgated but not yet in force do not change the current MST, so they are reported separately instead of silently
    reading as "unchanged"
  • Per-article amendment history is now opt-in (includeHistory=true to restore): it used to be dumped from original
    enactment every time, and on the Occupational Safety and Health Act (enacted 1981) that section alone exhausted the
    50k-char response budget — truncating the old-vs-new comparison table people actually needed
  • Image-only annexes now say so: some notices return discharge-limit tables as <img> tags with no text. That used to
    pass through as "has content", which is exactly where a model starts guessing numbers. Now it carries a warning plus the
    source URL and the original attachment (hwpx/pdf) links — which the API was already returning but the code never surfaced

v4.12.0 — 62-issue batch + closing the "it doesn't exist" failure paths

A batch that measured three axes (legal correctness, token efficiency, response latency) and closed 62 filed issues (#88–#149, PR #150 by @humdrum00001010), plus follow-up repairs for 31 defects found in pre-merge domain review. Tests 196 → 701.

The server no longer claims a record is absent when it is merely unreachable. For a legal research tool, the worst failure is not slowness — it is asserting that an existing statute or precedent does not exist.

  • Precedent lookups treated a single empty response right after a 503 or network error as confirmed absence; confirmation is now based on observation history, not attempt count
  • The HTML fallback path declared [NOT_FOUND] for real precedents when it received a maintenance or anti-bot page; it now distinguishes a broken recovery path from a missing record
  • Annex lookups silently turned HTML responses into empty lists and hardened into "not in the 법제처 database"

Requests no longer stall or get dropped whole.

  • Research chains take a 45-second deadline (MCP_CHAIN_DEADLINE_MS) — on expiry they assemble whatever branches returned and ship a partial result, marking the rest. Slow upstreams used to blow past the MCP client timeout (60s) and lose everything
  • Bodies over 2 MiB: 300-second hang → 13 ms explicit error (fixes a v4.11.0 regression)
  • Precedent miss 12.5s → 2.2s; system-tree hit 10.6–11.6s → 6.3–8.3s
  • Routing an 8.5k-character query takes 476 ms; the regex that took up to 45.9s on adversarial input is gone

Citation verification got sharper.

  • verify_citations now covers precedents as well as statutes, separating "cannot exist" from "unverified"
  • impact_map matches the statute name in addition to the article number — 군형법 Article 1 no longer contaminates a 형법 Article 1 query. Undecidable cases are held rather than dropped (including "구 OO법" citations common in constitutional review)
  • cite_check reads holdings that arrive as arrays or objects (previously a silent failure)

Annexes and search. Reaches annexes beyond the 100-item window (verified on 도로교통법 시행규칙: annex 28 of 263), blocks the silent substitution of annex 1 for annex 1의2, and cuts discover_tools responses by 65% with 10/10 correct answers retained.

Two user-visible changes: dates are now formatted 2024.01.05 instead of 2024.1.5. (empty enforcement dates render as N/A), and discover_tools returns a ranked pointer format.

v4.11.0 — Request and release boundary hardening

Closed the structures that let one request amplify into hundreds of upstream calls, or let the server keep working after the client disconnected.

  • Per-request execution budget: retries and anti-bot hops draw from the same budget (MCP_MAX_UPSTREAM_REQUESTS, default 48)
  • Cancellation propagation: HTTP disconnects and MCP cancellations now reach tools, chains, upstream fetches, and backoff waits
  • Packaging verification: artifacts without sources and missing exports targets are blocked before publish

⚠️ Breaking: HTTP bind default 0.0.0.0 → 127.0.0.1; TRUST_PROXY default 1 → false (only integers 1–10 accepted); get_batch_articles input caps (20 statutes, 50 articles each, 100 per request). See the CHANGELOG for migration details.

v4.10.0 — Repealed statutes now point to their successors

Searching for a repealed statute used to return nothing. The server now traces the revision history and reports the repeal reason along with the consolidated successor regulation, for both statutes and administrative rules — so questions about laws that no longer exist don't dead-end.

v4.9.7 — Fixing the 429 storm for shared-key users (token-bucket fallback quota)

Users hitting the public server (mcp.gomdori.app/law) without their own 법제처 key kept getting 429s. The server-key fallback quota is a global limit shared by every keyless user, and it used a fixed window — so once a few callers drained it early in the window, everyone else was blocked for the rest of it. Production measurement (2026-08-12): 2 of every 3 keyless requests were rejected immediately.

  • Replaced with a token bucket (src/lib/rate-limit.ts): continuous refill means a caller gets through seconds after depletion instead of waiting out the window. Same average throughput, bursts absorbed — which matches how MCP clients call several tools per conversation turn
  • Retry-After header + wait seconds in the message: 429 bodies now say retry in Ns, and the IP-limit response is JSON-RPC shaped (the previous plain {error} body could not be parsed by MCP clients)
  • New FALLBACK_DAILY_CAP: caps rolling 24h total usage so the per-minute limit can be relaxed without exposing the server key's upstream quota. 0 disables it (default)
  • Public server settings: per-minute 30 → 120, daily cap 43,200 (the 24h theoretical total of the old 30 rpm) — same total, 4× the burst headroom

Requests that carry their own 법제처 key via the apikey header never hit this gate (free signup: https://open.law.go.kr).

v4.9.0 — Three notations that made citation verification silently skip (current)

When verify_citations is wired into a pipeline as a hallucination gate, the dangerous failure is not "verification failed" but verification never ran. Without a law name it never reaches article-existence checking, yet the output only shows a warning (⚠) — so a fabricated article in the same text still produces no ✗. Users read that as "passed". Three notations, all found via real-world reports:

「노인장기요양보험법」 제38조제1항 및 같은 법 시행규칙 제30조
  ("Article 38(1) of the Long-Term Care Insurance Act and Article 30 of the
    Enforcement Rule of the same Act")

before  ⚠ 0 verified / 2 needs-check — matched only '119 Emergency Report ... Enforcement Rule'
after   ✓ Article 38(1) verified · ✓ Enforcement Rule Article 30 verified
        └ Article 999 in the same text → ✗ NOT_FOUND (range: 1–44) — gate actually fires
  • Extraction failure inside 「…」 (#69, @BW-YU): LAW_NAME_REGEX anchors the law-name ending with $, but the closing bracket left at the end of the lookback blocked the anchor (only trailing whitespace was stripped).
  • Interpunct mismatch (#69, @BW-YU): official statute names use the Hangul interpunct ㆍ(U+318D) while real documents, judgments and LLM output use ·(U+00B7). Now absorbs ·ㆍ‧•・ — unrelated-law blocking (민법→난민법) is unchanged.
  • 같은 법 (same Act) anaphora (#70, @gonnarun): the standard notation in statutes and government forms. Candidate shrinking produced suffix-only candidates (시행규칙) that pull in unrelated statutes, and the preceding law name was never inherited. Now inherited — but not across a blank line, and never without an antecedent: judging on the wrong statute is worse than not judging. With no viable candidate it reports ⚠ law name unclear instead of labelling zero search hits as ✗ NOT_FOUND.

+ v4.8.0 — Five external contributions (#63–#67)

Point-in-time law determination, history parsing, search resolver, retries, repealed-law handling.

v4.7.0 — Ordinance revision radar (ordinance_radar)

"The parent statute changed — is our ordinance stale?" One call answers the question local-government officials chase every year.

  • Automatic basis-law extraction: Parses the ordinance's Article 1 (Purpose) for its statutory basis — the parent act, enforcement decree, and enforcement rules cited in 「」 (including the "같은 법 시행령" shorthand). Scanning only the purpose article avoids false alarms from unrelated statutes cited in annex tables.
  • Revision cross-check: Compares each parent law's current enforcement date against the ordinance's enforcement date and flags "parent law amended after the ordinance took effect → review for revision", with MST identifiers for follow-up.
  • The official ordinance-linkage API (lnkOrd) has poor coverage, so this parses the standard citation format in ordinance text instead.
  • Also in this release: JSON-RPC batch requests now count each tools/call against rate/fallback quotas (amplification fix, per-request cap 20 via MCP_MAX_BATCH_CALLS), clean graceful shutdown, and exact-match-first law resolution in get_article_history.

+ v4.7.1–v4.7.4 — Search accuracy & citation-verification patches

  • v4.7.4: Stop search_law from returning the wrong statute. The common name "인공지능법" isn't a substring of the official title 「인공지능 발전과 신뢰 기반 조성 등에 관한 기본법」, so the LIKE search returned 0 hits and the expanded query ("AI법") got back 50 unrelated statutes with the query ignored. Registers the aliases and adds a hasRelatedHit guard: if no result's title or alias overlaps the query, the response is rejected instead of accepted.
  • v4.7.2: verify_citations degraded to PARTIAL_VERIFIED — and thus missed hallucinations — when a modifier preceded the statute name ("절도죄는 형법 제329조…"). Fixed by retrying findLaws while progressively trimming leading words (#55). Also patches hono (5 HIGH advisories, #54).
  • v4.7.1: legal_research now absorbs a scenario value mistakenly passed as task instead of failing the tool call, and ordinance_radar accepts a query alias (PlayMCP review feedback).

v4.6.0 — Citation verification goes deeper (content) + cloud anti-bot

  • verify_citations content check: Beyond confirming an article exists, it now catches content hallucinations like 민법 제750조(계약해제) — a real article (§750) tagged with the wrong title. It compares the cited article title against the actual one ([CONTENT_MISMATCH]) using LexDiff's citation-content-matcher (normalized common substring + character bigram Jaccard). Same for legal_analysis(mode=verify_citations).
  • law.go.kr JS anti-bot bypass: When 법제처 serves a location.assign JS redirect instead of API data to cloud IPs (GCP/AWS/Fly), the client parses the obfuscated URL and follows the tokenized redirect (up to 3 hops, retrying the original URL on a 404). No-op on local/registered IPs — a defense layer for cloud deployments where Referer injection (v4.0.9) isn't enough.

v4.5.0 — Upcoming-law detection (prevents "renamed law not found" errors)

search_law runs a supplementary target=eflaw (enforcement-date) search and annotates results.

  • Pending rename: e.g. 「데이터기반행정 활성화에 관한 법률」 → 「인공지능 및 데이터 기반 행정 활성화에 관한 법률」 (effective 2026-08-28). Maps old ↔ new titles so searching the new name doesn't return only "no exact match" and mislead the LLM into "the law doesn't exist."
  • Pending amendment: when a current law has an amendment awaiting enforcement, surfaces its enforcement date, promulgation number, and pending-version MST.
  • Not-yet-in-force new law: separately flags promulgated-but-not-yet-effective laws that return 0 hits in a current search (with a no-legal-effect warning).

v4.4.1–4.4.3 — Stability patches

  • v4.4.3: Pin zod to ^4 — fixes a crash where a fresh install resolving zod 3.x threw z.toJSONSchema is not a function on the first listTools call.
  • v4.4.2: Restore get_annexes for administrative-rule tables/forms — parse the admrulbyl key first, auto-detect "...시행세칙", and split table/form collisions that share a bylSeq (#50/#49/#51).
  • v4.4.1: Fix advertised-schema required bug — .default() fields (legal_research.task, search_law.display) were exposed as required inputs (fixed via io:"input"); pass through legal_analysis cost options; warn on incompatible scenarios.

v4.4.0 — Exposed tools consolidated 19 → 9 (52% context reduction)

Shrinks the ListTools payload every MCP client reads per session from ~15.1KB to ~7.2KB.

  • 8 chain_* tools → one legal_research (task param: full_research·law_system·action_basis·dispute_prep·amendment_track·ordinance_compare·procedure_detail·document_review)
  • 4 killer features (verify_citations·cite_check·applicable_law·impact_map) → one legal_analysis (mode param)
  • Backward compatible: direct tool-name calls and execute_tool routing both still work; only the advertised list changes.

What's New in v4.3 — Precedent Citator + Point-in-Time Law

cite_check — "Is this precedent still good law?" (Korean Shepard's)

Give it a case number (e.g. 2007다27670). It back-traces every later decision citing that case via full-text search, deep-scans en banc decisions for overruling language ("…변경하기로 한다"), and tracks alias references like "(이하 '2008년 전원합의체 판결'이라 한다)". Verdict: ✅ still cited / ⚠️ en banc successor exists / ❌ overruling detected — with the exact holding context.

applicable_law — "Which version of the law applies to my case date?"

Give it a statute + a date. It pins the version in force on that date (MST), fetches the article as it read then, diffs against the current text, and extracts transitional provisions (적용례·경과조치) from every later amendment's addenda — plus lex temporis guidance (Criminal Act §1, General Act on Public Administration §14).


v3.5 — Citation Hallucination Guard

Catches fake article citations in AI-generated legal answers in real time. Cross-verifies every citation against Korea's official law database.

"Under Civil Act Article 750, damages may be claimed for tort;
 Labor Standards Act Article 60 Paragraph 1 provides annual leave;
 Commercial Act Article 401-2 Paragraph 7 imposes director liability;
 Criminal Act Article 9999 imposes aggravated punishment."

→ Run verify_citations (actual verification result against 법제처 API):

  • ✓ Civil Act Article 750 (Tort liability) — exists
  • ✓ Labor Standards Act Article 60 (Annual paid leave) Paragraph 1 — exists
  • ✗ Commercial Act Article 401-2 — Paragraph 7 doesn't exist (max Paragraph 2)
  • ✗ Criminal Act Article 9999 — no such article (valid range: Art.1~Art.372)

Don't blindly trust ChatGPT/Claude legal answers. Essential reliability check for legal AI services, law firms, students, contract review.


What's New in v3.2.0+ — Smart Scenarios

Same 10 tools, 9 analysis scenarios. Just ask in natural language — the AI detects what you need and runs extra analysis automatically.

Ask this Get this
"Food Sanitation Act penalty reduction possible?" Penalty schedule + violation clauses + appeal cases where penalties were reduced
"Import customs FTA check" Customs Act + customs interpretations + FTA treaties + tariff tables + tax tribunal rulings
"Building Act permit procedure" Legal basis (Act→Decree→Rule) + fees/forms + admin rules + local ordinance exceptions
"National Health Insurance Act delegation" Finds delegated provisions where implementing decrees haven't been created yet
"Building Act impact analysis" Subordinate laws + nationwide ordinances affected + related admin rules
"Labor Standards Act amendment timeline" Old/new comparison + article history + precedents/interpretations mapped chronologically
"Parking ordinance compliance check" Constitutional Court decisions + admin appeal cancellations + parent law basis

No changes to how you use it. Ask naturally, get deeper analysis automatically.

v3.3.0~v3.3.1 changes

v3.3.1 — Law alias dictionary expansion (11 → 52 entries, +41)

Triggered by a lexdiff hallucination case where "산안기준규칙" (산업안전보건기준에 관한 규칙) got keyword-matched to "국가표준기본법" by Korea Law Open API's aiSearch. Expanded LAW_ALIAS_ENTRIES in lib/search-normalizer.ts with high-frequency abbreviations across labor/safety (산안법, 중처법, 근기법), privacy/telecom (개보법, 정보통신망법), anti-corruption (청탁금지법, 이해충돌방지법), public contracting (국가계약법, 지방계약법), real estate (주임법, 상임법, 부거법), antitrust (공정거래법, 하도급법, 약관법, 표시광고법, 가맹사업법), finance (자본시장법, 특금법, 전금법), urban planning (국토계획법, 도정법), environment/health (감염병예방법, 대기환경법), transport (여객운수법, 화물운수법), procedure (민소법, 형소법, 민집법), social insurance (국건법, 산재보험법, 고보법), and telecom (전기통신사업법). Since api-client.ts and law-parser.ts already consume resolveLawAlias(), the existing search pipeline gets the benefit automatically. 45/45 tests passing (41 new + 4 regression).

v3.3.0 — HTTP stateless mode + kordoc 2.3.0

Root-cause fix for the remote server (korean-law-mcp.fly.dev) periodically losing sessions due to OOM-driven restarts. Switched to MCP's official stateless pattern (sessionIdGenerator: undefined): fresh Server + Transport per request, released on response close. Removed in-memory session Map, InMemoryEventStore, and idle cleanup — eliminating leak sources entirely. Survives restarts, scale-out, and rolling deploys with zero client disruption. GET /mcp and DELETE /mcp return 405 (matching the SDK example). API keys are isolated per-request via AsyncLocalStorage.

  • HTTP stateless transition — src/server/http-server.ts (ref: @modelcontextprotocol/sdk/examples/server/simpleStatelessStreamableHttp.js)
  • kordoc 2.2.5 → 2.3.0
  • Session management code removed — sessions Map, MAX_SESSIONS, 10-min idle setInterval, InMemoryEventStore, POST/GET/DELETE branching (~50 LOC net reduction)

v3.2.2 — get_annexes direct exposure. Auto-fetch annexes on refund/fee keywords.

v3.2.1 — kordoc 2.2.5 update.

v3.1.0~v3.1.5 changes

v3.1.5 — kordoc 2.2.4 + README modernization.

v3.1.4 — kordoc 2.2.4 update. HTML <table> for merged cells, markdownToHwpx improvements.

v3.1.3 — Empty search result hints for 18 tools. Session cleanup interval reduced.

v3.1.2 — kordoc 2.2.1 update. GFM table escaping.

v3.1.1 — kordoc 2.1→2.2 update.

v3.1.0 — Production hardening: 20 file fixes.

v3.1.3 — Empty search result hints for 18 tools. Session cleanup interval reduced (30min→10min).

v3.1.2 — kordoc 2.2.1 update. GFM table special character escaping and pipe collision prevention.

v3.1.1 — kordoc 2.1→2.2 update.

v3.1.0 — Production hardening: 20 file fixes. truncateResponse 50KB limit applied to 17 tools, HTTP session limit (MAX_SESSIONS=100), CORS wildcard warning, parameter pollution defense, chain tool auth error propagation, SSE server dead code removal.

v3.0.x changes

v2 structured 41 legal APIs into 89 MCP tools. v3 re-compresses them into 14 tools.

Raw APIs v2 v3
Tool count 41 89 14
AI context cost - ~110 KB ~20 KB
Coverage - 100% 100%
Profile management - lite/full split Single (none needed)

What changed: 34 individual search/get tools for precedents, constitutional court, tax tribunal, FTC, etc. are now unified into 2 tools: search_decisions(domain) + get_decision_text(domain), covering 17 domains with a single domain parameter.

  • kordoc 1.6 → 2.2.5 — Document parsing engine upgrade (XLSX/DOCX support, security hardening, form filler)
  • Bug fixes — Admin appeal text retrieval, English law text retrieval
v2.2.0
  • 23 New Tools (64 → 87) — Treaties, law-ordinance linkage, institutional rules, special administrative appeals, document analysis, and more.
  • Document Analysis Engine — 8 document types, 17 risk rules, amount/period extraction, clause conflict detection.
  • Law-Ordinance Linkage (4 tools) — Trace delegation chains between national laws and local ordinances.
  • Treaty Support (2 tools) — Bilateral/multilateral treaty search and retrieval.
  • Security Hardening — CORS origin control, API key header-only, security headers, session ID masking.
v1.8.0 – v1.9.0 features
  • 8 Chain Tools — Composite research workflows in a single call: chain_full_research (AI search → statutes → precedents → interpretations), chain_law_system, chain_action_basis, chain_dispute_prep, chain_amendment_track, chain_ordinance_compare, chain_procedure_detail.
  • Batch Article Retrieval — get_batch_articles accepts a laws array for multi-law queries in one call.
  • AI Search Type Filter — search_ai_law now supports lawTypes filter.
  • Structured Error Format — [ErrorCode] + tool name + suggestion across all 64 tools.
  • HWP Table Fix — Legacy HWP parser now extracts tables from paragraph.controls[].content path.

Why this exists

South Korea has 1,600+ active laws, 10,000+ administrative rules, and a precedent system spanning Supreme Court, Constitutional Court, tax tribunals, and customs rulings. All of this lives behind a clunky government API with zero developer experience.

This project wraps that entire legal system into 10 tools that any AI assistant or script can call. Built by a Korean civil servant who got tired of manually searching 법제처 for the hundredth time.


Quick Start

Option 1: MCP Server (Claude Desktop / Cursor / Windsurf)

Auto setup (recommended):

npx --ignore-scripts --omit=optional korean-law-mcp setup

Interactive wizard handles API key input, client selection, and config file registration.
Supports Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Gemini CLI, Zed, and Antigravity.
Project-folder configs (Claude Code .mcp.json, VS Code .vscode/mcp.json) may be committed to git, so the key is not written in plain text:
Claude Code gets a ${LAW_OC} reference (add export LAW_OC=your-key to your shell profile), and VS Code prompts for the key on first run.

Manual setup:

npm install --ignore-scripts --omit=optional -g korean-law-mcp

Add to your MCP client config:

{
  "mcpServers": {
    "korean-law": {
      "command": "korean-law-mcp",
      "env": {
        "LAW_OC": "your-api-key"
      }
    }
  }
}

Get your free API key at 법제처 Open API.

Client Config File
Claude Desktop %APPDATA%\Claude\claude_desktop_config.json (Win) / ~/Library/Application Support/Claude/claude_desktop_config.json (Mac)
Cursor .cursor/mcp.json
Windsurf .windsurf/mcp.json
Continue ~/.continue/config.json
Zed ~/.config/zed/settings.json

Option 2: Remote (No Install)

Claude Desktop does not support remote HTTP MCP servers directly. Use the mcp-remote adapter (requires Node.js 18+ for npx):

{
  "mcpServers": {
    "korean-law": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.gomdori.app/law?oc=your-api-key"
      ]
    }
  }
}

Cursor, Windsurf, and other clients with native remote HTTP support — use the URL directly:

{
  "mcpServers": {
    "korean-law": {
      "url": "https://mcp.gomdori.app/law?oc=your-api-key"
    }
  }
}

For web clients (Claude.ai, etc.) — same URL works everywhere. Only 10 tools are advertised by default, no profile selection needed.

10 tools (research + analysis + 3 law + ordinance radar + 2 unified + 2 meta) cover all 42 APIs. Use discover_tools → execute_tool for specialized tools.

API Key Delivery (priority order):

Method Example Notes
URL query ?oc=your-key Simplest for web clients. Auto-applies to entire session
HTTP header apikey: your-key Also supports law-oc, x-api-key, Authorization: Bearer
Tool parameter apiKey: "your-key" Per-tool override

Get your free API key at 법제처 Open API.

Option 3: CLI

npm install --ignore-scripts --omit=optional -g korean-law-mcp
export LAW_OC=your-api-key

korean-law search_law --query "관세법"
korean-law get_law_text --mst 160001 --jo "제38조"
korean-law search_precedents --query "부당해고"
korean-law list                          # all tools
korean-law list --category 판례          # filter by category
korean-law help search_law               # tool help

Option 4: Docker

docker build -t korean-law-mcp .
docker run -e LAW_OC=your-api-key -e MCP_HTTP_HOST=0.0.0.0 \
  -e MCP_AUTH_TOKEN=replace-with-a-secret -p 3000:3000 korean-law-mcp

Tool Structure (10 tools)

v4.4.0 consolidated the advertised tools (52% context reduction). The former 8 chain_* tools became task values of legal_research, and the 4 analysis features became mode values of legal_analysis. Other specialized tools stay reachable via discover_tools → execute_tool, and calling the old tool names directly still works for backward compatibility. v4.7.0 added ordinance_radar, bringing the total to 10.

Category Tool Description
Research (1) legal_research Multi-step legal research — pick one of 8 task values
Analysis (1) legal_analysis Verification & analysis — pick one of 4 mode values
Law (3) search_law Search statutes → get lawId, MST
get_law_text Full article text retrieval
get_annexes Annex/form retrieval (fee tables, rate tables, forms; date for the version in force that day)
Ordinance (1) ordinance_radar Ordinance revision radar — auto-diffs the parent statutes a local ordinance cites (v4.7.0)
Unified (2) search_decisions 18 domain unified search (precedents, constitutional court, tax tribunal, NTS, FTC, NLRC, customs, interpretations, admin appeals, PIPC, ACR, ACR special, appeal review, school rules, public corps, public institutions, treaties, English law)
get_decision_text 18 domain full text retrieval
Meta (2) discover_tools Search specialized tools (terms, annexes, history, comparison, etc.)
execute_tool Execute discovered specialized tool

Usage Examples

User: "관세법 제38조 알려줘"
→ search_law("관세법") → get_law_text(mst, jo="003800")

User: "화관법 최근 개정 비교"
→ "화관법" → "화학물질관리법" auto-resolved → compare_old_new(mst)

User: "근로기준법 제74조 해석례"
→ search_interpretations("근로기준법 제74조") → get_interpretation_text(id)

User: "산업안전보건법 별표1 내용"
→ get_annexes("산업안전보건법 별표1") → HWPX download → Markdown table

Features

  • 42 APIs → 10 Tools — Statutes, precedents, admin rules, ordinances, constitutional decisions, tax rulings, customs interpretations, treaties, institutional rules, legal terminology
  • MCP + CLI — Use from Claude Desktop or from your terminal
  • 17 Decision Domains — search_decisions covers precedents, constitutional court, tax tribunal, FTC, NLRC, customs, and 11 more domains in one tool
  • Korean Law Intelligence — Auto-resolves abbreviations (화관법 → 화학물질관리법), converts article numbers (제38조 ↔ 003800), visualizes 3-tier delegation
  • Annex Extraction — Downloads HWPX/HWP/PDF/XLSX/DOCX annexes and converts to Markdown (kordoc engine)
  • 8 Chain Tools — Composite research workflows in a single call (e.g. chain_full_research: AI search → statutes → precedents → interpretations)
  • Caching — 1-hour search cache, 24-hour article cache
  • Remote Endpoint — Use without installation via https://mcp.gomdori.app/law (the legacy korean-law-mcp.fly.dev/mcp stays backward compatible)

Environment Variables

Variable Required Default Description
LAW_OC Yes — 법제처 API key (get one free)
PORT No 8000 HTTP server port
CORS_ORIGIN No * CORS allowed origin. Setting it explicitly also allows that origin to pass Origin validation
ALLOWED_ORIGINS No — Comma-separated origin allowlist. Requests carrying an Origin header are rejected unless listed (DNS rebinding defense)
MCP_AUTH_TOKEN No — When set, /mcp requires x-mcp-token or Authorization: Bearer. Required for non-loopback deployments unless explicitly overridden
MCP_HTTP_HOST No 127.0.0.1 Bind address. A non-loopback host requires MCP_AUTH_TOKEN, unless the deliberate legacy override below is set
MCP_ALLOW_UNAUTHENTICATED_REMOTE No 0 Set to 1 only for a deliberately public, non-loopback deployment without MCP access authentication
TRUST_PROXY No false Set to a positive proxy-hop count (for example 1 behind one Fly/ingress proxy). Never use true/all
ALLOW_QUERY_API_KEY No 1 Set to 0 to reject the ?oc= query-string API key (it leaks into proxy access logs)
ACCESS_LOG No 0 Set to 1 to log each request. Only req.path is recorded, never the query string, so the oc= key never reaches the log
RATE_LIMIT_RPM No 60 Tool calls per minute per IP. 0 disables only the per-IP limiter; batch and execution limits remain active
MCP_MAX_BATCH_CALLS No 20 Maximum tools/call items in one JSON-RPC HTTP envelope
MCP_MAX_BODY_BYTES No 102400 Maximum incoming JSON request size. The older MCP_BODY_LIMIT (100kb, etc.) is accepted for compatibility
MCP_MAX_UPSTREAM_REQUESTS No 48 Request-wide upstream attempt budget, including retries and anti-bot hops
MCP_MAX_UPSTREAM_BODY_BYTES No 2097152 Maximum bytes read from one upstream response body
MCP_MAX_TOTAL_UPSTREAM_BODY_BYTES No 8388608 Maximum upstream body bytes read by one outer request
MCP_MAX_TOOL_RESPONSE_CHARS No 50000 Maximum returned MCP tool-response characters

All numeric limits are validated as whole numbers during startup. Invalid values fail startup rather than weakening a limit. legal_research and other documented chain tools share the 48-attempt request budget; JSON-RPC batch siblings share accounting but retain independent MCP cancellation signals.

HTTP deployment defaults

HTTP mode is local by default: it binds only to 127.0.0.1, does not trust X-Forwarded-For, and leaves token authentication optional for that loopback-only use. For a reverse-proxy deployment, set both the explicit public bind and the exact trusted hop count, for example:

MCP_HTTP_HOST=0.0.0.0 TRUST_PROXY=1 MCP_AUTH_TOKEN=replace-with-a-secret \
  korean-law-mcp --mode http --port 8000

MCP_ALLOW_UNAUTHENTICATED_REMOTE=1 preserves intentionally public legacy deployments, but emits a startup warning and should only be used where another access boundary is in place.

Dependency and install boundary

kordoc remains because annex parsing is a reachable server feature. Its known-good pure-JS pdfjs-dist@4.10.38 runtime is pinned as a normal dependency; optional OCR/ML/native helpers are not needed by this server. Plugin, documented, and Docker installs use --omit=optional --ignore-scripts. CI and publishing retain optional development-tool bindings with scripts disabled during validation, then prune to the production graph and run the PDF annex smoke test. Scanner reports for transitive HTTP-framework packages should be evaluated against the reachable server path rather than treated as proof that the server exposes the affected middleware.

FAQ

How do I search Korean statutes and court precedents from Claude or ChatGPT?
Connect this MCP server. In Claude.ai, add https://mcp.gomdori.app/law?oc=YOUR_KEY as a custom connector. For Claude Desktop, Cursor, Windsurf and Zed see Quick Start; for ChatGPT see the connection video (Korean narration).

Is it free?
Yes. The code is MIT-licensed, and the 법제처 Open API key it needs is free (open.law.go.kr).

Can it catch legal citations an LLM made up?
legal_analysis(mode="verify_citations") checks the statute articles and case numbers cited in a text against the official 법제처 source, for existence and for content. mode="cite_check" tells whether a precedent is still good law.

What does it cover?
Statutes, precedents, administrative rules, local ordinances, treaties and legal interpretations (including the National Tax Service), plus annexes and forms. It also resolves past versions of a law and points repealed statutes to their successors.

Documentation

Credits

  • 법제처 Open API — Korea's official legal database
  • Anthropic — Model Context Protocol
  • kordoc — HWP/HWPX parser (same author)

License

MIT


Made by a Korean civil servant @ 광진구청 AI동호회 AI.Do