get_article_detail
Retrieve precise article text from Korean laws, including specific paragraphs (hang), subparagraphs (ho), and items (mok). Provide law ID, article number, and optional subsections to get exact legal provisions.
Instructions
[법령조회] 조항호목 단위 정밀 조회. 제38조 제2항 제3호 같은 세부 단위 지정 가능. mst/lawId + jo 필수, hang/ho/mok 선택.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mst | No | 법령일련번호 (search_law에서 획득) | |
| lawId | No | 법령ID (search_law에서 획득) | |
| jo | Yes | 조문 번호 (예: '제38조' 또는 '003800') | |
| hang | No | 항 번호 (예: '2') | |
| ho | No | 호 번호 (예: '3') | |
| mok | No | 목 번호 (예: '1') | |
| apiKey | No | 법제처 Open API 인증키(OC). 사용자가 제공한 경우 전달 |
Implementation Reference
- src/tools/article-detail.ts:25-149 (handler)The main handler function `getArticleDetail` for the tool. It accepts a LawApiClient and GetArticleDetailInput, converts Korean article numbers to JO codes, builds API parameters, fetches data from the law.go.kr API, parses the JSON response, and formats the result including article, sub-paragraph (hang), clause (ho), and item (mok) details.
export async function getArticleDetail( apiClient: LawApiClient, input: GetArticleDetailInput ): Promise<{ content: Array<{ type: string, text: string }>, isError?: boolean }> { try { // 조문 번호가 한글이면 JO 코드로 변환 let joCode = input.jo if (/제\d+조/.test(joCode)) { joCode = buildJO(joCode) } const extraParams: Record<string, string> = {} if (input.mst) extraParams.MST = String(input.mst) if (input.lawId) extraParams.ID = String(input.lawId) extraParams.JO = String(joCode) if (input.hang) extraParams.HANG = String(input.hang) if (input.ho) extraParams.HO = String(input.ho) if (input.mok) extraParams.MOK = String(input.mok) const jsonText = await apiClient.fetchApi({ endpoint: "lawService.do", target: "eflaw", type: "JSON", extraParams, apiKey: input.apiKey }) const json = JSON.parse(jsonText) const lawData = json?.법령 if (!lawData) { return { content: [{ type: "text", text: "법령 데이터를 찾을 수 없습니다." }], isError: true } } const basicInfo = lawData.기본정보 || lawData const lawName = basicInfo?.법령명_한글 || basicInfo?.법령명한글 || basicInfo?.법령명 || "알 수 없음" // 조회 위치 표시 let locationLabel = `제${input.jo.replace(/^제/, "").replace(/조$/, "")}조` if (/^\d{4,6}$/.test(input.jo)) locationLabel = `JO=${input.jo}` if (input.hang) locationLabel += ` 제${input.hang}항` if (input.ho) locationLabel += ` 제${input.ho}호` if (input.mok) locationLabel += ` ${input.mok}목` let resultText = `법령명: ${lawName}\n` resultText += `조회 위치: ${locationLabel}\n\n` // 조문 추출 const rawUnits = lawData.조문?.조문단위 const articleUnits: any[] = Array.isArray(rawUnits) ? rawUnits : rawUnits ? [rawUnits] : [] if (articleUnits.length === 0) { return { content: [{ type: "text", text: resultText + "해당 조문을 찾을 수 없습니다." }], isError: true } } for (const unit of articleUnits) { if (unit.조문여부 !== "조문") continue const joNum = unit.조문번호 || "" const joBranch = unit.조문가지번호 || "" const joTitle = unit.조문제목 || "" const displayNum = joBranch && joBranch !== "0" ? `제${joNum}조의${joBranch}` : `제${joNum}조` resultText += `${displayNum}` if (joTitle) resultText += ` ${joTitle}` resultText += `\n` // 조문내용 if (unit.조문내용) { const content = typeof unit.조문내용 === "string" ? unit.조문내용 : String(unit.조문내용) resultText += `${content}\n` } // 항 내용 if (unit.항) { const hangList = Array.isArray(unit.항) ? unit.항 : [unit.항] for (const hang of hangList) { const hangNum = hang.항번호 || "" const hangContent = hang.항내용 || "" if (hangContent) { resultText += ` ${hangNum ? `(${hangNum})` : ""} ${hangContent}\n` } // 호 내용 if (hang.호) { const hoList = Array.isArray(hang.호) ? hang.호 : [hang.호] for (const ho of hoList) { const hoNum = ho.호번호 || "" const hoContent = ho.호내용 || "" if (hoContent) { resultText += ` ${hoNum}. ${hoContent}\n` } // 목 내용 if (ho.목) { const mokList = Array.isArray(ho.목) ? ho.목 : [ho.목] for (const mok of mokList) { const mokNum = mok.목번호 || "" const mokContent = mok.목내용 || "" if (mokContent) { resultText += ` ${mokNum}. ${mokContent}\n` } } } } } } } resultText += `\n` } return { content: [{ type: "text", text: truncateResponse(resultText) }] } } catch (error) { return formatToolError(error, "get_article_detail") } } - src/tools/article-detail.ts:11-21 (schema)The `GetArticleDetailSchema` Zod schema defining input parameters: mst (law serial number), lawId (law ID), jo (article number, required), hang (sub-paragraph), ho (clause), mok (item), and apiKey. Validates that at least one of mst or lawId is provided.
export const GetArticleDetailSchema = z.object({ mst: z.string().optional().describe("법령일련번호 (search_law에서 획득)"), lawId: z.string().optional().describe("법령ID (search_law에서 획득)"), jo: z.string().describe("조문 번호 (예: '제38조' 또는 '003800')"), hang: z.string().optional().describe("항 번호 (예: '2')"), ho: z.string().optional().describe("호 번호 (예: '3')"), mok: z.string().optional().describe("목 번호 (예: '1')"), apiKey: z.string().optional().describe("법제처 Open API 인증키(OC). 사용자가 제공한 경우 전달") }).refine(data => data.mst || data.lawId, { message: "mst 또는 lawId 중 하나는 필수입니다" }) - src/tool-registry.ts:110-115 (registration)Registration of the 'get_article_detail' tool in the allTools array. Defines the tool name, description ('조항호목 단위 정밀 조회'), assigns GetArticleDetailSchema for validation, and maps to the getArticleDetail handler function.
{ name: "get_article_detail", description: "[법령조회] 조항호목 단위 정밀 조회. 제38조 제2항 제3호 같은 세부 단위 지정 가능. mst/lawId + jo 필수, hang/ho/mok 선택.", schema: GetArticleDetailSchema, handler: getArticleDetail }, - src/tool-registry.ts:20-20 (registration)Import statement for the getArticleDetail handler and GetArticleDetailSchema from the article-detail tool module.
import { getArticleDetail, GetArticleDetailSchema } from "./tools/article-detail.js" - src/lib/law-parser.ts:63-79 (helper)The `buildJO` helper function called by the handler. Converts Korean article number notation (e.g., '제38조', '제10조의2') to 6-digit JO codes (e.g., '003800', '001002') for the legal API.
export function buildJO(input: string): string { if (!input) return "000000" // 이미 6자리 숫자면 그대로 const stripped = input.replace(/\s+/g, "") if (/^\d{6}$/.test(stripped)) return stripped const norm = normalizeArticle(input) const m = norm.match(/^제(\d+)조(?:의(\d+))?$/) if (!m) return "000000" const main = parseInt(m[1], 10) const branch = m[2] ? parseInt(m[2], 10) : 0 if (Number.isNaN(main)) return "000000" return String(main).padStart(4, "0") + String(branch).padStart(2, "0") }