Claude Desktop Research MCP Server
# Research MCP
> 개인용 연구 에이전트 — arXiv 검색·인용 그래프·멀티모달 논문 위키·시각화를 자연어 한 줄로 실행.
> **Claude Desktop (MCP)** 과 **self-hosted 웹 채팅 앱** 두 가지 인터페이스 사용.
---
## 주요 기능
### 1. 검색과 인용 그래프
- **arXiv 검색** — 키워드/카테고리로 검색하고 결과를 *최근 1년 / 3년 / 5년 / 그 이상* 으로 자동 분류.
- **인용 그래프** — 특정 논문의 references / citations를 가져와 정렬.
- `sort="count"` — 절대 인용수 순.
- `sort="velocity"` — **citation velocity** (`citations / (현재연도 − 발행연도)`) 순. 오래된 논문이 절대 인용수만으로 항상 이기는 문제를 보정해 최신 흐름에 가까운 결과를 보여준다.
- **인용 문맥 (citation contexts)** — Semantic Scholar의 `contexts` API로 *왜 인용했는지* 본문 스니펫을 수집.
### 2. 멀티모달 논문 위키 (Obsidian vault)
한 번 ingest한 논문은 폴더형 구조로 vault에 저장된다.
```
vault/papers/blip-2/
├── blip-2.md # frontmatter + TL;DR / Methods / Findings / References (파일명 = 폴더 slug)
└── figures/
├── fig_1_overview-of-blip-2s-framework.png
├── fig_2_q-former-architecture.png
└── ...
```
- **PDF 원본 보관** — `vault/pdfs/<arxiv_id>.pdf` 에 영구 저장. 동일 ID 재요청 시 다운로드 skip.
- **Vision 기반 figure / table 추출** — Gemini Vision으로 figure·table 영역을 crop한다. *(`GOOGLE_API_KEY` 필요)*
- **안정 hub 분류** — 큐레이트된 **hub 노트**(e.g. `topics/*.md` — `LLM`, `VLM`, `Diffusion`, `Agent-Reasoning`)에 1–3개로 매핑.
- **양방향 wikilink** — `[[clip]]` 같은 wikilink가 자동 누적.
- **vault 리트리벌** — `wiki_search`로 "질문 → 관련 노트"를 어휘 seed + `[[wikilink]]` 이웃 확장으로 검색. vault 전체를 로드하지 않고 관련 노트만 추린다.
- **종합 통찰 노트** — 세션에서 논문을 가로질러 얻은 통찰을 `insight-capture` 스킬로 `notes/<slug>.md`에 누적 (승인 게이트).
### 3. 시각화: Mermaid + Obsidian
한 anchor 논문을 중심으로 인용 흐름을 *카드 그래프* 로 출력.
- **Mermaid graph** — 응답에 즉시 임베드되어 Claude Desktop / GitHub / Obsidian이 그대로 렌더.
- **Mermaid 노트 저장** — 같은 다이어그램을 `vault/graphs/<slug>.md` 노트로도 저장. Obsidian이 노트를 열면 그래프로 렌더 (auto-layout이라 노드 겹침 없음).
- **통합 인용 네트워크 export** — vault 전체 논문의 인용 관계를 공통 노드(논문·hub) 기준 하나의 그래프로 통합해 CSV(Cosmograph)/GEXF(Gephi Lite)로 export. 엣지 200 이하 소형이면 `graphs/unified.md` Mermaid도 함께 산출.
```mermaid
graph LR
anchor["BLIP-2 (2023, cited 1234)"]
refs["CLIP (2021)"] --> anchor
anchor --> cite1["LLaVA (2023)"]
anchor --> cite2["InstructBLIP (2023)"]
```
### 4. 일일 인기 논문 피드
- **테크 블로그 다이제스트** — Anthropic·OpenAI·Google Gemini·DeepMind 블로그의 신규 포스트를 본문 기반(차단 소스는 RSS)으로 몇 문단 요약해 `tech-blog-digest/<date>.md`에 누적. seen 상태를 추적해 실행 시마다 미요약분만 소스별 최대 5개씩 처리.
---
## 아키텍처
```
sources/ → analysis/ → wiki/ → tools/ ─┬─ server.py (Claude Desktop · MCP)
(fetch) (rank/group) (vault) (24 tool) │
└─ agent/ → api/ → web/ (웹 앱 · SSE 채팅)
```
- **단방향 import** — 위 화살표 방향으로만 의존. 역방향 금지.
- **tool은 한 곳에 정의** — `tools/*.py`의 함수를 MCP(`server.py`)와 에이전트(`agent/`)가 동일하게 재사용한다. 같은 20개 도구가 두 transport로 노출된다.
- **에이전트** — Pydantic-AI. provider-prefixed 모델 문자열(`anthropic:` / `openai:` / `google:`)로 멀티 provider 전환. 스킬 정의를 system prompt로 로드.
---
## MCP Tool 카탈로그 (20)
각 tool은 한 카테고리에만 속하도록 직교적으로 설계 — 호출 순서를 가진 워크플로우는 아래 *스킬* 로 묶인다.
| 카테고리 | Tool |
|---|---|
| **fetch** | `search_papers`, `get_paper_by_id`, `get_citation_contexts` |
| **graph** | `get_references_by_citations`, `get_citations_by_citations` |
| **artifact** | `download_paper`, `read_paper`, `extract_paper_figures`, `extract_paper_tables`, `prune_paper_figures`, `prune_paper_tables`, `render_paper_page` |
| **wiki** | `wiki_read_note`, `wiki_write_note`, `wiki_list`, `wiki_list_hubs`, `wiki_search`, `wiki_backlinks`, `wiki_link` |
| **viz** | `build_citation_graph` |
---
## 스킬 (워크플로우)
자연어 한 줄로 호출 가능한 사전 정의 워크플로우 (도구 호출 시퀀스).
| 스킬 | 트리거 예시 | 하는 일 |
|---|---|---|
| `paper-ingest` | "이 논문 ingest", "BLIP-2 위키에 추가" | 메타·PDF·figure·table·요약을 한 번에 vault에 누적. 분야를 기존 hub에 매핑. |
| `citation-analysis` | "BLIP-2 흐름 보여줘", "<arxiv_id> 인용 분석" | anchor 1편 중심으로 refs/cites를 hub로 분류 + `cited_for` 채우기 + 시각화. vault 영구 누적은 사용자 승인 게이트. |
| `wiki-lint` | "위키 점검", "vault 정리" | vault 정합성 점검 — orphan·깨진 링크·누락 교차참조·stale hub·노트 간 모순 스캔 → 승인 게이트 diff. |
| `insight-capture` | "이 통찰 저장", "notes에 정리" | 논문을 가로질러 종합한 통찰을 `notes/<slug>.md`에 누적 (승인 게이트). |
| `tech-blog-digest` | "테크 블로그 요약", "blog digest" | Anthropic·OpenAI·Gemini·DeepMind 신규 포스트를 본문 기반 요약해 `tech-blog-digest/<date>.md`에 누적 (소스별 최대 5, 자동 이월). |
| `research-autopilot` | "밤새 논문 쌓아줘", `/loop 10m /research-autopilot scope=graph-rag,finance-agents` | 무인 축적 루프의 한 반복 — 대기열 유도 → 논문 1편 ingest → 인용 분석 → hub 판정 → 깨진 링크 정정을 자동 승인으로 수행하고 `_meta/autopilot-log`에 기록. `scope`(hub slug)는 실행마다 필수 — 없으면 hub 목록과 함께 묻고 돌지 않으며, 전체는 `all`을 명시할 때만. 큐가 비면 scope 안 중심 논문의 인용 이웃으로 리필. 중요도 게이트(citation velocity ≥ 10 또는 vault 참조 2곳 이상, hub가 부르는 논문은 면제)로 낮은 중요도 후보는 보류. figure/table은 추출하지 않는다(텍스트 요약만, 아침에 on-demand). 한도로 끊긴 반복은 vault 상태에서 이어받는다. 정지 시 들어온 논문 요약·통찰 후보·아침 할 일을 담은 실행 보고서를 채팅과 `research-autopilot/<date>.md`에 남긴다. 통찰·lint 반영은 사람 몫. 본 세션은 디스패처(`SKILL.md`)만, 반복은 서브에이전트 워커가 `WORKER.md`를 읽어 새 컨텍스트에서. `/loop`이 사용자가 멈출 때까지 반복. |
| `self-improve` | "회고 반영해줘", "self-improve" | 세션 회고·반복 실패를 분석해 `CLAUDE.md`/`docs/*` diff 제안 (승인 게이트, 메타 레이어). |
---
### research-autopilot 운용
```
시작 /loop 10m /research-autopilot scope=graph-rag,finance-agents max_papers=10 권장
/loop 10m /research-autopilot graph rag랑 금융 에이전트 자연어 — 첫 tick이 hub로 해석해 확정 slug를 보여주고 고정
/loop 10m /research-autopilot scope 없음 → hub 목록과 함께 묻고, 답할 때까지 돌지 않는다
/loop /research-autopilot scope=… 지켜볼 때만 (동적 self-pacing)
정지 "autopilot 멈춰" · 제어 노트 stop: true (다음 tick) · 자동(max_papers·큐 소진·연속 실패 3) · 세션 종료
재개 새 /loop. scope는 다시 준다 (max_papers·min_velocity는 남는다)
보고 정지 시 자동 → 채팅 + research-autopilot/<날짜>.md. "autopilot 보고" → 정지 없이 현재 실행 보고서만 (저장 없음)
탐색 제어 노트 explore: true → 실행 중 발견한 hub 후보도 의도 안이면 탐색 주제로 편입(실행당 max_topics, 기본 3). 기본 false
전제 세션 유지 (Mac 잠자기 방지 예: caffeinate -dimsu). 한 vault에 루프는 한 세션만
```
## 설치
### 요구사항
- Python `>=3.10`
- [uv](https://github.com/astral-sh/uv) (의존성 관리)
- Obsidian (vault·그래프를 보기 위해 — 권장)
```bash
uv sync
```
### 플러그인 설치 (권장 — Claude Desktop / Claude Code)
```
/plugin marketplace add cholhwanjung/research-mcp
/plugin install research-mcp@research-mcp
```
활성화(enable) 시 아래를 프롬프트로 입력한다. **secret은 repo가 아니라 keychain에 저장된다.**
| 설정 | 설명 |
|---|---|
| `vault_path` | vault 루트 (예: `/Users/you/Documents/research-wiki`). 비우면 `~/Documents/research-wiki` |
| `google_api_key` | Gemini Vision — figure/table 추출용. 없으면 멀티모달 skip, 텍스트 요약만 |
| `ss_api_key` | Semantic Scholar API key (선택) — rate-limit 완화 |
> **요구사항**: `uv`가 설치돼 있어야 한다 (플러그인이 `server.py`를 uv로 기동). 첫 기동 시 의존성 sync가 한 번 돈다(네트워크 필요, 수십 초). 업데이트는 `/plugin marketplace update` 후 재설치.
### Claude Desktop MCP 설정 (수동 — 대안)
> 플러그인 대신 **MCP 서버만** 직접 등록하는 방법. 이 경로는 **스킬을 포함하지 않는다** (플러그인은 6개 스킬까지 번들). tool만 필요할 때 사용.
`~/Library/Application Support/Claude/claude_desktop_config.json` 에 추가:
```json
{
"mcpServers": {
"research": {
"command": "uv",
"args": ["--directory", "/path/to/research-mcp", "run", "python", "server.py"],
"env": {
"OBSIDIAN_VAULT_PATH": "/Users/you/Documents/research-wiki",
"GOOGLE_API_KEY": "<Gemini Vision — figure/table 추출용>",
"SS_API_KEY": "<optional Semantic Scholar API key>"
}
}
}
}
```
| 변수 | 기본값 | 설명 |
|---|---|---|
| `OBSIDIAN_VAULT_PATH` | `~/Documents/research-wiki` | 노트·PDF·figure 저장 vault 루트 |
| `PDF_PATH` | `$OBSIDIAN_VAULT_PATH/pdfs` | PDF 원본 저장 위치 |
| `GOOGLE_API_KEY` | (없음) | Gemini Vision — figure/table bbox 추정에 필요 |
| `SS_API_KEY` | (없음) | Semantic Scholar API key. 설정 시 rate-limit 완화 |
---
## 웹 앱 (self-hosted) — 멀티 LLM 채팅
Claude Desktop 외에, 같은 도구·워크플로우를 **웹 채팅 UI**로도 쓸 수 있음.
### 구성
- `api/` — FastAPI + SSE 백엔드. `/chat`(스트리밍) · `/skills` · `/health`. Bearer 토큰 인증(옵션).
- `agent/` — Pydantic-AI 에이전트. MCP의 tool 재사용 + multi-provider.
- `web/` — Next.js 채팅 프론트 (스트리밍 + 모델 선택기 + 토큰 입력).
### 실행 — 한 번에 (로컬, 추천)
```bash
cp .env.example .env # 쓸 provider 키만 채우기 (예: GOOGLE_API_KEY)
./run-web.sh # .env 의 RESEARCH_MODEL (미설정 시 Claude)
./run-web.sh google # Gemini — GOOGLE_API_KEY 만 있으면 됨 (Anthropic 키 불필요)
./run-web.sh openai # GPT-4o — OPENAI_API_KEY
./run-web.sh anthropic # Claude — ANTHROPIC_API_KEY
```
→ 백엔드(:8000)+프론트(:3000) 동시 기동. 접속: **http://localhost:3000**
- 인자로 고른 모델이 백엔드 기본값(`RESEARCH_MODEL`)으로 적용 (웹 UI에서 메시지별 전환도 가능). `provider:model` 직접 지정도 됨 (예: `./run-web.sh google:gemini-2.0-flash`).
- 선택한 provider 키가 없으면 **부팅 전에 안내하고 멈춤** (lifespan 에러 회피).
- Ctrl-C 한 번으로 둘 다 종료. 최초 1회 `uv sync`·`npm install` 자동, Docker 불필요.
- `.env`는 백엔드(`core/config.py`)가 자동 로드, 프론트 기본 API_URL은 `http://localhost:8000`.
**사용**: 우상단 토큰칸에 `RESEARCH_API_TOKEN` 값 입력(설정 시) → 채팅. 예: `"BLIP-2 위키에 추가해줘"` → 채팅에 tool 실행 흐름 표시 → **Obsidian을 열어** 노트·그래프 확인.
### 실행 — Docker (self-hosted 배포)
```bash
cp .env.example .env # provider 키 + VAULT_HOST_PATH 채우기
docker compose up --build # 백엔드 → http://localhost:8000
```
- `VAULT_HOST_PATH`는 **Docker 파일공유 대상 경로**여야 한다 (홈 하위 `~/Documents/...`는 기본 공유됨; `/tmp` 등은 공유 안 될 수 있어 컨테이너가 안 뜬다).
- 세션 SQLite는 named volume(`sessions`)에 저장 — vault 바인드마운트와 분리해 안정성 확보.
- 프론트는 컨테이너에 없음 → 아래 "수동 실행"의 프론트 명령으로 별도 기동.
### 수동 실행 (개별 기동, 선택)
`run-web.sh` 대신 백엔드·프론트를 따로 띄울 때:
```bash
uv run uvicorn api.main:create_app --factory --port 8000 # 백엔드
cd web && npm run dev # 프론트(:3000)
```
백엔드를 비표준 호스트/포트로 띄우면 `web/.env.local`에 `NEXT_PUBLIC_API_URL=…` 지정.
### 환경 변수 (웹 앱)
| 변수 | 설명 |
|---|---|
| `RESEARCH_API_TOKEN` | 설정 시 API 호출에 `Authorization: Bearer` 강제 (비우면 인증 off) |
| `RESEARCH_MODEL` | 기본 채팅 모델 (`anthropic:…` / `openai:…` / `google:…`) |
| `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GEMINI_API_KEY` | 사용할 provider 키 |
| `GOOGLE_API_KEY` | Gemini Vision — figure/table 추출 (ingest 시) |
| `VAULT_HOST_PATH` | (compose) host vault 절대경로 → 컨테이너 `/vault` |
---
## Vault 레이아웃
```
vault/
├── papers/
│ └── <title-slug>/
│ ├── <title-slug>.md # frontmatter + 본문 (TL;DR / Methods / Findings / References)
│ └── figures/
│ └── fig_<n>_<caption-slug>.png
├── topics/
│ └── <hub-slug>.md # 안정 hub — 백링크로 논문이 자동 집계
├── notes/
│ └── <slug>.md # 논문 간 종합 통찰 (insight-capture)
├── tech-blog-digest/
│ └── <date>.md # 테크 블로그 다이제스트 노트
├── research-autopilot/
│ └── <date>.md # autopilot 실행 보고서 (정지 시 생성)
├── graphs/
│ └── <slug>.md # 인용 흐름 Mermaid 노트 (build_citation_graph)
└── pdfs/
└── <arxiv_id>.pdf
```
`papers/<title-slug>/<title-slug>.md` frontmatter 예:
```yaml
arxiv_id: 2301.12597
title: "BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders"
year: 2023
citation_count: 1234
citation_velocity: 411.3
topics: [vlm, multimodal]
references:
- paper_id: 2103.00020
topic: clip-contrastive
cited_for: "BLIP-2의 frozen 이미지 인코더 초기화 근거로 인용"
figures:
- file: figures/fig_1_overview.png
caption: "Figure 1: BLIP-2 architecture overview."
```
---
## 기술 스택
| 영역 | 선택 |
|---|---|
| MCP 서버 | FastMCP (stdio) |
| 에이전트 | Pydantic-AI — multi-provider (Anthropic / OpenAI / Google) |
| 백엔드 | FastAPI + SSE (스트리밍) |
| 프론트 | Next.js 16 · React 19 · Tailwind CSS v4 |
| 추출 | PyMuPDF (PDF) + Gemini Vision (figure/table bbox) |
| 저장 | Obsidian vault (Markdown), SQLite (대화 세션) |
| 데이터 | arXiv · Semantic Scholar · 테크 블로그 |
| 캐시 | 디스크 캐시 — 동일 paper_id 재요청은 0 네트워크 |
---
## 사용 예시
```
> BLIP-2 위키에 추가해줘
→ paper-ingest → papers/blip-2/ 생성, figure·table 추출·선별, 요약 + hub 매핑
> BLIP-2 흐름 보여줘
→ citation-analysis → refs/cites를 hub로 분류 + cited_for 채움
→ 사용자 승인 게이트 → vault 누적 + Mermaid 시각화(`graphs/` 노트) → Obsidian 그래프로 확인
> 오늘 트렌딩 논문 정리해줘
→ tech-blog-digest → tech-blog-digest/<date>.md 저장
```
---
## 라이선스
개인용 프로젝트.
TDQS
Scored across 19 tools
Each tool targets a distinct operation: paper search, metadata retrieval, full-text extraction, PDF download, figure/table extraction and pruning, citation/reference analysis with contexts, daily papers, recommendations, canvas visualization, and vault operations. No two tools have overlapping purposes; even the pair get_citations_by_citations and get_references_by_citations are clearly opposites.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., get_paper_by_id, extract_paper_figures, wiki_write_note). There are no deviations or mixed conventions, making the API predictable for an agent.
With 19 tools, the server is slightly above the typical well-scoped range (3-15), but each tool addresses a specific need in the research workflow—from paper discovery to vault management. The count feels justified and not excessive.
The tool surface covers the complete research lifecycle: search, metadata retrieval, download, full-text reading, figure/table extraction, citation/reference analysis with contexts, recommendations, daily papers, canvas visualization, and vault CRUD. The only minor gap is the absence of a dedicated note deletion tool, but overwriting via wiki_write_note is possible.