Learning MCP
# Learning MCP
## v2 적용 현황
프로젝트 식별자는 Git 원격 주소(없으면 최초 커밋)를 기준으로 유지하고, 로컬 경로는 별칭으로 기록합니다. 기능 시작과 종료 시 Git 증거를 SQLite에 저장합니다. 종료 후에는 `git:feature-diff`, `git:commits`, `git:working-final`, `git:staged-final`, `git:untracked-final` 등의 ref로 당시 내용을 조회할 수 있습니다. 종료된 기능의 `diff:working`과 `diff:staged`는 현재 작업 트리를 읽지 않습니다.
MCP의 `sync_codex_session`은 작업 ID를 즉시 반환합니다. Worker가 대화 동기화와 리뷰 작업을 처리하며, macOS에서는 `learning-mcp-cli install-worker-autostart`로 로그인 자동 실행을 설치할 수 있습니다. `get_system_status` 또는 CLI `status`로 heartbeat와 queue 상태를 확인합니다.
기능 종료 시 Git 증거는 정확한 종료 시점을 보존하기 위해 호출 안에서 캡처합니다. `request_feature_review`와 `request_daily_review`는 Gemini 분석을 작업 큐에 넣습니다. Worker는 압축된 근거를 전달하고 JSON 응답의 구조와 근거 ref를 검증한 뒤, Python 코드로 리뷰와 Obsidian 노트를 저장합니다. 기술 개념이 나오면 별도의 격리된 Antigravity 검색으로 기술 소유자의 문서, 표준, 원 논문 링크를 찾습니다. 검색 결과에서 확인되지 않은 URL은 만들지 않습니다. 생성 영역은 `LEARNING_MCP_OBSIDIAN_BASE_DIR` 아래에 만들며 기존 사용자 메모를 보존합니다.
실제 Gemini 분석에는 인증된 [Antigravity CLI `agy`](https://www.antigravity.google/docs/cli/headless/) 또는 [Gemini CLI](https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/headless.md)가 필요합니다. `agy`가 있으면 기본적으로 Gemini 모델 `gemini-3.8-flash-medium`을 사용하며, `LEARNING_MCP_GEMINI_MODEL`로 바꿀 수 있습니다. 기본 실행 파일이 PATH에 없으면 `LEARNING_MCP_GEMINI_EXECUTABLE`, 백엔드 선택이 필요하면 `LEARNING_MCP_GEMINI_BACKEND=agy` 또는 `gemini`를 설정하세요. `LEARNING_MCP_OBSIDIAN_VAULT`도 본인 Vault 경로로 설정해야 실제 Vault에 저장됩니다.
자동 시작을 설치하지 않은 환경에서는 MCP 서버와 별도로 `uv run learning-mcp-worker`를 실행해야 합니다. `uv`가 없으면 프로젝트에서 `PYTHONPATH=src python -m learning_mcp.worker`로 실행할 수 있습니다(Windows PowerShell: `$env:PYTHONPATH='src'; python -m learning_mcp.worker`). Gemini 호출에 실패하면 해당 작업은 재시도 후 `failed`가 되며 `get_job_status`에서 오류를 확인할 수 있습니다.
`evaluate_decision_candidate`는 큰 설계 결정을 판단하고 질문을 만들며, `record_user_answer`와 `record_review_confirmation`이 사용자 설명을 증거로 저장합니다. `get_learning_context`, `record_concept_use`, `request_delayed_recall`은 개념의 발견·설명·적용·지연 회상을 추적합니다. `mastered`는 자동 판정하지 않습니다.
AI와 함께 개발한 과정을 feature 단위로 기록하고, Git 변경 사항·AI 대화·토큰 사용량·기술적 판단·디버깅 과정을 학습 리뷰로 바꾸는 로컬 MCP 서버입니다.
단순히 “AI가 코드를 얼마나 작성했는가”를 계산하는 도구가 아닙니다. 사용자가 요구사항, 아키텍처, 구현, 디버깅, 테스트 중 무엇을 직접 판단했고 무엇을 AI와 함께 처리했는지 증거를 바탕으로 되돌아보는 것이 목적입니다.
## 목차
- [왜 만들었는가](#왜-만들었는가)
- [주요 기능](#주요-기능)
- [전체 구조와 동작 방식](#전체-구조와-동작-방식)
- [설치](#설치)
- [Codex에 MCP 등록](#codex에-mcp-등록)
- [Skills 설치](#skills-설치)
- [실제 사용 방법](#실제-사용-방법)
- [MCP 도구](#mcp-도구)
- [토큰과 대화 기록 방식](#토큰과-대화-기록-방식)
- [Obsidian과 책 집필 연결](#obsidian과-책-집필-연결)
- [구현 상세](#구현-상세)
- [테스트](#테스트)
- [현재 한계와 주의사항](#현재-한계와-주의사항)
- [문제 해결](#문제-해결)
## 왜 만들었는가
AI를 사용하면 비개발자도 빠르게 코드를 만들 수 있지만, 결과만 받아서 붙여 넣으면 다음 능력을 기르기 어렵습니다.
- 기능을 개발 가능한 크기로 나누는 능력
- 요구사항과 성공 조건을 정의하는 능력
- 기술과 아키텍처를 비교하고 선택하는 능력
- 코드가 실행되는 흐름을 설명하는 능력
- 오류에 대한 가설을 세우고 검증하는 능력
- AI가 작성한 코드를 검증하고 수정하는 능력
Learning MCP는 개발 결과보다 **개발 중 내린 판단과 검증 과정**을 남깁니다. feature가 끝나면 그 기록을 기반으로 다음 질문에 답합니다.
- 무엇을 만들었는가?
- 어떤 코드를 왜 변경했는가?
- 실행 흐름은 어떻게 되는가?
- 사용자가 직접 판단한 부분은 무엇인가?
- AI에 맡겼지만 사용자가 검증한 부분은 무엇인가?
- 다른 기술이나 더 단순한 방법은 없었는가?
- 어떤 오류를 어떤 가설로 해결했는가?
- 다음에 무엇을 공부해야 하는가?
- 이전 feature에서도 반복된 약점이 있는가?
## 주요 기능
| 기능 | 설명 |
|---|---|
| Feature 단위 기록 | 목표, 성공 조건, 사용자 담당 범위, AI 허용 범위를 개발 전에 선언합니다. |
| 다중 프로젝트 분리 | 서버와 DB는 하나를 공유하고, 각 호출의 현재 Git 루트로 프로젝트를 구분합니다. |
| 기술 결정 기록 | 선택한 기술, 선택 이유, 검토한 대안, 실제 결정 주체를 기록합니다. |
| 디버깅 훈련 | 증상, 가설, 최소 검증 방법, 결과와 상태를 기록합니다. |
| Git 증거 수집 | 기준 commit, branch, working/staged diff, 특정 commit을 필요할 때만 조회합니다. |
| Codex 대화 인덱싱 | feature 시작 이후 사용자·AI 메시지를 rollout JSONL에서 가져와 evidence로 저장합니다. |
| Feature별 토큰 집계 | Codex의 누적 token snapshot에서 시작값과 현재값의 차이를 계산합니다. |
| 토큰 절약형 리뷰 | 작은 manifest를 먼저 읽고 필요한 evidence만 선택 조회합니다. |
| 학습 기여도 리뷰 | 요구사항, 아키텍처, 구현, 디버깅, 테스트를 사람·AI 기여도로 구분합니다. |
| 반복 약점 추적 | 과거 리뷰의 약점과 다음 학습 주제를 프로젝트별로 요약합니다. |
| 공식 자료 연결 | 개념별로 공식 문서·표준·원 논문을 검색하고 검증된 공개 URL만 기록합니다. |
| Obsidian 내보내기 | 검토 결과를 프로젝트/feature별 Markdown 파일로 저장합니다. |
| 책 집필 연결 | 검증된 feature만 증거 묶음으로 만들어 기존 책 집필 Agent에 전달합니다. |
## 핵심 원칙
1. MCP는 증거 수집과 저장을 담당하고, 리뷰 판단은 Codex/Claude 같은 상위 Agent가 담당합니다.
2. 전체 대화와 전체 diff를 매번 읽지 않고 `manifest → selected evidence` 순서로 조회합니다.
3. 토큰 수를 AI 의존도나 사용자의 실력 점수로 해석하지 않습니다.
4. 사용자의 기여는 코드 작성량이 아니라 판단, 설명, 검증 증거로 평가합니다.
5. AI가 작성한 코드도 사용자가 흐름을 설명하고 테스트했다면 `ai-led-verified`로 구분합니다.
6. 검증되지 않은 feature 리뷰를 실제 경험처럼 책에 사용하지 않습니다.
7. 여러 프로젝트가 서버 하나를 공유하더라도 Git 증거는 feature에 저장된 프로젝트 루트에서만 읽습니다.
## 전체 구조와 동작 방식
```mermaid
flowchart TD
User["사용자"] --> Host["Codex / Claude Code"]
Host --> Skills["Learning Skills"]
Skills --> MCP["Learning MCP"]
MCP --> Git["현재 프로젝트 Git"]
MCP --> Logs["Codex rollout JSONL"]
MCP --> DB[("SQLite")]
DB --> Manifest["Compact Manifest"]
Manifest --> Skills
Skills --> Review["학습 리뷰"]
Review --> Vault["Obsidian Vault"]
Vault --> Book["책 집필 Agent"]
```
### 하나의 서버로 여러 프로젝트를 구분하는 방법
`LEARNING_MCP_PROJECT_ROOT`를 서버 설정에 고정하지 않습니다. `learning-session` skill이 현재 Codex 작업에서 다음 명령으로 대상 저장소를 확인합니다.
```bash
git rev-parse --show-toplevel
```
그 절대경로를 `start_feature.project_root`에 전달합니다. 서버는 받은 경로를 다시 `git rev-parse --show-toplevel`로 정규화하고, 실제 Git 저장소인지 검증한 뒤 feature에 저장합니다.
```text
Project A 작업 → project_root=/projects/a → Feature A
Project B 작업 → project_root=/projects/b → Feature B
↓
공용 Learning MCP + SQLite
```
이후 diff, branch, commit 조회는 호출 당시 현재 폴더가 아니라 **feature에 저장된 project root**를 사용합니다. 따라서 서로 다른 프로젝트에서 feature를 동시에 하나씩 진행할 수 있습니다.
안전 규칙은 다음과 같습니다.
- `start_feature.project_root`는 필수입니다.
- 하위 폴더를 전달해도 Git 최상위 폴더로 변환합니다.
- 존재하지 않는 폴더나 Git 저장소가 아닌 폴더는 거부합니다.
- 프로젝트 하나에는 동시에 active feature 하나만 허용합니다.
- 서로 다른 프로젝트에는 active feature가 각각 존재할 수 있습니다.
## 요구 사항
- macOS 또는 Linux
- Git
- Python 3.10 이상
- [`uv`](https://docs.astral.sh/uv/)
- MCP를 지원하는 Codex 또는 Claude Code 등의 host
- 선택 사항: Obsidian Vault
## 설치
현재 프로젝트 위치:
```text
/Users/juks86/Documents/Codex/2026-08-24/learning-mcp
```
의존성을 설치하고 SQLite DB를 초기화합니다.
```bash
cd /Users/juks86/Documents/Codex/2026-08-24/learning-mcp
uv sync
uv run learning-mcp-cli init
```
기본 DB 위치:
```text
/Users/juks86/Documents/Codex/2026-08-24/learning-mcp/data/learning.db
```
직접 서버를 실행해보려면 다음 명령을 사용합니다. stdio MCP 서버이므로 정상 실행 중에는 일반 웹 서버처럼 주소를 출력하지 않고 입력을 기다릴 수 있습니다.
```bash
uv run learning-mcp
```
## 환경 변수
| 환경 변수 | 역할 | 기본값 |
|---|---|---|
| `LEARNING_MCP_HOME` | 서버 데이터 기준 폴더 | Learning MCP 저장소 루트 |
| `LEARNING_MCP_DB` | SQLite DB 절대경로 | `<home>/data/learning.db` |
| `LEARNING_MCP_OBSIDIAN_VAULT` | 리뷰를 내보낼 Obsidian Vault | 미설정 시 내보내지 않음 |
| `LEARNING_MCP_OBSIDIAN_BASE_DIR` | Vault 내부의 Learning MCP 생성물 기준 경로 | `dev/wiki` |
| `LEARNING_MCP_CODEX_SESSION_ROOT` | 읽을 수 있는 Codex rollout 최상위 폴더 | `~/.codex/sessions` |
| `LEARNING_MCP_MAX_MANIFEST_CHARS` | manifest 최대 문자 수 | `8000` |
| `LEARNING_MCP_MAX_EVIDENCE_CHARS` | evidence 응답 최대 문자 수 | `12000` |
| `LEARNING_MCP_PROJECT_ROOT` | CLI `current`의 레거시 기본값 | 현재 실행 폴더 |
| `LEARNING_MCP_OFFICIAL_DOCS_EXECUTABLE` | 공식 자료 검색용 Antigravity 실행 파일 | `agy` |
MCP feature 시작에는 `LEARNING_MCP_PROJECT_ROOT`를 사용하지 않습니다. 현재 프로젝트의 Git 루트가 tool 호출 인자로 반드시 전달됩니다.
### Obsidian 저장 경로 지정
Obsidian 경로는 두 값으로 나눠 설정합니다.
| 설정 | 입력할 값 | 예시 |
|---|---|---|
| `LEARNING_MCP_OBSIDIAN_VAULT` | Obsidian Vault 자체의 절대경로 | `/Users/me/Documents/Obsidian Vault` |
| `LEARNING_MCP_OBSIDIAN_BASE_DIR` | Vault 안에서 Learning MCP가 사용할 상대경로 | `dev/learning-mcp` |
`LEARNING_MCP_OBSIDIAN_BASE_DIR`에는 Vault 절대경로를 넣지 않습니다. 절대경로나 `..`가 포함된 경로는 Vault 밖으로 나갈 수 있으므로 거부됩니다.
현재 이 저장소에서 사용하는 설정은 다음과 같습니다.
```bash
export LEARNING_MCP_OBSIDIAN_VAULT='/Users/juks86/Library/Mobile Documents/iCloud~md~obsidian/Documents/Obsidian Vault'
export LEARNING_MCP_OBSIDIAN_BASE_DIR='dev/learning-mcp'
```
이 설정에서는 파일이 다음 구조로 생성됩니다.
```text
Obsidian Vault/
└── dev/learning-mcp/
├── projects/<project>/features/<feature-id>/review-<title>.md
├── learning/daily/<year>/<date>-<project>.md
└── concepts/<development-or-cs>/<category>/<concept>.md
```
MCP 서버와 background Worker는 별도 프로세스이므로 두 곳 모두 같은 값을 설정해야 합니다. MCP 등록 예시는 아래 절을 따르고, Worker 설치 시에도 두 환경 변수를 함께 전달합니다.
## Codex에 MCP 등록
새로 등록할 때는 다음 명령을 사용합니다.
```bash
codex mcp add learning-mcp \
--env LEARNING_MCP_HOME=/Users/juks86/Documents/Codex/2026-08-24/learning-mcp \
--env LEARNING_MCP_DB=/Users/juks86/Documents/Codex/2026-08-24/learning-mcp/data/learning.db \
--env 'LEARNING_MCP_OBSIDIAN_VAULT=/Users/juks86/Library/Mobile Documents/iCloud~md~obsidian/Documents/Obsidian Vault' \
--env 'LEARNING_MCP_OBSIDIAN_BASE_DIR=dev/learning-mcp' \
-- /Users/juks86/.local/bin/uv run \
--directory /Users/juks86/Documents/Codex/2026-08-24/learning-mcp \
learning-mcp
```
이미 `learning-mcp`가 등록되어 있다면 기존 등록을 제거한 뒤 위 명령으로 다시 등록합니다. DB와 Obsidian 파일은 삭제되지 않고 Codex의 MCP 실행 설정만 교체됩니다.
```bash
codex mcp remove learning-mcp
```
등록 상태 확인:
```bash
codex mcp get learning-mcp
```
정상 예시:
```text
learning-mcp
enabled: true
transport: stdio
command: /Users/juks86/.local/bin/uv
args: run --directory .../learning-mcp learning-mcp
env: LEARNING_MCP_OBSIDIAN_BASE_DIR=*****, LEARNING_MCP_OBSIDIAN_VAULT=***** ...
```
새 도구 스키마를 반영하려면 MCP 등록 또는 서버 코드를 변경한 뒤 Codex를 재시작하거나 새 작업을 여는 것이 안전합니다.
## Skills 설치
저장소에는 다음 5개의 skill이 있습니다.
| Skill | 역할 |
|---|---|
| `learning-session` | feature 목표와 학습 범위를 선언하고 시작·종료합니다. |
| `feature-review` | Git과 기록 증거로 코드 흐름, 위험, 기여도, 학습 주제를 리뷰합니다. |
| `debugging-coach` | 사용자가 먼저 가설을 세우도록 돕고 최소 검증 실험을 기록합니다. |
| `architecture-critic` | 현재 방식, 단순한 방식, 확장형 방식을 비판적으로 비교합니다. |
| `promote-feature-to-book` | 검증된 feature 경험을 책 챕터 후보용 증거 묶음으로 변환합니다. |
모든 프로젝트에서 공통으로 사용하려면 전역 설치합니다.
```bash
cp -R /Users/juks86/Documents/Codex/2026-08-24/learning-mcp/skills/* \
/Users/juks86/.codex/skills/
```
특정 프로젝트에만 다른 정책을 적용하려면 대상 저장소의 `.codex/skills/`에 복사할 수 있습니다.
```bash
mkdir -p /path/to/project/.codex/skills
cp -R /Users/juks86/Documents/Codex/2026-08-24/learning-mcp/skills/* \
/path/to/project/.codex/skills/
```
Skill을 설치하거나 수정한 뒤에는 새 Codex 작업에서 사용하는 편이 안전합니다.
일반 개발 요청에서도 자동 추적을 기본값으로 만들려면 저장소의 정책 파일을 전역 Codex 지침으로 설치합니다. 기존 전역 지침이 있다면 덮어쓰지 말고 내용을 병합하세요.
```bash
cp config/CODEX_AGENTS.md ~/.codex/AGENTS.md
```
macOS에서 background worker를 로그인 시 자동 실행하려면:
```bash
LEARNING_MCP_OBSIDIAN_VAULT='/path/to/Obsidian Vault' \
LEARNING_MCP_OBSIDIAN_BASE_DIR='dev/learning-mcp' \
uv run learning-mcp-cli install-worker-autostart
uv run learning-mcp-cli status
```
LaunchAgent 로그는 `~/Library/Logs/LearningMCP/`에 저장됩니다.
## 실제 사용 방법
### 가장 효과적인 한 사이클
```text
Co-work 계획서에서 사용자 행동 단위 Feature 선택
→ $learning-session으로 성공 조건과 사람/AI 범위 선언
→ AI가 기술 대안을 비교하고 사용자가 핵심 방향 결정
→ AI에게 해당 Feature 범위만 구현 요청
→ 사용자가 직접 테스트
→ 오류가 나면 바로 수정을 맡기지 않고 가설→최소 검증부터 기록
→ 변경 파일만 stage하고 $feature-review
→ 사용자가 코드 흐름을 자기 말로 설명하고 기여도 확인
→ verified 리뷰 저장 → Feature ID 포함 commit → finish_feature
→ Obsidian 대시보드 확인 → 주간에 concept/debugging으로 승격
```
자동 추적 정책을 설치한 뒤에는 `$learning-session` 문구를 직접 입력하지 않아도 됩니다. 일반적인 기능·버그 수정·리팩터링 요청에서 Agent가 `ensure_feature`를 호출합니다. 오타, 포맷팅, 읽기 전용 질문은 Feature를 만들지 않습니다. 다른 결과로 전환하는 경계가 애매할 때만 사용자에게 확인하고, `verified`와 `mastered`는 계속 사용자 설명을 요구합니다.
Feature 시작 예시:
```text
$learning-session 계획서의 상품 검색 Feature를 시작하자.
검색 책임 위치와 테스트 전략은 내가 판단하고 반복 구현은 AI가 도와줘.
성공 조건은 빈 검색어 400, 정상 검색 결과 반환, 결과 없음은 빈 배열이야.
```
오류가 발생했을 때는 바로 `수정해줘`라고 하기보다 다음처럼 사용합니다.
```text
$debugging-coach 한글 검색만 실패해.
내 가설은 인코딩 문제 또는 Unicode 정규화 차이야.
아직 수정하지 말고 두 가설을 구분하는 최소 테스트부터 정해줘.
```
AI는 구현 속도를 담당하고, 사용자는 요구사항·아키텍처·가설·검증·최종 설명을 담당하는 흐름입니다.
### 1. 개발할 Git 프로젝트에서 작업 시작
Learning MCP 서버 폴더가 아니라 **실제로 개발할 프로젝트 폴더**를 Codex workspace로 엽니다.
```bash
cd /path/to/project-being-developed
git status
```
아직 Git 저장소가 아니라면 먼저 Git을 초기화해야 합니다.
```bash
git init
```
### 2. Feature 학습 세션 시작
예시 요청:
```text
$learning-session
로그인 API를 구현하면서 학습 기록을 시작하자.
요구사항과 인증 구조는 내가 판단하고, 반복적인 테스트 코드는 AI가 작성해도 돼.
성공 조건은 올바른 계정은 로그인되고 잘못된 비밀번호는 401을 반환하는 거야.
```
Skill은 다음 작업을 수행합니다.
1. 현재 workspace의 Git 루트를 확인합니다.
2. 목표와 관찰 가능한 성공 조건을 정리합니다.
3. 사용자가 직접 판단할 범위와 AI에 맡길 범위를 분리합니다.
4. `start_feature`를 호출합니다.
5. 정확한 Codex session 파일을 알 수 있으면 token 기준점을 연결합니다.
생성되는 feature ID 예시:
```text
F-20260825-001
```
### 3. 중요한 기술 판단 기록
모든 사소한 수정이 아니라 되돌아볼 가치가 있는 선택을 기록합니다.
```text
세션 방식 대신 JWT를 선택한 이유와 검토한 대안을 Learning MCP에 기록해줘.
이 결정은 내가 내렸어.
```
저장되는 정보:
- 어떤 질문에 대한 결정인지
- 최종 선택
- 선택 이유
- 검토한 대안
- 결정 주체: `human`, `shared`, `ai`
### 4. 디버깅 능력 훈련
```text
$debugging-coach
로그인 성공 후에도 다음 요청에서 인증이 풀려.
내 가설은 쿠키가 클라이언트에 저장되지 않았거나 SameSite 설정이 잘못된 거야.
```
`debugging-coach`는 바로 정답을 주기 전에 다음 순서를 사용합니다.
1. 관찰한 증상과 재현 조건을 분리합니다.
2. 사용자가 세운 가설을 먼저 보존합니다.
3. 가능한 추가 가설을 제안합니다.
4. 가설을 구분하는 가장 작은 로그·테스트·요청을 선택합니다.
5. 확인 전 예상 결과를 적습니다.
6. 실제 결과로 가설을 기각하거나 확정합니다.
7. `record_debug_attempt`로 저장합니다.
### 5. 커밋 또는 feature 리뷰
가능하면 리뷰할 변경을 먼저 stage합니다.
```bash
git add <review할 파일>
```
그다음 요청합니다.
```text
$feature-review F-20260825-001
staged 변경을 리뷰하고 코드 흐름, 내가 판단한 부분, AI가 작성한 부분,
다른 기술 대안과 다음 학습 주제를 알려줘.
```
리뷰는 기본적으로 다음 순서로 동작합니다.
```text
get_feature_manifest(detail="quick")
↓
필요한 evidence ref 선택
↓
get_evidence(["diff:staged", "decision:...", "debug:..."])
↓
코드 흐름·위험·대안·기여도 분석
↓
사용자 teach-back과 정정
↓
save_feature_review
```
사용자가 코드 흐름이나 핵심 설계를 자신의 말로 설명하고 기여도 판정을 확인하기 전에는 `verified=false`로 저장하는 것이 원칙입니다.
### 6. Feature 종료
```text
리뷰 내용을 확인했어. 이 feature를 완료 처리해줘.
```
`finish_feature`는 종료 시점의 Git 증거를 저장하고 연결된 Codex session의 최종 동기화를 Worker에 예약한 뒤 feature 상태를 `completed`로 변경합니다.
### 7. 과거 약점 확인
```text
이 프로젝트에서 반복해서 나타난 약점과 최근 학습 주제를 보여줘.
```
`get_learning_history`는 최근 리뷰와 약점 빈도 상위 5개를 반환합니다. 과거 기록에 없는 약점을 “반복 약점”이라고 추측하지 않습니다.
## 기여도 판정
다음 5개 영역을 각각 평가합니다.
- `requirements`: 요구사항과 성공 조건
- `architecture`: 책임 분리, 데이터 흐름, 기술 선택
- `implementation`: 실제 코드 구현
- `debugging`: 가설, 검증, 원인 규명
- `testing`: 테스트 전략과 검증
영역별 판정값:
| 값 | 의미 |
|---|---|
| `human-led` | 사용자가 방향을 세우고 주도적으로 판단했습니다. |
| `shared` | 사용자와 AI가 선택과 구현을 함께 진행했습니다. |
| `ai-led-verified` | AI가 주도했지만 사용자가 흐름을 설명하고 테스트·검증했습니다. |
| `ai-led-unverified` | AI가 주도했고 사용자의 이해나 검증 증거가 아직 부족합니다. |
토큰이 많다는 이유만으로 `ai-led`로 판정하지 않습니다. 사용자 발언, 결정 기록, 디버깅 가설, 코드 설명, 테스트 결과를 함께 봅니다.
## MCP 도구
일반 개발에서는 자동 추적용 `ensure_feature`, `checkpoint_feature`, `complete_feature`를 우선 사용합니다. 기존 세부 tool은 수동 복구와 정밀 제어를 위해 유지합니다.
### `ensure_feature`
실질적인 코드 변경 요청이 들어올 때 호출합니다. active feature가 있으면 이어가고, 없으면 새 feature를 시작하므로 재시도에도 중복 생성되지 않습니다. 정확한 Codex rollout 경로를 알고 있을 때만 `session_file`을 전달합니다.
### `checkpoint_feature`
테스트된 중간 이정표나 미완료 작업의 일시 정지를 기록합니다. checkpoint는 feature를 종료하지 않습니다.
### `complete_feature`
완료 신호와 테스트 근거를 저장하고, 최종 Git snapshot을 캡처한 뒤 `needs-confirmation` draft 리뷰를 자동 예약합니다. `verified`로 만들지는 않습니다.
### `get_system_status`
Worker heartbeat, pending/running/failed queue 수, 최근 오류와 선택적 프로젝트 active feature를 반환합니다.
### `get_project_context`
현재 경로를 실제 Git 최상위 경로로 정규화하고 branch, HEAD, 해당 프로젝트의 active feature를 반환합니다.
```text
get_project_context(project_root="/absolute/current/workspace")
```
### `start_feature`
feature 목표와 학습 책임 범위를 선언합니다. `project_root`는 필수입니다.
```text
start_feature(
project_root="/absolute/current/workspace",
title="로그인 API",
goal="계정 정보로 로그인하고 인증 실패를 구분한다",
success_conditions=["정상 계정은 성공", "잘못된 비밀번호는 401"],
user_owned_scope=["인증 구조", "API 성공 조건"],
ai_allowed_scope=["테스트 fixture", "반복 코드"],
project_name="auth-api"
)
```
### `record_decision`
기술 또는 구현 선택과 대안을 기록합니다.
```text
record_decision(
feature_id="F-20260825-001",
question="세션과 JWT 중 무엇을 사용할 것인가?",
chosen_option="서버 세션",
reason="현재는 단일 서버이며 즉시 폐기가 중요하다",
alternatives=["JWT access/refresh token"],
decided_by="human"
)
```
### `record_debug_attempt`
증상, 가설, 검증 방법, 결과를 저장합니다.
상태는 `open`, `confirmed`, `rejected`, `resolved` 중 하나입니다.
### `sync_codex_session`
Codex rollout JSONL을 feature에 연결하고 대화와 token delta를 동기화합니다.
단계는 다음과 같습니다.
- `start`: 현재 누적 토큰과 JSONL line을 기준점으로 저장
- `update`: 기준점 이후 대화와 현재 token delta 갱신
- `finish`: feature 종료 직전 최종 동기화
### `get_feature_manifest`
전체 원문 대신 리뷰에 필요한 작은 색인을 반환합니다.
포함 정보:
- 목표와 성공 조건
- 사용자/AI 범위
- Git status와 working/staged stat
- token 합계와 측정 품질
- 결정·디버깅·대화 evidence ref
- `standard`일 때 최근 학습 이력
평소에는 `detail="quick"`을 사용합니다.
### `get_evidence`
manifest에서 선택한 ref의 본문만 가져옵니다.
지원 ref:
| Ref | 내용 |
|---|---|
| `diff:working` | 아직 stage하지 않은 working diff |
| `diff:staged` | staged diff |
| `commit:<sha>` | 특정 commit의 정보와 stat |
| `decision:<id>` | 기술 결정 원문 |
| `debug:<id>` | 디버깅 시도 원문 |
| `evidence:<id>` | 저장된 대화 또는 기타 evidence |
한 번에 최대 10개 ref, 기본 최대 12,000자만 반환합니다.
### `save_feature_review`
요약, 코드 흐름, 기여도, 기술 대안, 약점, 다음 학습 주제를 저장합니다. 다음 학습 주제는 최대 3개로 제한합니다. Obsidian이 설정되어 있으면 Markdown도 내보냅니다.
### `finish_feature`
연결된 Codex session을 다시 읽고 token과 대화를 갱신한 뒤 feature를 완료합니다.
자동 추적 흐름에서는 직접 호출하는 대신 `complete_feature`를 사용합니다.
### `get_learning_history`
프로젝트의 최근 리뷰와 반복 약점을 반환합니다. 조회 개수는 최대 30개, 반복 약점은 상위 5개입니다.
### Resource
Feature별 quick manifest를 resource로도 조회할 수 있습니다.
```text
learning://feature/{feature_id}/manifest
```
## 토큰과 대화 기록 방식
### 토큰을 중복 합산하지 않는 이유
Codex rollout의 `token_count`는 매 이벤트의 독립 사용량이 아니라 누적 snapshot입니다. 모든 snapshot을 더하면 같은 토큰을 여러 번 계산하게 됩니다.
Learning MCP는 다음처럼 계산합니다.
```text
feature token usage = latest cumulative usage - start cumulative usage
```
수집 항목:
- `input_tokens`
- `cached_input_tokens`
- `output_tokens`
- `reasoning_output_tokens`
- `total_tokens`
측정 품질:
| 값 | 의미 |
|---|---|
| `exact-feature-delta` | feature 시작 시점에 session을 연결해 정확한 시작·현재 차이를 계산했습니다. |
| `whole-session` | feature 시작 뒤에 session을 연결해 session 전체 사용량일 수 있습니다. |
토큰은 비용과 작업 규모를 관찰하기 위한 지표이며, 코드 이해도나 AI 의존도를 자동 판정하는 점수가 아닙니다.
### 대화 기록
MCP 서버는 Codex 화면의 대화를 직접 볼 수 없습니다. `sync_codex_session`이 연결된 rollout JSONL을 읽어 기준 line 이후의 사용자·assistant 메시지를 evidence로 저장합니다.
- manifest에는 최대 240자의 요약과 ref만 표시합니다.
- evidence 본문은 메시지당 최대 4,000자 저장합니다.
- 같은 session line은 고유 ref를 사용해 중복 저장하지 않습니다.
- `session_file`은 `LEARNING_MCP_CODEX_SESSION_ROOT` 아래의 `.jsonl`만 허용합니다.
병렬 Codex 작업이 없을 때만 `session_file="latest"`를 사용할 수 있습니다. 작업이 여러 개라면 다른 작업의 최신 session을 선택할 수 있으므로 정확한 JSONL 경로를 전달해야 합니다.
## 토큰을 적게 사용하는 설계
리뷰 Agent에게 전체 프로젝트, diff, 대화를 한 번에 주지 않습니다.
```text
1차: quick manifest
목표 / stat / token / evidence index
↓
2차: selected evidence
실제로 필요한 diff / 결정 / 디버깅 / 대화
```
기본 제한:
- manifest: 최대 8,000자
- evidence: 최대 12,000자
- evidence ref: 한 요청에 최대 10개
- manifest 대화: 본문 대신 240자 요약
- Obsidian 저장 결과: 전체 Markdown 대신 경로와 SHA-256 hash만 반환
권장 운영 방식:
- 평소에는 `quick` manifest 사용
- staged diff부터 리뷰
- decision/debug ref는 필요한 것만 2~4개 조회
- `standard` manifest는 feature 완료 리뷰에서 사용
- architecture 비판이 필요한 경우에만 `architecture-critic` 사용
- LangGraph나 별도 리뷰 LLM을 MCP 내부에서 호출하지 않음
## Obsidian과 책 집필 연결
현재 LLM Wiki 구조에 맞춘 폴더 경계와 주간 운영법은 [Obsidian × Learning MCP 운영 가이드](docs/OBSIDIAN_LEARNING_WORKFLOW_KO.md)를 참고하세요. `vault-bootstrap/`에는 기존 원본과 일간 기록을 건드리지 않고 추가할 수 있는 홈·사용법·Dataview 대시보드가 들어 있습니다.
`LEARNING_MCP_OBSIDIAN_VAULT`가 설정되면 리뷰가 `LEARNING_MCP_OBSIDIAN_BASE_DIR` 아래 저장됩니다. 현재 권장 설정인 `dev/learning-mcp` 기준 경로는 다음과 같습니다.
```text
dev/learning-mcp/projects/<project-slug>/features/<feature-id>/review-<feature-title>.md
```
예를 들어 ID가 `F-20260825-001`, 제목이 `상품 키워드 검색 API`라면 다음처럼 저장됩니다.
```text
dev/learning-mcp/projects/shop-api/features/F-20260825-001/review-상품-키워드-검색-api.md
```
파일명은 feature 시작 때 전달한 `title`에서 만듭니다. 공백과 경로에 부적합한 문자는 `-`로 바꾸고 한글·영문·숫자는 유지하므로, Obsidian 파일 탐색기에서도 어떤 리뷰인지 바로 알 수 있습니다. 본문의 제목에는 원래 feature ID와 제목이 그대로 들어갑니다.
```markdown
# F-20260825-001 — 상품 키워드 검색 API
```
리뷰 Markdown에는 다음 항목이 들어갑니다.
- feature ID, 상태, 시작·종료 시각
- 요청한 기능과 사용자가 맡은 판단 범위
- 리뷰 요약과 코드 실행 흐름
- 영역별 기여도
- 다른 기술과 대안
- 반복 약점과 다음 학습 주제
- 다음 학습 주제의 공식 문서·표준·원 논문 링크
- token 사용량
일간 학습에서 생성되는 `dev/learning-mcp/concepts/` 노트에도 `공식 문서` 구역이 추가됩니다. 공식 자료 검색은 임시 작업공간에서 Antigravity의 `search_web`만 사용하며 URL 본문, 로컬 파일, 명령, 브라우저, MCP 도구는 사용하지 않습니다. 검색 결과에서 권위 있는 URL을 확인할 수 없으면 `검색으로 확인된 공식 문서 없음`으로 남깁니다. 이 별도 검색의 모델 사용량은 Antigravity/Gemini 계정 쪽에서 발생하며 Codex 대화 토큰 집계에는 포함되지 않습니다.
내보낼 경로가 설정한 Vault 밖으로 벗어나지 못하도록 resolved path를 검증합니다. 저장 결과에는 파일 경로와 내용의 SHA-256 hash가 반환됩니다.
재사용 가치가 있는 기록은 검토 후 다음 폴더로 승격할 수 있습니다.
```text
dev/learning-mcp/concepts/
dev/learning-mcp/debugging/
```
책 집필 연결:
```text
검증된 feature review
↓
$promote-feature-to-book
↓
learning evidence bundle
↓
chapter-writer
↓
read-only chapter-reviewer
```
`promote-feature-to-book`은 경험 주장을 feature/decision/debug ID와 연결하고, 코드 주장을 commit SHA와 파일 경로로 다시 검증하도록 요구합니다. 생성된 예시를 실제로 겪은 사건처럼 기록하면 안 됩니다.
## 구현 상세
### 기술 선택
- Python 3.10+
- MCP Python SDK 1.27 이상, 3 미만
- 로컬 stdio transport
- SQLite
- Git CLI
- Markdown/Obsidian
- 별도 LLM 호출 없음
- LangGraph 없음
MCP Python SDK v1.27의 `FastMCP` 경로와 v2의 `MCPServer` 경로를 모두 지원하도록 import fallback을 사용합니다.
### 주요 컴포넌트
| 파일 | 책임 |
|---|---|
| `src/learning_mcp/server.py` | MCP tool과 resource를 등록하고 stdio 서버를 실행합니다. |
| `src/learning_mcp/service.py` | feature, 결정, 디버깅, session, evidence, 리뷰 유스케이스를 처리합니다. |
| `src/learning_mcp/db.py` | SQLite schema, connection, commit/rollback을 관리합니다. |
| `src/learning_mcp/git_tools.py` | Git 루트 검증과 status/diff/commit 조회를 담당합니다. |
| `src/learning_mcp/codex_usage.py` | rollout JSONL의 token snapshot과 대화 이벤트를 파싱합니다. |
| `src/learning_mcp/obsidian.py` | 고정 형식의 리뷰 Markdown을 생성하고 Vault에 저장합니다. |
| `src/learning_mcp/config.py` | 환경 변수를 경로와 응답 제한 설정으로 변환합니다. |
| `src/learning_mcp/cli.py` | DB 초기화, active feature, manifest, session sync 보조 CLI를 제공합니다. |
### SQLite 데이터 모델
| 테이블 | 저장 내용 |
|---|---|
| `features` | 프로젝트 루트, 목표, 성공 조건, 학습 범위, 기준 commit, 상태 |
| `decisions` | 기술 질문, 선택, 이유, 대안, 결정 주체 |
| `debug_attempts` | 증상, 가설, 검증, 결과, 상태 |
| `sessions` | Codex session 경로, token 기준값·현재값, JSONL line 경계 |
| `evidence` | scope, 결정, 디버깅, 대화 등의 원문과 source ref |
| `reviews` | 코드 흐름, 기여도, 대안, 약점, 다음 주제, 검증 상태 |
SQLite foreign key를 사용하며 feature 삭제 시 연결 데이터가 함께 정리될 수 있도록 `ON DELETE CASCADE`를 설정했습니다. DB 작업은 성공 시 commit하고 예외가 발생하면 rollback합니다.
### Evidence 중심 구조
모든 리뷰 입력을 긴 문장 하나로 저장하지 않고 참조 가능한 evidence로 분리합니다.
```text
feature:F-20260825-001
decision:12
debug:7
codex:<session-id>:line:145
diff:staged
commit:<sha>
```
이 구조 덕분에 리뷰와 책 집필 시 어떤 주장에 어떤 코드·대화·판단이 사용됐는지 다시 확인할 수 있습니다.
### 프로젝트 폴더 구조
```text
learning-mcp/
├── README.md
├── PROJECT_CONTEXT.md
├── pyproject.toml
├── docs/
│ ├── ARCHITECTURE.md
│ └── USAGE_KO.md
├── skills/
│ ├── architecture-critic/
│ ├── debugging-coach/
│ ├── feature-review/
│ ├── learning-session/
│ └── promote-feature-to-book/
├── src/learning_mcp/
│ ├── cli.py
│ ├── codex_usage.py
│ ├── config.py
│ ├── db.py
│ ├── git_tools.py
│ ├── obsidian.py
│ ├── server.py
│ └── service.py
└── tests/
└── test_service.py
```
## CLI 보조 명령
MCP host 없이 DB와 feature 상태를 확인할 때 사용할 수 있습니다.
```bash
uv run learning-mcp-cli init
```
```bash
uv run learning-mcp-cli current --project-root /absolute/path/to/project
```
```bash
uv run learning-mcp-cli manifest F-20260825-001 --detail quick
```
```bash
uv run learning-mcp-cli sync-codex F-20260825-001 \
--session-file /Users/example/.codex/sessions/.../rollout.jsonl \
--phase update
```
## 테스트
전체 단위 테스트:
```bash
uv run python -m unittest discover -s tests -v
```
현재 테스트하는 핵심 동작:
- feature 시작부터 리뷰·Obsidian 저장·종료까지 전체 흐름
- 프로젝트 하나에 active feature 하나만 허용
- 하위 경로를 실제 Git 루트로 정규화
- `project_root` 누락 거부
- Codex 누적 token snapshot의 delta 계산
- feature 시작 이후 대화 evidence 인덱싱
- working/staged Git evidence 선택 조회
MCP Inspector:
```bash
uv run mcp dev src/learning_mcp/server.py:mcp
```
Inspector 실행에는 Node.js의 `npx`가 필요할 수 있습니다.
## 보안과 데이터 경계
- 서버는 로컬 stdio로 동작하며 별도 HTTP 포트를 열지 않습니다.
- session 파일은 설정한 Codex session root 아래의 `.jsonl`만 읽습니다.
- commit ref는 16진수 SHA 형식만 허용합니다.
- Obsidian 출력 경로가 Vault 밖으로 빠져나가지 못하도록 검증합니다.
- Git 도구는 status, diff, show 같은 읽기 작업만 수행합니다.
- 전체 대화는 MCP 응답에 자동 포함하지 않고 선택한 evidence만 반환합니다.
- DB와 Obsidian에는 개발 대화와 코드 일부가 저장될 수 있으므로 외부 동기화·공유 전에 민감정보 포함 여부를 확인해야 합니다.
## 현재 한계와 주의사항
- Codex rollout JSONL만 token adapter가 구현되어 있습니다. 다른 AI provider는 아직 지원하지 않습니다.
- MCP는 host의 현재 대화를 직접 구독하지 못하므로 `sync_codex_session` 연결이 필요합니다.
- `latest` session 자동 선택은 병렬 Codex 작업이 없을 때만 안전합니다.
- 코드 line별로 사람/AI 작성자를 자동 판정하지 않습니다. patch 기록만으로 실제 이해와 판단 주체를 정확히 알 수 없기 때문입니다.
- 리뷰의 기여도는 Agent의 제안이며 사용자의 확인이 최종 판정입니다.
- feature 완료 전에 리뷰를 저장하지 않아도 서버가 막지는 않으므로 skill의 작업 순서를 따라야 합니다.
- Git 저장소가 아닌 프로젝트는 추적할 수 없습니다.
- `project_slug`는 현재 영문 소문자·숫자 중심으로 정규화됩니다. 한글 이름만 사용하면 `project`가 될 수 있으므로 여러 한글 프로젝트에서는 `project_name`에 구분 가능한 영문 이름을 주는 편이 안전합니다.
- 아직 자동 commit이나 자동 push는 하지 않습니다. Git 변경은 읽기 전용으로 수집합니다.
- LangGraph는 사용하지 않습니다. 중단·재개, 승인 분기, 재검토 loop가 복잡해질 때 도입을 검토합니다.
## 문제 해결
### MCP가 보이지 않을 때
```bash
codex mcp get learning-mcp
```
`enabled: true`인지 확인하고 Codex를 재시작하거나 새 작업을 엽니다.
### `project_root must be inside a Git worktree` 오류
현재 Codex workspace가 실제 개발 프로젝트인지 확인합니다.
```bash
git rev-parse --show-toplevel
```
Git 저장소가 아니라면 올바른 프로젝트를 열거나 `git init`을 실행합니다.
### `feature ... is already active` 오류
같은 프로젝트에서 이전 feature가 아직 완료되지 않았습니다.
```text
get_project_context(project_root=<현재 Git 루트>)
```
active feature를 리뷰하고 `finish_feature`로 종료한 뒤 새 feature를 시작합니다.
### 토큰이 feature 전체보다 많아 보일 때
session을 feature 시작 후에 연결하면 측정값이 `whole-session`이 됩니다. 다음 feature에서는 시작 직후 `sync_codex_session(..., phase="start")`를 호출합니다.
### 대화가 다른 Codex 작업과 섞였을 때
병렬 작업 중 `session_file="latest"`를 사용했을 가능성이 있습니다. 해당 feature에 정확한 rollout JSONL 경로를 연결합니다.
### Obsidian 파일이 생성되지 않을 때
다음을 확인합니다.
- MCP 등록에 `LEARNING_MCP_OBSIDIAN_VAULT`와 `LEARNING_MCP_OBSIDIAN_BASE_DIR`가 있는가?
- Worker LaunchAgent에도 두 환경 변수가 같은 값으로 들어 있는가?
- 경로가 실제 Vault 절대경로인가?
- `save_feature_review`에서 `export_to_obsidian=true`인가?
- MCP 설정을 바꾼 뒤 Codex를 재시작했는가?
## 추가 문서
- [설치 및 사용법](docs/USAGE_KO.md)
- [아키텍처와 데이터 흐름](docs/ARCHITECTURE.md)
- [프로젝트 의사결정 기록](PROJECT_CONTEXT.md)
TDQS
Scored across 10 tools
Each tool targets a distinct phase of the learning workflow: feature lifecycle, context, decision records, debug attempts, session sync, manifest retrieval, evidence details, and final review. There is no meaningful overlap that would cause an agent to pick the wrong tool.
All tool names follow a clear snake_case verb_noun pattern, with get_, record_, start_, save_, finish_, and sync_ as predictable action prefixes. The naming is internally consistent and easy to navigate.
Ten tools is well-scoped for a learning-tracking MCP server covering feature lifecycle, context, decision/debug capture, Codex session synchronization, evidence retrieval, and review export. Each tool has a clear purpose and none feel redundant.
The core lifecycle is well covered: start a feature, capture decisions and debugging, sync sessions, retrieve evidence, save reviews, and finish. The main gap is the lack of update/correction or delete/abandon operations for recorded data, though this can be worked around by appending new records.