MCP Research Friend Server
공식연구 도구, Sqlite 기반 문서 저장소 포함
문서
Research Friend
웹에서 정보를 찾고 로컬 연구 보관함을 관리해야 하는 AI 어시스턴트를 위한 친절한 도우미입니다.
Research Friend는 AI 도구가 웹 페이지를 가져오고 인터넷을 검색할 수 있게 해주는 MCP 서버입니다. 내부적으로 실제 웹 브라우저를 사용하므로 JavaScript에 크게 의존하는 최신 웹사이트에서도 잘 작동합니다. 또한 문서를 저장하고, 텍스트를 추출하며, 라이브러리 전체를 검색할 수 있는 로컬 "보관함" 기능도 포함합니다.
모든 기능을 활용하려면 프롬프트(일반적)와 샘플링(덜 일반적)을 지원하는 MCP 클라이언트가 필요합니다. Research Friend는 두 가지를 모두 지원하는 Chabeau와 함께 개발하고 있습니다.
무엇을 할 수 있나요?
- 실제 브라우저로 웹 페이지 가져오기 (JS가 많은 사이트 포함)
- PDF 가져오기 및 텍스트 콘텐츠 추출
- DuckDuckGo 또는 Google을 통해 웹 검색
- 검색, 목록 보기, 추출을 위한 로컬 문서 보관함 유지
시작하기
컴퓨터에 Node.js 버전 20 이상이 설치되어 있어야 합니다.
1. 의존성 설치
이 폴더에서 터미널을 열고 다음을 실행하세요:
npm install
2. 브라우저 지원 설치
Research Friend는 Playwright를 사용하여 웹 브라우저를 제어합니다. 의존성을 설치한 후 브라우저를 설치해야 합니다:
npx playwright install chromium
이 명령은 Playwright가 사용할 Chromium 사본을 다운로드합니다. 이미 설치된 브라우저와는 별개입니다.
3. 서버 시작
node src/index.js
서버는 표준 입출력(stdio)을 통해 통신하며, 이것이 MCP 클라이언트가 연결하는 방식입니다.
MCP 클라이언트에 추가하기
Research Friend를 추가하는 방법은 사용 중인 MCP 클라이언트에 따라 다릅니다. 다음은 구성이 어떻게 보일지에 대한 일반적인 예시입니다:
[[mcp_servers]]
id = "research-friend"
command = "node"
args = ["/path/to/mcp-research-friend/src"]
transport = "stdio"
/path/to/mcp-research-friend을 컴퓨터에서 이 폴더의 실제 경로로 바꾸세요.
도구
웹 도구
friendly_web_fetch
웹 페이지를 가져와 콘텐츠를 반환합니다. 기본적으로 링크가 보존된 마크다운을 반환하여 LLM에 이상적입니다. Readability를 사용하여 주요 콘텐츠를 추출합니다(탐색 메뉴, 광고 등 제거). PDF, 페이지 매김 또는 콘텐츠 내 검색에는 friendly_web_extract를 대신 사용하세요.
매개변수:
url(필수) - 가져올 웹 주소outputFormat- 출력 형식:markdown(기본값),text, 또는htmlwaitMs- 콘텐츠가 천천히 나타나는 경우 페이지 로드 후 추가 대기 시간timeoutMs- 포기하기 전까지 기다릴 시간 (기본값: 15초)maxChars- 반환할 최대 콘텐츠 양 (기본값: 40,000자)includeHtml- 콘텐츠와 함께 원시 HTML도 반환하려면true로 설정headless- 브라우저 창을 보려면false로 설정 (디버깅에 유용)
반환값:
url- 요청된 URLfinalUrl- 리디렉션 후의 URLtitle- 페이지 제목content- 추출된 콘텐츠 (요청된 형식)html- 원시 HTML (includeHtml이 true인 경우에만)meta- 페이지 메타데이터 (설명, 저자, 게시 시간 등)fetchedAt- 페이지를 가져온 ISO 타임스탬프truncated- 콘텐츠가maxChars에 맞게 잘렸는지 여부
friendly_search
웹을 검색하고 결과 목록을 반환합니다.
매개변수:
query(필수) - 검색할 내용engine- 사용할 검색 엔진 (duckduckgo또는google)maxResults- 반환할 결과 수 (기본값: 10, 최대: 50)timeoutMs- 포기하기 전까지 기다릴 시간 (기본값: 15초)headless- 브라우저 창을 보려면false로 설정
반환값:
query- 사용된 검색 쿼리engine- 사용된 검색 엔진results- 결과 배열, 각 결과는title,url,snippet포함searchedAt- 검색이 수행된 ISO 타임스탬프fallback_result_html- 페이지의 원시 HTML (결과가 없을 때만 포함)debug_info- 검색 시도에 대한 진단 정보
CAPTCHA 처리:
헤드리스 모드에서 실행 중 CAPTCHA가 감지되면, 도구는 자동으로 보이는 브라우저 창으로 다시 시도합니다. 이를 통해 수동으로 CAPTCHA를 해결할 기회를 제공합니다. debug_info.retried 필드는 이 대체 방법이 사용되었는지 나타냅니다.
friendly_web_extract
URL에서 콘텐츠를 추출합니다. URL이 PDF인지 웹 페이지인지 자동 감지하여 각각 적절하게 처리합니다.
매개변수:
url(필수) - 가져올 URL (PDF 또는 웹 페이지)maxChars- 반환할 최대 텍스트 양 (기본값: 40,000자)offset- 시작할 문자 위치 (기본값: 0). 큰 콘텐츠를 페이지별로 나누는 데 사용합니다.search- 전체 콘텐츠 대신 구문을 검색하고 주변 문맥과 함께 일치 항목 반환contextChars- 각 검색 일치 항목 주변의 문맥 문자 수 (기본값: 200)waitMs- 동적 콘텐츠를 위한 페이지 로드 후 추가 대기 시간 (웹 페이지 전용)timeoutMs- 포기하기 전까지 기다릴 시간 (기본값: 15초, 웹 페이지 전용)headless- 브라우저 창을 보려면false로 설정 (웹 페이지 전용)
반환값 (일반 모드):
url- 요청된 URLcontentType-pdf또는htmltitle- 페이지/문서 제목author- PDF 저자 (PDF 전용, 가능한 경우)creationDate- PDF 생성 시기 (PDF 전용, 가능한 경우)pageCount- 페이지 수 (PDF 전용)totalChars- 총 문자 수 (페이지 매김을 위해offset와 함께 사용)offset- 사용된 오프셋content- 추출된 텍스트 콘텐츠fetchedAt- ISO 타임스탬프truncated- 이 청크 이후에 더 많은 콘텐츠가 남아 있는지 여부
반환값 (검색 모드):
url,contentType,title,totalChars,fetchedAt- 위와 동일search- 사용된 검색 구문matchCount- 발견된 일치 항목 수matches- 일치 항목 배열, 각 항목은position,context,prefix,suffix포함
friendly_web_ask
URL(PDF 또는 웹 페이지)을 가져와 LLM이 이에 대한 질문에 답하도록 합니다. 콘텐츠 유형을 자동 감지합니다. 문서는 별도의 컨텍스트에서 처리되므로 주 대화를 간결하게 유지합니다.
매개변수:
url(필수) - 가져올 URL (PDF 또는 웹 페이지)ask(필수) - LLM에 대한 질문 또는 지시 (요약, 정보 추출, 질문 답변 등)askMaxInputTokens- LLM 호출당 최대 입력 토큰 (기본값: 150,000)askMaxOutputTokens- LLM 호출당 최대 출력 토큰 (기본값: 4,096)askTimeout- 밀리초 단위 타임아웃 (기본값: 300,000 = 5분)askSplitAndSynthesize- 큰 문서의 경우: 청크로 분할하여 각각 처리한 후 결과 합성 (기본값: false). 경고: 많은 토큰을 소비합니다.waitMs- 동적 콘텐츠를 위한 페이지 로드 후 추가 대기 시간 (웹 페이지 전용)timeoutMs- 포기하기 전까지 기다릴 시간 (기본값: 15초, 웹 페이지 전용)headless- 브라우저 창을 보려면false로 설정 (웹 페이지 전용)
반환값:
url- 요청된 URLcontentType-pdf또는htmltitle- 페이지/문서 제목totalChars- 문서의 총 문자 수ask- 주어진 지시 사항answer- LLM의 응답model- 응답을 생성한 모델chunksProcessed- 처리된 청크 수 (작은 문서는 1,askSplitAndSynthesize사용 시 더 많음)fetchedAt- ISO 타임스탬프
질문 모드는 MCP 샘플링을 사용하여 LLM이 모든 지시 사항으로 문서를 처리하도록 합니다. 이는 다음에 유용합니다:
- 컨텍스트를 압도할 큰 문서
- 주 대화의 토큰 비용 절감
askSplitAndSynthesize이 활성화되면 askMaxInputTokens을 초과하는 문서는 자동으로 겹치는 청크로 분할됩니다. 각 청크는 개별적으로 처리되고 결과는 하나의 일관된 답변으로 합성됩니다. 최종 응답은 문서의 언어와 관계없이 요청과 동일한 언어로 제공됩니다.
문서 보관함
보관함은 로컬에서 검색 가능한 문서 라이브러리입니다. PDF, HTML 파일 및 일반 텍스트(Markdown/TXT)를 지원합니다. 문서를 추가하면 Research Friend는 원본 파일을 저장하고, 텍스트를 추출하며(PDF/HTML의 경우), 메타데이터를 로컬 데이터베이스에 저장합니다. 검색은 내부적으로 ripgrep을 사용하여 빠르고 구문 인식이 가능한 매칭을 수행합니다.
보관함 위치
보관함은 ~/.research-friend/ 아래에 위치합니다:
inbox/- 처리할 파일을 여기에 드롭하세요store/- 정리된 문서 저장소 및 추출된 텍스트stash.db- 메타데이터 데이터베이스
지원 파일 형식
- PDF:
.pdf(텍스트 추출됨) - HTML:
.html,.htm(텍스트 추출됨) - Markdown:
.md,.markdown(일반 텍스트로 저장됨) - 텍스트:
.txt(일반 텍스트로 저장됨)
보관함 도구
stash_open_inbox
드래그 앤 드롭을 쉽게 하기 위해 파일 관리자에서 보관함 받은 편지함 폴더를 엽니다.
반환값:
opened- 폴더 열기 요청이 전송되었는지 여부inboxPath- 받은 편지함의 절대 경로command- 사용된 OS 명령args- 사용된 명령 인수
stash_process_inbox
inbox/에 있는 파일을 처리하여 주제별로 분류하고, 텍스트를 추출하며, 결과를 저장합니다.
긴 문서의 경우, 분류는 샘플링된 섹션(시작/중간/끝과 몇 개의 무작위 청크)을 사용하여 주제 정확도를 향상시킵니다.
반환값:
processed- 성공적으로 처리된 파일 이름 배열errors- 발생한 모든 오류documents- 생성된 문서 레코드 배열
reindex_stash
보관된 문서에 대한 요약을 재생성하고, 주제를 재할당하며, 저장소 메타데이터를 업데이트합니다. ids이 생략되거나 비어 있으면 모든 문서가 재색인됩니다.
매개변수:
ids- 재색인할 문서 ID (선택 사항)
반환값:
reindexed- 재색인된 문서 IDerrors- 발생한 모든 오류documents- 업데이트된 문서 레코드 배열
stash_list
보관함의 문서를 나열합니다.
매개변수:
topic- 주제로 필터링 (선택 사항)limit- 최대 결과 수 (기본값: 50)offset- 페이지 매김 오프셋 (기본값: 0)
반환값:
type-all또는topictotalDocuments- 총 문서 수 (type가all일 때만)count- 페이지 매김 후 반환된 결과offset- 사용된 페이지 매김 오프셋limit- 사용된 페이지 매김 제한topics- 알려진 주제 및 문서 수 요약documents- 메타데이터가 포함된 문서 목록 (주제 나열 시isPrimary포함)
stash_search
보관함 전체에서 파일 이름과 콘텐츠를 검색합니다. 모든 검색어가 존재해야 합니다(AND 논리). 파일 이름 일치 항목이 먼저 나열됩니다. 정확한 구문에는 따옴표를 사용하세요.
매개변수:
query(필수) - 검색어. 구문에는 따옴표 사용:"sparkling wine"topic- 주제로 필터링 (선택 사항)ids- 특정 문서 ID로 필터링 (선택 사항)limit- 반환할 최대 문서 수 (기본값: 20)offset- 페이지 매김 오프셋 (기본값: 0)maxMatchesPerDoc- 문서당 최대 일치 항목 수 (기본값: 50)context- 각 일치 항목 주변의 문맥 줄 수 (기본값: 1, 최대: 5). 용어가 일치하기 위해 얼마나 가까이 나타나야 하는지와 반환되는 주변 텍스트의 양을 모두 제어합니다. 반환값:totalMatches- 페이지네이션 전 일치하는 총 문서 수count- 페이지네이션 후 반환된 결과results- 문서 배열, 각 문서는 다음을 포함:id,filename,fileType,summary,charCount,createdAtmatchType-filename,content, 또는filename+contentmatches- 각 일치 위치에 대한{ line, context }배열
line 값과 stash_extract을 사용하여 일치 위치로 바로 이동하세요.
stash_extract
보관된 문서에서 내용을 추출하여 읽습니다. stash_search 결과의 줄 번호를 사용하여 일치 항목으로 바로 이동하세요.
매개변수:
id(필수) -stash_list/stash_search의 문서 IDmaxChars- 반환할 최대 텍스트 양 (기본값: 40,000자)offset- 시작할 문자 위치 (line과 상호 배타적)line- 시작할 줄 번호 (offset과 상호 배타적)
반환값:
id,filename,fileType,summary- 문서 메타데이터totalChars- 문서의 총 문자 수offset- 문자 오프셋 (참조용으로line사용 시 포함)line- 줄 번호 (line매개변수가 사용된 경우에만)content- 추출된 텍스트 내용truncated- 이 청크 이후에 더 많은 내용이 남아 있는지 여부
stash_ask
보관된 문서에 대해 LLM이 질문에 답변하도록 합니다. 문서는 별도의 컨텍스트에서 처리되므로 주 대화를 간결하게 유지할 수 있습니다.
매개변수:
id(필수) -stash_list/stash_search의 문서 IDask(필수) - LLM에 대한 질문 또는 지시사항askMaxInputTokens- LLM 호출당 최대 입력 토큰 (기본값: 150,000)askMaxOutputTokens- LLM 호출당 최대 출력 토큰 (기본값: 4,096)askTimeout- 제한 시간(밀리초) (기본값: 300,000 = 5분)askSplitAndSynthesize- 대용량 문서의 경우: 청크로 분할하여 각각 처리한 후 결과 합성 (기본값: false)
반환값:
id,filename,fileType,summary- 문서 메타데이터totalChars- 문서의 총 문자 수ask- 주어진 지시사항answer- LLM의 응답model- 응답을 생성한 모델chunksProcessed- 처리된 청크 수
일반적인 흐름
~/.research-friend/inbox/에 파일 드롭stash_process_inbox실행stash_list를 사용하여 주제 탐색stash_search를 사용하여 관련 문서 찾기stash_extract을 사용하여 특정 문서 읽기 또는stash_ask을 사용하여 문서에 대해 질문하기
문제 해결
"브라우저가 예기치 않게 닫혔습니다" 또는 유사한 오류
브라우저 재설치를 시도하세요:
npx playwright install chromium --force
Linux에서는 시스템 종속성이 필요할 수도 있습니다:
npx playwright install-deps chromium
서버가 시작되지 않음
Node.js 20 이상을 사용하고 있는지 확인하세요:
node --version
버전이 더 낮은 경우 nodejs.org를 방문하여 최신 버전을 다운로드하세요.
라이선스
MIT