vibetutor-mcp
README.md
# VibeTutor MCP
> **내가 실제로 쓴 코드** 위에 학습 개념을 붙여 설명하는 AI 튜터 MCP 서버.
> 로컬 코드를 분석하여 일관된 양식의 **맞춤형 실습 교재(PDF/HTML/Markdown)**를 자동 생성하고 검색 가능한 개인 학습 자산으로 누적합니다.
---
## 목차
- [주요 기능](#주요-기능)
- [요구 사항](#요구-사항)
- [설치 방법](#설치-방법)
- [로컬 설치 (uv)](#로컬-설치-uv)
- [Docker 설치](#docker-설치)
- [Claude / MCP 클라이언트 연동](#claude--mcp-클라이언트-연동)
- [사용법](#사용법)
- [MCP 도구 · 리소스](#mcp-도구--리소스)
- [환경 변수](#환경-변수)
- [프로젝트 구조](#프로젝트-구조)
- [알려진 제약 사항](#알려진-제약-사항)
- [라이선스](#라이선스)
---
## 주요 기능
| 기능 | 설명 |
|-----------------|-------------------------------------------------------------|
| **다중 포맷 출력** | PDF(인쇄·배포용) · HTML(웹 열람용, 변환 비용 없음) · Markdown(원문 보존용) 중 선택 생성 |
| **맞춤형 교재 생성** | 로컬 코드를 AST로 스캔하여 실제 코드 예제가 삽입된 교재를 생성 |
| **표준 교재 양식 강제** | 마크다운 입력을 표준 양식으로 변환하여 누가/언제 만들어도 일관된 교재 출력 |
| **한글 PDF 출력** | Pretendard 폰트 임베딩으로 한글이 깨지지 않는 인쇄용 PDF |
| **학습 자산 인덱싱** | SQLite에 교재 메타데이터를 누적, 제목 부분일치로 검색 가능 |
| **재현성 보장** | 콘텐츠 해시(SHA-256)로 동일 입력 → 동일 산출물 보장 |
| **실패 진단** | 각 처리 단계(스캔 → 렌더 → 변환 → 저장) 실패 시 단계·원인·힌트 제공 |
---
## 요구 사항
| 항목 | 버전 |
|-----------------------------------------------|----------------------------|
| Python | 3.11 이상 |
| [uv](https://docs.astral.sh/uv/) | 최신 권장 |
| [Docker](https://www.docker.com/get-started/) | Windows에서 PDF 생성 시 필수 |
| WeasyPrint 네이티브 의존성 | Pango / cairo / GDK-PixBuf |
> **⚠️ Windows 로컬 환경:** WeasyPrint가 GTK 네이티브 라이브러리를 요구하므로
> PDF 변환은 **Docker**를 통해서만 가능합니다. 린트·타입검사·테스트는 로컬에서 실행 가능합니다.
---
## 설치 방법
### 로컬 설치 (uv)
1. 저장소 클론
```cmd
git clone https://github.com/PEANUTBUTTER1001/vibetutor-mcp.git
cd vibetutor-mcp
```
2. 의존성 설치 (.venv 자동 생성)
```
uv sync
```
### Docker 설치
모든 네이티브 의존성이 컨테이너에 포함되어 있어 OS에 상관없이 동일한 PDF를 생성합니다.
이미지 빌드
```cmd
docker build -t vibetutor-mcp .
```
한글 PDF 1장 생성 테스트 (output\ 폴더에 저장)
```
docker run --rm ^
-e VIBETUTOR_PROJECT_ROOT=/app/src ^
-v "%cd%\output":/app/output ^
-v "%cd%\scripts":/app/scripts ^
vibetutor-mcp /app/.venv/bin/python scripts/smoke_generate.py
```
---
## Claude / MCP 클라이언트 연동
VibeTutor MCP는 **stdio 전송**으로 동작합니다. Claude Desktop 또는 다른 MCP 클라이언트의 설정 파일에 아래 내용을 추가하세요.
### Claude Desktop (`claude_desktop_config.json`)
```json
{
"mcpServers": {
"vibetutor": {
"command": "uv",
"args": [
"run",
"--directory",
"/절대경로/vibetutor-mcp",
"vibetutor-mcp"
],
"env": {
"VIBETUTOR_PROJECT_ROOT": "/분석할-프로젝트-루트-경로"
}
}
}
}
```
> `VIBETUTOR_PROJECT_ROOT`를 교재에 포함할 코드가 있는 프로젝트 루트로 지정하세요.
> 지정하지 않으면 vibetutor-mcp 패키지 디렉터리를 스캔합니다.
### Docker로 서버 실행 시
```json
{
"mcpServers": {
"vibetutor": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-v",
"C:\\분석할\\프로젝트\\루트:/workspace",
"-v",
"C:\\원하는\\출력\\경로:/app/output",
"-e",
"VIBETUTOR_PROJECT_ROOT=/workspace",
"vibetutor-mcp"
]
}
}
}
```
---
## 사용법
### MCP 도구 · 리소스
연동 후 Claude에서 아래 도구와 리소스를 사용할 수 있습니다.
#### Tool — `Generate book from markdown`
마크다운 텍스트를 입력받아 통 교재를 생성합니다. `output_format` 파라미터로 산출물 포맷을 선택하며,
생성된 교재는 `output/` 폴더에 저장되고 SQLite에 메타데이터가 기록됩니다.
**출력 포맷 (`output_format`)**
| 값 | 설명 | Docker 필요 여부 |
|-------------------|-----------------------------------------------|----------------|
| `pdf` (기본값) | 인쇄·배포용 완성 교재. 한글 폰트 임베딩, 표지·콜로폰 포함 | 필요 |
| `html` | 웹에서 바로 열어보는 교재. PDF와 동일 레이아웃, 변환 비용 없음 | 불필요 |
| `markdown` | PDF 변환 전 단계의 원본 마크다운을 그대로 저장. 빠른 텍스트·토큰 절약 | 불필요 |
포맷을 명시하지 않고 "교재 만들어줘"라고만 요청하면, Claude가 임의로 기본값(PDF)을 선택하지 않고
먼저 어떤 포맷으로 만들지 되물어봅니다(예: "PDF, HTML, Markdown 중 어떤 형식으로 만들어 드릴까요?").
대답으로 포맷을 지정하면 그에 맞춰 이 도구가 호출됩니다.
**마크다운 작성 규칙**
챕터는 `# 01장. 챕터 제목` 형태로 시작하며, 각 챕터는 아래 11개 서브섹션으로 구성됩니다.
```
### 1. 들어가며
### 2. 학습 목표
### 3. 핵심 이론 비교표
### 4. 핵심 이론 설명
### 5. 핵심 코드 분석
### 6. 마주친 문제와 디버깅
### 7. 실무 연동 팁
### 8. 심화 학습
### 9. Q&A 표
### 10. 용어 사전
### 11. 공식 링크
```
**사용 예시:**
```
여기서 채팅한 내용을 토대로 HTML 교재로 만들어줘
```
**출력 예시 (포맷별):**
```
통교재 생성 완료(pdf) → output/프로젝트_기초.pdf (id=42, hash=a1b2c3d4)
통교재 생성 완료(html) → output/프로젝트_기초.html (id=43, hash=b2c3d4e5)
통교재 생성 완료(markdown) → output/프로젝트_기초.md (id=44, hash=c3d4e5f6)
```
---
#### Tool — `Search material`
생성된 교재를 제목 키워드로 검색합니다.
**사용 예시:**
```
제목이 파이썬이 들어간 파일목록 보여줘
```
---
#### Resource — `vibetutor://materials`
저장된 모든 교재의 메타데이터 목록(JSON 배열)을 반환합니다.
#### Resource — `vibetutor://materials/{material_id}`
특정 교재의 상세 정보(JSON)를 반환합니다. 존재하지 않으면 `{}`를 반환합니다.
---
### 환경 변수
모든 경로 설정은 환경변수로 오버라이드할 수 있습니다. `.env` 파일도 지원합니다.
| 변수 | 기본값 | 설명 |
|--------------------------|-----------------------------------|-----------------------|
| `VIBETUTOR_PROJECT_ROOT` | 패키지 루트 | 코드 스캔 대상 프로젝트 경로 |
| `VIBETUTOR_OUTPUT_DIR` | `<root>/output` | PDF 및 DB 저장 디렉터리 |
| `VIBETUTOR_TEMPLATE_DIR` | `<root>/templates` | Jinja2 교재 템플릿 디렉터리 |
| `VIBETUTOR_FONT_DIR` | `<root>/templates/fonts` | WeasyPrint 한글 폰트 디렉터리 |
| `VIBETUTOR_DB_PATH` | `<root>/output/vibetutor.sqlite3` | SQLite DB 파일 경로 |
---
## 프로젝트 구조
```
vibetutor-mcp/
├── src/vibetutor_mcp/
│ ├── main.py # FastMCP 서버 엔트리포인트 (Composition Root)
│ ├── core/
│ │ ├── config.py # 환경변수 기반 설정 (VIBETUTOR_*)
│ │ ├── exceptions.py # 도메인 예외 (PipelineError 등)
│ │ └── security.py # 경로 안전 검증 · 민감 파일 차단
│ ├── domain/material/ # 순수 Python 도메인 (프레임워크 의존 없음)
│ │ ├── model.py # StudySection · MaterialRequest · StudyMaterial
│ │ ├── ports.py # 인터페이스 (PracticalMaterialRenderer / MaterialExporter / Clock)
│ │ ├── repository.py # Repository 인터페이스
│ │ ├── usecase.py # GenerateTutorMaterialUseCase
│ │ ├── query.py # Search · List · Get UseCase
│ │ └── hashing.py # SHA-256 콘텐츠 해시
│ ├── data/material/ # 인터페이스 구현체
│ │ ├── renderer.py # JinjaMaterialRenderer
│ │ ├── markdown_parser.py # 마크다운 → PracticalMaterialRequest 파서
│ │ ├── exporter.py # FormatRouterExporter (PDF/HTML/Markdown 라우팅)
│ │ ├── repository_impl.py # SqliteMaterialRepository
│ │ └── db.py # SQLAlchemy 엔티티
│ └── presentation/
│ ├── prompts/template.py # @mcp.prompt study_material_template
│ ├── tools/ # @mcp.tool (generate · search · markdown)
│ └── resources/ # @mcp.resource vibetutor://materials
├── templates/
│ ├── practical_material.html.j2 # 10단계 실전 교재 Jinja2 템플릿
│ ├── styles/ # tokens.css · components.css
│ └── fonts/ # Pretendard TTF/OTF (SIL OFL 1.1)
├── tests/
│ ├── test_scaffolding.py # 아키텍처 규칙 검증
│ ├── test_pipeline.py # 단위 · 통합 테스트
│ ├── test_e2e.py # 전구간 E2E + 재현성
│ ├── test_export_formats.py # 포맷별(PDF/HTML/Markdown) 내보내기 테스트
│ ├── test_practical.py # 10단계 실전 교재 파이프라인 테스트
│ ├── test_search_material.py # 검색 테스트
│ └── test_resources.py # Resource 테스트
├── scripts/
│ ├── smoke_generate.py # MCP 없이 PDF 1장 실생성 확인 스크립트
│ └── smoke_practical.py # 실전 교재 생성 확인 스크립트
├── Dockerfile
└── pyproject.toml
```
**아키텍처:** Clean Architecture — `Presentation → Domain ← Data`
## 알려진 제약 사항
- **Windows 로컬에서 PDF 변환 불가:** VibeTutor는 PDF 생성을 위해 WeasyPrint를 사용하는데, Dockerfile에는 이 의존성이 미리 설치되어 있으므로, Windows 사용자는 PDF 생성 시 Docker를 사용하세요.
- **검색 범위:** 현재 제목 LIKE 부분일치만 지원합니다.
---
## 라이선스
이 프로젝트의 소스 코드는 **MIT License**를 따릅니다. 자세한 내용은 [`LICENSE`](LICENSE)를 참고하세요.
### 서드파티 폰트
`templates/fonts/`의 Pretendard 글꼴은 **SIL Open Font License 1.1**로 배포되며, PDF 교재의 한글 임베딩 폰트로 동봉됩니다.
- Pretendard © 2021 Kil Hyung-jin — <https://github.com/orioncactus/pretendard>
- 라이선스 전문: `templates/fonts/LICENSE.txt`
TDQS
A3.8/5.0
Scored across 2 tools
Disambiguation5/5
Both tools have entirely distinct purposes: one generates a book from markdown, the other searches materials. There is no overlap or ambiguity between them.
Naming Consistency5/5
Both tool names follow a consistent verb_noun (or verb_noun_preposition) pattern using snake_case, making them predictable and readable.
Tool Count2/5
With only 2 tools, the server feels under-scoped for a tutor. Expected tools like listing books, deleting, or retrieving specific books are missing, making the surface thin.
Completeness2/5
The tool set covers generation and search but lacks basic CRUD operations like listing, updating, or deleting materials. Important operations for managing a book collection are absent.
Maintenance
ActivityStale
ResponsivenessUnresponsive