Skip to main content
Glama
scvcoder

korean-privacy-law-mcp

by scvcoder

get_term_articles

Retrieve all legal articles containing a specified term from Korean privacy laws, grouped by matching term variants, with optional body preview.

Instructions

법령용어가 사용된 조문 추적 (법제처 lawService · target=lstrmRltJo). 법령용어 키워드 → 매칭 용어 그룹별로 그 용어가 등장하는 모든 조문 목록 반환. 예: '개인정보' → PIPA·정보통신망법·신용정보법 등 ~700개 조문 (상위 N건). 동음이의 용어는 별도 그룹으로 분리. 페이징 X — maxArticles로 절단. 다음: get_law_text(lawId=...)로 해당 조문 전문, get_legal_term(query)로 정의 확인.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes법령용어명 (예: '개인정보', '가명정보', '고유식별정보'). 정확한 용어명 매칭.
maxArticlesNo용어 그룹별 표시할 최대 연계 조문 수 (기본 20). 응답 절단 한도.
includeBodyNo조문 본문 미리보기(200자) 포함 여부 (기본 true).

Implementation Reference

  • Main handler for the get_term_articles tool. Calls lstrmRltJo API (lawService.do), parses XML response to group terms by homonym, returns linked articles with lawId/joCode for further navigation.
    export const getTermArticles: Tool<typeof inputSchema> = {
      name: "get_term_articles",
      description:
        "법령용어가 사용된 조문 추적 (법제처 lawService · target=lstrmRltJo). " +
        "법령용어 키워드 → 매칭 용어 그룹별로 그 용어가 등장하는 모든 조문 목록 반환. " +
        "예: '개인정보' → PIPA·정보통신망법·신용정보법 등 ~700개 조문 (상위 N건). " +
        "동음이의 용어는 별도 그룹으로 분리. 페이징 X — maxArticles로 절단. " +
        "다음: get_law_text(lawId=...)로 해당 조문 전문, get_legal_term(query)로 정의 확인.",
      inputSchema,
    
      async handler(args, client) {
        try {
          const xml = await client.fetchApi({
            endpoint: "lawService.do",
            target: "lstrmRltJo",
            type: "XML",
            extraParams: { query: args.query },
          });
    
          // rootTag: <lstrmRltJoService>
          const service = extractTag(xml, "lstrmRltJoService") || xml;
          const totalCnt = parseInt(extractTag(service, "검색결과개수"), 10) || 0;
    
          if (totalCnt === 0) {
            return notFoundResponse(`법령용어-조문 연계 결과 없음: "${args.query}"`, [
              `get_legal_term(query="${args.query}") — 정의·동음이의 확인`,
              `intelligent_law_search(query="${args.query}") — 의미검색`,
            ]);
          }
    
          // <법령용어> 그룹 추출 — 동음이의 가능
          const groupXmls = extractTagAll(service, "법령용어");
          const groups: TermGroup[] = [];
    
          for (const groupXml of groupXmls) {
            const 법령용어명 = extractTag(groupXml, "법령용어명");
            const 연계XmlAll = extractTagAll(groupXml, "연계법령");
    
            const 연계법령: LinkedArticle[] = [];
            for (const linkXml of 연계XmlAll) {
              const linkUrl = extractTag(linkXml, "조문연계용어링크");
              const { lawId, joCode } = parseLinkParams(linkUrl);
              연계법령.push({
                법령명: extractTag(linkXml, "법령명"),
                조번호: extractTag(linkXml, "조번호"),
                조가지번호: extractTag(linkXml, "조가지번호"),
                조문내용: extractTag(linkXml, "조문내용"),
                용어구분: extractTag(linkXml, "용어구분"),
                lawId,
                joCode,
              });
            }
            groups.push({ 법령용어명, 연계법령 });
          }
    
          const totalLinks = groups.reduce((sum, g) => sum + g.연계법령.length, 0);
    
          let text = `법령용어-조문 연계 — "${args.query}"\n`;
          text += `용어 그룹 ${groups.length}건 · 연계 조문 총 ${totalLinks}건`;
          if (totalLinks > args.maxArticles * groups.length) {
            text += ` (그룹별 상위 ${args.maxArticles}건 표시)`;
          }
          text += "\n\n";
    
          for (let gi = 0; gi < groups.length; gi++) {
            const g = groups[gi];
            if (!g) continue;
            text += `📌 [법령용어 ${gi + 1}] ${g.법령용어명}\n`;
            text += `   연계 조문 ${g.연계법령.length}건`;
            const truncated = g.연계법령.length > args.maxArticles;
            if (truncated) text += ` (상위 ${args.maxArticles}건 표시)`;
            text += "\n";
    
            const items = g.연계법령.slice(0, args.maxArticles);
            for (let i = 0; i < items.length; i++) {
              const it = items[i];
              if (!it) continue;
              const articleStr = articleNumber(it.조번호, it.조가지번호);
              text += `   [${i + 1}] ${it.법령명} ${articleStr}`;
              if (it.용어구분) text += ` (${it.용어구분})`;
              if (it.lawId) text += ` [lawId=${it.lawId} jo=${it.joCode}]`;
              text += "\n";
              if (args.includeBody && it.조문내용) {
                text += `       ${clip(it.조문내용, PREVIEW_CHARS)}\n`;
              }
            }
            text += "\n";
          }
    
          // 첫 그룹·첫 조문에 대해 다음 도구 권유
          const firstGroup = groups[0];
          const firstItem = firstGroup?.연계법령[0];
          if (firstItem) {
            const suggestions: Array<{
              tool: string;
              args: Record<string, unknown>;
              reason: string;
            }> = [];
            if (firstItem.lawId) {
              suggestions.push({
                tool: "get_law_text",
                args: { lawId: firstItem.lawId },
                reason: `${firstItem.법령명} 전문`,
              });
            }
            suggestions.push({
              tool: "get_legal_term",
              args: { query: args.query },
              reason: `"${args.query}" 정의 확인`,
            });
            text = appendSuggestions(text, suggestions);
          }
    
          return { content: [{ type: "text", text }] };
        } catch (err) {
          return formatToolError(err, "get_term_articles");
        }
      },
    };
  • Input schema for get_term_articles: query (string, min 1), maxArticles (1-100, default 20), includeBody (boolean, default true).
    const inputSchema = z.object({
      query: z
        .string()
        .min(1)
        .describe(
          "법령용어명 (예: '개인정보', '가명정보', '고유식별정보'). 정확한 용어명 매칭."
        ),
      maxArticles: z
        .number()
        .int()
        .min(1)
        .max(100)
        .default(20)
        .describe("용어 그룹별 표시할 최대 연계 조문 수 (기본 20). 응답 절단 한도."),
      includeBody: z
        .boolean()
        .default(true)
        .describe("조문 본문 미리보기(200자) 포함 여부 (기본 true)."),
    });
  • getTermArticles is imported from its implementation file and added to the ALL_TOOLS array (under 'W2 — terminology primitives' section, line 83).
    import { getTermArticles } from "./primitives/get-term-articles.js";
    import { getLawAbbreviations } from "./primitives/get-law-abbreviations.js";
    import { getLawTree } from "./primitives/get-law-tree.js";
    // W3 — Layer C corpus
    import { searchPrivacyCorpus } from "./corpus/search-privacy-corpus.js";
    import { searchPrivacyCases } from "./corpus/search-privacy-cases.js";
    import { searchPrivacyGuides } from "./corpus/search-privacy-guides.js";
    // W3 — Layer B+ hints (PIPC 공식 출처 인덱스화)
    import { getSectoralRelatedLaws } from "./hints/get-sectoral-related-laws.js";
    import { getPipcCuratedCorpus } from "./hints/get-pipc-curated-corpus.js";
    // W4 — Validator (4계층 환각 검증)
    import { verifyPipaCitation } from "./validator/verify-pipa-citation.js";
    
    export const ALL_TOOLS: Tool[] = [
      // W1.5
      searchLaw,
      getLawText,
      intelligentLawSearch,
      getRelatedLaws,
      getAnnexes,
      // W2 — search primitives (admin rule + decisions + interpretations + english)
      searchAdminRule,
      searchPipcDecisions,
      searchConstitutionalDecisions,
      searchAdminAppeals,
      searchInterpretations,
      searchEnglishLaw,
      // W2 — get text primitives
      getAdminRuleText,
      getPipcDecisionText,
      getConstitutionalDecisionText,
      getAdminAppealText,
      getInterpretationText,
      getEnglishLawText,
      // W2 — comparison primitives
      compareAdminRuleOldNew,
      compareArticles,
      // W2 — temporal primitives
      getLawHistory,
      getHistoricalLaw,
      compareOldNew,
      getThreeTier,
      getArticleChangeHistory,
      getDelegatedLaws,
      getLawSystemTree,
      getIntelligentRelatedLaws,
      // W2 — terminology primitives
      getLegalTerm,
      getTermArticles,
      getLawAbbreviations,
  • Tools are indexed into a Map by name (TOOL_INDEX), making get_term_articles discoverable via findTool('get_term_articles').
    const TOOL_INDEX = new Map<string, Tool>(ALL_TOOLS.map((t) => [t.name, t]));
    
    export function findTool(name: string): Tool | undefined {
      return TOOL_INDEX.get(name);
    }
  • Helper functions: parseLinkParams extracts lawId/joCode from link URLs, articleNumber formats article number with branches, clip truncates text for preview.
    function parseLinkParams(linkUrl: string): { lawId: string; joCode: string } {
      const lawIdMatch = linkUrl.match(/[?&]ID=([^&]+)/);
      const joMatch = linkUrl.match(/[?&]JO=([^&]+)/);
      return {
        lawId: lawIdMatch?.[1] ?? "",
        joCode: joMatch?.[1] ?? "",
      };
    }
    
    function articleNumber(조번호: string, 조가지번호: string): string {
      const main = parseInt(조번호, 10) || 0;
      const branch = parseInt(조가지번호, 10) || 0;
      return branch > 0 ? `제${main}조의${branch}` : `제${main}조`;
    }
Behavior5/5

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

No annotations are provided, so the description carries full responsibility. It discloses key behaviors: returns results grouped by matched term, separates homonyms into distinct groups, has no paging, and truncates via maxArticles. It also references the underlying API target. This is thorough for a tool with no annotations.

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 relatively long but well-structured: purpose first, then behavior details, then next steps. Every sentence adds value, though a slight reduction in length could improve conciseness. Overall, it is efficient and front-loaded.

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

Completeness4/5

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

Given the complexity (multiple term groups, homonym handling, no paging) and lack of output schema, the description provides essential context. It covers the main limitation and suggests follow-up tools. It could explicitly mention that output is grouped, but it is implied. Fairly complete.

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 description coverage is 100%, so baseline is 3. The description adds value by explaining that 'query' must be an exact term name, 'maxArticles' is per-group limit, and 'includeBody' provides a 200-character preview. This enriches understanding beyond the schema alone.

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?

The description clearly states the tool's purpose: tracking articles that use a specific legal term, returning a list of all articles per matched term group. It uses specific verbs (추적, 반환) and distinguishes itself from siblings by mentioning next steps to other tools.

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 (to find articles containing a legal term) and provides guidance on subsequent actions (use get_law_text for full article, get_legal_term for definition). It also notes limitations (no paging, maxArticles truncation). It does not explicitly state when not to use it, but the context of sibling tools implies alternatives.

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