MVP 설계는 MCP하이브리드로_전환하기로 했고, 드디어 코드를 짰다. "내 볼트(노트 저장소)를 규칙대로 찾고·저 장·수정하는 도구를 만들어 Codex에 붙이는 것"이 목표. 그런데 코딩 과정 보다는 "AI가 내 파일을 함부로 못 건드리게 막고" "설계의 숨은 가정이 현장에서 깨지는" 일이 연속됐다. 하루치 빌드 실전 기록.
이런 분들께 도움돼요
Claude Code·Codex 같은 LLM CLI에 "내 데이터/규칙을 아는 도구(MCP)"를 직접 붙여보고 싶다
AI에게 파일 쓰기 권한을 주는 게 무섭다 — 어떻게 안전장치를 거는지 궁금하다
만든 게 "진짜 되는지" 어떻게 검증하는지 알고 싶다
무엇을 만들었나
MCP(Model Context Protocol)는 "LLM에게 도구를 붙이는 표준 규격" 이다. 내가 도구를 한 번 만들어 두면, Codex든 Claude든 같은 방식으로 그 도구를 불러 쓴다.
이번에 만든 건 볼트 MCP 서버 — 내 지식저장소(NewKnol)를 다루는 4개 도구:
도구
하는 일
search_vault
볼트에서 검색 → 경로·발췌·출처 반환
read_note
노트 한 개 전문 읽기
write_note
새 노트 미리보기(아직 안 씀)
update_note
기존 노트 보강 미리보기
apply_change
승인된 변경만 실제로 쓰고 git 커밋
핵심은 이 도구들이 "내 볼트 규칙"을 코드로 알고 있다는 것. 폴더 분류(개념→concepts/, 사례→cases/…), 파일명 규칙, frontmatter 양식, 그리고 금지선(특정 폴더엔 못 씀)을 강제한다. 그래서 어느 두뇌(모델)가 붙어도 볼트가 망가지지 않는다.
순서를 거꾸로: '위험한 것'부터 막고 시작했다
보통은 "되는 것"부터 만든다. 나는 반대로 갔다.
① 착수 전, 가장 큰 리스크부터 검증. 설계에 "Codex가 커스텀 MCP를 지원하는지 착수 직전 확인" 이라고 못박아 뒀었다. 그래서 코드 한 줄 짜기 전에 CLI로 직접 확인했고, MCP 서버가 등록돼 도는 것을 확인하고 나서야 빌드를 시작했다. (안 됐으면 이 시점에 방향을 틀었을 것이다.)
② "안전 핵심"을 LLM·키 없이 먼저 굳혔다. 가장 먼저 짠 건 화려한 검색이 아니라 규칙 엔진(rules.py) — AI가 엉뚱한 폴더에 쓰거나, frontmatter를 날리거나, 한 번에 수십 개 파일을 건드리는 걸 막는다. 그리고 64개 단위 테스트로 이걸 못 박았다. LLM도 API 키도 필요 없는 순수 로직이라, 돈 한 푼 안 쓰고 안전장치를 100% 검증할 수 있었다.
핵심 가드 6종: 폴더 자동분류 · 한글 파일명 정규화 · frontmatter 생성/검증 · frontmatter 제거 차단 · 다른 트랙(프로젝트) 폴더 쓰기 거부 · 아카이브·10개 초과·볼트 밖 차단.
③ 그 위에 도구·서버를 얹었다. 규칙 엔진이 단단하니, 그 위의 4개 도구와 MCP 서버는 빠르게 올라갔다. 특히 쓰기는 2단계로 만들었다 — write_note는 미리보기만 돌려주고, 동의 후 apply_change를 불러야 그때 실제로 쓰고 git에 커밋한다.
현장에서 부딪힌 3가지 함정
설계는 깔끔했지만, 손을 대자마자 가정이 깨졌다.
1) "ripgrep으로 검색한다" 그런데 ripgrep이 없었다
설계엔 "빠른 검색을 위해 ripgrep(rg) 사용" 이라고 적어뒀다. 그런데 테스트가 rg를 찾을 수 없음으로 깨졌다. 파보니 - 내가 평소 터미널에서 쓰던 rg는 Claude Code가 제공하는 셸 함수였지, 시스템에 깔린 진짜 프로그램이 아니었다. 즉 Codex가 서버를 띄우면 rg가 없다.
→ 검색을 순수 Python으로 다시 짰다. 결과적으로 외부 프로그램 의존을 없애 배포가 더 단순·견고해졌다. 함정이 더 나은 설계로 이어진 케이스.
2) 한글이 깨졌다 — 윈도우 인코딩의 늪
검색·git 커밋이 한글 파일명에서 와장창 깨졌다. 윈도우가 출력을 옛 한국어 코드(cp949)로 해석한 탓. → 모든 외부 명령 호출에 UTF-8을 명시하고, 실행파일 경로도 안전하게 해석하도록 고쳤다.
3) "승인"이 두 얼굴이었다
자동 점검(헤드리스)에서 Codex가 검색 도구를 부르자마자 "사용자 취소" 로 멈췄다. 당황. 알고 보니 — 사람이 없는 자동 모드에선 "승인할 사람이 없으니 그냥 취소" 한 것이었다. 일반 대화 모드에선 정반대로, 도구 호출 때마다 내게 "실행할까요?"를 물어본다. 그게 바로 내가 의도한 승인 게이트였다. 함정이 아니라 기능이었던 셈.
"진짜 되는 지"를 다섯 겹으로 확인했다
만들었다고 끝이 아니다. 신뢰는 층층이 쌓았다:
단위 테스트(64) — 규칙 엔진 로직 (키·LLM 불필요)
통합 테스트(15) — 임시 볼트에 실제 쓰기·트랙가드·링크보존
스모크 테스트 — 진짜 MCP 클라이언트로 서버에 붙어 도구 호출 (미리보기가 파일을 안 만드는지까지)
Codex 실연동 — Codex가 직접
search_vault를 불러 실제 볼트 20건을 출처와 함께 반환사람 수용 테스트 — 대화로 직접 시켜봄: ① 찾기(출처표시) ② 저장(미리보기→승인) ③ 추가(링크보존·날짜갱신) ④ 금지폴더 쓰기 거부 — 4종 모두 통과 ✅
각 층이 다른 종류의 실수를 잡는다. 아래로 갈수록 "현실"에 가깝고, 위로 갈수록 "싸고 빠르다."
배운 점
1) 가장 큰 리스크를 '코딩 전에' 먼저 검증하자. "Codex가 MCP 되나?"를 1분 만에 확인한 게 헛코딩 가능성을 처음부터 잘라냈다.
2) 안전장치는 LLM 없이, 가장 먼저, 테스트로 굳혀라. AI에게 쓰기 권한을 주는 도구일수록 — 되는 기능보다 못 하게 막는 가드를 먼저. 그것도 돈 안 드는 순수 로직 + 테스트로.
3) 쓰기는 '미리보기 → 승인' 2단계로. AI가 곧장 파일을 못 바꾸게 하고, 사람이 보고 OK해야 적용 + git 커밋. 무서움이 사라진다.
4) 설계의 '당연한 가정'도 현장에서 깨진다. "rg 쓰면 되지"가 틀렸다. 깨진 가정을 붙잡고 가지 말고, 확인하고 더 단순한 길로 가자. 종종 그게 더 좋은 설계다.
가장 와닿은 건 — "되게 만들기"보다 "안전하게·확실하게 만들기"에 시간을 더 쓴 게 지름길이었다는 점이다.
향후 계획
✅ 1단계 완료 — 볼트 MCP 서버(4도구+규칙) + Codex 연결 + 수용테스트 통과
1.5단계 — 의미검색(임베딩)으로 "표현이 달라도 관련된 노트"까지 끌어오기 +
synthesize합성 도구 (합성이 1순위니까)이후 — 미니PC 배포 → 밖에서 접근(웹/텔레그램) → 메신저 연동
재사용 가능한 프롬프트
이 작업의 가장 큰 기술 리스크(이게 안 되면 다 무너지는 것)가 뭔지 먼저 짚고,
코드 짜기 전에 그것부터 검증할 방법을 알려줘.
AI가 내 파일을 쓰는 도구를 만든다. '되는 기능'보다 '못 하게 막아야 할 것'을
먼저 목록화하고, LLM·API 키 없이 단위 테스트로 검증할 수 있게 설계해줘.
방금 만든 걸 신뢰하려면 어떤 검증을 '층층이' 쌓아야 할까?
싸고 빠른 것부터 현실에 가까운 것까지 단계로 정리해줘.