search_pipc_decisions
Search PIPC decisions to find violation cases, fines, and corrective orders by keyword. Retrieve summaries or full text of rulings.
Instructions
개인정보보호위원회(PIPC) 결정문 검색 (법제처 lawSearch · target=ppc). 심의·의결, 침해요인 평가, 분쟁조정 등 PIPC가 발한 모든 결정문 조회. 도메인 핵심 — 위반 사례·과징금·시정조치 직접 확인 가능. 다음: get_pipc_decision_text(W2.5)로 결정문 전문.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | PIPC 결정문 키워드. 안건명·결정구분 등 매칭. | |
| display | No | 결과 개수 (기본 20) | |
| page | No | 페이지 번호 (기본 1) |
Implementation Reference
- The main tool handler for search_pipc_decisions. Calls the lawApiClient to fetch PIPC decisions from lawSearch.do with target=ppc, parses XML, formats results with decision IDs, names, and metadata, and appends suggestions for next actions like get_pipc_decision_text.
export const searchPipcDecisions: Tool<typeof inputSchema> = { name: "search_pipc_decisions", description: "개인정보보호위원회(PIPC) 결정문 검색 (법제처 lawSearch · target=ppc). " + "심의·의결, 침해요인 평가, 분쟁조정 등 PIPC가 발한 모든 결정문 조회. " + "도메인 핵심 — 위반 사례·과징금·시정조치 직접 확인 가능. " + "다음: get_pipc_decision_text(W2.5)로 결정문 전문.", inputSchema, async handler(args, client) { try { const xml = await client.fetchApi({ endpoint: "lawSearch.do", target: "ppc", extraParams: { query: args.query, display: String(args.display), page: String(args.page), }, }); const result = parseSearchXML<PipcDecisionItem>( xml, "Ppc", "ppc", (itemXml) => ({ 결정문일련번호: extractTag(itemXml, "결정문일련번호"), 안건명: extractTag(itemXml, "안건명"), 의안번호: extractTag(itemXml, "의안번호"), 회의종류: extractTag(itemXml, "회의종류"), 결정구분: extractTag(itemXml, "결정구분"), 의결일: extractTag(itemXml, "의결일"), }) ); if (result.totalCnt === 0) { return notFoundResponse(`PIPC 결정문 검색 결과 없음: "${args.query}"`, [ `intelligent_law_search(query="${args.query}") — 법령 조문 검색 fallback`, ]); } let text = `PIPC 결정문 — "${args.query}"\n`; text += `총 ${result.totalCnt}건 중 ${result.items.length}건 표시 (페이지 ${result.page})\n\n`; for (const item of result.items) { text += `[id=${item.결정문일련번호}] ${item.안건명}\n`; if (item.의안번호) text += ` 의안: ${item.의안번호}\n`; if (item.결정구분) text += ` 구분: ${item.결정구분}\n`; if (item.회의종류) text += ` 회의: ${item.회의종류}\n`; if (item.의결일) text += ` 의결일: ${item.의결일}\n`; text += "\n"; } const firstItem = result.items[0]; if (firstItem) { text = appendSuggestions(text, [ { tool: "get_pipc_decision_text", args: { id: firstItem.결정문일련번호 }, reason: `결정문 전문 — "${firstItem.안건명.slice(0, 30)}..."`, }, ]); text += `\n📎 출처: 개인정보보호위원회 결정문 — 첫 결과 ${pipcDecisionUrl(firstItem.결정문일련번호)}`; } return { content: [{ type: "text", text }] }; } catch (err) { return formatToolError(err, "search_pipc_decisions"); } }, }; - Input schema using zod: requires query (string, min 1), optional display (1-100, default 20), optional page (default 1).
const inputSchema = z.object({ query: z .string() .min(1) .describe("PIPC 결정문 키워드. 안건명·결정구분 등 매칭."), display: z.number().int().min(1).max(100).default(20).describe("결과 개수 (기본 20)"), page: z.number().int().min(1).default(1).describe("페이지 번호 (기본 1)"), }); - TypeScript interface for each PIPC decision item parsed from XML response.
interface PipcDecisionItem { 결정문일련번호: string; 안건명: string; 의안번호: string; 회의종류: string; 결정구분: string; 의결일: string; } - src/tools/registry.ts:13-57 (registration)Imported and registered in ALL_TOOLS array at line 57, making it available to the MCP server.
import { searchPipcDecisions } from "./primitives/search-pipc-decisions.js"; import { searchConstitutionalDecisions } from "./primitives/search-constitutional-decisions.js"; import { searchAdminAppeals } from "./primitives/search-admin-appeals.js"; import { searchInterpretations } from "./primitives/search-interpretations.js"; import { searchEnglishLaw } from "./primitives/search-english-law.js"; import { getAdminRuleText } from "./primitives/get-admin-rule-text.js"; import { getPipcDecisionText } from "./primitives/get-pipc-decision-text.js"; import { getConstitutionalDecisionText } from "./primitives/get-constitutional-decision-text.js"; import { getAdminAppealText } from "./primitives/get-admin-appeal-text.js"; import { getInterpretationText } from "./primitives/get-interpretation-text.js"; import { getEnglishLawText } from "./primitives/get-english-law-text.js"; import { compareAdminRuleOldNew } from "./primitives/compare-admin-rule-old-new.js"; import { getLawHistory } from "./primitives/get-law-history.js"; import { getHistoricalLaw } from "./primitives/get-historical-law.js"; import { compareOldNew } from "./primitives/compare-old-new.js"; import { getThreeTier } from "./primitives/get-three-tier.js"; import { getArticleChangeHistory } from "./primitives/get-article-change-history.js"; import { getDelegatedLaws } from "./primitives/get-delegated-laws.js"; import { getLawSystemTree } from "./primitives/get-law-system-tree.js"; import { getIntelligentRelatedLaws } from "./primitives/get-intelligent-related-laws.js"; import { compareArticles } from "./primitives/compare-articles.js"; import { getLegalTerm } from "./primitives/get-legal-term.js"; 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, - src/lib/errors.ts:24-95 (helper)Error formatting helper used by the handler to standardize error responses with API key masking.
export function formatToolError(error: unknown, toolName: string): ToolResponse { const message = error instanceof Error ? error.message : String(error); return { content: [{ type: "text", text: `[ERROR] ${toolName}: ${maskApiKey(message)}` }], isError: true, }; } /** 에러 메시지·로그에 OC API 키가 노출되지 않도록 마스킹 */ export function maskApiKey(text: string): string { return text.replace(/OC=[^&\s]+/gi, "OC=***"); }