korean-law-mcp 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -10
- package/build/server/http-server.js +4 -2
- package/build/tool-registry.js +3 -0
- package/build/tools/admin-rule.js +1 -1
- package/build/tools/chains.js +10 -0
- package/build/tools/customs-interpretations.js +1 -1
- package/build/tools/interpretations.js +1 -1
- package/build/tools/law-tree.js +1 -1
- package/build/tools/ordinance-search.js +1 -1
- package/build/tools/ordinance.js +1 -1
- package/build/tools/tax-tribunal-decisions.js +1 -1
- package/build/tools/treaties.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,15 @@
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
## v2.3.
|
|
17
|
+
## v2.3.1 변경사항
|
|
18
|
+
|
|
19
|
+
- **URL 쿼리 API 키 지원** — 원격 MCP 접속 시 `?oc=your-key`로 API 키를 URL에 포함 가능. 매 요청마다 키를 전달할 필요 없이 세션 전체에 자동 적용. Claude.ai 등 커스텀 헤더 설정이 어려운 웹 클라이언트에서 유용.
|
|
20
|
+
- **체인 도구 자동 전문 조회** — `chain_ordinance_compare`가 자치법규 검색 후 상위 1건 전문을 자동 조회하여 반환. 별도로 `get_ordinance`를 호출할 필요 없음.
|
|
21
|
+
- **lite 프로필 도구 라우팅 개선** — 체인/메타 도구 description을 INPUT 의도 기반으로 재작성. 예시 포함으로 Claude 웹이 자치법규 검색·조회 등 올바른 도구를 선택하도록 개선.
|
|
22
|
+
- **도구 힌트 execute_tool 경로 통일** — 비lite 도구 안내를 `execute_tool()` 호출 예시로 변경. Claude 웹이 존재하지 않는 도구를 직접 호출하는 문제 방지.
|
|
23
|
+
|
|
24
|
+
<details>
|
|
25
|
+
<summary>v2.3.0 변경사항</summary>
|
|
18
26
|
|
|
19
27
|
- **도구 프로필 (lite/full)** — 웹 클라이언트(Claude.ai 등)용 lite 프로필 도입. 89개 → 14개로 자동 축소하여 컨텍스트 소비 87% 절감. `/mcp?profile=lite`로 사용.
|
|
20
28
|
- **체인 8개** + 핵심 직접 도구 4개 + 메타 도구 2개 = 14개로 동일 기능 커버
|
|
@@ -22,6 +30,8 @@
|
|
|
22
30
|
- `execute_tool`: discover로 찾은 도구를 프록시 실행
|
|
23
31
|
- **kordoc 통합 파서** — 자체 HWP5/HWPX/PDF 파서 5개를 [kordoc](https://github.com/chrisryugj/kordoc) 통합 파서로 교체. 의존성 경량화.
|
|
24
32
|
|
|
33
|
+
</details>
|
|
34
|
+
|
|
25
35
|
<details>
|
|
26
36
|
<summary>v2.2.0 변경사항</summary>
|
|
27
37
|
|
|
@@ -89,11 +99,13 @@ API 키는 [법제처 Open API](https://open.law.go.kr/LSO/openApi/guideResult.d
|
|
|
89
99
|
|
|
90
100
|
### 원격 MCP (설치 없이 바로)
|
|
91
101
|
|
|
102
|
+
API 키를 URL에 포함하여 바로 사용:
|
|
103
|
+
|
|
92
104
|
```json
|
|
93
105
|
{
|
|
94
106
|
"mcpServers": {
|
|
95
107
|
"korean-law": {
|
|
96
|
-
"url": "https://korean-law-mcp.fly.dev/mcp"
|
|
108
|
+
"url": "https://korean-law-mcp.fly.dev/mcp?oc=your-api-key"
|
|
97
109
|
}
|
|
98
110
|
}
|
|
99
111
|
}
|
|
@@ -101,18 +113,22 @@ API 키는 [법제처 Open API](https://open.law.go.kr/LSO/openApi/guideResult.d
|
|
|
101
113
|
|
|
102
114
|
**Claude.ai 등 웹 클라이언트** — 컨텍스트 절약을 위해 lite 프로필 권장:
|
|
103
115
|
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
"mcpServers": {
|
|
107
|
-
"korean-law": {
|
|
108
|
-
"url": "https://korean-law-mcp.fly.dev/mcp?profile=lite"
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
116
|
+
```
|
|
117
|
+
https://korean-law-mcp.fly.dev/mcp?profile=lite&oc=your-api-key
|
|
112
118
|
```
|
|
113
119
|
|
|
114
120
|
> lite 프로필은 체인 8개 + 핵심 4개 + 메타 2개 = **14개 도구**로 동일 기능 커버. 특수 도구가 필요하면 `discover_tools` → `execute_tool`로 접근.
|
|
115
121
|
|
|
122
|
+
**API 키 전달 방법** (우선순위순):
|
|
123
|
+
|
|
124
|
+
| 방법 | 예시 | 설명 |
|
|
125
|
+
|------|------|------|
|
|
126
|
+
| URL 쿼리 | `?oc=your-key` | 웹 클라이언트에서 가장 간편. 세션 전체에 자동 적용 |
|
|
127
|
+
| HTTP 헤더 | `apikey: your-key` | `law-oc`, `x-api-key`, `Authorization: Bearer` 등도 지원 |
|
|
128
|
+
| 도구 파라미터 | `apiKey: "your-key"` | 개별 도구 호출 시 직접 전달 |
|
|
129
|
+
|
|
130
|
+
> API 키는 [법제처 Open API](https://open.law.go.kr/LSO/openApi/guideResult.do)에서 무료 발급.
|
|
131
|
+
|
|
116
132
|
### CLI
|
|
117
133
|
|
|
118
134
|
```bash
|
|
@@ -101,8 +101,10 @@ export async function startHTTPServer(createServer, port) {
|
|
|
101
101
|
// POST /mcp - 클라이언트 요청 처리
|
|
102
102
|
app.post("/mcp", async (req, res) => {
|
|
103
103
|
console.error(`[POST /mcp] Received request`);
|
|
104
|
-
// Extract API key
|
|
105
|
-
const
|
|
104
|
+
// Extract API key: URL query > header > 기존 세션
|
|
105
|
+
const apiKeyFromQuery = req.query.oc;
|
|
106
|
+
const apiKeyFromHeader = apiKeyFromQuery ||
|
|
107
|
+
req.headers["apikey"] ||
|
|
106
108
|
req.headers["law_oc"] ||
|
|
107
109
|
req.headers["law-oc"] ||
|
|
108
110
|
req.headers["LAW_OC"] ||
|
package/build/tool-registry.js
CHANGED
|
@@ -670,6 +670,9 @@ export function registerTools(server, apiClient, profile = "full") {
|
|
|
670
670
|
};
|
|
671
671
|
}
|
|
672
672
|
catch (error) {
|
|
673
|
+
console.error(`[CallTool] Error in ${name}:`, error instanceof Error ? error.message : error);
|
|
674
|
+
if (error instanceof Error && error.stack)
|
|
675
|
+
console.error(error.stack);
|
|
673
676
|
const errResult = formatToolError(error, name);
|
|
674
677
|
return {
|
|
675
678
|
content: errResult.content.map(c => ({ type: "text", text: c.text })),
|
|
@@ -59,7 +59,7 @@ export async function searchAdminRule(apiClient, input) {
|
|
|
59
59
|
resultText += ` - 구분: ${ruleType}\n`;
|
|
60
60
|
resultText += ` - 소관부처: ${orgName}\n\n`;
|
|
61
61
|
}
|
|
62
|
-
resultText += `\n💡 상세
|
|
62
|
+
resultText += `\n💡 상세 조회: execute_tool(tool_name="get_admin_rule", params={adminRuleSeq:"일련번호"})`;
|
|
63
63
|
return {
|
|
64
64
|
content: [{
|
|
65
65
|
type: "text",
|
package/build/tools/chains.js
CHANGED
|
@@ -16,6 +16,7 @@ import { searchAdminAppeals } from "./admin-appeals.js";
|
|
|
16
16
|
import { compareOldNew } from "./comparison.js";
|
|
17
17
|
import { getArticleHistory } from "./article-history.js";
|
|
18
18
|
import { searchOrdinance } from "./ordinance-search.js";
|
|
19
|
+
import { getOrdinance } from "./ordinance.js";
|
|
19
20
|
import { getAnnexes } from "./annex.js";
|
|
20
21
|
import { searchAiLaw } from "./life-law.js";
|
|
21
22
|
import { getLawText } from "./law-text.js";
|
|
@@ -382,6 +383,15 @@ export async function chainOrdinanceCompare(apiClient, input) {
|
|
|
382
383
|
const ordinances = await callTool(searchOrdinance, apiClient, { query: ordinanceQuery, display: 20, apiKey: input.apiKey });
|
|
383
384
|
if (!ordinances.isError)
|
|
384
385
|
parts.push(sec("전국 자치법규 검색 결과", ordinances.text));
|
|
386
|
+
// Step 3: 상위 1건 전문 자동 조회
|
|
387
|
+
if (!ordinances.isError) {
|
|
388
|
+
const seqMatch = ordinances.text.match(/\[(\d+)\]/);
|
|
389
|
+
if (seqMatch) {
|
|
390
|
+
const fullText = await callTool(getOrdinance, apiClient, { ordinSeq: seqMatch[1], apiKey: input.apiKey });
|
|
391
|
+
if (!fullText.isError)
|
|
392
|
+
parts.push(sec("조례 전문 (상위 1건)", fullText.text));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
385
395
|
// 키워드 확장
|
|
386
396
|
const exp = detectExpansions(input.query);
|
|
387
397
|
if (exp.includes("interpretation")) {
|
|
@@ -70,7 +70,7 @@ export async function searchCustomsInterpretations(apiClient, args) {
|
|
|
70
70
|
}
|
|
71
71
|
output += `\n`;
|
|
72
72
|
}
|
|
73
|
-
output += `\n💡
|
|
73
|
+
output += `\n💡 전문 조회: execute_tool(tool_name="get_customs_interpretation_text", params={id:"해석례ID"})\n`;
|
|
74
74
|
return {
|
|
75
75
|
content: [{
|
|
76
76
|
type: "text",
|
|
@@ -80,7 +80,7 @@ export async function searchInterpretations(apiClient, args) {
|
|
|
80
80
|
}
|
|
81
81
|
output += `\n`;
|
|
82
82
|
}
|
|
83
|
-
output += `\n💡
|
|
83
|
+
output += `\n💡 전문 조회: execute_tool(tool_name="get_interpretation_text", params={id:"해석례ID"})\n`;
|
|
84
84
|
return {
|
|
85
85
|
content: [{
|
|
86
86
|
type: "text",
|
package/build/tools/law-tree.js
CHANGED
|
@@ -89,7 +89,7 @@ export async function getLawTree(apiClient, input) {
|
|
|
89
89
|
output += ` └─ ... 외 ${structure.rule.length - 5}개 조항\n`;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
output += `\n\n💡
|
|
92
|
+
output += `\n\n💡 위임관계: chain_law_system(query="법령명") 또는 execute_tool(tool_name="get_three_tier", params={mst:"법령MST"})`;
|
|
93
93
|
return {
|
|
94
94
|
content: [{
|
|
95
95
|
type: "text",
|
|
@@ -79,7 +79,7 @@ export async function searchOrdinance(apiClient, input) {
|
|
|
79
79
|
}
|
|
80
80
|
output += `\n`;
|
|
81
81
|
}
|
|
82
|
-
output += `\n💡
|
|
82
|
+
output += `\n💡 전문 조회: execute_tool(tool_name="get_ordinance", params={ordinSeq:"일련번호"})\n`;
|
|
83
83
|
return {
|
|
84
84
|
content: [{
|
|
85
85
|
type: "text",
|
package/build/tools/ordinance.js
CHANGED
|
@@ -77,7 +77,7 @@ export async function getOrdinance(apiClient, input) {
|
|
|
77
77
|
parentLawHints.forEach(h => { resultText += ` - ${h}\n`; });
|
|
78
78
|
}
|
|
79
79
|
else {
|
|
80
|
-
resultText += `\n💡 상위법령 확인: search_law 또는 get_related_laws
|
|
80
|
+
resultText += `\n💡 상위법령 확인: search_law(query="법령명") 또는 execute_tool(tool_name="get_related_laws", params={query:"키워드"})`;
|
|
81
81
|
}
|
|
82
82
|
return {
|
|
83
83
|
content: [{
|
|
@@ -65,7 +65,7 @@ export async function searchTaxTribunalDecisions(apiClient, args) {
|
|
|
65
65
|
}
|
|
66
66
|
output += `\n`;
|
|
67
67
|
}
|
|
68
|
-
output += `\n💡
|
|
68
|
+
output += `\n💡 전문 조회: execute_tool(tool_name="get_tax_tribunal_decision_text", params={id:"사건ID"})\n`;
|
|
69
69
|
return {
|
|
70
70
|
content: [{
|
|
71
71
|
type: "text",
|
package/build/tools/treaties.js
CHANGED
|
@@ -60,7 +60,7 @@ export async function searchTreaties(apiClient, args) {
|
|
|
60
60
|
}
|
|
61
61
|
output += `\n`;
|
|
62
62
|
}
|
|
63
|
-
output += `\n
|
|
63
|
+
output += `\n전문 조회: execute_tool(tool_name="get_treaty_text", params={treatySeq:"조약번호"})\n`;
|
|
64
64
|
return { content: [{ type: "text", text: truncateResponse(output) }] };
|
|
65
65
|
}
|
|
66
66
|
catch (error) {
|