kim57uak/search-mcp-server
If you are the rightful owner of search-mcp-server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
MCP Naver Search Server is a Node.js server implementing the Model Context Protocol (MCP) to provide Naver web search functionality.
MCP Search Server (Node.js)
다양한 웹 검색 기능을 제공하는 모델 컨텍스트 프로토콜(MCP)을 구현한 Node.js 서버입니다. 이 프로젝트는 @modelcontextprotocol/sdk를 사용하여 MCP 호환 도구를 노출합니다.
✨ 주요 기능
- 유연한 검색 엔진 지원:
search_engines.json파일을 통해 다양한 검색 엔진 설정을 지원하며, 특정 엔진 검색 및 여러 엔진 통합 검색이 가능합니다. - 일반 웹 검색 도구 (
search):- 주어진 검색어에 대해 특정 검색 엔진 또는 여러 엔진에서 웹 검색을 수행합니다.
- 검색 결과에서 HTML 태그를 포함하거나 제거하는 옵션을 제공합니다.
- 언어 코드를 지정하여 해당 언어를 지원하는 엔진을 대상으로 검색할 수 있습니다.
- 특수 Google 검색 도구 (
googleSearch):- CAPTCHA 우회를 시도하는
HumanLikeGoogleCrawler를 사용하여 Google 검색을 수행합니다.
- CAPTCHA 우회를 시도하는
- Perplexity AI 검색 도구 (
perplexitySearch):- Perplexity AI의 검색 API를 사용하여 실시간 웹 검색 결과를 제공합니다.
- 지역별 검색 결과 필터링 및 최대 3개 결과 반환 (maxResult: 3, maxTokenPerPage: 1024).
- URL 콘텐츠 가져오기 및 사용자 정의 URL 검색 (
fetchUrl):- 지정된 URL의 웹 페이지 콘텐츠를 가져옵니다.
- URL과 함께 검색어 및 검색 파라미터 이름을 제공하여, 해당 URL 기반으로 사용자 정의 검색을 실행할 수 있습니다.
- MCP 호환:
@modelcontextprotocol/sdk를 사용하여 MCP 표준을 따르는 도구를 제공합니다. - 설정 가능:
- 검색 엔진 관련 설정:
search_engines.json(엔진별 URL, 쿼리 파라미터 등) - 서비스 및 크롤러 설정:
src/config/serviceConfig.js(크롤러 타입, 상세 옵션, Google UI 선택자 등)
- 검색 엔진 관련 설정:
- 구조화된 로깅:
winston을 활용하여 상세한 로그를 제공합니다. - SOLID 설계 원칙: 유지보수성과 확장성을 고려하여 개발되었습니다.
⚙️ 모델 컨텍스트 프로토콜(MCP)에 대하여
모델 컨텍스트 프로토콜(MCP) SDK (@modelcontextprotocol/sdk)는 이 서버의 핵심 구성 요소입니다. 이 서버가 노출하는 도구를 정의하고 관리하기 위한 프레임워크와 유틸리티를 제공합니다.
MCP SDK는 package.json 파일에 프로젝트 종속성으로 나열되어 있으며, npm install 명령을 실행하면 자동으로 설치됩니다.
🚀 시작하기
1. NPX를 이용한 직접 실행 (권장, 설치 불필요)
이 도구는 npx를 사용하여 GitHub 저장소에서 직접 실행할 수 있습니다. 별도의 설치 과정이 필요 없습니다.
npx github:kim57uak/search-mcp-server
위 명령을 실행하면 자동으로 최신 버전의 도구를 GitHub에서 내려받아 실행합니다. MCP 서버가 시작되고 표준 입출력을 통해 통신할 준비가 됩니다.
2. 로컬 개발 및 테스트를 위한 설정
로컬 환경에서 개발하거나 테스트하려면 다음 단계를 따르세요.
- 저장소 복제:
git clone https://github.com/kim57uak/search-mcp-server.git cd search-mcp-server - 종속성 설치:
npm install - 서버 실행:
또는 개발 모드(nodemon 사용):
npm startnpm run dev
서버가 시작되면 표준 입력(stdin)을 통해 MCP 요청을 수신하고 표준 출력(stdout)을 통해 응답합니다.
search_engines.json 파일을 통해 사용할 검색 엔진을 설정할 수 있습니다.
환경 변수 설정
Perplexity AI 검색 기능을 사용하려면 API 키가 필요합니다:
-
환경 변수로 설정:
export PERPLEXITY_API_KEY="your_api_key_here" -
.env파일 생성:cp .env.example .env # .env 파일을 편집하여 실제 API 키 입력.env파일 내용:PERPLEXITY_API_KEY=your_api_key_here
중요: 타 플랫폼(Claude Desktop, VS Code 등)에서 MCP 서버를 사용할 때는 해당 플랫폼의 환경 변수 설정 방법을 따라야 합니다. 예를 들어:
- Claude Desktop:
claude_desktop_config.json에서env섹션에 환경 변수 설정 - VS Code: 워크스페이스 설정 또는 시스템 환경 변수 사용
📄 개발자 문서
개발, 기여 가이드라인 및 프로젝트 아키텍처에 대한 자세한 정보는 ****를 참조하십시오.
🛠️ 사용 가능한 MCP 도구
1. search (일반 검색)
- 설명: 웹 검색을 수행합니다.
engineName으로 특정 검색 엔진을 지정하거나,languageCode를 제공하여 해당 언어를 지원하는 여러 엔진에서 검색할 수 있습니다.engineName이 지정되지 않으면languageCode를 기반으로 (또는 모든) 사용 가능한 여러 엔진에서 통합 검색을 시도합니다. (search_engines.json에 정의된 엔진 사용) - 입력 (
inputs):query(string, 필수): 검색할 단어나 문장입니다.engineName(string, 선택): 검색을 수행할 특정 엔진의 이름입니다 (예: "Naver", "Bing".search_engines.json파일 참고).languageCode(string, 선택): 검색 결과의 언어를 지정하거나, 통합 검색 시 해당 언어를 지원하는 엔진을 필터링하는 데 사용됩니다 (예: "ko", "en").includeHtml(boolean, 선택, 기본값:false):true로 설정하면 결과에 HTML 태그를 포함하고,false이면 제거된 텍스트만 반환합니다.
- 예상 출력 (MCP 응답의
result.content[0].text내부 JSON 문자열):- 특정 엔진 검색 시 (
engineName제공):{ "query": "검색어", "engine": "엔진이름", "language": "언어코드", // 제공된 경우 "resultText": "검색 결과 내용 (HTML 포함 또는 제거됨)", "retrievedAt": "YYYY-MM-DDTHH:mm:ss.sssZ", "searchUrl": "실제요청된검색URL" } - 통합 검색 시 (
engineName미제공):[ // 여러 엔진 결과의 배열 { "query": "검색어", "searchEngine": "엔진이름1", "language": "언어코드", // 제공된 경우 "resultText": "엔진1 검색 결과...", "retrievedAt": "YYYY-MM-DDTHH:mm:ss.sssZ", "searchUrl": "실제요청된검색URL1" }, { "query": "검색어", "searchEngine": "엔진이름2", // ... (오류 발생 시 error 필드 포함) "error": "엔진2 검색 실패 메시지", "retrievedAt": "YYYY-MM-DDTHH:mm:ss.sssZ" } ]
- 특정 엔진 검색 시 (
- 호출 예시 (Stdio):
- Naver에서 "Node.js" 검색:
{ "tool": "search", "inputs": { "query": "Node.js", "engineName": "Naver", "languageCode": "ko", "includeHtml": false }, "id": "readme-generic-naver" } - 한국어를 지원하는 엔진들에서 "날씨" 통합 검색:
{ "tool": "search", "inputs": { "query": "날씨", "languageCode": "ko", "includeHtml": false }, "id": "readme-integrated-ko" }
- Naver에서 "Node.js" 검색:
2. googleSearch (Google 특화 검색)
- 설명: Google 검색을 "인간처럼" 수행하여 결과를 반환합니다. CAPTCHA 우회를 시도하는 특수 크롤러(
HumanLikeGoogleCrawler)를 사용합니다. 검색 결과는 주로 Google 설정 및 검색어의 언어에 따라 반환됩니다. - 입력 (
inputs):query(string, 필수): 검색할 단어나 문장입니다.includeHtml(boolean, 선택, 기본값:false): HTML 태그 포함 여부.
- 예상 출력 (MCP 응답의
result.content[0].text내부 JSON 문자열):{ "query": "검색어", "resultText": "Google 검색 결과 내용 (HTML 포함 또는 제거됨)", "retrievedAt": "YYYY-MM-DDTHH:mm:ss.sssZ", "searchEngine": "google" } - 호출 예시 (Stdio):
{ "tool": "googleSearch", "inputs": { "query": "오늘의 구글 검색", "includeHtml": false }, "id": "readme-example-google" }
3. perplexitySearch (Perplexity AI 검색)
- 설명: Perplexity AI의 검색 API를 사용하여 최신 정보를 검색합니다. 실시간 웹 검색 결과를 제공하며, 지역별 검색 결과 필터링이 가능합니다.
- 입력 (
inputs):query(string, 필수): 검색할 단어나 문장입니다.country(string, 선택): 지역별 검색 결과를 위한 ISO 3166-1 alpha-2 국가 코드 (예: "US", "KR", "JP").includeHtml(boolean, 선택, 기본값:false): HTML 태그 포함 여부.
- 예상 출력 (MCP 응답의
result.content[0].text내부 JSON 문자열):{ "query": "검색어", "country": "KR", // 제공된 경우 "results": [ { "title": "검색 결과 제목", "url": "https://example.com", "snippet": "검색 결과 요약 내용...", "date": "2024-01-01", // 제공된 경우 "last_updated": "2024-01-01" // 제공된 경우 } ], "retrievedAt": "YYYY-MM-DDTHH:mm:ss.sssZ", "searchEngine": "perplexity", "totalResults": 3 } - 호출 예시 (Stdio):
{ "tool": "perplexitySearch", "inputs": { "query": "최신 AI 동향 2024", "country": "KR", "includeHtml": false }, "id": "readme-perplexity-search" }
4. fetchUrl (URL 콘텐츠 가져오기 및 사용자 정의 URL 검색)
- 설명: 제공된 URL의 웹 페이지 콘텐츠를 가져옵니다. 선택적으로 검색어(
query)와 검색어 파라미터명(queryParamName)을 제공하여, 해당 URL에 검색어를 추가하여 요청하고 그 결과를 반환할 수 있습니다 (예: 특정 검색 엔진의 URL 템플릿에 검색어 삽입). - 입력 (
inputs):url(string, 필수): 내용을 가져올 웹 페이지의 전체 URL 또는 검색을 위한 기본 URL입니다.query(string, 선택):url에 추가할 검색어입니다. 이 값이 제공되면 사용자 정의 URL 검색으로 동작합니다.queryParamName(string, 선택, 기본값:q):query를 전달할 URL 파라미터의 이름입니다.includeHtml(boolean, 선택, 기본값:false): 결과에 HTML 태그 포함 여부.
- 예상 출력 (MCP 응답의
result.content[0].text내부 JSON 문자열):{ "url": "요청된 최종 URL", // query가 사용된 경우 변경된 URL "textContent": "추출된 텍스트 내용...", "retrievedAt": "YYYY-MM-DDTHH:mm:ss.sssZ", "originalUrl": "사용자가 입력한 초기 URL", // query 사용 시에만 포함될 수 있음 "queryUsed": "사용된 검색어", // query 사용 시에만 포함될 수 있음 "targetUrl": "실제 요청된 최종 URL" // query 사용 시 변경된 URL과 동일 } - 호출 예시 (Stdio):
- 단순 URL 내용 가져오기:
{ "tool": "fetchUrl", "inputs": { "url": "https://developer.mozilla.org/ko/docs/Web/JavaScript", "includeHtml": false }, "id": "readme-fetch-simple" } - 사용자 정의 URL로 검색 (DuckDuckGo URL 템플릿 사용):
{ "tool": "fetchUrl", "inputs": { "url": "https://duckduckgo.com/", "query": "Node.js MCP", "queryParamName": "q", "includeHtml": true }, "id": "readme-fetch-custom-search" }
- 단순 URL 내용 가져오기:
📦 프로젝트 구조
mcp-search-server/ ├── logs/ # 로그 파일 (gitignored) ├── src/ # 소스 코드 │ ├── config/ # 설정 파일 (serviceConfig.js) │ ├── crawlers/ # 크롤러 구현 (humanLikeGoogleCrawler.js 등) │ ├── services/ # 비즈니스 로직 (searchService.js) │ ├── tools/ # MCP 도구 정의 (genericSearchTool.js, googleSearchTool.js, urlFetcherTool.js, index.js) │ ├── transports/ # 전송 계층 설정 (stdioTransport.js) │ └── utils/ # 유틸리티 함수 (logger.cjs, htmlParser.js, searchEngineManager.js 등) ├── tests/ # 테스트 코드 ├── .gitignore ├── .prettierrc.json # Prettier 설정 ├── DEVELOPER_MANUAL.ko.md ├── INSTALL.md ├── README.md # 현재 파일 ├── eslint.config.mjs # ESLint 설정 (flat config) ├── jest.config.js # Jest 설정 ├── nodemon.json # Nodemon 설정 ├── package.json ├── package-lock.json └── search_engines.json # 검색 엔진 URL 및 파라미터 설정
🌐 크롤러 상세: Google 검색 및 CAPTCHA 우회
이 프로젝트의 googleSearch 도구는 src/crawlers/humanLikeGoogleCrawler.js에 구현된 특수 크롤러를 사용합니다. 이 크롤러는 Google의 CAPTCHA 및 봇 탐지 메커니즘을 우회하기 위해 다양한 전략을 사용합니다.
Google 검색 크롤러 (HumanLikeGoogleCrawler)
- Puppeteer 기반: 실제 Chrome 브라우저를 제어하는 Puppeteer 라이브러리를 사용하여 웹 페이지와 상호작용합니다. 이를 통해 JavaScript 실행, 사용자 입력 시뮬레이션 등 실제 사용자와 유사한 환경을 구성합니다.
- Stealth 기능:
puppeteer-extra-plugin-stealth플러그인을 사용하여 Puppeteer가 자동화된 브라우저임을 나타내는 다양한 지표(예:navigator.webdriver플래그)를 숨깁니다. 또한 User-Agent, 브라우저 플러그인 정보, 언어 설정 등을 실제 사용자와 유사하게 위장합니다.
CAPTCHA 우회 및 탐지 회피 전략
Google의 정교한 봇 탐지 시스템에 대응하기 위해 다음과 같은 기법들이 적용되었습니다:
- 다양한 User-Agent 랜덤 사용: 미리 정의된 최신 브라우저 User-Agent 목록에서 무작위로 선택하여 사용합니다.
- Viewport 설정: 일반적인 데스크톱 해상도(예: 1920x1080)로 브라우저 Viewport를 설정하여 일관성을 높입니다.
- 인간과 유사한 행동 시뮬레이션:
- 마우스 커서의 자연스러운 이동 및 클릭 위치의 미세한 랜덤 변화.
- 검색어 입력 시 실제 타이핑과 유사한 랜덤 딜레이 적용.
- 페이지 로드 후 랜덤 스크롤 및 마우스 이동.
- 요청 간 랜덤 딜레이: 페이지 이동, 클릭, 입력 등 주요 작업 전후에 예측 불가능한 랜덤 딜레이를 추가하여 자동화된 패턴을 깨뜨립니다.
- CAPTCHA 감지 시 재시도 로직:
- "로봇이 아닙니다", "비정상 트래픽" 등의 키워드로 CAPTCHA 페이지를 감지합니다.
- 감지 시, 최대 2회까지 재시도를 수행합니다. (총 3회 시도)
- 재시도 사이에는 5~10초의 비교적 긴 랜덤 대기 시간을 가집니다.
최근 개선 사항
- Viewport 설정 추가: 모든 Google 검색 시 동일한 Viewport(1920x1080)를 사용하도록 설정했습니다.
- 딜레이 강화: 크롤링 과정 전반의 랜덤 딜레이 값을 조정하고 다양성을 높였습니다.
- 재시도 로직 개선: CAPTCHA 발생 시 재시도 횟수를 늘리고, 재시도 간 대기 시간을 증가시켰습니다.
한계점 및 주의사항
- 완벽한 우회는 어려움: Google의 봇 탐지 알고리즘은 지속적으로 업데이트되므로, 현재 적용된 방법으로도 CAPTCHA가 간헐적으로 발생하거나 향후 다시 문제가 될 수 있습니다.
- IP 주소 평판: 사용되는 서버의 IP 주소가 과거에 스팸이나 어뷰징에 사용된 적이 있다면 CAPTCHA 발생 빈도가 높아질 수 있습니다. 깨끗한 IP를 사용하는 것이 중요합니다.
- 과도한 요청: 짧은 시간에 너무 많은 요청을 보내면 IP가 차단되거나 CAPTCHA가 더 자주 발생할 수 있습니다. 적절한 요청 간격을 유지해야 합니다.
추가 고려 사항 (향후 개선 방향)
- 프록시 서버 또는 IP 로테이션: 다양한 IP 주소를 사용하여 요청을 분산시키면 탐지 가능성을 낮출 수 있습니다.
- 요청 빈도 제어: 애플리케이션 레벨에서 전역적인 요청 빈도를 제어하여 특정 시간 동안 보낼 수 있는 요청 수를 제한합니다.
- 헤더 및 브라우저 핑거프린트 정교화: User-Agent 외의 HTTP 헤더(Accept-Language, Accept-Encoding 등)와 브라우저 핑거프린트 요소들을 더욱 실제 사용자와 유사하게 설정합니다.