본문 바로가기

이 포트폴리오의 원본은 https://ai.iruyo.com (심재빈) 입니다 · 출처 식별자 jbx-7f3a2e9b

← 기술 블로그

AI·RAG

RAG를 MCP로 Claude Code에 물리기

사내 보안 정책상 외부 LLM으로 코드를 전송할 수 없는 환경에서, 자체 구축한 로컬 RAG(TextRAG)와 GitLab MR 리뷰봇을 MCP 프로토콜로 Claude에 연동한 구축 사례를 다룬다. Claude Code 내에서 코드 분석과 리뷰 자동화를 내부 리소스로 처리하게끔 구성한 과정과, 이를 통해 반복 작업의 토큰 비용 제거 및 내부 데이터(경력 DB·이력서 자동화 등)까지 확장한 방법을 구체적으로 정리했다.

보안 제품 코드는 사내 경계를 넘어 한 줄도 밖으로 나갈 수 없다. 이 전제 하나만으로도 시중의 LLM 자동화 도구 대부분은 사용할 수 없다. diff를 외부 API로 전송하는 순간 규정 위반이 되기 때문이다. 여기에 호출당 토큰 비용이 계속 누적되는 부담까지 더해진다. 이 두 가지 제약이 출발점이었다.

만든 것은 두 가지다. 사내 코드와 문서를 의미 단위로 검색하는 로컬 RAG 서버(TextRAG), 그리고 GitLab MR을 자동으로 리뷰하는 로컬 봇이다. 두 시스템 모두 사내 환경에서 자체 모델을 구동하고, MCP 서버로 연결해 Claude에 붙였다. 그 결과 사용자는 Claude Code 안에서 사내 코드 검색과 코드 리뷰 기능을 그대로 활용할 수 있다. diff도 코드도 경계 밖으로 나가지 않으며, 반복 호출에 따른 토큰 비용은 사실상 0이다.

모델을 사내에 두면 두 제약이 같이 풀린다

결론은 단순했다. 사내에 이미 상주하는 로컬 LLM을 활용하면 된다. 모델을 내부에서 돌리면 코드가 외부 경계 밖으로 나가지 않고, 호출당 비용은 사실상 0이 된다.

비용 0은 절약을 위한 문구가 아니라 구조적 전제다. 호출마다 비용이 발생하면 “이 MR은 리뷰할 가치가 있나”라는 판단 과정을 매번 거쳐야 하지만, 0이면 그 고민이 사라진다. 모든 MR에 제약 없이 리뷰를 붙일 수 있게 된다.

코어는 이미 존재했다. TextRAG는 사내 코드와 문서를 의미 기반으로 검색하고, diff를 받아 관련 코드를 찾아 리뷰를 생성하는 코드 리뷰 API가 포함돼 있었다. 다시 만들어야 할 것은 모델이 아니라, 그 검색과 리뷰 기능을 개발자가 직접 사용하는 도구 안에서 호출할 수 있게 하는 조립 계층이었다.

그 매개가 MCP다. TextRAG의 검색 및 코드 리뷰 API를 MCP 서버로 감싸 Claude에 연결하면, 개발자는 Claude Code 안에서 사내 코드 컨텍스트를 가져와 리뷰를 받을 수 있다. MR 리뷰봇은 동일한 코드 리뷰 API를 자동으로 호출하는 또 다른 소비자일 뿐이다 — 같은 코어를 두고, 호출자만 다르다.

패턴 하나로 수렴했다

조립 계층을 구성하다 보니 구조가 하나로 모였다. 어떤 입력을 받든 흐름은 같다.

입력(diff·경력 데이터) → 사내 RAG로 관련 컨텍스트 검색
                       → 로컬 LLM이 정해진 형식으로 생성
                       → 정형 출력(MR 코멘트·문서)

가운데의 “사내 RAG → 로컬 LLM” 구간은 고정이고, 양 끝의 입력과 출력만 목적에 맞게 달라진다. 이 세 단계가 아래에서 다루는 모든 도구의 공통 골격이 된다.

입력 (용도별로 다름) 코드 diff 경력 데이터 고정 코어 사내 RAG 컨텍스트 검색 로컬 LLM 정형 생성

출력 (용도별로 다름) MR 코멘트 이력서·문서

두 전제는 어떤 용도에서도 같다 — 외부로 데이터를 내보내지 않음 · 토큰 비용 0

점진 적용, 그리고 MR 리뷰봇

전 단계를 한 번에 자동화하진 않았다. 설계 → 구현 → 리뷰 → 문서화의 순서로 LLM을 도입했고, 매 단계마다 무엇을 넘기고 무엇을 직접 쥘지는 사람이 갈랐다. 설계 단계에선 사내 코드를 검색해 컨텍스트를 모으는 데 활용했고, 반복적인 형식의 명세 작성은 LLM에 맡겼다. 대신 도메인 판단은 사람이 직접 담당했다.

가장 손에 잡히는 결과물은 GitLab의 MR 리뷰봇이다. iOS 팀 리뷰 가이드에는 “24시간 이내 리뷰” 원칙이 있지만, 릴리즈 시즌이나 고객 이슈가 겹치면 리뷰가 밀리곤 했다. 그 공백을 봇이 메운다.

동작 구조는 단순하다. MR 이벤트를 받아 TextRAG 코드 리뷰 API를 호출하고, 결과를 MR 코멘트로 단다. 리뷰는 버그·보안·성능·품질·정합성 다섯 축으로 나누며, 의견을 달기 전에는 관련 소스 근거부터 제시한다. 근거 없는 지적을 줄이기 위한 절차다.

MR 이벤트 GitLab 리뷰봇 조립 계층 코드 리뷰 API RAG + 로컬 LLM MR 코멘트

가용성도 직접 책임 — 일시 장애 흡수 / 빈 컨텍스트 차단

임베더 과부하 → 재시도 LLM 재시작 → 재시도 코퍼스 없는 프로젝트 → 자동 건너뜀

막힌 건 품질이 아니라 가용성이었다

문제를 일으킨 건 리뷰의 품질이 아니라 가용성이었다. 임베더가 과부하에 걸리거나 로컬 LLM이 재시작될 때 생긴 일시 장애가 운영 중 그대로 드러났다. 외부 API였다면 그쪽 SLA 뒤에 숨을 수도 있었겠지만, 모델을 외부로 옮길 수 없었기에 가용성까지 직접 책임져야 했다. 로컬로 들여오는 순간 함께 따라온 청구서 같았다.

두 가지 방식으로 막았다. 일시 장애는 재시도로 흡수해 다음 호출에서 자연스럽게 회복하도록 했고, 코퍼스가 없는 프로젝트는 자동으로 건너뛰게 하여 봇이 빈 컨텍스트로 쓸모없는 리뷰를 남기지 않게 했다. 지금은 iOS 팀 7개 제품 MR에 자동 리뷰가 붙어 있다.

봇은 의견을 달지, 승인을 하지 않는다

선을 분명히 그었다. 봇이 남기는 것은 어디까지나 의견이고, 머지의 판단권은 사람에게 있다. 24시간 원칙을 바꾸는 것이 아니라 이를 보완하는 역할이다. 특히 보안 코드의 머지를 자동 리뷰에 맡기는 것은 위험하다. 자동화된 부분은 리뷰 의견을 빠짐없이, 그리고 즉시 남기는 일까지이고, 사람이 해야 할 일은 그 의견을 검토해 실제로 머지할지 판단하는 결정이다.

같은 골격을 다른 곳에도 붙였다

리뷰봇을 만들고 나서 보니, 이 골격이 꼭 코드 리뷰 전용일 필요는 없었다. 입력을 코드 diff 대신 경력 데이터로 바꾸고, 출력을 MR 코멘트 대신 문서로 전환하자 그대로 경력 DB와 이력서, 자소서 작성까지 확장되었다. 경계 밖 접근 금지와 토큰 0이라는 두 전제는 어느 쪽에서도 동일하게 작동했다. 흩어져 있던 개인 OSS — 도서 원고를 docx로 변환하는 book-forge, 로컬 모델과 메모리 제어 레이어인 Glimi — 도 결국 “RAG 컨텍스트 + 로컬 LLM + 정형 출력”이라는 하나의 패턴으로 묶이면서 사내 도구와 동일한 골격을 공유하게 되었다.

남는 것

처음에는 토큰 비용을 고려해 로컬 모델을 선택했는데, 계속 쓰게 된 이유는 비용이 아니라 경계였다. 코드를 외부로 내보내지 못한다는 제약이 오히려 사내에서 통하는 구조를 기본값으로 자리 잡게 했고, 그 덕분에 같은 골격이 리뷰·문서화·개인 도구로 자연스럽게 이어졌다. 직접 만들어 운영하기 전까지는 어디까지 자동화하고 어디서 사람이 멈춰야 하는지 감이 잡히지 않았다.