LexLink
Enables AI systems to search, retrieve, and analyze Korean legal information from the National Law Information API (law.go.kr), including laws, administrative rules, English translations, and law-ordinance linkages.
README
<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)
LexLink is an MCP (Model Context Protocol) server that exposes the Korean National Law Information API (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
- 15 MCP Tools 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 (위임법령)
- 100% Semantic Validation - All 15 tools confirmed returning real law data
- Session Configuration - Configure once, use across all tool calls
- Error Handling - Actionable error messages with resolution hints
- Korean Text Support - Proper UTF-8 encoding for Korean characters
- Response Formats - HTML or XML (multiple formats supported)
Project Status
🎉 Production Ready!
| Metric | Status |
|---|---|
| Tools Implemented | 15/15 (100%) ✅ |
| Semantic Validation | 15/15 (100%) ✅ |
| API Coverage | essential ~10% of 150+ endpoints |
| LLM Integration | ✅ Validated (Gemini) |
| Code Quality | Clean, documented, tested |
Achievement: All 15 tools confirmed returning real Korean law data through comprehensive validation testing.
Prerequisites
- Python 3.10+
- Smithery API key (optional, for deployment): Get yours at smithery.ai/account/api-keys
- law.go.kr OC identifier: Get key from open.law.go.kr
Quick Start
1. Install Dependencies
uv sync
2. Configure Your OC Identifier
Choose one of three methods:
Option A: Session Configuration (Recommended)
# Start dev server with OC in URL
uv run dev
# Then in Smithery UI, set oc field in session config
Option B: Environment Variable
# Copy example file
cp .env.example .env
# Edit .env and set your OC
LAW_OC=your_id_here
Option C: Pass in Tool Arguments
# Override OC in each tool call
eflaw_search(query="법령명", oc="your_id")
3. Run the Server
# Development mode (with hot reload)
uv run dev
# Interactive testing with Smithery Playground
uv run playground
Available Tools
Phase 1: Core Law APIs (6 tools)
1. eflaw_search - Search Laws by Effective Date
Search for laws organized by effective date (시행일 기준).
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 (공포일 기준).
law_search(
query="민법",
display=10,
type="XML"
)
3. eflaw_service - Retrieve Law Content (Effective Date)
Get full law text and articles by effective date.
eflaw_service(
id="001823", # Law ID
type="XML",
jo="0001" # Optional: specific article
)
4. law_service - Retrieve Law Content (Announcement Date)
Get full law text and articles by announcement date.
law_service(
id="001823",
type="XML"
)
5. eflaw_josub - Query Article/Paragraph (Effective Date)
Query specific article, paragraph, or sub-item by effective date.
eflaw_josub(
id="001823",
jo="0001", # Article number
type="XML"
)
6. law_josub - Query Article/Paragraph (Announcement Date)
Query specific article, paragraph, or sub-item by announcement date.
law_josub(
id="001823",
jo="0001",
type="XML"
)
Phase 2: Extended APIs (9 tools)
7. elaw_search - Search English-Translated Laws
Search for Korean laws translated to English.
elaw_search(
query="employment",
display=10,
type="XML"
)
8. elaw_service - Retrieve English Law Content
Get full English-translated law text.
elaw_service(
id="009589",
type="XML"
)
9. admrul_search - Search Administrative Rules
Search administrative rules (훈령, 예규, 고시, 공고, 지침).
admrul_search(
query="학교",
display=10,
type="XML"
)
10. admrul_service - Retrieve Administrative Rule Content
Get full administrative rule text with annexes.
admrul_service(
id="62505",
type="XML"
)
11. lnkLs_search - Search Law-Ordinance Linkage
Find laws linked to local ordinances.
lnkLs_search(
query="건축",
display=10,
type="XML"
)
12. lnkLsOrdJo_search - Search Ordinance Articles by Law
Find ordinance articles linked to specific law articles.
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.
lnkDep_search(
org="1400000", # Ministry code
display=10,
type="XML"
)
14. drlaw_search - Retrieve Law-Ordinance Linkage Statistics
Get linkage statistics table (HTML format).
drlaw_search(
lid="001823", # Law ID
type="HTML"
)
15. lsDelegated_service - Retrieve Delegated Law Information
Get information about delegated laws, rules, and ordinances.
lsDelegated_service(
id="001823",
type="XML"
)
Configuration
Session Configuration Schema
Configure once in Smithery UI or URL parameters:
{
"oc": "your_id", # Required: law.go.kr user ID
"debug": false, # Optional: Enable verbose logging
"base_url": "http://www.law.go.kr", # Optional: API base URL
"http_timeout_s": 15 # Optional: HTTP timeout (5-60s)
}
Parameter Priority
When resolving the OC identifier:
- Tool argument (highest priority) -
ocparameter in tool call - Session config - Set in Smithery UI/URL
- Environment variable -
LAW_OCin .env file
Usage Examples
Example 1: Basic Search
# 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
# Find laws effective in 2024
result = eflaw_search(
query="교통",
ef_yd="20240101~20241231",
type="XML"
)
Example 3: Error Handling
# 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. Session config: Set 'oc' in Smithery settings",
"3. Environment variable: LAW_OC=your_value"
]
}
Development
Project Structure
lexlink-ko-mcp/
├── src/lexlink/
│ ├── server.py # Main MCP server with 15 tools
│ ├── config.py # Session configuration schema
│ ├── params.py # Parameter resolution & mapping
│ ├── validation.py # Input validation
│ ├── client.py # HTTP client for law.go.kr API
│ └── errors.py # Error codes & responses
├── pyproject.toml # Project configuration
└── README.md # This file
Running Tests
# 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 tests/unit/
uv run pytest tests/integration/
uv run pytest tests/e2e/
Adding New Tools
Current Status: 15/15 core tools implemented and validated
For implementing additional tools from the 150+ available APIs:
- Follow the pattern established in
src/lexlink/server.py - Use Context injection for session configuration
- Add semantic validation tests
Tool Implementation Pattern:
- Each tool is a decorated function with MCP schema
- Uses
ctx: Context = Noneparameter for session config - 3-tier parameter resolution: tool arg > session > env
- Comprehensive error handling with actionable hints
Deployment
Deploy to Smithery
-
Create a GitHub repository:
git init git add . git commit -m "Initial commit" git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO.git git push -u origin main -
Deploy at smithery.ai/new
-
Configure session settings in Smithery UI
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:
export PYTHONIOENCODING=utf-8
"Timeout" errors
Solution: Increase timeout in session config:
{
"oc": "your_id",
"http_timeout_s": 30 # Increase from default 15s
}
Server won't start after updating dependencies
Solution: Re-sync dependencies:
uv sync --reinstall
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for new functionality
- Ensure all tests pass (
uv run pytest) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - 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
- Smithery - MCP server deployment platform
Support
- Issues: GitHub Issues
- Documentation: See
docs/directory - law.go.kr API: Official Documentation
Changelog
v1.0.7 - 2025-11-10
Fix: Improve search reliability and LLM guidance
- Issue: LLMs often failed to find common laws like "민법" (Civil Code) because:
- Ranking fetch limit (50 results) was too small for large result sets (e.g., 77 results for "민법")
- LLMs defaulted to small
displayvalues (e.g., 5), missing exact matches joparameter rejected integers, causing validation errors and retry loops
- Root Cause:
- v1.0.5 ranking fetched only 50 results; "민법" was beyond position 50 alphabetically
- Tool descriptions didn't guide LLMs to use larger display values
- Parameter type strictness caused UX friction
- Solution:
- Increased ranking fetch limit from 50 to 100 results (API maximum)
- Updated
joparameter to acceptUnion[str, int]with auto-conversion - Added guidance in tool descriptions: "Recommend 50-100 for law searches (법령 검색) to ensure exact matches are found"
- Changes:
- All 4 search tools now fetch up to 100 results for ranking
- All 4 tools with
joparameter (eflaw_service,law_service,eflaw_josub,law_josub) now accept integers - All 7 search tool descriptions updated with display recommendations
- Impact:
- LLMs now find "민법" correctly even with small initial display values
- No more validation errors when LLMs pass article numbers as integers
- Better guidance leads to more efficient searches
v1.0.6 - 2025-11-10
Enhancement: Improve MCP server quality score (Smithery.ai optimization)
- Changes:
- Set OC configuration default value to "test" for easier onboarding
- Added tool annotations to all 15 tools (readOnlyHint=True, destructiveHint=False, idempotentHint=True)
- Enhanced parameter descriptions in docstrings for all tools
- Implemented 3 MCP prompts for common use cases
- Prompts Added:
search-korean-law: Search for a Korean law by name and provide a summaryget-law-article: Retrieve and explain a specific article from a lawsearch-admin-rules: Search administrative rules by keyword
- Impact: Expected Smithery quality score improvement from 47/100 to ~73/100 (+26 points)
- Tool annotations: +9pts
- Parameter descriptions: +12pts
- MCP prompts: +5pts
v1.0.5 - 2025-11-10
Fix: Improve ranking by fetching more results before ranking
- Issue: v1.0.4 ranking was not working properly because it only ranked the limited results returned by the API (e.g., with
display=5, only 5 alphabetically-ordered results were fetched). If "민법" wasn't in those first 5 results, ranking couldn't help. - Root Cause: Ranking logic was applied AFTER API returned limited results, so relevant matches outside the initial page were never considered.
- Solution:
- When ranking is enabled and
display < 50, automatically fetch up to 50 results from API - Apply ranking to the larger result set (50 results)
- Trim back to original requested
displayamount after ranking - Update
numOfRowsin response to reflect actual number of results returned
- When ranking is enabled and
- Implementation:
- Updated all 4 search tools:
eflaw_search,law_search,elaw_search,admrul_search - Added
original_displaytracking andranking_enabledflag - Fetch 50 results when ranking applies, then trim to requested amount
- Updated all 4 search tools:
- Examples:
- User requests
display=5for query "민법" - System fetches 50 results (includes "민법" even if it's not in first 5 alphabetically)
- Ranking places "민법" first
- System returns top 5 ranked results (now "민법" appears first)
- User requests
- Impact: Ranking now actually works - exact matches appear first regardless of alphabetical position in API results
v1.0.4 - 2025-11-10
Feature: Add relevance ranking to search results
- Issue: law.go.kr API returns results in alphabetical order, causing irrelevant matches to appear first (e.g., searching "민법" returned "난민법" first instead of exact match "민법")
- Solution:
- Added intelligent relevance ranking that prioritizes exact matches over alphabetical ordering
- Ranking applies automatically to XML responses for keyword searches
- Results are reordered: exact match → starts with query → contains query → other matches
- Implementation:
- Added
ranking.pymodule withrank_search_results(),should_apply_ranking(), anddetect_query_language()functions - Added
parser.pymodule for XML parsing and structured data extraction - Updated 4 major search tools:
eflaw_search,law_search,elaw_search,admrul_search - Ranking preserves raw XML while adding
ranked_datafield for LLM consumption - Special handling for
elaw_search: Detects query language (Korean vs English) and ranks by matching name field
- Added
- Examples:
- Query "민법" now returns: "민법" (exact) → "민법 시행령" (starts with) → "난민법" (alphabetical)
- Query "insurance" ranks: "Insurance Act" → "Insurance Business Act" → other matches
- Impact: Significantly improves search relevance, reducing LLM confusion and providing better user experience
v1.0.3 - 2025-11-10
Fix: Clarify article number format in tool descriptions
- Issue: LLMs misinterpreted the 6-digit article number format (
joparameter), generating "000200" for Article 20 (제20조) instead of correct "002000", resulting in wrong article retrieval - Root Cause: Tool descriptions used ambiguous example "000200" for "Article 2", leading LLMs to incorrectly pattern-match Article 20 → "000200"
- Solution:
- Added comprehensive article number format documentation with multiple examples
- Added
format_article_number()helper function invalidation.pyfor future use - Clarified that XXXXXX format = first 4 digits (article number, zero-padded) + last 2 digits (branch article suffix)
- Changes:
- Updated 4 tools:
eflaw_service,law_service,eflaw_josub,law_josub - Updated
lnkLsOrdJo_searchwhich uses separate 4+2 digit format - Added clear examples: "000200" (Art. 2), "002000" (Art. 20), "001502" (Art. 15-2)
- Updated 4 tools:
- Impact: LLMs will now correctly format article numbers, preventing queries from returning wrong articles
v1.0.2 - 2025-11-10
Fix: Accept both string and integer for id/mst parameters
- Issue: LLMs extract numeric values from XML responses as integers (e.g.,
<법령일련번호>188376</법령일련번호>→mst=188376), but tools expected strings, causing Pydantic validation errors - Solution: Changed parameter types to accept both strings and integers with automatic conversion
- Changes:
- Updated 7 tool signatures:
id: Optional[str]→id: Optional[Union[str, int]] - Added automatic string conversion at start of each affected tool
- Applied to:
eflaw_service,law_service,eflaw_josub,law_josub,elaw_service,admrul_service,lsDelegated_service
- Updated 7 tool signatures:
- Impact: LLMs can now pass numeric IDs as integers without validation errors
v1.0.1 - 2025-11-10
Fix: Remove JSON format option from all tools
- Issue: LLMs were selecting JSON format, but law.go.kr API does not support JSON despite documentation (returns HTML error pages with "미신청된 목록/본문" message)
- Solution: Removed JSON as an option from all 14 tool descriptions
- Changes:
- Updated
typeparameter documentation to explicitly state "JSON not supported by API" - Added warning in module docstring about JSON format limitation
- Tool defaults remain XML (working format)
- Updated
- Impact: Prevents LLMs from requesting JSON format and receiving error pages
v1.0.0 - 2025-11-10
Initial Release
- 15 MCP tools for Korean law information access
- 6 core law APIs (eflaw/law search and retrieval)
- 9 extended APIs (English laws, administrative rules, law-ordinance linkage)
- Session configuration via Context injection
- 100% semantic validation
- Production-ready for Smithery deployment
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.