만든 도구를 검증하다 — 테스트가 설계를 바꾼 이야기
도구를 검증하려 했더니 설계를 바꾸게 됐습니다. 개발자 테스트에서 버그를 발견하고, 비개발자 테스트를 기획하면서 배포 아키텍처 자체를 전환한 경험을 정리합니다.
TL;DR 비개발자 E2E를 기획하다가 설치 경로 자체가 없다는 걸 발견했습니다. 테스트가 버그 수정이 아니라 배포 아키텍처 전환(6단계→2단계)의 계기가 됐습니다.
검증하러 갔다가 설계를 바꾸게 됐다
지난 포스팅에서 이슈 사이클로 첫 도구를 만들었습니다. 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와 함께 작업했습니다.