
MCP 설정에 비밀 정보를 섞지 않기 위한 mcp-config-lint 제작기
요약
MCP(Model Context Protocol) 설정 파일의 오류를 방지하기 위해 제작된 linter인 mcp-config-lint를 소개합니다. 복잡한 JSON 설정과 인자(args) 오류로 인해 MCP 서버가 기동되지 않는 문제를 해결하고자 개발되었습니다.
핵심 포인트
- MCP는 AI와 외부 도구를 연결하는 표준 규격(USB-C와 유사)임
- MCP 설정 파일의 미묘한 문법 및 인자 오류를 잡아주는 Linter 필요성 강조
- mcp-config-lint를 통해 설정 오류로 인한 디버깅 시간 단축 가능
결제는 하고 싶지 않다. 하지만 그 기능은 쓰고 싶다.
그런 생각에서 시작된 개발의 늪.
(참고로 필자는 음악 하는 사람이라 비유가 대부분 음악 계열이라서 용서해줘... 시테...)
일단 "Github Copilot을 사용해둬라"라고 스승님께 조언을 들었기에,
AI 에이전트로 코딩을 하면서 "와~ 즐겁다(백안)(에너지 드링크 5캔째)"
같은 상태로 있다가, 문득 생각이 들었습니다.
MCP를 만지다 보면, 모델보다 먼저 인간 쪽이 막히는 순간이 있지 않나?
그렇습니다, 설정 파일입니다.
그리고 그 MCP 설정 파일.
편리하긴 한데, 고장 나는 방식이 아주 미묘합니다.
- JSON 형식이 맞는 것처럼 보인다
command도 썼고args도 그럴싸하다 - 하지만 MCP 서버가 기동하지 않는다- 로그를 본다
- 기도한다
- 다시 로그를 본다
같은 상황 말이죠.
JSON은 잘못이 없다.
대부분 잘못된 것은 인간과, 어제의 나 자신, 그리고 대충 복사 붙여넣기한 args입니다.
그래서 MCP 설정 파일용 linter로서 mcp-config-lint를 만들었습니다.
그전에 Linter란 무엇인가? MCP란 무엇인가?
라고 궁금해하실 분들을 위해 아주 대충 그리고 거칠게 설명하겠습니다.
제가 당시 딱 그렇게 생각했던 내용과 말투로 쓰기 때문에,
다소(?) 격식 없는 말투지만 양해 부탁드립니다.
MCP (Model Context Protocol [이었던 것 같음])는 AI와 외부 도구를 연결하는
"공통 규격의 접속구"
이해하기 쉽게 말하자면, USB-C 포트가 자주 예로 들리곤 하죠.
옛날 스마트폰은 충전 케이블이 제조사마다 제각각이라
"이 케이블은 여기에 안 꽂히잖아! 이 망할" 이랬던 적이 있었죠.
그게 USB-C로 통일되면서 어디서든 쓸 수 있게 되었습니다. MCP가 바로 그것입니다.
AI (Claude나 GPT 등)는 원래 텍스트를 반환할 뿐인 존재지만, MCP를 사용하면 GitHub, 데이터베이스, 브라우저, Figma 같은 외부 도구에 "표준화된 동일한 방식"으로 연결될 수 있게 됩니다.
MCP가 없었을 때는 도구마다 "연결하기 위한 코드"를
매번 처음부터 써야 해서 엄청나게 번거로웠습니다.
예를 들어 AI에게 "이 리포지토리의 코드를 읽고 수정해줘"라고 부탁했을 때:
- AI가 "GitHub에 접속해야겠다"라고 판단
- MCP를 통해 GitHub 서버에 접속
- 코드 취득 → 수정 → 푸시까지 전 자동
이것을 Cursor나 Cline 같은 AI 에디터가 평범하게 해줍니다.
MCP 서버만 있다면 AI의 "할 수 있는 일"이 무한히 확장되는 느낌입니다.
Linter는 코드의 "문법·매너 위반을 자동으로 지적해 주는 선생님" 같은 것입니다.
음악으로 비유하자면, 만든 곡을 DAW에 넣었을 때 "이 부분의 노트가 음이 틀렸습니다", "여기 리듬이 어긋났습니다"라고 자동으로 지적해 주는 기능 같은 것이죠.
음... 이해하기 어렵나..? 음악에 살고 음악에 죽는 사람이라 다른 비유가 떠오르지 않네요 ( ´・ω・)
뭐 어쨌든, 프로그래밍에도
"돌아가긴 하지만 지저분하고·위험한 코드"라는 게 산더미처럼 있습니다.
스파게티 코드(Spaghetti code)라고 불리기도 한다더군요.
맛있어 보이네요. 버그 같은 건 미트볼 코드(Meatball code)라고 하나요?
잘 모르겠습니다 (゜-゜)
예를 들어, 사용하지 않는 변수를 대량으로 방치하고 있다거나
인덴트(Indent)가 제각각이라거나
위험한 패턴으로 작성되어 있는 경우,
이것을 인간이 전부 체크하는 것은 지옥의 2번지 같은 일이기에,
Linter가 자동으로 "여기 이상해!"라며 빨간 줄을 그어줍니다.
ESLint, Biome, textlint 등이 유명한 것들이죠.
| 한 마디로 말하면 | 음악으로 비유하면 |
|---|---|
| MCP | AI와 외부 도구를 잇는 USB-C |
| Linter | 코드의 품질 관리 도구 |
↑ 참고로 이거 만드는 데 시간 엄청 걸렸습니다 (불필요한 설명)
MCP = AI의 손발을 늘리는 규격, Linter = 코드 품질 관리 도구이며,
이 둘을 조합하면 "AI가 쓰고, 체크하고, 고치는" 것을
전부 자동화할 수 있는 최강의 워크플로우를 만들 수 있다는 느낌입니다!
그럼 본론으로 들어갑니다.
mcp-config-lint는 MCP 설정 파일을 정적으로 체크하기 위한 CLI 도구입니다.
아주 대충 말하자면,
MCP 클라이언트를 실행한 다음에 설정 실수를 깨닫는 것이 아니라, 실행하기 전에 혼나고 싶다~ 하는 마음을 위한 도구입니다.
설정 파일이라는 게, 규모가 작을 때는 "뭐 눈으로 직접 확인하면 되겠지"라고 생각하기 쉽습니다.
하지만 MCP의 config에는 command, args, env가 들어갑니다.
즉, 단순한 JSON처럼 보이지만 실질적으로는 "로컬에서 무엇을 실행할 것인가"에 대한 정의입니다.
작은 얼굴을 한 인프라랄까요. 귀여운 척하지만 평범하게 강력합니다.
기본적인 사용법은 다음과 같습니다.
npx mcp-config-lint
파일 경로 나 glob 패턴을 직접 전달할 수도 있습니다.
npx mcp-config-lint ./mcp.json
프로젝트에 포함하여 사용한다면, dev dependency (개발 의존성)로 설치해도 좋습니다.
npm install -D mcp-config-lint
npx mcp-config-lint
CI에 포함하는 경우에는 예를 들어 다음과 같이 작성합니다.
name: lint-mcp-config
on:
pull_request:
...
MCP 설정은 로컬에 두는 경우도 많지만,
팀에서 공유하는 템플릿이나 dotfiles, 개발 환경 설정 절차에 포함시킨다면,
CI에서 체크할 수 있다는 것만으로도 상당히 마음이 편해집니다.
"실행하고 나서 깨닫는 것"보다 "PR에서 떨어지는 것"이 그나마 인간에게 친절합니다.
PR에서 빨간 불이 들어오는 것도 괴롭긴 하지만, 새벽 2시에 비몽사몽한 상태로 MCP 로그를 읽는 것보다는 대체로 건강한 방식입니다.
mcp-config-lint가 보고 있는 것은 MCP 설정 파일의 "스키마 (Schema)로서의 올바름"보다는 "그대로 공개했을 때 위험할 수 있는 패턴"입니다.
예를 들어 다음과 같은 것들을 검출합니다.
- JSON / JSONC로서 깨져 있는 설정
env에 직접 작성된 token / secret / password 같은 값 - 고엔트로피 (High entropy)를 가진 secret 같은 환경 변수 값curl | sh나eval계열의 위험한 쉘 (Shell) 실행sudo,chmod 777,rm -rf /등의 권한 상승 또는 파괴적인 조작 같은 명령npx/dlx/uvx를 사용하여 패키지 버전이 고정되지 않은 실행~/.ssh,.aws/credentials,.kube/config등의 기밀 파일 참조 - 홈 디렉토리 하위를 넓게 참조하는 설정curl/wget등의 네트워크 취득 명령
예를 들어, 대략 이런 설정이 있다고 가정해 봅시다.
{
"mcpServers": {
"github": {
...
겉보기에는 그럴싸해 보이지만,
token으로 보이는 것이 직접 작성되어 있습니다.
(개발을 배우기 시작한 초기에 저도 자주 저질렀던 실수입니다)
이런 설정에 대해 linter (린터) 측에서 다음과 같이 출력합니다.
path/to/mcp.json
HIGH hardcoded-env-secret line 6
Environment key GITHUB_TOKEN contains a literal secret value.
...
실행 전에 알아챌 수 있을 뿐만 아니라, 출력되는 snippet (코드 조각) 부분은 값이 제대로 가려집니다.
로그에 생(raw) token이 남지 않는 것도 은근히 중요한 부분입니다.
만들 때 의식했던 점은 주로 이 부분들입니다.
linter에서 흔히 발생하는 패턴이, 화는 내는데 무엇을 고쳐야 할지 모르는 경우입니다.
Invalid config라고만 나오면, 사용자 입장에서는 "그렇겠지"라는 표정을 지을 수밖에 없습니다.
그래서 가급적이면
- 어떤 서버 정의에서
- 어떤 키가
- 왜 안 되는지
- 어떻게 고치는 것이 좋을지
가 전달되도록 만들고 싶습니다.
에러 메시지는 UI입니다.
CLI도 UI입니다.
인간이 읽는 이상, 거기에는 UX (사용자 경험)가 발생합니다.
mcp-config-lint는 기본적으로 설정 파일을 정적 (Static)으로 체크하는 도구입니다.
즉, 설정에 적혀 있는 command를 멋대로 실행하지 않는다는 방침을 가지고 있습니다.
이것은 정말 중요합니다.
MCP 설정에는 로컬 명령어나 환경 변수가 들어가기 때문에, linter가 멋대로 실행하기 시작하면 그것은 더 이상 linter라기보다 "호기심 많은 어떤 괴물"에 가깝습니다.
정적으로 보고 알 수 있는 실수는 정적으로 해결한다.
실행이 필요한 검증과는 분리한다.
이 선긋기를 굉장히 의식하고 있습니다.
개인적으로 이런 도구는 CI에 들어갔을 때 비로소 가치가 급상승한다고 생각합니다.
로컬에서 마음 내킬 때 실행하는 도구도 편리하지만,
설정 파일은 "실수로 망가지는" 법입니다.
실수를 방지하려면 인간의 주의력에 의존하기보다 기계에 맡기는 편이 좋습니다.
인간의 주의력은 유한합니다.
게다가 금요일 저녁에는 급격히 저하됩니다.
심지어 월요일은 하루 종일, 화요일도 하루 종일, 목요일은 셧다운(Shutdown) 상태입니다.
수요일 정도나 되어야 주의력이 조금 나아지는 날이죠.
그래서 mcp-config-lint는
CI에서 사용하기 쉽도록,
문제가 있으면 종료 코드(Exit Code)를 0이 아닌 값으로 반환하는 CLI(Command Line Interface)로 취급할 수 있게 만들었습니다.
mcp-config-lint는
MCP 서버의 안전성을 완전히 보장하는 도구는 아닙니다.
아니, 그런 도구가 있다면 오히려 (ヽ゚д゚) 주세요.
예를 들면 이런 것들 말이죠:
- 해당 MCP 서버 자체가 안전한가
- 실행 시 어떤 통신을 하는가
- tool call (도구 호출)의 내용이 타당한가
- 권한 설계가 적절한가
이런 부분까지는 이 도구만으로 판단하지 않습니다.
거기까지 하면 더 이상 config lint (설정 린트)가 아니라 보안 감사(Security Audit) 도구입니다.
그것도 정말 원하긴 합니다만 (두 번째 말함), 우선은 발밑의 JSON부터 챙기려 합니다.
"현관문을 잠그기 전에 집의 구조 계산을 시작하지 않는다" 정도의 입도(Granularity)입니다.
MCP 관련해서는 앞으로 설정이 더 늘어날 것이라고 생각합니다.
사용하는 도구가 늘어납니다.
연결하는 서비스가 늘어납니다.
팀에서 공유하고 싶은 설정도 늘어납니다.
로컬에서만 완결되었던 config가 점점 "관리해야 할 대상"이 되어갑니다.
그렇게 되면 설정 파일에도 최소한의 품질 체크가 필요해집니다.
코드에는 ESLint나 Prettier를 도입하면서, MCP config는 육안 검사만 한다는 것은 조금 불안합니다.
게다가 MCP config는 망가지면 AI 에이전트 측의 동작에 영향을 줍니다.
정말이지 제발 안 그랬으면 좋겠습니다 (절실).
에이전트가 똑똑한지 여부를 떠나서, 입구인 JSON에서 넘어지면 너무 슬프니까요.
F1 머신을 타고 가다가 편의점 연석에 긁히는 것과 같은 이야기입니다.
앞으로는 규칙을 조금 더 늘려가고 싶습니다.
예를 들어:
- 클라이언트별 설정 파일 탐지
- 자주 사용되는 MCP 서버 설정의 프리셋(Preset) 체크
- secret (비밀 정보) 탐지 규칙 강화
- 규칙의 활성화/비활성화 전환
- JSON Schema로서의 재사용
- GitHub Actions를 위한 CI 예시 추가 보강
- 에러 표시 개선
정도를 생각하고 있습니다.
특히 secret 관련은 제대로 하고 싶습니다.
MCP config에 token (토큰)을 대충 두면, 편리함을 대가로 미래의 내가 묘한 표정을 짓게 될 테니까요...
묘한 표정 정도가 아니라 타락하게 됩니다.
미래의 나는 타인입니다.
게다가 대개 엄격한 리뷰를 해옵니다.
2년 뒤에 "뭐야 이 설계는. 어떤 바보가 쓴 거야"라고 말하며,
냉정하게 "저입니다"라고 답하고 소멸하게 됩니다.
mcp-config-lint는
화려하지도 않고 만능 도구도 아닙니다.
AI 에이전트를 똑똑하게 만드는 것도 아니고,
MCP 서버를 자동 생성하는 것도 아닙니다.
그저 설정 실수로 허비하는 시간을 조금이라도 줄일 수 있다면 좋겠다는 생각으로 만든 도구입니다.
하지만 이런 사소한 부분을 없애 나가는 것이
개발 경험(DX)에는 효과적이라고 생각합니다.
설정 파일은 작동하고 있을 때는 공기 같습니다.
망가지는 순간에만 갑자기 주인공인 척 굴러옵니다.
그 주인공 교체를 가급적 막고 싶습니다.
그러니 MCP 설정 파일에서 "왜 안 돌아가지?"를
몇 번인가 경험해 본 적이 있는 분은 꼭 mcp-config-lint를
사용해 보세요.
Issue, PR, 피드백 모두 환영합니다.
Star도 환영합니다. OSS 제작자에게 Star는 합법적인 잎사귀 같은 것이니까요.
하지만 너무 엄격하게 말씀하시면 현실을 직시하게 되어 아저씨가 울어버릴지도 모르니 용서해 주세요.
아니었습니다.
글을 쓰다 보니 마지막에 깨달았는데 리포지토리 URL을 안 붙였네요.
잘 부탁드립니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기