만든 도구를 검증하다 — 테스트가 설계를 바꾼 이야기
도구를 검증하려 했더니 설계를 바꾸게 됐습니다. 개발자 테스트에서 버그를 발견하고, 비개발자 테스트를 기획하면서 배포 아키텍처 자체를 전환한 경험을 정리합니다.
검증하러 갔다가 설계를 바꾸게 됐다
지난 포스팅에서 이슈 사이클로 첫 도구를 만들었습니다. Slack 스레드를 Notion으로 정리하는 MCP 플러그인, claude-slack-to-notion이었습니다.
만들고 나서 실전에 투입하고 싶었습니다. 그런데 그 전에 해야 할 일이 있었습니다. 제작 과정에서 계속 신경 쓰였던 부분 — 비개발자 관점의 검증이 빠져 있다는 점이었습니다.
그래서 실전 투입 전에 테스트부터 시작했습니다. 버그 몇 개 잡고 끝날 줄 알았습니다. 결과적으로 배포 아키텍처 자체를 바꾸게 됐습니다.
테스트 전략 — 누가 어떤 관점으로 볼 것인가
테스트를 시작하기 전에 한 가지를 먼저 정했습니다. “누가 테스트하는가”에 따라 보는 것이 다르기 때문입니다.
| 구분 | 개발자 테스트 | 비개발자 E2E |
|---|---|---|
| 관점 | MCP 서버 내부 동작 | 설치부터 결과 확인까지 |
| 방법 | JSON-RPC stdin 직접 호출 | Claude Code에서 자연어로 요청 |
| 목적 | 기능 정확성 검증 | 사용자 경험 검증 |
개발자 테스트는 직접 할 수 있었습니다. 비개발자 E2E는 실제 비개발자에게 부탁해야 했습니다.
테스트 환경도 분리했습니다. 프로덕션 워크스페이스를 오염시키지 않도록 별도의 Slack 테스트 워크스페이스를 만들었습니다.
개발자 테스트 — 에러 케이스가 말해준 것들
MCP 서버는 JSON-RPC 프로토콜로 동작합니다. stdin으로 요청을 보내면 stdout으로 응답이 옵니다. 이 방식으로 서버를 직접 테스트했습니다.
정상 케이스 12개는 모두 통과했습니다. 문제는 에러 케이스에서 나왔습니다.
에러 메시지 한글화 누락
에러가 발생하면 영문 메시지가 그대로 노출됐습니다. 이 도구의 사용자는 비개발자입니다. “Invalid token” 대신 “토큰이 유효하지 않습니다”가 나와야 합니다.
에러 메시지 전체를 한글화했습니다. 동시에 에러 코드 체계도 정리했습니다.
limit=0 검증 누락
메시지 조회 시 limit 파라미터에 0을 넣으면 검증 없이 그대로 Slack API에 전달됐습니다. Slack API는 limit=0을 허용하지만 빈 결과를 반환합니다. 사용자 입장에서는 “왜 아무것도 안 나오지?”가 됩니다.
최소값 검증을 추가하고, 범위를 벗어나면 이유를 설명하는 메시지를 넣었습니다.
설치 가이드를 직접 따라가봤다
제작 과정에서도 비개발자용 가이드를 다듬었지만, 개발자 테스트를 하면서 다시 처음부터 따라가봤습니다. 관점이 달라지니 새로운 것이 보였습니다.
- 클론 위치에 대한 안내가 모호해서 어디서 실행해야 하는지 헷갈림
.env파일 경로가 상대경로라 현재 디렉토리에 따라 동작이 달라짐- “터미널에서 다음을 실행하세요”가 비개발자에겐 첫 번째 벽
이전에 다듬었던 건 Notion UI 용어나 봇 초대 방식 같은 것이었습니다. 이번에 발견한 건 그보다 앞단 — 설치 자체의 혼란이었습니다.
비개발자 E2E를 기획하다 — 설치 경로가 없었다
개발자 테스트에서 버그를 잡은 뒤, 비개발자 E2E 테스트를 기획했습니다.
시나리오를 작성하려고 첫 단계부터 적어봤습니다.
“1. 설치한다.”
여기서 멈췄습니다.
현행 설치 과정은 이랬습니다.
# 6단계
git clone https://github.com/.../claude-slack-to-notion.git
cd claude-slack-to-notion
cp .env.example .env
# .env 편집...
cd ~/my-project
claude --plugin-dir ~/claude-slack-to-notion # 매 세션마다
6단계. git clone부터 시작합니다. 비개발자에게 Git은 낯선 도구입니다. Python 가상환경 설정은 더 낯섭니다.
비개발자 설치 경로 자체가 존재하지 않았습니다.
E2E 테스트를 “기획”하는 단계에서 아키텍처 문제를 발견한 겁니다.
공식 MCP 서버는 어떻게 하고 있나
Claude Code 공식 플러그인들의 설치 방식을 조사했습니다.
| 패턴 | 예시 | 특징 |
|---|---|---|
| HTTP 원격 서버 | Sentry, Linear | 서버 운영 필요 |
| npx / uvx | mcp-server-git | 패키지 레지스트리에서 자동 실행 |
| 번들 스크립트 | 커뮤니티 플러그인 | 의존성 관리 복잡 |
Anthropic 공식 MCP 서버인 mcp-server-git이 사용하는 패턴은 uvx(Python) 또는 npx(Node.js) 기반 자동 실행이었습니다.
4가지 옵션을 비교하다
| 옵션 | 장점 | 단점 |
|---|---|---|
| uvx (선택) | 공식 패턴, 원커맨드 실행 | PyPI 배포 필요 |
| pip + source | PyPI 불필요 | venv 관리 부담 |
| HTTP 원격 | 설치 없음 | 서버 운영 비용 |
| 현행 유지 | 변경 없음 | 비개발자 사용 불가 |
uvx를 선택했습니다. 이유는 세 가지였습니다.
- 공식 패턴 준수 —
mcp-server-git과 정확히 같은 구조 - 사용자 경험 —
uvx slack-to-notion-mcp한 줄로 실행 - 자동 의존성 관리 — 가상환경과 패키지 설치를 uvx가 처리
자바 개발자 관점에서 이 생태계가 어떻게 보였는지는 uvx — 자바 개발자를 위한 안내서에 정리했습니다.
6단계에서 2단계로
전환 결과는 명확했습니다.
변경 전 — 6단계:
git clone → cd → cp .env → 편집 → cd → claude --plugin-dir
변경 후 — 2단계:
brew install uv # 최초 1회
claude mcp add slack-to-notion \
-- uvx slack-to-notion-mcp # 최초 1회
6단계에서 2단계로.
git clone도, Python 설정도, 매 세션--plugin-dir지정도 사라졌습니다.
돌아보며
버그 2건, 문서 2건, 아키텍처 1건 — 가장 큰 발견은 아키텍처였습니다.
테스트를 시작할 때는 “버그를 찾자”가 목표였습니다. 버그도 찾았습니다.
“비개발자 E2E를 기획한다”는 행위 자체가 관점을 바꿨습니다. 개발자 관점에서는 보이지 않던 것 — “이 도구를 설치할 수 있는 사람이 개발자뿐이다” — 이 E2E 시나리오 첫 줄에서 드러났습니다.
테스트는 만든 것이 동작하는지 확인하는 거라고 생각했습니다. 이번 경험은 달랐습니다. 테스트가 확인이 아니라 재설계의 계기가 될 수 있었습니다.
아키텍처를 바꿨으니, 이제 진짜 비개발자에게 건네볼 차례입니다.
이 글은 Claude의 도움을 받아 작성했습니다.