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을 명시하고, 실행파일 경로도 안전하게 해석하도록 고쳤다.