
MCP 도구가 중간에 실패하면 어떻게 될까요? 실패를 회귀 테스트로 전환하기
요약
MCP(Model Context Protocol) 도구의 신뢰성을 검증하기 위한 ResiliReplay 도구를 소개합니다. 단순한 스모크 테스트를 넘어 결함 주입과 회귀 테스트를 통해 시스템의 복구 능력과 안정성을 확인하는 방법을 다룹니다.
핵심 포인트
- MCP Inspector는 기능 작동 여부를 확인하지만, ResiliReplay는 실패 상황에서의 복구력을 검증함
- 결함 주입을 통해 예산 내 복구 및 중복 부작용 방지 여부를 테스트 가능
- 정형화된 검토 계획과 캠페인 해시를 통해 테스트 결과의 재현성 확보
- npx를 이용한 간편한 드라이 런 및 감사(audit) 기능 제공
저는 ResiliReplay를 관리하고 있으며, 일반적인 MCP 스모크 테스트(smoke tests)를 통과해 버리는 한 가지 질문을 중심으로 이를 구축했습니다. 그것은 바로 서버가 발견된 후, "요청 수락(request accepted)"과 "유용한 결과 반환(useful result returned)" 사이의 경계에서 도구가 실패하면 어떤 일이 발생하는가 하는 점입니다.
대부분의 1차 점검은 필연적으로 낙관적입니다. 서버를 시작하고, tools/list를 호출하며, 유효한 인수로 도구 하나를 실행한 뒤 깔끔한 응답을 확인합니다. 이는 통합(integration)이 작동할 수 있음을 증명합니다. 하지만 이것이 클라이언트가 정해진 예산(budget) 내에서 복구되는지, 중복된 부작용(side effects)을 피하는지, 적대적인 출력을 거부하는지, 또는 나중에 코드가 변경된 후에도 동일한 동작을 유지하는지를 증명하지는 않습니다.
신뢰성(Reliability) 작업은 바로 그 깔끔한 호출이 멈추는 지점에서 시작됩니다.
Inspector와 ResiliReplay는 서로 다른 질문에 답합니다
MCP Inspector는 서버와 상호작용하는 데 유용합니다. 도구를 발견하고, 스키마(schemas)를 검사하며, 인수를 제공하고, 실제 응답을 확인할 수 있습니다. ResiliReplay는 Inspector 형태의 설정을 수용하지만, 해당 대화형 워크플로우(interactive workflow)를 대체하는 것은 아닙니다.
제가 사용하는 구분 방식은 간단합니다:
- Inspector는 "이 서버가 무엇을 노출하며, 일반적인 호출이 작동하는가?"라는 질문에 답합니다.
- ResiliReplay는 "선언된 실패가 삽입되었을 때 어떤 일이 발생하는가, 복구가 예산 내에서 유지되는가, 그리고 나중에 결과를 재생(replay)할 수 있는가?"라고 묻습니다.
두 번째 질문에는 무작위 결함 주입(fault injection) 이상의 것이 필요합니다. 유용한 캠페인은 경계가 정해져 있고 검토 가능해야 합니다. 즉, 하나의 시드(seed), 명시적인 시나리오, 작은 도구 허용 목록(allowlist), 고정된 재시도 및 시간 예산, 선언된 기대치, 그리고 로컬 증거가 필요합니다. 캠페인이 도구를 호출할 경우, ResiliReplay는 정형화된 검토 계획을 출력하며 실행 전에 정확한 캠페인 해시(campaign hash)를 반환할 것을 요구합니다.
서버에 접속하지 않고 시작하기
Node.js 22 또는 24를 사용하면, 최소한의 진입점은 드라이 런(dry run)입니다:
npx --yes resilireplay@0.3.1 mcp audit \
--inspector-config ./mcp.json \
--server my-server \
...
출력 결과에는 실행 파일(executable), 인자 목록(argument list), 작업 디렉토리(working directory), 전송 방식(transport), 타임아웃(timeouts), 그리고 환경 변수(environment-variable) 이름이 기술됩니다. 서버를 시작하거나 도구(tool)를 호출하지는 않습니다. 덕분에 잘못된 대상(target)이나 예상치 못하게 광범위한 설정을 잡아내는 데 유용한 지점이 됩니다.
그다음 캠페인 템플릿(campaign template)을 생성합니다:
npx --yes resilireplay@0.3.1 campaign init reliability.campaign.yml
npx --yes resilireplay@0.3.1 campaign validate reliability.campaign.yml
초기 필드 테스트(field test)를 위해, 저는 동시성(concurrency)을 1로 유지하고, 정확히 하나의 읽기 전용 멱등성 도구(read-only idempotent tool)를 허용하며, 재시도(retries)를 1회로 설정하고, 세 가지 시나리오를 사용합니다.
1. 깨끗한 대조군(control) 설정
대조군은 fault: none을 사용하며, 재시도 없이 통과(pass)할 것을 기대합니다. 이는 단순히 의례적인 절차가 아닙니다. 깨끗한 대조군이 없다면, 주입된 실패(injected failure)가 잘못된 설치, 유효하지 않은 작업 디렉토리, 누락된 브라우저 바이너리(browser binary), 또는 호환되지 않는 서버 버전과 혼동될 수 있기 때문입니다.
제가 실행했던 Playwright MCP 설정 중 하나에서 이 점이 증명되었습니다. Chrome for Testing이 설치되어 있지 않아 복구(recovery)에 실패했습니다. 그것은 환경의 실패였지, Playwright MCP 복구에 대한 증거가 아니었습니다. 문서화된 설치 프로그램을 사용한 후에야, 깨끗한 대조군과 제한된 캠페인(bounded campaign)을 정직하게 해석할 수 있었습니다.
2. 결과 수준의 실패를 주입하고 한 번 재시도하기
다음 시나리오는 recovery: retry와 함께 mcp-tool-error를 사용합니다. ResiliReplay는 실제 도구 호출이 완료되도록 허용하되, 테스트 경계(test boundary)에서 관찰된 결과를 제어된 오류(controlled error)로 교체하고 한 번의 재시도를 허용합니다. 어설션(assertions)은 성공적인 복구, 1회 이하의 재시도, 중복된 부작용(side-effect) 시도 없음, 그리고 정책 준수를 요구합니다.
이러한 구분이 중요합니다. 서버에 주입된 오류가 포함되어 있었던 것이 아니라, 하네스(harness)가 오류를 도입한 것입니다. 통과(pass)되었다는 것은 단지 관찰된 동작이 선언된 이 실험과 일치함을 의미할 뿐입니다.
3. 악의적인 카나리(malicious-canary) 부정 대조군 추가
세 번째 시나리오는 mcp-malicious-canary-instruction을 주입하고 실패를 예상합니다. 이 시나리오의 목적은 캠페인이 입력값에 관계없이 무조건 성공(green)을 보고하는 대신, 알려진 잘못된 상태를 감지할 수 있음을 보여주는 것입니다.
이는 취약점 주장(vulnerability claim)이 아닌 부정 대조군(negative control)입니다. 카나리는 합성된 것이며 실제 비밀 정보는 사용되지 않고, 예상되는 결과는 실행 전에 기록됩니다. 예상된 실패가 발생하면, ResiliReplay는 인과적 추적(causal trace)을 축소하여 시나리오, 최소화된 픽스처(fixture), 실행 가능한 Node 테스트 및 매니페스트(manifest)를 작성합니다. 캠페인 러너(campaign runner)는 생성된 해당 회귀 테스트를 즉시 실행합니다.
베이스라인은 실패 시 차단되어야 합니다 (fail closed)
기대치 일치 실행(expectation-matching run)이 완료된 후, 명시적으로 승인하십시오:
npx --yes resilireplay@0.3.1 campaign approve runs/field-test \
--output baselines/field-test.json
...
비교 과정에서는 검증된 실행 ID와 점수 하락, 재시도(retries), 중복 시도와 같이 선언된 지표(metrics)를 확인합니다. 불완전하거나 해시가 유효하지 않은 증거는 묵인되어 통과(pass)로 처리되지 않습니다. 이 부분이 일회성 실험을 CI 경계(CI boundary)로 전환하는 핵심입니다.
세 가지 제한된 필드 검증 (Three bounded field validations)
저는 공개된 resilireplay@0.3.0 패키지를 문서화된 로컬 stdio 경로를 통해 독립적으로 유지 관리되는 세 가지 고정된 프로젝트에 대해 실행했습니다:
- MCP Everything Server: 해롭지 않은 생성된 텍스트를 포함한
echo. - Playwright MCP: 탐색(navigation)이 없는 빈 격리된 헤드리스(headless) 페이지에서의
browser_snapshot. - UI5 MCP Server: 프로젝트 분석 없이 번들된 가이드를 대상으로 하는
get_guidelines.
각 캠페인은 클린 대조군(clean control), 한 번의 성공적인 재시도를 포함한 도구 결과 오류 주입(injected tool-result error), 그리고 카나리 부정 대조군(canary negative control)을 실행했습니다. 각 부정 대조군은 검증된 실행 가능한 회귀 테스트를 생성했습니다. 승인된 각 베이스라인 비교에서는 차이점이 0으로 보고되었습니다. 전체 명령어, 버전, 경계 및 정제된 증거는 field results에서 확인할 수 있습니다.
이것들은 보편적인 벤치마크가 아닌 세 가지 좁은 범위의 사례 연구입니다. 각 서버당 검토된 하나의 작업을 다룹니다. 이 연구는 프로젝트의 순위를 매기거나, 업스트림 채택을 암시하거나, 보안을 인증하지 않습니다. Streamable HTTP는 ResiliReplay의 로컬 자동화 픽스처(fixtures)에 의해 실행되지만, 선택된 세 가지 외부 패키지 중 어느 것도 이를 문서화된 로컬 기본 경로로 사용하지 않았으므로, 이를 제3자 HTTP 증거로 제시하지는 않습니다.
안전 경계 및 한계 (Safety boundaries and limitations)
ResiliReplay는 방어적 신뢰성 소프트웨어(defensive reliability software)이지, OS 샌드박스(sandbox)가 아닙니다. 사용자가 권한을 부여한 도구는 여전히 해당 서버의 권한을 사용하여 파일, 데이터베이스, 브라우저 또는 원격 시스템을 변경할 수 있습니다. 로컬에서 시작하십시오. 읽기 전용(read-only) 및 멱등성(idempotent) 호출을 선호하십시오. 허용 목록(allowlist)에 있는 모든 도구를 검토하십시오. 그리고 단순히 실패를 유도하기 위해 프로덕션 데이터를 사용하지 마십시오.
보고서는 정제(sanitized)되지만, 패턴 삭제(pattern redaction)가 모든 애플리케이션별 비밀 정보가 사라졌음을 증명할 수는 없습니다. 해시(Hash)는 증거를 연결하고 변경 사항을 감지하지만, 서명자의 신원을 확립하지는 않습니다. 현재의 스코어러(scorer)는 선언된 관찰 가능한 증거를 평가하며, 개방형의 의미론적 품질(semantic quality)을 평가하지는 않습니다. 부수 효과(side-effecting)를 일으키는 캠페인은 중단 후 의도적으로 재개되지 않는데, 이는 부분적인 작업을 다시 실행(replaying)하는 것이 안전하지 않을 수 있기 때문입니다.
프로젝트, npm 패키지 및 5분 현장 테스트 가이드는 ResiliReplay 사이트에서 확인할 수 있습니다. 만약 MCP 서버를 운영 중이라면, 검토된 실제 도구 하나로부터 정제된 결과를 얻을 수 있다면 매우 가치 있을 것입니다. 어떤 경계가 가장 유용한 동작을 노출했습니까? 전송 실패(transport failure), 결과 수준의 실패(result-level failure), 중복 호출(duplicate invocation), 또는 부분 완료 후 복구(recovery after partial completion) 중 무엇입니까?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기