도입
모델 컨텍스트 프로토콜(Model Context Protocol, MCP)은 대규모 언어 모델(LLM) 애플리케이션과 외부 데이터 소스 및 도구 사이에 표준화된 브리지를 구축하는 것을 목표로 합니다. 이 글에서는 MCP의 핵심 개념, 생명주기, 주요 기능, 실용 도구를 심층적으로 분석하고, 최신 2025-03-26 프로토콜 수정 버전과 구체적인 JSON-RPC 요청/응답 예제를 함께 다루어 개발자를 위한 포괄적인 실전 가이드를 제공합니다.
MCP 핵심 구성요소
MCP는 서로 협업하는 여러 핵심 구성요소로 이루어집니다.
- 기본 프로토콜: 핵심 JSON-RPC 메시지 유형을 정의합니다.
- 생명주기 관리: 연결 초기화, 기능 협상, 세션 관리를 제어합니다.
- 서버 기능: 서버가 제공하는 리소스(Resources), 프롬프트(Prompts), 도구(Tools) 등의 기능입니다.
- 클라이언트 기능: 클라이언트가 제공하는 샘플링(Sampling), 루트 디렉터리(Roots) 등의 기능입니다.
- 실용 도구: 로깅(Logging), 자동 완성(Completion), 진행 상황 추적(Progress), 취소(Cancellation) 등 여러 영역에 걸친 기능입니다.
모든 구현은 기본 프로토콜과 생명주기 관리를 반드시 (MUST) 지원해야 합니다. 다른 구성요소는 애플리케이션 요구 사항에 따라 선택적으로 구현할 수 있습니다.
기본 프로토콜: JSON-RPC 메시지
MCP는 전적으로 JSON-RPC 2.0 명세를 따릅니다.
요청
작업을 시작할 때 사용합니다.
응답
요청에 대한 답신으로 결과나 오류를 담습니다.
응답에서는 result와 error 중 반드시 하나만 (MUST) 설정해야 하며, 둘을 동시에 설정해서는 안 됩니다 (MUST NOT).
알림
응답이 필요 없는 단방향 메시지입니다.
알림에는 id를 포함해서는 안 됩니다 (MUST NOT).
배치 처리
MCP 구현은 배치 요청이나 알림을 보낼 수 있습니다 (MAY). 다만 배치를 수신하는 것은 반드시 (MUST) 지원해야 합니다.
생명주기 관리
MCP 연결은 초기화 → 작업 → 종료라는 엄격한 생명주기를 따릅니다.
초기화 단계
클라이언트와 서버 간의 첫 상호작용으로, 프로토콜 버전을 협상하고 기능을 교환하는 단계입니다.
초기화 요청(클라이언트에서 전송)
참고: 초기화 요청은 배치에 포함할 수 없습니다 (MUST NOT).
초기화 응답(서버에서 전송)
버전 협상: 클라이언트는 지원하는 최신 버전을 전송합니다. 서버가 해당 버전을 지원하면 같은 버전을 반환하고, 지원하지 않으면 서버가 지원하는 최신 버전을 반환합니다. 클라이언트가 서버가 반환한 버전을 지원하지 않는다면 연결을 끊는 것이 권장됩니다 (SHOULD).
기능 협상: 양측 당사자는 capabilities 객체를 통해 지원 기능과 하위 기능(예: listChanged, subscribe)을 선언합니다. 이후 작업에서는 협상에 성공한 기능만 사용할 수 있습니다.
초기화 완료 알림(클라이언트에서 전송)
성공한 initialize 응답을 받은 뒤 클라이언트는 작업 단계로 진입할 준비가 되었음을 나타내기 위해 이 알림을 반드시 (MUST) 보내야 합니다.
initialize 응답을 받기 전까지 클라이언트는 ping을 제외한 요청을 보내면 안 됩니다. initialized 알림을 받기 전까지 서버는 ping과 logging을 제외한 요청을 보내면 안 됩니다.
작업 단계
양측 당사자는 협상된 기능과 프로토콜 버전에 따라 정상적으로 통신합니다.
종료 단계
일반적으로 클라이언트가 시작하며, 기본 전송 메커니즘(예: stdio 스트림 또는 HTTP 연결 종료)을 사용해 연결을 종료합니다. MCP에는 전용 종료 메시지가 없습니다.
서버 기능 상세
서버는 다음 핵심 기능을 노출할 수 있습니다.
1. 리소스(Resources)
서버가 컨텍스트 데이터(파일, 데이터베이스 스키마 등)를 공유할 수 있게 하며, 각 리소스는 고유한 URI로 식별됩니다.
기능: resources (subscribe, listChanged는 선택 사항)
리소스 목록(resources/list) (페이지네이션 지원)
리소스 읽기(resources/read)
리소스 변경 구독(resources/subscribe) (subscribe 기능 필요)
리소스 업데이트 알림(notifications/resources/updated) (서버가 구독자에게 전송)
클라이언트는 이 알림을 받으면 보통 resources/read를 다시 호출해 최신 내용을 가져옵니다.
리소스 목록 변경 알림(notifications/resources/list_changed) (listChanged 기능 필요)
클라이언트는 이 알림을 받으면 보통 resources/list를 다시 호출합니다.
리소스 템플릿: 서버는 resources/templates/list를 통해 매개변수가 포함된 URI 템플릿(RFC6570)을 노출할 수 있습니다.
일반적인 URI 스킴: https://, file://, git:// (구현에 따라 사용자 정의할 수 있음).
2. 도구(Tools)
언어 모델이 서버가 제공하는 외부 기능(API, 계산 등)을 호출할 수 있게 합니다.
기능: tools (listChanged는 선택 사항)
도구 목록(tools/list) (페이지네이션 지원)
참고: 클라이언트는 신뢰할 수 있는 서버에서 받은 경우가 아니라면 도구 어노테이션을 신뢰할 수 없는 것으로 반드시 (MUST) 처리해야 합니다.
도구 호출(tools/call)
도구 목록 변경 알림(notifications/tools/list_changed) (listChanged 기능 필요)
보안: 클라이언트는 민감한 작업 전에 사용자 확인을 요청하고, 데이터 유출을 막기 위해 도구 입력을 표시해야 합니다 (SHOULD).
3. 프롬프트(Prompts)
서버는 사용자가 명시적으로 선택해 LLM과 상호작용할 수 있도록 구조화된 메시지 템플릿을 제공합니다.
기능: prompts (listChanged는 선택 사항)
프롬프트 목록(prompts/list) (페이지네이션 지원)
프롬프트 가져오기(prompts/get)
프롬프트 목록 변경 알림(notifications/prompts/list_changed) (listChanged 기능 필요)
클라이언트 기능 상세
클라이언트는 다음 핵심 기능을 노출할 수 있습니다.
1. 루트 디렉터리(Roots)
클라이언트가 파일 시스템 접근 범위를 서버에 노출할 수 있게 합니다.
기능: roots (listChanged는 선택 사항)
루트 디렉터리 목록(roots/list) (서버가 요청)
루트 디렉터리 목록 변경 알림(notifications/roots/list_changed) (클라이언트가 전송하며 listChanged 기능 필요)
2. 샘플링(Sampling)
서버가 클라이언트에 LLM을 통한 콘텐츠 생성(텍스트, 이미지, 오디오)을 요청할 수 있게 합니다. 어떤 모델에 접근하고 어떤 모델을 선택할지는 클라이언트가 제어합니다.
기능: sampling
메시지 생성(sampling/createMessage) (서버가 요청)
보안: 클라이언트는 전송 전에 사용자가 프롬프트를 검토하고 편집할 수 있도록 사용자 승인 절차를 구현하는 것이 권장됩니다 (SHOULD).
실용 도구
MCP는 일련의 선택적 보조 기능을 제공합니다.
핑
연결이 살아 있는지 확인하는 데 사용합니다.
진행 상황(Progress)
오래 걸리는 작업의 진행 상황을 보고하는 데 사용합니다.
요청에 progressToken 포함: 송신자(예: 클라이언트)는 요청의 _meta에 고유한 progressToken을 포함합니다.
진행 알림(notifications/progress): 수신자(예: 서버)가 진행 상황 업데이트를 보냅니다.
로깅(Logging)
서버가 클라이언트에 구조화된 로그를 보낼 수 있게 합니다.
기능: logging
로그 수준 설정(logging/setLevel): 클라이언트는 서버가 전송해야 하는 최소 로그 수준(debug, info, notice, warning, error, critical, alert, emergency)을 설정할 수 있습니다.
로그 메시지 알림(notifications/message): 서버가 로그를 보냅니다.
취소(Cancellation)
한 당사자가 이전에 보냈으며 아직 진행 중인 요청의 취소를 요청할 수 있게 합니다.
취소 알림(notifications/cancelled): 송신자가 보냅니다.
수신자는 취소된 요청의 처리를 중지해야 하며 (SHOULD), 그 요청에 대한 응답을 보내지 않는 것이 권장됩니다 (SHOULD NOT). 송신자는 이후 수신할 수 있는 취소된 요청의 응답을 무시해야 합니다 (SHOULD).
자동 완성(Completion)
서버가 프롬프트 인수나 리소스 URI에 자동 완성 제안을 제공합니다.
기능: completions
자동 완성 요청(completion/complete)
페이지네이션(Pagination)
잠재적으로 많은 결과를 반환할 수 있는 목록 작업(resources/list, tools/list, prompts/list, resources/templates/list)에는 MCP가 커서 기반 페이지네이션을 사용합니다.
서버 응답: 결과에 nextCursor를 포함합니다. 값이 비어 있지 않으면 추가 페이지가 있음을 의미합니다.
클라이언트의 다음 페이지 요청: 받은 cursor를 요청의 params에 포함합니다.
클라이언트는 커서를 불투명 문자열로 반드시 (MUST) 처리해야 합니다.
오류 처리
MCP는 표준 JSON-RPC 오류 코드를 사용합니다.
- -32600 Invalid Request: 잘못된 JSON이거나 명세를 따르지 않습니다.
- -32601 Method not found: 메서드가 존재하지 않거나 사용할 수 없습니다.
- -32602 Invalid params: 메서드 인수가 잘못되었습니다.
- -32603 Internal error: 서버 내부 오류입니다.
- -32000 to -32099 Server error: 구현에 특정한 서버 오류입니다(예: 리소스를 찾을 수 없는 오류는
-32002).
보안과 신뢰
MCP 구현자는 보안 및 신뢰 관련 문제를 신중히 검토해야 합니다 (MUST).
- 사용자 동의와 제어: 모든 데이터 접근 및 작업에는 사용자의 명시적 동의가 필요합니다.
- 데이터 프라이버시: 동의 없이 사용자 데이터를 공유해서는 안 됩니다.
- 도구 안전성: 도구 호출은 코드 실행을 의미하므로 신중하게 처리하고 사용자 동의를 받아야 합니다.
- 샘플링 제어: 사용자가 샘플링 요청을 제어하고 결과를 검토할 수 있어야 합니다.
- 검증: 클라이언트와 서버 모두 입력과 출력을 검증해야 합니다.
- 권한: 적절한 접근 제어를 적용해야 합니다.
결语
모델 컨텍스트 프로토콜(MCP)은 표준화된 메시지 형식, 생명주기 관리, 풍부한 기능 세트를 바탕으로 강력하고 안전하며 상호 운용 가능한 AI 애플리케이션을 구축할 수 있는 견고한 기반을 제공합니다. 핵심 개념과 프로토콜 세부 사항을 이해하고 구체적인 요청/응답 예제를 함께 살펴보면, 개발자는 MCP를 활용해 LLM을 외부 세계와 효과적으로 연결할 수 있습니다.
참고 자료: