feat: MCP 서버 추가 — AI 에이전트용 웹 검사 도구
Node.js + TypeScript MCP 서버 구현: - 5개 도구: inspect_page, inspect_site, get_inspection, get_issues, get_history - 듀얼 트랜스포트: stdio (Claude Desktop) + Streamable HTTP (Docker/원격) - i18n 지원 (영어/한국어) - Docker 통합 (port 3100) + Nginx /mcp 프록시 - Smithery 레지스트리 배포 설정 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1
mcp/dist/i18n/en.d.ts
vendored
Normal file
1
mcp/dist/i18n/en.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare const en: Record<string, string>;
|
||||
49
mcp/dist/i18n/en.js
vendored
Normal file
49
mcp/dist/i18n/en.js
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
export const en = {
|
||||
// --- Tool descriptions ---
|
||||
"inspect_page.description": "Inspect a single web page for HTML/CSS quality, accessibility (WCAG/KWCAG), SEO, and performance/security. Returns scores, grades, and top issues. Takes 10-30 seconds.",
|
||||
"inspect_page.param.url": "The URL of the web page to inspect (must start with http:// or https://)",
|
||||
"inspect_page.param.standard": "Accessibility standard to check against (default: wcag_2.1_aa)",
|
||||
"inspect_site.description": "Start a site-wide crawl and inspection. Crawls links from the root URL and inspects each page. Returns a site_inspection_id for tracking. Use get_inspection to check results later.",
|
||||
"inspect_site.param.url": "Root URL of the site to crawl and inspect",
|
||||
"inspect_site.param.max_pages": "Maximum number of pages to crawl (default: 20, max: 500, 0: unlimited)",
|
||||
"inspect_site.param.max_depth": "Maximum link depth to crawl (default: 2, max: 3)",
|
||||
"get_inspection.description": "Get detailed inspection results by inspection ID. Works for both single-page and site inspections.",
|
||||
"get_inspection.param.id": "The inspection_id or site_inspection_id to retrieve",
|
||||
"get_issues.description": "Get a filtered list of issues found during an inspection. Filter by category and/or severity.",
|
||||
"get_issues.param.id": "The inspection_id to get issues for",
|
||||
"get_issues.param.category": "Filter by category: html_css, accessibility, seo, or performance_security",
|
||||
"get_issues.param.severity": "Filter by severity: critical, major, minor, or info",
|
||||
"get_history.description": "List recent inspection history. Optionally filter by URL substring.",
|
||||
"get_history.param.url": "Optional URL substring to filter results",
|
||||
"get_history.param.limit": "Number of results to return (default: 10)",
|
||||
"common.param.language": "Response language: 'en' for English, 'ko' for Korean",
|
||||
// --- Result formatting ---
|
||||
"result.title": "Web Inspection Result",
|
||||
"result.overall_score": "Overall Score",
|
||||
"result.duration": "Duration",
|
||||
"result.standard": "Standard",
|
||||
"result.category_scores": "Category Scores",
|
||||
"result.category": "Category",
|
||||
"result.score": "Score",
|
||||
"result.grade": "Grade",
|
||||
"result.issues": "Issues",
|
||||
"result.issue_summary": "Issue Summary",
|
||||
"result.total": "Total",
|
||||
"result.top_issues": "Top Issues (Critical/Major)",
|
||||
"result.message": "Message",
|
||||
"result.element": "Element",
|
||||
"result.suggestion": "Suggestion",
|
||||
"result.severity": "Severity",
|
||||
"result.more_issues_hint": "Use `get_issues` with inspection_id '{inspectionId}' to see all issues with filtering.",
|
||||
// --- Tool responses ---
|
||||
"inspect_page.timeout": "Inspection timed out for {url}. Inspection ID: {inspectionId}. Try get_inspection later.",
|
||||
"inspect_site.started": "Site inspection started successfully.",
|
||||
"inspect_site.follow_up_hint": "The crawl is running in the background. Use `get_inspection` with ID '{id}' to check the result after a few minutes.",
|
||||
"get_inspection.not_found": "Inspection '{id}' not found.",
|
||||
"get_issues.title": "Issue List",
|
||||
"get_issues.total": "Total Issues",
|
||||
"get_issues.filters": "Filters",
|
||||
"get_history.title": "Inspection History",
|
||||
"get_history.total": "Total Records",
|
||||
};
|
||||
//# sourceMappingURL=en.js.map
|
||||
1
mcp/dist/i18n/en.js.map
vendored
Normal file
1
mcp/dist/i18n/en.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"en.js","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,EAAE,GAA2B;IACxC,4BAA4B;IAC5B,0BAA0B,EACxB,yKAAyK;IAC3K,wBAAwB,EACtB,0EAA0E;IAC5E,6BAA6B,EAC3B,gEAAgE;IAClE,0BAA0B,EACxB,sLAAsL;IACxL,wBAAwB,EAAE,2CAA2C;IACrE,8BAA8B,EAC5B,wEAAwE;IAC1E,8BAA8B,EAC5B,kDAAkD;IACpD,4BAA4B,EAC1B,oGAAoG;IACtG,yBAAyB,EACvB,qDAAqD;IACvD,wBAAwB,EACtB,+FAA+F;IACjG,qBAAqB,EAAE,qCAAqC;IAC5D,2BAA2B,EACzB,2EAA2E;IAC7E,2BAA2B,EACzB,qDAAqD;IACvD,yBAAyB,EACvB,qEAAqE;IACvE,uBAAuB,EAAE,0CAA0C;IACnE,yBAAyB,EAAE,2CAA2C;IACtE,uBAAuB,EAAE,sDAAsD;IAE/E,4BAA4B;IAC5B,cAAc,EAAE,uBAAuB;IACvC,sBAAsB,EAAE,eAAe;IACvC,iBAAiB,EAAE,UAAU;IAC7B,iBAAiB,EAAE,UAAU;IAC7B,wBAAwB,EAAE,iBAAiB;IAC3C,iBAAiB,EAAE,UAAU;IAC7B,cAAc,EAAE,OAAO;IACvB,cAAc,EAAE,OAAO;IACvB,eAAe,EAAE,QAAQ;IACzB,sBAAsB,EAAE,eAAe;IACvC,cAAc,EAAE,OAAO;IACvB,mBAAmB,EAAE,6BAA6B;IAClD,gBAAgB,EAAE,SAAS;IAC3B,gBAAgB,EAAE,SAAS;IAC3B,mBAAmB,EAAE,YAAY;IACjC,iBAAiB,EAAE,UAAU;IAC7B,yBAAyB,EACvB,wFAAwF;IAE1F,yBAAyB;IACzB,sBAAsB,EACpB,0FAA0F;IAC5F,sBAAsB,EAAE,uCAAuC;IAC/D,6BAA6B,EAC3B,sHAAsH;IACxH,0BAA0B,EAAE,8BAA8B;IAC1D,kBAAkB,EAAE,YAAY;IAChC,kBAAkB,EAAE,cAAc;IAClC,oBAAoB,EAAE,SAAS;IAC/B,mBAAmB,EAAE,oBAAoB;IACzC,mBAAmB,EAAE,eAAe;CACrC,CAAC"}
|
||||
6
mcp/dist/i18n/index.d.ts
vendored
Normal file
6
mcp/dist/i18n/index.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Translate a key with optional interpolation.
|
||||
* Usage: t("inspect_page.description", "ko")
|
||||
* t("result.title", "en", { url: "..." })
|
||||
*/
|
||||
export declare function t(key: string, lang: "en" | "ko", params?: Record<string, string | number>): string;
|
||||
18
mcp/dist/i18n/index.js
vendored
Normal file
18
mcp/dist/i18n/index.js
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
import { en } from "./en.js";
|
||||
import { ko } from "./ko.js";
|
||||
const messages = { en, ko };
|
||||
/**
|
||||
* Translate a key with optional interpolation.
|
||||
* Usage: t("inspect_page.description", "ko")
|
||||
* t("result.title", "en", { url: "..." })
|
||||
*/
|
||||
export function t(key, lang, params) {
|
||||
let text = messages[lang]?.[key] || messages["en"]?.[key] || key;
|
||||
if (params) {
|
||||
for (const [k, v] of Object.entries(params)) {
|
||||
text = text.replace(new RegExp(`\\{${k}\\}`, "g"), String(v));
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
mcp/dist/i18n/index.js.map
vendored
Normal file
1
mcp/dist/i18n/index.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,MAAM,QAAQ,GAA2C,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AAEpE;;;;GAIG;AACH,MAAM,UAAU,CAAC,CACf,GAAW,EACX,IAAiB,EACjB,MAAwC;IAExC,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IACjE,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
||||
1
mcp/dist/i18n/ko.d.ts
vendored
Normal file
1
mcp/dist/i18n/ko.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export declare const ko: Record<string, string>;
|
||||
49
mcp/dist/i18n/ko.js
vendored
Normal file
49
mcp/dist/i18n/ko.js
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
export const ko = {
|
||||
// --- 도구 설명 ---
|
||||
"inspect_page.description": "단일 웹 페이지의 HTML/CSS 품질, 접근성(WCAG/KWCAG), SEO, 성능/보안을 검사합니다. 점수, 등급, 주요 이슈를 반환합니다. 10-30초 소요.",
|
||||
"inspect_page.param.url": "검사할 웹 페이지 URL (http:// 또는 https://로 시작)",
|
||||
"inspect_page.param.standard": "접근성 검사 표준 (기본값: wcag_2.1_aa)",
|
||||
"inspect_site.description": "사이트 전체 크롤링 및 검사를 시작합니다. 루트 URL에서 링크를 따라가며 각 페이지를 검사합니다. site_inspection_id를 반환하며, get_inspection으로 결과를 확인할 수 있습니다.",
|
||||
"inspect_site.param.url": "크롤링 및 검사할 사이트의 루트 URL",
|
||||
"inspect_site.param.max_pages": "최대 크롤링 페이지 수 (기본값: 20, 최대: 500, 0: 무제한)",
|
||||
"inspect_site.param.max_depth": "최대 크롤링 깊이 (기본값: 2, 최대: 3)",
|
||||
"get_inspection.description": "검사 ID로 상세 결과를 조회합니다. 단일 페이지 및 사이트 검사 모두 지원.",
|
||||
"get_inspection.param.id": "조회할 inspection_id 또는 site_inspection_id",
|
||||
"get_issues.description": "검사에서 발견된 이슈 목록을 필터링하여 조회합니다. 카테고리 및 심각도로 필터링 가능.",
|
||||
"get_issues.param.id": "이슈를 조회할 inspection_id",
|
||||
"get_issues.param.category": "카테고리 필터: html_css, accessibility, seo, performance_security",
|
||||
"get_issues.param.severity": "심각도 필터: critical, major, minor, info",
|
||||
"get_history.description": "최근 검사 이력을 조회합니다. URL로 필터링 가능.",
|
||||
"get_history.param.url": "결과를 필터링할 URL (부분 문자열)",
|
||||
"get_history.param.limit": "반환할 결과 수 (기본값: 10)",
|
||||
"common.param.language": "응답 언어: 'en' 영어, 'ko' 한국어",
|
||||
// --- 결과 포맷 ---
|
||||
"result.title": "웹 검사 결과",
|
||||
"result.overall_score": "종합 점수",
|
||||
"result.duration": "소요 시간",
|
||||
"result.standard": "검사 표준",
|
||||
"result.category_scores": "카테고리별 점수",
|
||||
"result.category": "카테고리",
|
||||
"result.score": "점수",
|
||||
"result.grade": "등급",
|
||||
"result.issues": "이슈",
|
||||
"result.issue_summary": "이슈 요약",
|
||||
"result.total": "전체",
|
||||
"result.top_issues": "주요 이슈 (Critical/Major)",
|
||||
"result.message": "메시지",
|
||||
"result.element": "요소",
|
||||
"result.suggestion": "개선 제안",
|
||||
"result.severity": "심각도",
|
||||
"result.more_issues_hint": "`get_issues` 도구에 inspection_id '{inspectionId}'를 사용하여 모든 이슈를 필터링해서 확인할 수 있습니다.",
|
||||
// --- 도구 응답 ---
|
||||
"inspect_page.timeout": "{url} 검사가 시간 초과되었습니다. Inspection ID: {inspectionId}. 나중에 get_inspection으로 확인해 보세요.",
|
||||
"inspect_site.started": "사이트 검사가 성공적으로 시작되었습니다.",
|
||||
"inspect_site.follow_up_hint": "크롤링이 백그라운드에서 실행 중입니다. 몇 분 후 `get_inspection`에 ID '{id}'를 사용하여 결과를 확인하세요.",
|
||||
"get_inspection.not_found": "검사 '{id}'를 찾을 수 없습니다.",
|
||||
"get_issues.title": "이슈 목록",
|
||||
"get_issues.total": "전체 이슈 수",
|
||||
"get_issues.filters": "필터",
|
||||
"get_history.title": "검사 이력",
|
||||
"get_history.total": "전체 레코드",
|
||||
};
|
||||
//# sourceMappingURL=ko.js.map
|
||||
1
mcp/dist/i18n/ko.js.map
vendored
Normal file
1
mcp/dist/i18n/ko.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"ko.js","sourceRoot":"","sources":["../../src/i18n/ko.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,EAAE,GAA2B;IACxC,gBAAgB;IAChB,0BAA0B,EACxB,6FAA6F;IAC/F,wBAAwB,EACtB,yCAAyC;IAC3C,6BAA6B,EAC3B,8BAA8B;IAChC,0BAA0B,EACxB,oHAAoH;IACtH,wBAAwB,EAAE,uBAAuB;IACjD,8BAA8B,EAC5B,yCAAyC;IAC3C,8BAA8B,EAC5B,2BAA2B;IAC7B,4BAA4B,EAC1B,6CAA6C;IAC/C,yBAAyB,EACvB,yCAAyC;IAC3C,wBAAwB,EACtB,kDAAkD;IACpD,qBAAqB,EAAE,uBAAuB;IAC9C,2BAA2B,EACzB,6DAA6D;IAC/D,2BAA2B,EACzB,sCAAsC;IACxC,yBAAyB,EACvB,+BAA+B;IACjC,uBAAuB,EAAE,uBAAuB;IAChD,yBAAyB,EAAE,oBAAoB;IAC/C,uBAAuB,EAAE,0BAA0B;IAEnD,gBAAgB;IAChB,cAAc,EAAE,SAAS;IACzB,sBAAsB,EAAE,OAAO;IAC/B,iBAAiB,EAAE,OAAO;IAC1B,iBAAiB,EAAE,OAAO;IAC1B,wBAAwB,EAAE,UAAU;IACpC,iBAAiB,EAAE,MAAM;IACzB,cAAc,EAAE,IAAI;IACpB,cAAc,EAAE,IAAI;IACpB,eAAe,EAAE,IAAI;IACrB,sBAAsB,EAAE,OAAO;IAC/B,cAAc,EAAE,IAAI;IACpB,mBAAmB,EAAE,wBAAwB;IAC7C,gBAAgB,EAAE,KAAK;IACvB,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,KAAK;IACxB,yBAAyB,EACvB,gFAAgF;IAElF,gBAAgB;IAChB,sBAAsB,EACpB,oFAAoF;IACtF,sBAAsB,EAAE,wBAAwB;IAChD,6BAA6B,EAC3B,0EAA0E;IAC5E,0BAA0B,EAAE,uBAAuB;IACnD,kBAAkB,EAAE,OAAO;IAC3B,kBAAkB,EAAE,SAAS;IAC7B,oBAAoB,EAAE,IAAI;IAC1B,mBAAmB,EAAE,OAAO;IAC5B,mBAAmB,EAAE,QAAQ;CAC9B,CAAC"}
|
||||
Reference in New Issue
Block a user