Skip to main content
Glama
scvcoder

korean-privacy-law-mcp

by scvcoder

get_legal_term

Search legal terms defined in Korean statutes and retrieve their official definitions. Compare definitions across multiple laws for the same term.

Instructions

법령용어 검색 + 정의 통합 (법제처 lawSearch · target=lstrm 검색 → lawService · target=lstrm 본문). 키워드 매칭 용어 목록과 각 정의 본문(법령정의사전)을 한 번에 노출. 동일 용어가 여러 법령에서 정의되는 경우 각 정의·출처 모두 펼침. 예: '개인정보' → 「개인정보 보호법」§2·시행령·각 부처 훈령 정의 비교. withDefinitions=false면 목록만. 다음: get_term_articles(용어ID)로 해당 용어 사용 조문 추적.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes법령용어 키워드 (예: '개인정보', '가명정보', '고유식별정보')
displayNo결과 개수 (기본 5, 최대 20). 본문 정의 자동 첨부.
pageNo페이지 번호 (기본 1)
withDefinitionsNo각 용어의 정의 본문 자동 fetch (lawService 1회 추가 호출). false면 검색 결과만 — trmSeqs 노출, 정의 미포함.

Implementation Reference

  • The main Tool export for 'get_legal_term'. Contains the handler function that: (1) searches legal terminology via lawSearch.do with target=lstrm, (2) optionally fetches definitions via lawService.do with target=lstrm, (3) parses flat XML responses into TermDefinition objects using parseDefinitions(), and (4) assembles a text response with suggestions for next tools.
    export const getLegalTerm: Tool<typeof inputSchema> = {
      name: "get_legal_term",
      description:
        "법령용어 검색 + 정의 통합 (법제처 lawSearch · target=lstrm 검색 → lawService · target=lstrm 본문). " +
        "키워드 매칭 용어 목록과 각 정의 본문(법령정의사전)을 한 번에 노출. " +
        "동일 용어가 여러 법령에서 정의되는 경우 각 정의·출처 모두 펼침. " +
        "예: '개인정보' → 「개인정보 보호법」§2·시행령·각 부처 훈령 정의 비교. " +
        "withDefinitions=false면 목록만. 다음: get_term_articles(용어ID)로 해당 용어 사용 조문 추적.",
      inputSchema,
    
      async handler(args, client) {
        try {
          // 1단계: 검색
          const searchXml = await client.fetchApi({
            endpoint: "lawSearch.do",
            target: "lstrm",
            extraParams: {
              query: args.query,
              display: String(args.display),
              page: String(args.page),
            },
          });
    
          const search = parseSearchXML<TermSearchItem>(
            searchXml,
            "LsTrmSearch",
            "lstrm",
            (itemXml) => ({
              법령용어ID: extractTag(itemXml, "법령용어ID"),
              법령용어명: extractTag(itemXml, "법령용어명"),
              사전구분코드: extractTag(itemXml, "사전구분코드"),
              법령종류코드: extractTag(itemXml, "법령종류코드"),
            })
          );
    
          if (search.totalCnt === 0 || search.items.length === 0) {
            return notFoundResponse(`법령용어 검색 결과 없음: "${args.query}"`, [
              `intelligent_law_search(query="${args.query}") — 조문 의미검색`,
              `search_law(query="${args.query}") — 법령명·내용 검색`,
            ]);
          }
    
          // 2단계: 본문(정의) 통합 fetch (옵션)
          let definitions: TermDefinition[] = [];
          if (args.withDefinitions) {
            // 각 항목의 법령용어ID(콤마 구분 다중값 가능)를 모두 모아 한 번에 호출
            const allTrmSeqs = search.items
              .flatMap((it) => it.법령용어ID.split(",").map((s) => s.trim()))
              .filter((s) => s.length > 0);
            const uniqueTrmSeqs = [...new Set(allTrmSeqs)];
    
            if (uniqueTrmSeqs.length > 0) {
              try {
                const detailXml = await client.fetchApi({
                  endpoint: "lawService.do",
                  target: "lstrm",
                  extraParams: { trmSeqs: uniqueTrmSeqs.join(",") },
                });
                definitions = parseDefinitions(detailXml);
              } catch {
                // 본문 fetch 실패 시 검색 결과만 출력
                definitions = [];
              }
            }
          }
    
          const defByTrmSeq = new Map<string, TermDefinition>();
          for (const d of definitions) defByTrmSeq.set(d.trmSeq, d);
    
          // 응답 조립
          let text = `법령용어 — "${args.query}"\n`;
          text += `총 ${search.totalCnt}건 중 ${search.items.length}건 표시 (페이지 ${search.page})\n\n`;
    
          for (let i = 0; i < search.items.length; i++) {
            const item = search.items[i];
            if (!item) continue;
            text += `[${i + 1}] ${item.법령용어명}\n`;
            text += `  trmSeqs: ${item.법령용어ID}\n`;
    
            const trmSeqList = item.법령용어ID.split(",").map((s) => s.trim()).filter(Boolean);
            const matchedDefs = trmSeqList
              .map((seq) => defByTrmSeq.get(seq))
              .filter((d): d is TermDefinition => d !== undefined);
    
            if (args.withDefinitions && matchedDefs.length > 0) {
              for (const d of matchedDefs) {
                const sourceLine = d.출처
                  ? `  📖 ${d.출처}`
                  : `  📖 (출처 없음)`;
                text += `${sourceLine}\n`;
                text += `     ${d.정의 || "(정의 비어 있음)"}\n`;
              }
            } else if (args.withDefinitions) {
              text += `  (정의 본문 fetch 실패 또는 비어 있음)\n`;
            }
            text += "\n";
          }
    
          const firstItem = search.items[0];
          if (firstItem) {
            text = appendSuggestions(text, [
              {
                tool: "get_term_articles",
                args: { trmSeqs: firstItem.법령용어ID },
                reason: `"${firstItem.법령용어명.slice(0, 30)}" 사용 조문 추적`,
              },
              {
                tool: "search_law",
                args: { query: args.query },
                reason: `"${args.query}" 사용된 법령 본문 검색`,
              },
            ]);
          }
    
          return { content: [{ type: "text", text }] };
        } catch (err) {
          return formatToolError(err, "get_legal_term");
        }
      },
    };
  • Zod input schema for get_legal_term: accepts query (string, min 1), display (number 1-20, default 5), page (number, default 1), and withDefinitions (boolean, default true).
    const inputSchema = z.object({
      query: z
        .string()
        .min(1)
        .describe("법령용어 키워드 (예: '개인정보', '가명정보', '고유식별정보')"),
      display: z
        .number()
        .int()
        .min(1)
        .max(20)
        .default(5)
        .describe("결과 개수 (기본 5, 최대 20). 본문 정의 자동 첨부."),
      page: z.number().int().min(1).default(1).describe("페이지 번호 (기본 1)"),
      withDefinitions: z
        .boolean()
        .default(true)
        .describe(
          "각 용어의 정의 본문 자동 fetch (lawService 1회 추가 호출). " +
            "false면 검색 결과만 — trmSeqs 노출, 정의 미포함."
        ),
    });
  • TypeScript interfaces TermSearchItem (for search results) and TermDefinition (for fetched definitions) used within the handler.
    interface TermSearchItem {
      법령용어ID: string;
      법령용어명: string;
      사전구분코드: string;
      법령종류코드: string;
    }
    
    interface TermDefinition {
      trmSeq: string;
      용어명: string;
      출처: string;
      정의: string;
    }
  • parseDefinitions() helper: parses flat XML from lawService response by extracting arrays of tag values (법령용어일련번호, 법령용어명_한글, 출처, 법령용어정의) with extractTagAll and zips them by index into TermDefinition objects.
    function parseDefinitions(xml: string): TermDefinition[] {
      const seqs = extractTagAll(xml, "법령용어일련번호");
      const names = extractTagAll(xml, "법령용어명_한글");
      const sources = extractTagAll(xml, "출처");
      const defs = extractTagAll(xml, "법령용어정의");
    
      const len = Math.min(seqs.length, names.length, sources.length, defs.length);
      const out: TermDefinition[] = [];
      for (let i = 0; i < len; i++) {
        const seq = seqs[i];
        const name = names[i];
        const source = sources[i];
        const def = defs[i];
        if (!seq || !name) continue;
        out.push({
          trmSeq: seq,
          용어명: name,
          출처: source ?? "",
          정의: (def ?? "").trim(),
        });
      }
      return out;
    }
  • Import of getLegalTerm from primitives/get-legal-term.js in the registry module.
    import { getLegalTerm } from "./primitives/get-legal-term.js";
  • Registration of getLegalTerm in the ALL_TOOLS array, under the 'W2 — terminology primitives' section.
    getLegalTerm,
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry full weight. It discloses integration of two services, automatic fetching of definitions, and the expansion of all definitions per term. However, it lacks explicit statements about safety (read-only nature), rate limits, or error handling, leaving some behavioral aspects implied.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded with the main purpose. It uses four sentences to cover purpose, integration details, example, and next steps. No fluff, but slightly lengthy for a single tool description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema is provided, yet the description gives a high-level view of what is returned (list and definitions) and mentions trmSeqs when withDefinitions=false. However, it does not detail the structure of the list or error states, leaving some gaps for an agent invoking the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds value by explaining that withDefinitions=true triggers an extra lawService call and that withDefinitions=false exposes trmSeqs. It also provides a concrete example for the query parameter, enhancing usability beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool searches legal terms and integrates definitions from two services (lawSearch and lawService). It provides an example and differentiates from sibling get_term_articles by mentioning it as a next step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use the tool (for legal term search with integrated definitions) and mentions the alternative get_term_articles for tracking usage articles. It also covers the withDefinitions parameter for opting out of definitions. However, it does not explicitly state when not to use the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/scvcoder/korean-privacy-law-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server