Skip to main content
Glama
rabqatab

LexLink

by rabqatab
README.md
[![MseeP.ai Security Assessment Badge](https://mseep.net/pr/rabqatab-lexlink-ko-mcp-badge.png)](https://mseep.ai/app/rabqatab-lexlink-ko-mcp)

<div align="center">
  <img src="assets/LexLink_logo.png" alt="LexLink Logo" width="200"/>
  <h1>LexLink - Korean National Law Information MCP Server</h1>
</div>

**🌐 Read this in other languages:** **English** | [ν•œκ΅­μ–΄ (Korean)](README_kr.md)

[![Kakao PlayMCP 10 3rd Prize](https://img.shields.io/badge/Kakao_PlayMCP_10-3rd_Prize_πŸ†-CD7F32)](https://playmcp.kakao.com/)
[![smithery badge](https://smithery.ai/badge/@rabqatab/lexlink-ko-mcp)](https://smithery.ai/server/@rabqatab/lexlink-ko-mcp)
[![MCP](https://img.shields.io/badge/MCP-Compatible-blue)](https://modelcontextprotocol.io)
[![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)

LexLink is an MCP (Model Context Protocol) server that exposes the Korean National Law Information API ([open.law.go.kr](http://open.law.go.kr)) to AI agents and LLM applications. It enables AI systems to search, retrieve, and analyze Korean legal information through standardized MCP tools.

## Features

- **54 MCP Tools + 2 MCP Resources** for comprehensive Korean law information access
  - Search and retrieve Korean laws (effective date & announcement date)
  - Search and retrieve English-translated laws
  - Search and retrieve administrative rules (ν–‰μ •κ·œμΉ™)
  - Query specific articles, paragraphs, and sub-items
  - Law-ordinance linkage (법령-μžμΉ˜λ²•κ·œ 연계)
  - Delegated law information (μœ„μž„λ²•λ Ή)
  - **Phase 3 - Case Law & Legal Research**
    - Court precedents (νŒλ‘€)
    - Constitutional Court decisions (ν—Œμž¬κ²°μ •λ‘€)
    - Legal interpretations (법령해석둀)
    - Administrative appeal decisions (ν–‰μ •μ‹¬νŒλ‘€)
  - **Phase 4 - Article Citation Extraction**
    - Extract legal citations from any law article (100% accuracy)
  - **NEW: Phase 5 - AI-Powered Search**
    - Semantic search for natural language queries (aiSearch)
    - Related laws discovery (aiRltLs_search)
  - **MCP Resources - Law ID Cache**
    - Cached mapping of ~20 frequently-used law names to stable 법령ID codes
    - Template lookup by Korean name or abbreviation (`lexlink://law/{name}`)
    - Dynamic caching: search results automatically populate the cache
- **Smart Features** (inspired by [korean-law-mcp](https://github.com/chrisryugj/korean-law-mcp)):
  - **Intelligent Caching** - Per-tool TTL caching (search 1hr, articles 24hr, AI search 30min)
  - **Law Name Resolution** - Auto-resolves Korean abbreviations (μžν†΅λ²•β†’μžλ³Έμ‹œμž₯κ³Ό κΈˆμœ΅νˆ¬μžμ—…μ— κ΄€ν•œ 법λ₯ ), 52 seed aliases + dynamic learning
  - **Chain Tools** - Multi-step research workflows in one call (Phase 9)
- **100% Semantic Validation** - All Phase 1-5 tools confirmed returning real law data
- **Error Handling** - Actionable error messages with resolution hints
- **Korean Text Support** - Proper UTF-8 encoding for Korean characters
- **Response Formats** - JSON (default), HTML, or XML (multiple formats supported)

## Project Status

πŸŽ‰ **Production Ready - Phase 9 Complete!**

| Metric | Status |
|--------|--------|
| **Tools Implemented** | 54/54 (100%) βœ… |
| **Semantic Validation** | 26/26 (Phase 1-5 tools) βœ… |
| **MCP Prompts** | 9/9 (100%) βœ… |
| **MCP Resources** | 2 (1 static + 1 template) βœ… |
| **API Coverage** | ~28% of 191+ endpoints |
| **LLM Integration** | βœ… Validated (Gemini) |
| **Code Quality** | Clean, documented, tested |
| **Version** | v2.1.0 |

**Latest:** v2.1.0 β€” 54 tools (Phase 9 added), intelligent caching (`cache.py`), law name resolution (`resolver.py`), chain tools for multi-step research workflows.

## Prerequisites

- **Python 3.10+**
- **law.go.kr OC identifier**: Register at [open.law.go.kr](https://open.law.go.kr)

## Quick Start

### 1. Install Dependencies

```bash
uv sync
```

### 2. Configure Your OC Identifier

**Option A: Environment Variable (Recommended)**
```bash
# Set OC in your environment
export OC=your_id_here
```

**Option B: Pass in Tool Arguments**
```python
# Override OC in each tool call
eflaw_search(query="법령λͺ…", oc="your_id")
```

### 3. Run the Server

```bash
# Stdio transport (for Claude Code, Cursor, etc.)
OC=your_oc uv run stdio

# HTTP transport (for Kakao PlayMCP)
OC=your_oc TRANSPORT=http uv run serve
```

## Available Tools

### Phase 1: Core Law APIs (6 tools)

#### 1. `eflaw_search` - Search Laws by Effective Date
Search for laws organized by effective date (μ‹œν–‰μΌ κΈ°μ€€).

```python
eflaw_search(
    query="μžλ™μ°¨κ΄€λ¦¬λ²•",      # Search keyword
    display=10,                # Results per page
    type="XML",                # Response format
    ef_yd="20240101~20241231"  # Optional date range
)
```

#### 2. `law_search` - Search Laws by Announcement Date
Search for laws organized by announcement date (곡포일 κΈ°μ€€).

```python
law_search(
    query="민법",
    display=10,
    type="XML"
)
```

#### 3. `eflaw_service` - Retrieve Law Content (Effective Date)
Get full law text and articles by effective date.

> **IMPORTANT:** For specific article queries (e.g., "제174쑰"), use the `jo` parameter. Some laws have 400+ articles and responses can exceed 1MB without `jo`.

```python
# Get specific article (RECOMMENDED)
eflaw_service(
    mst="279823",              # Law MST
    jo="017400",               # Article 174 (제174쑰)
    type="XML"
)

# Get full law (WARNING: large response)
eflaw_service(
    id="001823",
    type="XML"
)
```

#### 4. `law_service` - Retrieve Law Content (Announcement Date)
Get full law text and articles by announcement date.

> **IMPORTANT:** For specific article queries (e.g., "제174쑰"), use the `jo` parameter. Some laws have 400+ articles and responses can exceed 1MB without `jo`.

```python
# Get specific article (RECOMMENDED)
law_service(
    mst="279823",              # Law MST
    jo="017400",               # Article 174 (제174쑰)
    type="XML"
)
```

#### 5. `eflaw_josub` - Query Article/Paragraph (Effective Date)
**Best tool for querying specific articles.** Returns only the requested article/paragraph.

```python
eflaw_josub(
    mst="279823",              # Law MST
    jo="017400",               # Article 174 (제174쑰)
    type="XML"
)
# jo format: "XXXXXX" where first 4 digits = article (zero-padded), last 2 = branch (00=main)
# Examples: "017400" (제174쑰), "000300" (제3쑰), "001502" (제15쑰의2)
```

#### 6. `law_josub` - Query Article/Paragraph (Announcement Date)
**Best tool for querying specific articles.** Returns only the requested article/paragraph.

```python
law_josub(
    mst="279823",              # Law MST
    jo="017200",               # Article 172 (제172쑰)
    type="XML"
)
```

### Phase 2: Extended APIs (9 tools)

#### 7. `elaw_search` - Search English-Translated Laws
Search for Korean laws translated to English.

```python
elaw_search(
    query="employment",
    display=10,
    type="XML"
)
```

#### 8. `elaw_service` - Retrieve English Law Content
Get full English-translated law text.

```python
elaw_service(
    id="009589",
    type="XML"
)
```

#### 9. `admrul_search` - Search Administrative Rules
Search administrative rules (ν›ˆλ Ή, 예규, κ³ μ‹œ, 곡고, μ§€μΉ¨).

```python
admrul_search(
    query="학ꡐ",
    display=10,
    type="XML"
)
```

#### 10. `admrul_service` - Retrieve Administrative Rule Content
Get full administrative rule text with annexes.

```python
admrul_service(
    id="62505",
    type="XML"
)
```

#### 11. `lnkLs_search` - Search Law-Ordinance Linkage
Find laws linked to local ordinances.

```python
lnkLs_search(
    query="건좕",
    display=10,
    type="XML"
)
```

#### 12. `lnkLsOrdJo_search` - Search Ordinance Articles by Law
Find ordinance articles linked to specific law articles.

```python
lnkLsOrdJo_search(
    knd="002118",              # Law ID
    display=10,
    type="XML"
)
```

#### 13. `lnkDep_search` - Search Law-Ordinance Links by Ministry
Find laws linked to ordinances by government ministry.

```python
lnkDep_search(
    org="1400000",             # Ministry code
    display=10,
    type="XML"
)
```

#### 14. `drlaw_search` - Retrieve Law-Ordinance Linkage Statistics
Get linkage statistics table (HTML format).

```python
drlaw_search(
    lid="001823",              # Law ID
    type="HTML"
)
```

#### 15. `lsDelegated_service` - Retrieve Delegated Law Information
Get information about delegated laws, rules, and ordinances.

```python
lsDelegated_service(
    id="001823",
    type="XML"
)
```

### Phase 3: Case Law & Legal Research (8 tools - NEW!)

> **Tip:** All `*_service` tools in Phase 3 support a `sections="summary"` parameter to return only a brief summary instead of the full document text.

#### 16. `prec_search` - Search Court Precedents
Search Korean court precedents from Supreme Court and lower courts.

```python
prec_search(
    query="λ‹΄λ³΄κΆŒ",
    display=10,
    type="XML",
    curt="λŒ€λ²•μ›"             # Optional: Court name filter
)
```

#### 17. `prec_service` - Retrieve Court Precedent Full Text
Get complete court precedent text with case details.

```python
prec_service(
    id="228541",
    type="XML"
)
```

#### 18. `detc_search` - Search Constitutional Court Decisions
Search Korean Constitutional Court decisions.

```python
detc_search(
    query="벌금",
    display=10,
    type="XML"
)
```

#### 19. `detc_service` - Retrieve Constitutional Court Decision Full Text
Get complete Constitutional Court decision text.

```python
detc_service(
    id="58386",
    type="XML"
)
```

#### 20. `expc_search` - Search Legal Interpretations
Search legal interpretation precedents issued by government agencies.

```python
expc_search(
    query="μž„μ°¨",
    display=10,
    type="XML"
)
```

#### 21. `expc_service` - Retrieve Legal Interpretation Full Text
Get complete legal interpretation text.

```python
expc_service(
    id="334617",
    type="XML"
)
```

#### 22. `decc_search` - Search Administrative Appeal Decisions
Search Korean administrative appeal decisions.

```python
decc_search(
    query="*",                # Search all decisions
    display=10,
    type="XML"
)
```

#### 23. `decc_service` - Retrieve Administrative Appeal Decision Full Text
Get complete administrative appeal decision text.

```python
decc_service(
    id="243263",
    type="XML"
)
```

### Phase 4: Article Citation Extraction (1 tool - NEW!)

#### 24. `article_citation` - Extract Citations from Law Article
Extract all legal citations referenced by a specific law article.

```python
# First, search for the law to get MST
eflaw_search(query="건좕법")  # Returns MST: 268611

# Then extract citations
article_citation(
    mst="268611",              # Law MST from search result
    law_name="건좕법",          # Law name
    article=3                  # Article number (제3쑰)
)
```

**Response:**
```json
{
    "success": true,
    "law_name": "건좕법",
    "article": "제3쑰",
    "citation_count": 12,
    "internal_count": 4,
    "external_count": 8,
    "citations": [
        {
            "type": "external",
            "target_law_name": "γ€Œκ΅­ν† μ˜ κ³„νš 및 μ΄μš©μ— κ΄€ν•œ 법λ₯ γ€",
            "target_article": 56,
            "target_paragraph": 1
        }
    ]
}
```

**Key Features:**
- 100% accuracy via HTML parsing (not LLM-based)
- Zero API cost (no external LLM calls)
- ~350ms average extraction time
- Distinguishes internal vs external citations

### Phase 5: AI-Powered Search (2 tools - NEW!)

#### 25. `aiSearch` - AI-Powered Semantic Law Search
⭐ **PREFERRED TOOL for vague or natural language queries.** Use this FIRST when user's intent is unclear or conversational.

Uses intelligent/semantic search to find relevant law articles with full article text.

```python
aiSearch(
    query="λΊ‘μ†Œλ‹ˆ 처벌",           # Natural language query
    search=0,                      # 0: law articles, 1: appendix, 2: admin rules, 3: admin appendix
    display=20,                    # Results per page
    page=1,                        # Page number
    type="JSON"                    # Response format (JSON default)
)
```

**Best for:** Natural language queries like "μŒμ£Όμš΄μ „ 벌금", "이혼 μž¬μ‚°λΆ„ν• ", "상속 문제"

#### 26. `aiRltLs_search` - AI-Powered Related Laws Search
⭐ **PREFERRED TOOL for discovering related laws from vague topics.** Use this when user wants to explore laws around a general subject.

Finds laws semantically related to a given law name or keyword.

```python
aiRltLs_search(
    query="민법",                  # Law name or keyword
    search=0,                      # 0: law articles, 1: admin rule articles
    type="JSON"                    # Response format (JSON default)
)
```

**Best for:** Finding related laws like "민법" β†’ 상법, μ˜λ£Œλ²•, μ†Œμ†‘μ΄‰μ§„λ²•

### Phase 7: Extended Legal Information (18 tools)

| Category | Tools |
|----------|-------|
| μžμΉ˜λ²•κ·œ (Local Ordinances) | `ordin_search`, `ordin_service`, `ordinLsCon_search` |
| μ‘°μ•½ (Treaties) | `trty_search`, `trty_service` |
| 법령정보 μ§€μ‹λ² μ΄μŠ€ (Knowledge Base) | `lstrm_ai_search`, `dlytrm_search`, `lstrm_rlt_search`, `dlytrm_rlt_search`, `lstrm_rlt_jo_search`, `jo_rlt_lstrm_search`, `ls_rlt_search` |
| μœ„μ›νšŒ κ²°μ •λ¬Έ (Committee Decisions) | `committee_search`, `committee_service` |
| μ€‘μ•™λΆ€μ²˜ 1μ°¨ 해석 (Ministry Interpretations) | `cgm_expc_search`, `cgm_expc_service` |
| νŠΉλ³„ν–‰μ •μ‹¬νŒ (Special Appeals) | `special_decc_search`, `special_decc_service` |

### Phase 9: Chain Tools (5 tools)

Inspired by [korean-law-mcp](https://github.com/chrisryugj/korean-law-mcp), these tools run multi-step research workflows in a single call β€” eliminating the need for an LLM to orchestrate sequential tool calls manually.

| Tool | Description |
|------|-------------|
| `chain_full_research` | Complete legal research: statutes + precedent analysis + interpretations |
| `chain_amendment_track` | Revision history + article-level diff across amendments |
| `chain_dispute_prep` | All case law sources across 4 databases (νŒλ‘€, ν—Œμž¬κ²°μ •λ‘€, 법령해석둀, ν–‰μ •μ‹¬νŒλ‘€) |
| `chain_law_system` | Full law hierarchy: delegation tree + admin rules + ordinances |
| `cache_stats` | Cache and resolver performance monitoring |

### Tool Selection Guide

When searching Korean law, select tools based on query clarity:

| Query Type | Recommended Tools | Examples |
|------------|-------------------|----------|
| πŸ” **Vague/Natural language** | `aiSearch`, `aiRltLs_search` | "μŒμ£Όμš΄μ „ 처벌", "이혼 μž¬μ‚°λΆ„ν• " |
| πŸ“‹ **Specific law/article** | `eflaw_search`, `law_search` | "ν˜•λ²• 제148쑰의2", "민법 μƒμ†νŽΈ" |
| βš–οΈ **Case law** | `prec_search`, `detc_search` | "λŒ€λ²•μ› 2023λ‹€12345" |
| πŸ”— **Related laws** | `aiRltLs_search` | "민법과 κ΄€λ ¨λœ 법λ₯ " |

## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `OC` | *(required)* | law.go.kr API identifier (email local part) |
| `LEXLINK_BASE_URL` | `http://www.law.go.kr` | API base URL |
| `LEXLINK_TIMEOUT` | `60` | HTTP request timeout in seconds |
| `SLIM_RESPONSE` | *(unset)* | Set `true` to remove redundant raw XML when parsed data exists (for PlayMCP) |
| `TRANSPORT` | `sse` | Transport type: `sse` or `http` |

### OC Priority

When resolving the OC identifier:
1. **Tool argument** (highest priority) - `oc` parameter in tool call
2. **Environment variable** - `OC` env var (set via .env or HTTP header middleware)

## Usage Examples

### Example 1: Basic Search

```python
# Search for automobile management law
result = eflaw_search(
    query="μžλ™μ°¨κ΄€λ¦¬λ²•",
    display=5,
    type="XML"
)

# Returns:
{
    "status": "ok",
    "request_id": "uuid",
    "upstream_type": "XML",
    "data": {
        # Law search results...
    }
}
```

### Example 2: Search with Date Range

```python
# Find laws effective in 2024
result = eflaw_search(
    query="ꡐ톡",
    ef_yd="20240101~20241231",
    type="XML"
)
```

### Example 3: Error Handling

```python
# Missing OC parameter
result = eflaw_search(query="test")

# Returns helpful error:
{
    "status": "error",
    "error_code": "MISSING_OC",
    "message": "OC parameter is required but not provided.",
    "hints": [
        "1. Tool argument: oc='your_value'",
        "2. Environment variable: OC=your_value"
    ]
}
```

## Golden MCP Tool Trajectories

These examples demonstrate real-world conversation flows showing how LLMs interact with LexLink tools to answer legal research questions.

### Trajectory 1: Basic Law Research
**User Query:** "What is Article 20 of the Civil Code?"

**Tool Calls:**
1. `law_search(query="민법", display=50, type="XML")` β†’ Find Civil Code ID
2. `law_service(id="000021", jo="002000", type="XML")` β†’ Retrieve Article 20 text

**Result:** LLM provides formatted explanation of Civil Code Article 20 with full legal text and context.

---

### Trajectory 2: Court Precedent Analysis
**User Query:** "Find recent Supreme Court precedents about security interests"

**Tool Calls:**
1. `prec_search(query="λ‹΄λ³΄κΆŒ", curt="λŒ€λ²•μ›", display=50, type="XML")` β†’ Search Supreme Court precedents
2. `prec_service(id="228541", type="XML")` β†’ Retrieve top precedent details

**Result:** LLM summarizes key precedents with case numbers, dates, and holdings related to security interests.

---

### Trajectory 3: Cross-Phase Legal Research
**User Query:** "How does the Labor Standards Act handle overtime, and are there relevant court precedents?"

**Tool Calls:**
1. `eflaw_search(query="κ·Όλ‘œκΈ°μ€€λ²•", display=50, type="XML")` β†’ Find Labor Standards Act
2. `eflaw_service(id="001234", jo="005000", type="XML")` β†’ Retrieve Article 50 (overtime provisions)
3. `prec_search(query="κ·Όλ‘œκΈ°μ€€λ²• μ—°μž₯근둜", display=30, type="XML")` β†’ Search overtime precedents
4. `prec_service(id="234567", type="XML")` β†’ Retrieve leading precedent

**Result:** LLM provides comprehensive analysis combining statutory text with judicial interpretation, showing how courts apply the overtime provisions.

---

### Trajectory 4: Constitutional Review
**User Query:** "Has the Constitutional Court reviewed laws about fines?"

**Tool Calls:**
1. `detc_search(query="벌금", display=50, type="XML")` β†’ Search Constitutional Court decisions
2. `detc_service(id="58386", type="XML")` β†’ Retrieve decision full text
3. `law_search(query=<law_name_from_decision>, type="XML")` β†’ Find related law for context

**Result:** LLM explains Constitutional Court holdings on fine-related provisions and their impact on specific laws.

---

### Trajectory 5: Administrative Law Research
**User Query:** "What administrative rules exist for schools, and are there related legal interpretations?"

**Tool Calls:**
1. `admrul_search(query="학ꡐ", display=50, type="XML")` β†’ Search school-related administrative rules
2. `admrul_service(id="62505", type="XML")` β†’ Retrieve rule content
3. `expc_search(query="학ꡐ", display=30, type="XML")` β†’ Search legal interpretations
4. `expc_service(id="334617", type="XML")` β†’ Retrieve interpretation details

**Result:** LLM provides overview of administrative framework for schools with official agency interpretations.

---

### Trajectory 6: Comprehensive Legal Analysis
**User Query:** "I'm researching rental housing disputes. Show me the relevant law, court precedents, and administrative appeal decisions."

**Tool Calls:**
1. `eflaw_search(query="μ£Όνƒμž„λŒ€μ°¨λ³΄ν˜Έλ²•", display=50, type="XML")` β†’ Find Housing Lease Protection Act
2. `eflaw_service(id="002876", type="XML")` β†’ Retrieve full law text
3. `prec_search(query="μ£Όνƒμž„λŒ€μ°¨", display=50, type="XML")` β†’ Search housing lease precedents
4. `prec_service(id="156789", type="XML")` β†’ Retrieve key precedent
5. `decc_search(query="μ£Όνƒμž„λŒ€μ°¨", display=30, type="XML")` β†’ Search administrative appeal decisions
6. `decc_service(id="243263", type="XML")` β†’ Retrieve appeal decision

**Result:** LLM provides comprehensive legal research report covering statutory framework, judicial interpretation, and administrative precedents for rental housing disputes.

---

### Trajectory 7: Citation Network Analysis (Phase 4)
**User Query:** "What laws does Article 3 of the Building Act cite?"

**Tool Calls:**
1. `eflaw_search(query="건좕법", display=50, type="XML")` β†’ Find Building Act, get MST
2. `article_citation(mst="268611", law_name="건좕법", article=3)` β†’ Extract all citations

**Result:** LLM provides complete citation analysis showing 12 citations (8 external laws, 4 internal references) including specific article and paragraph references.

---

### Trajectory 8: AI-Powered Natural Language Search (Phase 5)
**User Query:** "What's the penalty for hit-and-run accidents?"

**Tool Calls:**
1. `aiSearch(query="λΊ‘μ†Œλ‹ˆ 처벌", search=0, display=20, type="XML")` β†’ Semantic search for hit-and-run penalties

**Result:** LLM receives full article text from relevant laws (νŠΉμ •λ²”μ£„ κ°€μ€‘μ²˜λ²Œ 등에 κ΄€ν•œ 법λ₯  제5쑰의3) with complete provisions about hit-and-run penalties, enabling comprehensive answer without needing to know specific law names.

---

### Trajectory 9: Discovering Related Laws (Phase 5)
**User Query:** "What laws are related to the Civil Code?"

**Tool Calls:**
1. `aiRltLs_search(query="민법", search=0, type="XML")` β†’ Find semantically related laws

**Result:** LLM discovers related laws like 상법 (Commercial Act), μ˜λ£Œλ²• (Medical Service Act), μ†Œμ†‘μ΄‰μ§„λ²• (Act on Special Cases Concerning Expedition of Litigation), showing connections across legal domains.

---

### Key Patterns

1. **AI Tools for Vague Queries**: Use `aiSearch` or `aiRltLs_search` FIRST when user intent is unclear or conversational
2. **Search First, Then Retrieve**: Always search to find IDs before calling service tools
3. **Use display=50-100 for Law Searches**: Ensures exact matches are found due to relevance ranking
4. **Combine Phases**: Mix Phase 1 (laws), Phase 2 (administrative rules), Phase 3 (precedents), and Phase 5 (AI search) for complete research
5. **Type Parameter**: Default is `type="JSON"`; specify `type="XML"` if your pipeline requires XML
6. **Article Numbers**: Use 6-digit format (e.g., "002000" for Article 20) when querying specific articles

## Development

### Project Structure

```
lexlink-ko-mcp/
β”œβ”€β”€ src/lexlink/
β”‚   β”œβ”€β”€ server.py        # Main MCP server with 54 tools
β”‚   β”œβ”€β”€ _helpers.py      # Shared helpers: run_search, run_service, TOOL_ANNOTATIONS
β”‚   β”œβ”€β”€ cache.py         # Intelligent per-tool TTL caching (~183 lines)
β”‚   β”œβ”€β”€ resolver.py      # Korean law name/abbreviation resolution (~225 lines)
β”‚   β”œβ”€β”€ http_server.py   # HTTP/SSE server for Kakao PlayMCP
β”‚   β”œβ”€β”€ stdio_server.py  # Stdio transport entry point
β”‚   β”œβ”€β”€ params.py        # Parameter resolution & mapping
β”‚   β”œβ”€β”€ validation.py    # Input validation
β”‚   β”œβ”€β”€ parser.py        # XML parsing utilities
β”‚   β”œβ”€β”€ ranking.py       # Relevance ranking
β”‚   β”œβ”€β”€ citation.py      # Article citation extraction (Phase 4)
β”‚   β”œβ”€β”€ client.py        # HTTP client for law.go.kr API
β”‚   β”œβ”€β”€ errors.py        # Error codes & responses
β”‚   β”œβ”€β”€ raw_logger.py    # PlayMCP traffic logging
β”‚   └── log_processor.py # Log format converter
β”œβ”€β”€ logs/playmcp/         # PlayMCP traffic logs (daily JSONL)
β”œβ”€β”€ pyproject.toml        # Project configuration
└── README.md             # This file
```

### Running Tests

```bash
# Install test dependencies
uv sync

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=src/lexlink --cov-report=html

# Run specific test category
uv run pytest -m unit
uv run pytest -m integration
uv run pytest -m e2e
```

### Adding New Tools

**Current Status:** 54/54 tools implemented (Phase 1-9 complete). Phase 1-5 tools validated.

For implementing additional tools from the 124+ remaining APIs:
1. Follow the pattern established in `src/lexlink/server.py`
2. Use `ctx: Context = None` parameter for MCP logging/progress
3. Use generic parser functions (`extract_items_list`, `update_items_list`)
4. Add semantic validation tests

**Tool Implementation Pattern:**
- Each tool is a decorated function with MCP schema
- Uses `ctx: Context = None` parameter for MCP context
- 2-tier OC resolution: tool arg > env var
- Generic parser functions work with any XML tag
- Comprehensive error handling with actionable hints

## Deployment

### Deploy to Kakao PlayMCP (HTTP Server)

LexLink can also be deployed as an HTTP server for platforms like Kakao PlayMCP.

> **Important:** Kakao PlayMCP does not accept port numbers in URLs.
> You must use Nginx as a reverse proxy to serve on port 80.

**Quick Start (Local Testing):**
```bash
# Run the HTTP server
OC=your_oc uv run serve

# Server starts at: http://localhost:8000/sse
```

**Production Setup:**
```
Internet β†’ Nginx (port 80) β†’ LexLink (port 8000)
```

**PlayMCP Registration:**

| Field | Value |
|-------|-------|
| **MCP Endpoint** | `http://YOUR_SERVER_IP/sse` (no port!) |
| **Authentication** | Key/Token (Header: `OC`) |

For detailed deployment instructions (AWS EC2, Nginx, systemd, HTTPS), see [docs/DEPLOYMENT_GUIDE.md](docs/DEPLOYMENT_GUIDE.md).

### PlayMCP Traffic Logging

LexLink includes built-in logging for PlayMCP traffic analysis. Logs are saved in dashboard-compatible JSONL format.

**Log Location:** `logs/playmcp/YYYY-MM-DD.jsonl`

**Log Schema:**
```json
{
  "rpc_id": "3",
  "request_id": "d8ee45eb",
  "session_id": "9ff9dc23431848a4901b4cb6326ba5bd",
  "timestamp": "2025-12-25T05:40:23.957987",
  "duration_ms": 1.52,
  "method": "tools/call",
  "tool_name": "aiSearch",
  "params": { "arguments": {"query": "λΊ‘μ†Œλ‹ˆ 처벌"} },
  "client": "PlayMCP",
  "client_version": "2025.0.0",
  "protocol_version": "2025-06-18",
  "client_ip": "220.64.111.219",
  "oc": "user_id",
  "status": "success",
  "status_code": 200,
  "result": { ... }
}
```

**Features:**
- Daily log rotation (one file per day)
- Dashboard-compatible format for filtering and analysis
- Captures request/response pairs with timing
- SSE streaming response parsing

**Converting Old Raw Logs:**
```bash
uv run python -m lexlink.log_processor input.jsonl output.jsonl
```

## Troubleshooting

### "OC parameter is required" error

**Solution:** Set your OC identifier using one of the three methods above.

### Korean characters not displaying correctly

**Solution:** Ensure your terminal supports UTF-8:
```bash
export PYTHONIOENCODING=utf-8
```

### "Timeout" errors

**Solution:** Increase timeout via environment variable:
```bash
export LEXLINK_TIMEOUT=90  # Increase from default 60s
```

### Server won't start after updating dependencies

**Solution:** Re-sync dependencies:
```bash
uv sync --reinstall
```

## Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Write tests for new functionality
4. Ensure all tests pass (`uv run pytest`)
5. Commit changes (`git commit -m 'Add amazing feature'`)
6. Push to branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request

## License

This project is open source. See LICENSE file for details.

## Acknowledgments

- **law.go.kr** - Korean National Law Information API
- **MCP** - Model Context Protocol by Anthropic
- **[korean-law-mcp](https://github.com/chrisryugj/korean-law-mcp)** - Inspiration for caching, law name resolution, and chain tools (Phase 9)

## Support

- **Issues:** [GitHub Issues](https://github.com/rabqatab/LexLink-ko-mcp/issues)
- **law.go.kr API:** [Official Documentation](http://open.law.go.kr)

---

## Changelog

### v2.1.0 - 2026-03-30
**New: Caching, Law Name Resolution, Chain Tools (Phase 9)**

- Added intelligent per-tool TTL caching (`cache.py`): search 1hr, articles 24hr, AI search 30min
- Added law name/abbreviation resolution (`resolver.py`): 52 seed aliases + dynamic learning
- Added 5 Phase 9 chain tools: `chain_full_research`, `chain_amendment_track`, `chain_dispute_prep`, `chain_law_system`, `cache_stats`
- Inspired by [korean-law-mcp](https://github.com/chrisryugj/korean-law-mcp)
- See [CHANGELOG.md](CHANGELOG.md) for full details

### v2.0.0 - 2026-03-30
**Major Release: Phase 7 Tools, JSON Default, sections Parameter**

- Added 18 new Phase 7 tools (μžμΉ˜λ²•κ·œ, μ‘°μ•½, 법령정보 μ§€μ‹λ² μ΄μŠ€, μœ„μ›νšŒ κ²°μ •λ¬Έ, μ€‘μ•™λΆ€μ²˜ 해석, νŠΉλ³„ν–‰μ •μ‹¬νŒ)
- JSON is now the default response format (was XML)
- Added `sections="summary"` parameter for case law service tools
- Refactored shared logic into `_helpers.py`
- See [CHANGELOG.md](CHANGELOG.md) for full details

### v1.5.0 - 2026-02-28
**Refactor: Remove Smithery Dependency**

- Removed `smithery` package and 8 transitive dependencies
- Simplified OC resolution to 2-tier (tool arg > env var)
- Added `stdio_server.py` entry point for stdio transport
- See [CHANGELOG.md](CHANGELOG.md) for full details

For the full changelog (v1.0.0 – v2.1.0), see [CHANGELOG.md](CHANGELOG.md).

---

**Powered by [MCP](https://modelcontextprotocol.io)**

TDQS

A3.7/5.0

Scored across 26 tools

Disambiguation3/5

The tools are organized into clear categories like laws, administrative rules, precedents, and interpretations, which helps distinguish them. However, there is significant overlap within categories, such as multiple search tools for laws (eflaw_search, law_search, aiSearch, aiRltLs_search) that could confuse agents about which to use first. The descriptions provide guidance (e.g., 'PREFERRED TOOL' notes), but the redundancy creates ambiguity.

Naming Consistency2/5

Naming is inconsistent across the toolset. Some tools use snake_case (admrul_search, eflaw_service), others use camelCase (aiRltLs_search, lnkDep_search), and some mix styles (drlaw_search). There is no uniform verb_noun pattern; for example, search tools vary (search vs. service suffixes), and tools like article_citation deviate entirely. This inconsistency makes the set harder to navigate.

Tool Count2/5

With 26 tools, the count is excessive for a legal search server, leading to complexity and potential confusion. While the domain (Korean legal research) is broad, many tools are redundant (e.g., eflaw_search and law_search for similar law searches) or highly specialized (e.g., drlaw_search for linkage statistics). A more streamlined set of 10-15 tools could cover the same functionality more coherently.

Completeness4/5

The toolset is highly complete for Korean legal research, covering laws, administrative rules, precedents, interpretations, English translations, and linkages. Each category typically includes search and retrieval tools (e.g., search and service pairs), providing good lifecycle coverage. Minor gaps exist, such as no tool for comparing law versions over time, but overall, the surface is comprehensive for the domain.

Maintenance

ActivityInactive
ResponsivenessResponsive