DEV Community

Cover image for MCP 서버 테스트 플레이북: Apidog 활용 수동 및 자동화
Rihpig
Rihpig

Posted on • Originally published at apidog.com

MCP 서버 테스트 플레이북: Apidog 활용 수동 및 자동화

이번 주 초, “Ableton Live MCP” Show HN 게시물이 118점과 78개의 댓글을 받았습니다. 이제 익숙한 패턴입니다. 누군가 예상치 못한 도구를 위한 MCP(Model Context Protocol) 서버를 만들고, Claude Desktop 사용자가 이를 사용하며, 곧바로 “X용 MCP 서버도 만들 수 있나요?”라는 질문이 이어집니다. MCP는 1년도 채 되지 않아 Anthropic 중심의 실험에서 에이전트 통합을 위한 기본 계층으로 빠르게 확산되었습니다.

지금 Apidog 사용해 보기

하지만 MCP 서버가 늘어나는 속도에 비해 테스트 방식은 아직 성숙하지 않았습니다. stdio로 JSON-RPC를 직접 입력하며 디버깅하는 방식은 hello-world 수준에서는 충분하지만, 도구 12개, 프롬프트 3개, 불안정한 업스트림 API가 붙는 순간 유지보수가 어렵습니다. 이 글은 MCP 서버를 수동으로 검증한 뒤 Apidog로 테스트를 자동화하는 실전 흐름을 정리합니다. 목표는 MCP 서버도 일반 API처럼 계약, 목(mock), 회귀 테스트 스위트를 갖춘 상태로 배포하는 것입니다.

에이전트 문서화 관점에서 접근하고 있다면 agents.md 가이드도 함께 참고하세요. 해당 가이드의 규칙은 MCP 서버 계약을 팀에 전달할 때 유용합니다.

요약: TL;DR

  • MCP는 Anthropic의 Model Context Protocol입니다. stdio 또는 HTTP 위에서 JSON-RPC 2.0으로 동작하며 tools, resources, prompts를 노출합니다.
  • MCP 서버 테스트는 initialize, tools/list, tools/call, resources/read, prompts/get 응답이 계약을 지키는지 검증하는 일입니다.
  • 먼저 수동으로 시작하세요. stdio 또는 MCP Inspector로 서버를 실행하고, 응답 형태를 확인한 뒤 클라이언트를 붙이기 전에 shape 버그를 제거합니다.
  • 이후 자동화하세요. Apidog에 JSON-RPC 요청을 저장하고, 응답 shape와 콘텐츠에 대한 assertion을 추가한 뒤 CI에서 실행합니다.
  • MCP 서버가 호출하는 외부 API는 Apidog의 목(mock) 서버로 대체해 테스트를 결정론적으로 만듭니다.
  • Apidog 다운로드를 통해 요청 컬렉션, 목 서버, CI 실행을 한 곳에서 관리할 수 있습니다.

MCP를 2분 안에 이해하기

Model Context Protocol 사양은 JSON-RPC 2.0 기반의 작은 와이어 프로토콜을 정의합니다. Claude Desktop, Cursor, 자체 에이전트 같은 클라이언트는 MCP 서버를 시작하고 initialize 핸드셰이크를 수행한 뒤 필요한 호출을 보냅니다.

테스트에서 가장 많이 다루는 호출은 다음입니다.

  • initialize: 프로토콜 버전 협상 및 기능(capabilities) 공개
  • tools/list: 서버가 제공하는 도구 목록과 인수 JSON Schema 반환
  • tools/call: 도구 이름과 인수를 전달해 도구 실행
  • resources/list, resources/read: URI로 접근 가능한 리소스 목록 및 읽기
  • prompts/list, prompts/get: 클라이언트가 렌더링할 수 있는 프롬프트 템플릿 제공

전송 방식은 보통 두 가지입니다.

  • stdio: stdin/stdout에서 newline-delimited JSON-RPC 프레임 사용
  • HTTP: 일반적으로 POST /와 SSE를 사용해 스트리밍 처리

대부분의 로컬 MCP 서버는 stdio를 사용하고, 원격 서버는 HTTP를 사용합니다.

테스트가 중요한 이유는 단순합니다. tools/list 응답의 shape가 깨지면 Claude Desktop, Cursor, MCP 지원 IDE가 모두 영향을 받습니다. MCP 서버는 작아 보여도 실제로는 여러 클라이언트가 의존하는 API 계약입니다.

무엇을 테스트해야 하나

MCP 서버 테스트 스위트는 최소한 다음 여섯 영역을 포함해야 합니다.

1. 프로토콜 준수

initialize 응답이 올바른 protocolVersion을 반환하는지 확인합니다. 서버가 실제로 지원하는 capability만 광고하는지도 검증해야 합니다.

2. 스키마 정확성

tools/list의 각 도구가 유효한 inputSchema를 제공해야 합니다.

확인할 항목:

  • name이 존재하는가
  • description이 비어 있지 않은가
  • inputSchema가 유효한 JSON Schema인가
  • 필수 인수가 required에 포함되어 있는가

빈 description은 Claude의 도구 선택 품질을 떨어뜨릴 수 있습니다.

3. 도구 동작

tools/call이 올바른 콘텐츠 블록을 반환하는지 확인합니다.

예:

{
  "content": [
    {
      "type": "text",
      "text": "Weather in Tokyo: 22°C"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

도구 실행 실패는 JSON-RPC 오류로 던지기보다 isError: true를 포함한 정상 결과로 반환해야 합니다.

{
  "isError": true,
  "content": [
    {
      "type": "text",
      "text": "Missing required argument: city"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

4. 리소스 접근

resources/list에서 반환한 URI가 resources/read로 실제 읽히는지 확인합니다. 페이지네이션이 있다면 첫 페이지만이 아니라 다음 페이지도 검증합니다.

5. 프롬프트 렌더링

prompts/get이 잘 구성된 messages 배열을 반환하는지 확인합니다. 인수 치환이 예상 위치에 들어가는지도 테스트해야 합니다.

6. 실패 모드

다음 상황을 반드시 포함하세요.

  • 업스트림 API 장애
  • 필수 인수 누락
  • 잘못된 타입 전달
  • 타임아웃
  • 빈 응답
  • 동시 tools/call

이 문제들은 로컬 happy path에서는 잘 드러나지 않고, 실제 사용 중에 발견되는 경우가 많습니다.

stdio로 수동 테스트하기

가장 단순한 테스트 환경은 다음 세 가지입니다.

  • 터미널
  • MCP 서버 실행 파일
  • MCP Inspector 또는 직접 작성한 JSON-RPC 요청

아직 서버가 없다면 Python 또는 TypeScript용 공식 MCP SDK 퀵스타트로 스캐폴드를 만드세요. 날씨 예제처럼 도구 1~2개만 있어도 테스트 흐름을 충분히 연습할 수 있습니다.

1. MCP Inspector로 서버 실행

npx @modelcontextprotocol/inspector node your-server.js
Enter fullscreen mode Exit fullscreen mode

Inspector는 MCP 서버와 통신하는 로컬 웹 UI를 띄우고 요청/응답을 보여줍니다. 먼저 여기서 다음을 확인하세요.

  • 서버가 정상적으로 시작되는가
  • initialize가 성공하는가
  • capability가 예상대로 표시되는가
  • tools/list가 도구 목록을 반환하는가
  • 각 도구를 호출할 수 있는가

2. 원시 stdio 요청 실행

Inspector에서 기본 동작을 확인했다면, 저장 가능한 JSON-RPC 프레임을 직접 실행합니다.

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-04-01","capabilities":{}}}' | node your-server.js
Enter fullscreen mode Exit fullscreen mode

stdout으로 JSON-RPC 응답이 출력됩니다. 이 요청과 응답을 저장해 두세요. 이후 다음 호출도 같은 방식으로 캡처합니다.

  • tools/list
  • tools/call
  • resources/list
  • resources/read
  • prompts/list
  • prompts/get

이 과정을 마치면 서버의 와이어 레벨 계약을 나타내는 6~12개의 기준 요청/응답 쌍이 생깁니다.

3. 콘텐츠 블록 확인

도구 결과는 보통 다음 형태 중 하나입니다.

{
  "content": [
    {
      "type": "text",
      "text": "..."
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

또는 이미지 결과일 수 있습니다.

{
  "content": [
    {
      "type": "image",
      "data": "...",
      "mimeType": "image/png"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

한 응답에서 여러 타입을 섞는 것도 가능하지만, 클라이언트별 렌더링 차이가 있을 수 있으므로 테스트에 포함해야 합니다.

4. 오류 처리 방식 확인

MCP에서 도구 실행 실패는 프로토콜 실패와 구분해야 합니다.

잘못된 방식:

{
  "jsonrpc": "2.0",
  "id": 42,
  "error": {
    "code": -32603,
    "message": "Tool failed"
  }
}
Enter fullscreen mode Exit fullscreen mode

도구 내부 실패는 보통 다음처럼 반환하는 것이 안전합니다.

{
  "jsonrpc": "2.0",
  "id": 42,
  "result": {
    "isError": true,
    "content": [
      {
        "type": "text",
        "text": "Upstream API timeout"
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

JSON-RPC 오류는 프로토콜 수준 실패를 의미합니다. 일부 클라이언트는 프로토콜 오류가 발생하면 연결을 끊을 수 있습니다.

수동 테스트를 Apidog 자동화로 전환하기

수동 테스트는 초기 디버깅에 좋습니다. 하지만 변경할 때마다 10개 이상의 JSON-RPC 요청을 직접 실행하는 방식은 오래가지 못합니다.

자동화 흐름은 다음과 같습니다.

  1. 수동 테스트에서 확보한 JSON-RPC 요청을 Apidog에 저장합니다.
  2. 각 요청에 assertion을 추가합니다.
  3. 업스트림 API를 목(mock)으로 대체합니다.
  4. CI에서 전체 스위트를 실행합니다.

1. MCP 서버용 Apidog 프로젝트 만들기

Apidog에서 새 프로젝트를 생성합니다. 기본 URL은 MCP 서버의 HTTP 엔드포인트로 설정합니다.

stdio 서버만 있다면 테스트용 HTTP 래퍼를 하나 둡니다.

구성 예:

Apidog request
  -> HTTP wrapper
    -> stdio MCP server
Enter fullscreen mode Exit fullscreen mode

HTTP 래퍼는 JSON-RPC 요청을 HTTP로 받아 stdio MCP 서버에 전달하고, 응답을 다시 HTTP 응답으로 반환합니다. 공식 Inspector가 비슷한 역할을 하며, 간단한 Node.js 스크립트로도 구현할 수 있습니다.

비-HTTP 백엔드를 테스트할 때도 같은 패턴을 사용할 수 있습니다. 관련 내용은 2026년 Postman 없이 API 테스트하기에서 다룹니다.

2. 표준 JSON-RPC 요청 저장하기

Apidog에 다음 요청을 각각 저장합니다.

  • initialize
  • tools/list
  • tools/call
  • resources/list
  • resources/read
  • prompts/list
  • prompts/get

tools/call 요청 예시는 다음과 같습니다.

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "city": "Tokyo"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

같은 도구라도 케이스별로 요청을 분리하세요.

예:

  • 정상 입력
  • 필수 인수 누락
  • 잘못된 타입
  • 업스트림 API 오류
  • 빈 결과

3. Assertion 추가하기

자동화의 핵심은 요청 전송이 아니라 응답 검증입니다.

tools/list에는 최소한 다음 assertion을 추가합니다.

  • $.result.tools가 존재한다
  • $.result.tools가 배열이다
  • $.result.tools.length가 0보다 크다
  • 각 도구에 name이 있다
  • 각 도구에 description이 있다
  • 각 도구에 inputSchema가 있다
  • inputSchema가 유효한 JSON Schema다

정상 tools/call에는 다음을 검증합니다.

  • $.result.isErrorfalse이거나 존재하지 않는다
  • $.result.content가 배열이다
  • $.result.content[0].type이 예상 타입이다
  • 텍스트 또는 리소스 값이 예상 패턴과 일치한다

잘못된 입력에 대한 tools/call에는 다음을 검증합니다.

  • $.result.isErrortrue
  • $.result.content[0].text가 오류 내용을 포함한다
  • 가능하다면 안정적인 오류 코드 또는 정규식으로 검증한다

정확한 오류 문자열 전체에 의존하지 마세요. 메시지는 바뀌기 쉽습니다.

4. 업스트림 API 목(mock) 처리하기

대부분의 MCP 서버는 외부 API를 감쌉니다.

예:

  • 날씨 API
  • GitHub
  • Linear
  • Notion
  • 내부 데이터베이스
  • 사내 사고 관리 API

CI가 매번 실제 API를 호출하면 다음 문제가 생깁니다.

  • 호출 비용 증가
  • rate limit
  • 네트워크 불안정
  • 외부 장애로 인한 flaky test
  • 테스트 데이터 변동

Apidog의 목 서버를 사용하면 각 업스트림 엔드포인트를 고정된 응답으로 대체할 수 있습니다.

테스트 환경에서는 MCP 서버 설정을 목 URL로 지정합니다.

UPSTREAM_API_BASE_URL=https://mock.example.apidog.io
Enter fullscreen mode Exit fullscreen mode

프로덕션에서는 실제 API URL을 사용합니다.

UPSTREAM_API_BASE_URL=https://api.example.com
Enter fullscreen mode Exit fullscreen mode

이 방식은 계약 우선 API 개발에서도 다루는 패턴입니다.

5. CI에서 테스트 스위트 실행하기

Apidog 프로젝트는 CLI runner로 실행할 수 있습니다. apidog run은 저장된 요청을 실행하고 assertion을 평가한 뒤 실패 시 non-zero exit code로 종료됩니다.

GitHub Actions 예시:

name: MCP server tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 22

      - run: npm ci

      - name: Start MCP HTTP wrapper
        run: node test/wrapper.js &

      - name: Run Apidog suite
        run: npx apidog run --project-id $APIDOG_PROJECT --env ci
        env:
          APIDOG_PROJECT: ${{ secrets.APIDOG_PROJECT }}
          APIDOG_TOKEN: ${{ secrets.APIDOG_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

이제 모든 push와 pull request에서 MCP 계약을 검증할 수 있습니다. 특정 도구의 인수 스키마가 깨지면 배포 전에 실패합니다.

좋은 MCP 테스트 커버리지의 기준

Apidog에서 MCP 서버 테스트 계획을 구성할 때는 보통 다음 정도를 기준으로 잡습니다.

  • capability assertion이 포함된 initialize 요청 1개
  • shape 및 JSON Schema assertion이 포함된 tools/list 요청 1개
  • 각 도구별 tools/call 요청 2~4개
    • 정상 경로
    • 필수 인수 누락
    • 잘못된 타입
    • 업스트림 오류
  • 리소스 그룹별 resources/list 1개와 resources/read 1개
  • 프롬프트 템플릿별 prompts/list 1개와 prompts/get 1개
  • HTTP MCP 서버라면 SSE 스트리밍 응답 테스트
  • 공유 상태가 있다면 동시성 테스트

예를 들어 도구 10개, 리소스 3개, 프롬프트 4개가 있는 서버라면 전체 스위트는 대략 50~70개 요청이 됩니다. 목 서버가 준비되어 있으면 로컬에서도 빠르게 반복 실행할 수 있습니다.

MCP 서버 테스트에서 자주 하는 실수

initialize를 건너뛰는 것

일부 서버는 initialize 과정에서 도구 레지스트리를 지연 생성합니다. 이 경우 initialize 없이 tools/list를 호출하면 실패할 수 있습니다.

항상 다음 순서를 기본으로 두세요.

initialize -> tools/list -> tools/call
Enter fullscreen mode Exit fullscreen mode

오류 문자열 전체에 assertion을 거는 것

오류 메시지는 쉽게 바뀝니다. 다음처럼 전체 문자열에 의존하지 마세요.

"City is required and must be a valid string"
Enter fullscreen mode Exit fullscreen mode

대신 다음을 검증하세요.

  • isError: true
  • 안정적인 오류 코드
  • 핵심 단어를 포함하는 정규식

목(mock)이 실제 API와 달라지는 것

목 응답이 실제 API와 다르면 테스트는 통과하지만 통합은 깨질 수 있습니다. 릴리스 주기마다 실제 응답을 기반으로 목 fixture를 갱신하세요.

스트리밍을 테스트하지 않는 것

HTTP MCP 서버는 SSE로 도구 결과를 스트리밍할 수 있습니다. 테스트 runner에서 SSE를 활성화하고, 최종 조립된 스트림에 대해 assertion을 걸어야 합니다.

동시성 테스트를 빼는 것

에이전트 루프에서는 여러 tools/call이 동시에 발생할 수 있습니다. 서버가 공유 상태를 잠금 없이 사용한다면 단일 요청 테스트는 통과해도 프로덕션에서 깨질 수 있습니다.

프로토콜 오류와 도구 오류를 혼동하는 것

도구 내부 실패는 isError: true 결과로 반환하고, JSON-RPC 오류는 프로토콜 수준 실패에만 사용하세요. 이 구분은 MCP 클라이언트 안정성에 중요합니다. 비슷한 계약 버그는 API 플랫폼 계약 우선 개발에서도 다룹니다.

실제 사용 사례

사내 사고 관리 API용 MCP 서버를 만든 한 팀은 Apidog에서 tools/list shape assertion을 추가한 뒤 일주일 동안 세 가지 회귀를 발견했습니다. 테스트가 없었다면 잘못된 도구 스키마가 Claude Desktop을 사용하는 모든 엔지니어에게 동시에 배포될 수 있었습니다.

Notion용 오픈소스 MCP 서버를 운영하는 개인 개발자는 CI에서 Notion API rate limit에 걸리지 않도록 Apidog 목 서버를 사용합니다. 테스트 스위트는 모든 PR에서 실행되며, 목 fixture를 저장소에 캐싱해 기여자가 실제 API 접근 권한 없이도 개발할 수 있게 합니다.

14개의 내부 MCP 서버를 운영하는 플랫폼 팀은 모든 서버 계약을 공유 Apidog 워크스페이스에 저장했습니다. 새 서버는 기본 테스트 스위트를 상속받고, 리뷰어는 병합 전에 스키마 차이를 비교할 수 있습니다. 이 팀은 이름이 변경된 인수가 배포되는 문제를 tools/list shape assertion으로 사전에 발견했습니다.

내부 observability 플랫폼용 MCP 서버를 구축한 팀은 Apidog의 환경 전환 기능을 사용해 staging과 production에 같은 스위트를 실행합니다. 각 환경은 다른 목 fixture를 가리키지만, assertion은 동일하게 유지합니다.

결론

MCP는 빠르게 주류가 되었지만 테스트 방식은 아직 임시적이고 수동적인 경우가 많습니다. MCP 서버도 API입니다. 따라서 REST API와 같은 수준으로 계약을 정의하고, 목을 만들고, CI에서 회귀 테스트를 실행해야 합니다.

핵심 정리:

  • MCP 서버는 JSON-RPC API입니다. API 계약으로 다루세요.
  • MCP Inspector로 수동 검증을 시작하고, 표준 요청을 캡처하세요.
  • Apidog에서 JSON-RPC 요청, assertion, 목 서버, CI 실행을 관리하세요.
  • 프로토콜 준수, 스키마 정확성, 도구 동작, 리소스 접근, 프롬프트 렌더링, 실패 모드를 모두 테스트하세요.
  • 업스트림 API는 목(mock)으로 대체해 테스트를 빠르고 결정론적으로 만드세요.

다음 단계는 간단합니다. Apidog를 열고 프로젝트를 만든 뒤, 수동으로 캡처한 initializetools/list 요청을 붙여넣으세요. 그런 다음 JSONPath assertion을 추가하고 스위트를 실행하세요. 한 시간 안에 MCP 서버 계약이 배포 가능한 수준인지 확인할 수 있습니다.

자주 묻는 질문

MCP란 무엇인가요?

MCP, 즉 Model Context Protocol은 Claude Desktop 같은 AI 클라이언트가 외부 도구, 리소스, 프롬프트를 호출하는 방식을 정의한 Anthropic의 공개 사양입니다. stdio 또는 스트림 가능한 HTTP 위에서 JSON-RPC 2.0으로 동작합니다. 전체 MCP 사양modelcontextprotocol.io에 게시되어 있습니다.

HTTP 래퍼 없이 MCP 서버를 테스트할 수 있나요?

네. 공식 MCP Inspector는 stdio를 직접 사용하며 수동 테스트용 UI를 제공합니다. 다만 Apidog로 자동화하려면 CI에서 stdio 서버를 얇은 HTTP 래퍼 뒤에 두는 방식이 실용적입니다. 프로덕션 트래픽은 계속 stdio를 사용할 수 있습니다.

MCP 서버가 호출하는 업스트림 API는 어떻게 목(mock) 처리하나요?

각 업스트림 엔드포인트를 Apidog 프로젝트의 목 서버에 정의하고, 테스트 환경에서는 MCP 서버가 해당 목 URL을 바라보게 설정합니다. 런타임에서는 프로덕션 URL로 전환하면 됩니다. 같은 패턴은 QA 엔지니어를 위한 API 테스트 도구에서도 설명합니다.

도구 결과 스트리밍은 어떻게 테스트하나요?

HTTP MCP 서버는 SSE(Server-Sent Events)를 통해 결과를 스트리밍할 수 있습니다. Apidog의 저장된 요청에서 SSE를 활성화하고, 최종 조립된 스트림 또는 이벤트 단위 응답에 대해 assertion을 추가하세요.

프로토콜 버전도 테스트해야 하나요?

네. initialize 응답의 protocolVersion을 고정하고 assertion을 추가하세요. 버전 불일치는 클라이언트와 서버 간 조용한 비호환성을 만들 수 있습니다.

실제 Claude Desktop으로도 테스트해야 하나요?

네. 릴리스 전 최소 한 번은 실제 Claude Desktop으로 smoke test를 수행하는 것이 좋습니다. 하지만 회귀 테스트 루프를 Claude Desktop에 의존하지는 마세요. 느리고 수동적이며 결정론적이지 않습니다. 회귀 테스트는 Apidog로 자동화하고, Claude Desktop은 최종 확인 용도로 사용하세요.

실제 MCP 서버 예시는 어디에서 볼 수 있나요?

공식 MCP 서버 저장소에 파일 시스템, GitHub, Slack, Postgres 등을 위한 참조 구현이 있습니다. 도구 정의와 inputSchema를 읽어보면 좋은 MCP 응답 형태를 빠르게 파악할 수 있습니다.

Top comments (0)