Skip to content

디버깅 (Debugging)

MCP(Model Context Protocol) 연동을 디버깅하는 종합적인 가이드입니다. MCP 서버를 만들 때든, 서버를 애플리케이션에 통합할 때든 실제로 문제가 생기면 어디서부터 손을 대야 할지 막막하죠. 이 문서는 MCP 생태계에서 쓸 수 있는 디버깅 도구와 접근 방식을 정리한 내용입니다.

디버깅 도구 개요

MCP는 여러 수준에서 디버깅할 수 있도록 몇 가지 도구를 제공합니다.

  1. MCP Inspector: 대화형이고 transport에 구애받지 않는 테스트 UI예요. stdio나 Streamable HTTP 서버에 연결해서 도구(tools), 프롬프트(prompts), 리소스(resources)를 호출해 보고, 알림(notification) 스트림도 지켜볼 수 있어요. 무엇보다 이걸 제일 먼저 써 보세요.
  2. 서버 로깅: 구조화된 로그를 stderr(stdio transport의 경우)나 OpenTelemetry(모든 transport)로 남길 수 있어요. 프로토콜을 통한 로깅(notifications/message)은 프로토콜 버전 2026-07-28부터 deprecated 처리됐어요.
  3. 클라이언트 개발자 도구: 대부분의 MCP 클라이언트는 로그와 연결 상태를 노출해 줍니다. 아래에서 Claude Desktop의 디버깅을 예시로 보여 드릴게요. 다른 클라이언트를 쓴다면 해당 클라이언트의 문서를 참고하세요.

로깅 구현하기

서버 측 로깅

로컬 stdio transport를 쓰는 서버를 만들 때는, stderr(표준 에러)로 남긴 모든 메시지가 호스트 애플리케이션에 자동으로 잡힙니다. 로컬 MCP 서버는 stdout(표준 출력)으로 로그를 남기면 안 돼요. 프로토콜 동작을 방해하거든요.

Streamable HTTP transport를 쓰는 서버라면 이야기가 달라요. 이 경우 stderr가 클라이언트에 잡히지 않습니다. 자체 서버 측 로그 집계(aggregation)나 OpenTelemetry로 로그를 다루고, 요청과 SSE 스트림을 확인하려면 표준 HTTP 도구(curl, 브라우저 DevTools의 Network 패널)를 쓰세요.

아래 notifications/message 메커니즘은 프로토콜 버전 2026-07-28부터 deprecated예요. 이후에도 deprecation 기간 동안에는 계속 사용할 수 있습니다.

어느 transport든, 서버가 실행되는 동안 무엇을 하고 있는지 기록해 두는 습관을 들이세요.

import logging

from mcp.server import MCPServer

logger = logging.getLogger(__name__)

mcp = MCPServer("reports")

@mcp.tool()
async def fetch_report(report_id: str) -> str:
    """Fetch a report by id."""
    logger.info("Fetching report %s", report_id)
    return f"Report {report_id} is ready."
await server.sendLoggingMessage({
  level: "info",
  data: "Server started successfully",
});

MCP는 RFC 5424의 심각도 수준 8단계(debug부터 emergency까지)를 정의합니다. 클라이언트는 요청의 _meta에 있는 io.modelcontextprotocol/logLevel 필드를 설정해 요청별로 로그 메시지를 받도록 옵트인(opt in)해요. 이 필드를 생략한 요청에 대해서는 서버가 notifications/message를 보내면 안 됩니다.

로그를 남기면 좋은 이벤트:

  • 시작 단계(Startup steps)
  • 리소스 접근(Resource access)
  • 도구 실행(Tool execution)
  • 오류 조건(Error conditions)
  • 성능 지표(Performance metrics)

자주 겪는 문제

아래 예시는 Claude Desktop의 claude_desktop_config.json을 기준으로 하지만, 같은 원칙이 stdio 기반 MCP 클라이언트라면 어디든 적용돼요.

작업 디렉터리(Working directory)

MCP 클라이언트가 stdio 서버를 띄울 때:

  • 클라이언트의 config로 띄운 서버의 작업 디렉터리는 정의되지 않을 수 있어요(예: macOS에서 /). 클라이언트가 어디에서 시작됐는지에 따라 달라지거든요.
  • 안정적으로 동작하게 하려면config와 .env 파일에서 항상 절대 경로를 쓰세요.
  • 명령줄에서 서버를 직접 테스트할 때는, 명령을 실행한 위치가 작업 디렉터리가 됩니다.

예를 들어 claude_desktop_config.json에서는 이렇게 씁니다:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/data"
      ]
    }
  }
}

./data 같은 상대 경로 대신 말이죠.

환경 변수(Environment variables)

stdio로 띄운 MCP 서버는 제한된 환경 변수만 자동으로 상속합니다(정확한 집합은 플랫폼에 따라 달라요). 기본 변수를 덮어쓰거나 자체 변수를 제공하려면 claude_desktop_config.jsonenv 키를 지정하면 됩니다:

{
  "mcpServers": {
    "myserver": {
      "command": "mcp-server-myapp",
      "env": {
        "MYAPP_API_KEY": "some_key"
      }
    }
  }
}

서버 시작(Server startup)

자주 겪는 시작 문제들:

  • 경로 문제(Path Issues)
  • 서버 실행 파일 경로가 잘못됨
  • 필요한 파일이 없음
  • 권한 문제
  • command에는 절대 경로를 쓰세요.
  • 설정 오류(Configuration Errors)
  • JSON 문법 오류
  • 필수 필드 누락
  • 타입 불일치
  • 환경 문제(Environment Problems)
  • 환경 변수 누락
  • 변수 값이 잘못됨
  • 권한 제약

연결 문제(Connection problems)

서버가 연결되지 않을 때:

  • 클라이언트 로그를 확인하세요.
  • 서버 프로세스가 실행 중인지 확인하세요.
  • Inspector로 단독 테스트를 해 보세요.
  • 프로토콜 호환성을 확인하세요. server/discover를 호출하면 서버가 지원하는 프로토콜 버전을 알 수 있어요. UnsupportedProtocolVersionError(-32022)가 나면 그 data 필드에 서버가 지원하는 버전 목록이 들어 있습니다.
  • 요청별 _meta 필드를 확인하세요. 모든 요청은 io.modelcontextprotocol/protocolVersionio.modelcontextprotocol/clientCapabilities를 반드시 담아야 하고, 클라이언트는 io.modelcontextprotocol/clientInfo도 포함하는 게 좋아요. 필수 필드가 빠진 요청은 오류 -32602(Invalid params)로 거부되는데, 이 코드는 다른 여러 잘못된 입력에도 같은 코드가 사용됩니다. 요청의 clientCapabilities가 선언하지 않은 기능(elicitation 같은)이 서버에 필요한 경우, MissingRequiredClientCapabilityError(-32021)가 누락된 기능을 명시해서 반환돼요. 요청의 _metaserver/discover 응답을 들여다보면 양쪽이 기대한 대로 선언했는지 확인할 수 있습니다.

Claude Desktop에서 디버깅

Claude Desktop은 여러 MCP 클라이언트 중 하나입니다. macOS와 Windows에서 사용할 수 있어요.

서버 상태 확인(Checking server status)

채팅 입력란에 있는 "Add files, connectors, and more" 더하기 아이콘을 클릭한 뒤 Connectors 메뉴에 마우스를 올리면 연결된 서버와 사용 가능한 도구를 볼 수 있어요.

로그 보기(Viewing logs)

로그 파일은 다음 위치에 기록됩니다:

  • macOS: ~/Library/Logs/Claude
  • Windows: %APPDATA%\Claude\logs
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log

로그에는 다음 내용이 담깁니다:

  • 서버 연결 이벤트
  • 설정 문제
  • 런타임 오류
  • 메시지 교환

Chrome DevTools 사용하기

Claude Desktop 안에서 Chrome의 개발자 도구를 열면 클라이언트 측 오류를 들여다볼 수 있어요. allowDevToolstrue로 설정한 developer_settings.json 파일을 만드세요:

echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json

그다음 DevTools를 여세요. macOS는 Command-Option-I, Windows는 Ctrl+Alt+I예요. 참고로 DevTools 창이 두 개 열립니다:

  • 메인 콘텐츠 창
  • 앱 타이틀 바 창

Console 패널에서 클라이언트 측 오류를 확인하고, Network 패널에서는 다음을 살펴보세요:

  • 메시지 페이로드
  • 연결 타이밍

디버깅 워크플로

개발 사이클

  • 초기 개발(Initial Development)
  • Inspector로 기본 테스트
  • 핵심 기능 구현
  • 로깅 지점 추가
  • 통합 테스트(Integration Testing)
  • 대상 MCP 클라이언트에서 테스트
  • 로그 모니터링
  • 오류 처리 확인

변경 사항 테스트(Testing changes)

변경 사항을 효율적으로 테스트하려면:

  • 설정 변경: MCP 클라이언트를 재시작하세요.
  • 서버 코드 변경: 클라이언트를 재시작하세요(Claude Desktop은 창을 닫는 것만으로는 부족하고 완전히 종료 후 다시 열어야 해요).
  • 빠른 반복: 개발 중에는 Inspector를 활용하세요.

모범 사례

로깅 전략

  • 구조화된 로깅(Structured Logging)
  • 일관된 형식 사용
  • 컨텍스트 포함
  • 타임스탬프 추가
  • 요청 ID 추적
  • 오류 처리(Error Handling)
  • 스택 트레이스 로깅
  • 오류 컨텍스트 포함
  • 오류 패턴 추적
  • 복구 상태 모니터링
  • 성능 추적(Performance Tracking)
  • 작업 시간 로깅
  • 리소스 사용량 모니터링
  • 메시지 크기 추적
  • 지연 시간 측정

보안 고려 사항

디버깅할 때:

  • 민감한 데이터(Sensitive Data)
  • 로그 정리(sanitize)
  • 자격 증명 보호
  • 개인 정보 마스킹
  • 접근 제어(Access Control)
  • 권한 확인
  • 인증 확인
  • 접근 패턴 모니터링

MCP 공격 벡터와 완화 방법에 대한 전체 내용은 보안 모범 사례(Security Best Practices)를 참고하세요.

도움 받기(Getting help)

문제가 생겼을 때:

  • 첫 단계(First Steps)
  • 서버 로그 확인
  • Inspector로 테스트
  • 설정 검토
  • 환경 확인
  • 지원 채널(Support Channels)
  • GitHub issues
  • GitHub discussions
  • 제공 정보(Providing Information)
  • 로그 발췌
  • 설정 파일
  • 재현 절차
  • 환경 세부 사항

다음 단계

  • MCP Inspector: MCP Inspector 사용법 배우기
  • MCP 서버 만들기: 처음부터 서버를 만드는 과정 따라 해 보기
  • 로컬 서버 연결: 전체 claude_desktop_config.json 참조와 문제 해결