MCP 클라이언트 이해하기
MCP 클라이언트는 특정 MCP 서버와 통신하기 위해 호스트 애플리케이션이 생성합니다. Claude.ai나 IDE 같은 호스트 애플리케이션은 전체 사용자 경험을 관리하고 여러 클라이언트를 조율합니다. 각 클라이언트는 서버 하나와의 직접 통신 하나를 담당합니다.
이 차이를 이해하는 것이 중요합니다. _호스트_는 사용자가 상호작용하는 애플리케이션이고, _클라이언트_는 서버 연결을 가능하게 하는 프로토콜 수준의 구성 요소입니다.
핵심 클라이언트 기능
클라이언트는 서버가 제공하는 컨텍스트를 사용하는 것 외에도 서버에 여러 기능을 제공할 수 있습니다. 이러한 클라이언트 기능을 통해 서버 작성자는 더 풍부한 상호작용을 만들 수 있습니다.
| 기능 | 설명 | 예시 |
|---|---|---|
| 정보 요청 | 정보 요청(elicitation)을 사용하면 서버가 상호작용 도중 사용자에게 특정 정보를 요청할 수 있으며, 필요할 때 정보를 수집하는 구조화된 방법을 제공합니다. | 여행 예약 서버가 예약을 마치기 위해 항공기 좌석, 객실 유형, 연락처 등의 선호 정보를 요청할 수 있습니다. |
| 루트 | 루트(roots)를 사용하면 클라이언트가 서버가 집중할 디렉터리를 지정하여 조정 메커니즘을 통해 의도한 범위를 전달할 수 있습니다. 루트는 프로토콜 버전 2026-07-28부터 지원 중단 예정입니다. | 여행 예약 서버에 사용자의 캘린더를 읽을 수 있는 특정 디렉터리 접근 권한을 줄 수 있습니다. |
| 샘플링 | 샘플링을 사용하면 서버가 클라이언트를 통해 LLM 완성을 요청하여 에이전트형 워크플로를 구현할 수 있습니다. 이 방식에서는 사용자 권한과 보안 조치를 클라이언트가 완전히 통제합니다. 샘플링은 프로토콜 버전 2026-07-28부터 지원 중단 예정입니다. | 여행 예약 서버가 항공편 목록을 LLM에 보내 사용자에게 가장 알맞은 항공편을 고르도록 요청할 수 있습니다. |
정보 요청
정보 요청을 사용하면 서버가 상호작용 도중 사용자에게 특정 정보를 요청할 수 있어 더 동적이고 반응성 높은 워크플로를 만들 수 있습니다.
개요
정보 요청은 서버가 필요할 때 필수 정보를 수집하는 구조화된 방법을 제공합니다. 모든 정보를 처음부터 요구하거나 데이터가 없을 때 실패하는 대신, 서버는 작업을 일시 중지하고 사용자에게 특정 입력을 요청할 수 있습니다. 서버가 경직된 패턴을 따르지 않고 사용자의 필요에 맞추는 더 유연한 상호작용이 가능해집니다.
정보 요청은 두 가지 모드를 지원합니다.
- 폼 모드: 서버가 클라이언트에 사용자로부터 구조화된 데이터를 수집하도록 요청합니다. 요청에는 클라이언트가 입력 폼을 만들고 응답을 검증하는 데 사용하는 스키마가 포함됩니다.
- URL 모드: 서버가 사용자가 열 URL을 제공합니다. 상호작용은 대역 외(out-of-band)에서 이루어지고 데이터가 클라이언트를 통과하지 않으므로, 자격 증명 입력이나 서드 파티 OAuth 권한 부여처럼 민감한 흐름에 적합합니다.
정보 요청은 다중 왕복 요청(MRTR) 패턴을 따릅니다. 서버가 tools/call 같은 요청을 처리하는 도중 사용자 입력이 필요하면, 하나 이상의 elicitation/create 요청을 inputRequests 필드에 담은 InputRequiredResult로 응답합니다. 클라이언트는 입력을 수집한 뒤 원래 요청을 다시 시도하면서 수집한 inputResponses를 첨부하고 서버가 포함한 requestState를 그대로 돌려보냅니다.
정보 요청 흐름:
sequenceDiagram
participant User
participant Client
participant Server
Client->>Server: tools/call (id: 1)
Note over Server: Server needs more information
Server-->>Client: InputRequiredResult with elicitation/create request
Note over Client,User: Human interaction
Client->>User: Present elicitation UI
User-->>Client: Provide requested information
Note over Client,Server: Retry request with user input
Client->>Server: tools/call (id: 2, inputResponses)
Note over Server: Continue processing with new information
Server-->>Client: Final result
이 흐름을 통해 동적으로 정보를 수집할 수 있습니다. 서버는 필요할 때 특정 데이터를 요청하고, 사용자는 적절한 UI를 통해 정보를 제공하며, 서버는 새로 얻은 컨텍스트를 사용해 재시도된 요청을 완료합니다.
정보 요청 예시(InputRequiredResult.inputRequests 내부에 전달됨):
{
method: "elicitation/create",
params: {
mode: "form",
message: "Please confirm your Barcelona vacation booking details:",
requestedSchema: {
type: "object",
properties: {
confirmBooking: {
type: "boolean",
description: "Confirm the booking (Flights + Hotel = $3,000)"
},
seatPreference: {
type: "string",
enum: ["window", "aisle", "no preference"],
description: "Preferred seat type for flights"
},
roomType: {
type: "string",
enum: ["sea view", "city view", "garden view"],
description: "Preferred room type at hotel"
},
travelInsurance: {
type: "boolean",
default: false,
description: "Add travel insurance ($150)"
}
},
required: ["confirmBooking"]
}
}
}
예시: 휴가 예약 승인
여행 예약 서버는 최종 예약 확인 과정을 통해 정보 요청의 활용 방식을 보여 줍니다. 사용자가 바르셀로나 휴가 패키지를 선택했다면, 서버는 진행하기 전에 최종 승인과 누락된 세부 정보를 수집해야 합니다.
서버는 여행 요약(6월 15~22일 바르셀로나 항공편, 해변 호텔, 총 3,000달러)과 좌석 선택, 객실 유형, 여행자 보험 같은 추가 선호 사항을 입력할 필드를 포함한 구조화된 요청으로 예약 확인을 받습니다.
예약이 진행되면 서버는 예약 완료에 필요한 연락처 정보를 요청합니다. 항공편 예약을 위한 여행자 정보, 호텔에 전달할 특별 요청, 긴급 연락처 등을 물을 수 있습니다.
사용자 상호작용 모델
정보 요청 상호작용은 명확하고 맥락에 맞으며 사용자의 자율성을 존중하도록 설계되었습니다.
요청 표시: 클라이언트는 어느 서버가 요청하는지, 정보가 필요한 이유와 사용 방법을 명확한 맥락과 함께 보여 줍니다. 요청 메시지는 목적을 설명하고 스키마는 구조와 검증 규칙을 제공합니다.
응답 선택지: 사용자는 적절한 UI 컨트롤(텍스트 필드, 드롭다운, 체크박스)을 통해 요청된 정보를 제공하거나, 선택적으로 이유를 설명하며 제공을 거부하거나, 전체 작업을 취소할 수 있습니다. 클라이언트는 응답을 서버에 반환하기 전에 제공된 스키마에 따라 검증합니다.
URL 처리: URL 모드에서는 클라이언트가 URL 전체를 표시하고 명시적 동의를 받은 뒤 열며, URL을 자동으로 가져오지 않습니다. 클라이언트가 알게 되는 정보는 사용자의 동의 여부뿐입니다. 상호작용 자체는 사용자와 대상 사이트 사이에서만 이루어집니다.
개인정보 고려 사항: 서버는 폼 모드로 비밀번호, API 키, 액세스 토큰, 결제 자격 증명 같은 민감한 정보를 요청해서는 안 됩니다. 이러한 상호작용은 URL 모드에서 처리해야 합니다. 데이터를 대역 외에 유지해 클라이언트나 LLM 컨텍스트를 통과하지 않게 하기 때문입니다. 클라이언트는 의심스러운 요청을 경고하고 사용자가 전송 전에 폼 데이터를 검토할 수 있게 합니다.
루트
루트는 서버 작업의 파일 시스템 경계를 정의하여 클라이언트가 서버가 집중할 디렉터리를 지정할 수 있게 합니다.
개요
루트는 클라이언트가 파일 시스템 접근 경계를 서버에 전달하는 메커니즘입니다. 서버가 작업할 수 있는 디렉터리를 나타내는 파일 URI로 구성되며, 서버가 사용 가능한 파일과 폴더의 범위를 이해하도록 돕습니다. 루트는 의도한 경계를 전달하지만 보안 제한을 강제하지는 않습니다. 실제 보안은 운영 체제 수준에서 파일 권한이나 샌드박싱으로 강제해야 합니다.
루트 구조:
{
"uri": "file:///Users/agent/travel-planning",
"name": "Travel Planning Workspace"
}
루트는 파일 시스템 경로만 나타내며 항상 file:// URI 스킴을 사용합니다. 서버가 프로젝트 경계, 워크스페이스 구성, 접근 가능한 디렉터리를 이해하도록 돕습니다. 사용자가 다른 프로젝트나 폴더에서 작업하면 루트 목록이 바뀔 수 있습니다. 서버는 다음에 루트 목록을 요청할 때 갱신된 경계를 받습니다.
예시: 여행 계획 워크스페이스
여러 고객의 여행을 다루는 여행 상담사는 루트를 활용해 파일 시스템 접근을 체계화할 수 있습니다. 여행 계획의 여러 측면을 서로 다른 디렉터리에 둔 워크스페이스를 생각해 보겠습니다.
클라이언트는 여행 계획 서버에 다음 파일 시스템 루트를 제공합니다.
file:///Users/agent/travel-planning- 모든 여행 파일이 들어 있는 기본 워크스페이스file:///Users/agent/travel-templates- 재사용 가능한 일정 템플릿과 리소스file:///Users/agent/client-documents- 고객 여권과 여행 서류
상담사가 바르셀로나 일정을 만들 때 올바르게 동작하는 서버는 이 경계를 준수합니다. 지정된 루트 안에서 템플릿에 접근하고 새 일정을 저장하며 고객 서류를 참조합니다. 서버는 일반적으로 루트 디렉터리 기준 상대 경로나 루트 경계를 준수하는 파일 검색 도구를 사용해 루트 내부 파일에 접근합니다.
상담사가 file:///Users/agent/archive/2023-trips 같은 보관 폴더를 열면 클라이언트가 루트 목록에 추가하고, 서버는 다음 roots/list 요청에서 새 경계를 확인합니다.
루트를 준수하는 완전한 서버 구현은 공식 서버 저장소의 파일 시스템 서버를 참고하세요.
설계 철학
루트는 클라이언트와 서버 사이의 조정 메커니즘이지 보안 경계가 아닙니다. 서버는 클라이언트가 통제할 수 없는 코드를 실행하므로 명세에서는 서버가 루트 경계를 "반드시 강제해야 한다(MUST enforce)"가 아니라 "준수하는 것이 좋다(SHOULD respect)"고 요구합니다.
루트는 서버가 신뢰할 수 있거나 검토되었고, 사용자가 권고적 성격을 이해하며, 악의적 행동 차단보다 실수 방지가 목표일 때 가장 효과적입니다. 컨텍스트 범위 지정(서버가 집중할 위치 알림), 사고 방지(올바르게 동작하는 서버가 경계 안에 머물도록 도움), 워크플로 구성(예: 프로젝트 경계 자동 관리)에 특히 유용합니다.
사용자 상호작용 모델
루트는 보통 사용자 작업에 따라 호스트 애플리케이션이 자동으로 관리하지만, 일부 애플리케이션은 수동 루트 관리를 제공할 수 있습니다.
자동 루트 감지: 사용자가 폴더를 열면 클라이언트가 이를 루트로 자동 노출합니다. 여행 워크스페이스를 열면 클라이언트가 해당 디렉터리를 루트로 노출하여 현재 작업 범위에 포함된 일정과 문서를 서버가 이해하도록 돕습니다.
수동 루트 구성: 고급 사용자는 구성을 통해 루트를 지정할 수 있습니다. 예를 들어 재사용 가능한 리소스를 위해 /travel-templates를 추가하면서 재무 기록이 있는 디렉터리는 제외할 수 있습니다.
샘플링
샘플링을 사용하면 서버가 클라이언트를 통해 언어 모델 완성을 요청할 수 있어, 보안과 사용자 통제를 유지하면서 에이전트형 동작을 구현할 수 있습니다.
개요
샘플링을 사용하면 서버가 AI 모델을 직접 통합하거나 비용을 부담하지 않고도 AI 의존 작업을 수행할 수 있습니다. 대신 이미 AI 모델 접근 권한이 있는 클라이언트에 이러한 작업을 대신 처리하도록 요청할 수 있습니다. 이 방식에서는 사용자 권한과 보안 조치를 클라이언트가 완전히 통제합니다. 샘플링 요청은 데이터 분석 도구 같은 다른 작업의 컨텍스트 안에서 발생하더라도 별도의 모델 호출로 처리되므로, 서로 다른 컨텍스트 사이의 명확한 경계를 유지하고 컨텍스트 창을 더 효율적으로 사용할 수 있습니다.
샘플링은 다중 왕복 요청 흐름을 따릅니다. 이 흐름은 정보 요청에서 설명한 것과 같으며, InputRequiredResult에 sampling/createMessage 요청이 들어갑니다.
서버는 요청에 tools 배열과 선택적 toolChoice 필드를 포함하여 샘플링 중 도구 사용을 요청할 수도 있습니다. 도구 정의는 해당 샘플링 요청에만 적용되며 서버가 노출하는 도구와 일치할 필요가 없습니다. 클라이언트는 sampling.tools 기능을 통해 지원 여부를 선언하고, 서버는 이를 선언하지 않은 클라이언트에 도구가 포함된 샘플링 요청을 보내서는 안 됩니다. 자세한 내용은 명세의 샘플링을 참고하세요.
샘플링 흐름:
sequenceDiagram
participant LLM
participant User
participant Client
participant Server
Client->>Server: tools/call (id: 1)
Note over Server: Server needs an LLM completion
Server-->>Client: InputRequiredResult with sampling/createMessage request
Note over Client,User: Human-in-the-loop review
Client->>User: Present request for approval
User-->>Client: Review and approve/modify
Note over Client,LLM: Model interaction
Client->>LLM: Forward approved request
LLM-->>Client: Return generation
Note over Client,User: Response review
Client->>User: Present response for approval
User-->>Client: Review and approve/modify
Note over Client,Server: Retry request with approved response
Client->>Server: tools/call (id: 2, inputResponses)
Server-->>Client: Final result
이 흐름은 여러 사람 개입 체크포인트를 통해 보안을 보장합니다. 클라이언트가 승인된 응답과 함께 원래 요청을 다시 시도하기 전에 사용자는 최초 요청과 생성된 응답을 모두 검토하고 수정할 수 있습니다.
요청 매개변수 예시:
{
messages: [
{
role: "user",
content: {
type: "text",
text: "Analyze these flight options and recommend the best choice:\n" +
"[47 flights with prices, times, airlines, and layovers]\n" +
"User preferences: morning departure, max 1 layover"
}
}
],
modelPreferences: {
hints: [{
name: "claude-sonnet-4-20250514" // Suggested model
}],
costPriority: 0.3, // Less concerned about API cost
speedPriority: 0.2, // Can wait for thorough analysis
intelligencePriority: 0.9 // Need complex trade-off evaluation
},
systemPrompt: "You are a travel expert helping users find the best flights based on their preferences",
maxTokens: 1500
}
예시: 항공편 분석 도구
findBestFlight라는 도구로 샘플링을 사용해 이용 가능한 항공편을 분석하고 최적의 선택을 추천하는 여행 예약 서버를 생각해 보겠습니다. 사용자가 "다음 달 바르셀로나행 최고의 항공편을 예약해 줘"라고 요청하면 도구는 복잡한 절충안을 평가하기 위해 AI의 도움이 필요합니다.
도구는 항공사 API를 조회해 47개 항공편 선택지를 수집합니다. 그런 다음 "다음 항공편 선택지를 분석하고 최선의 선택을 추천하세요: [가격, 시간, 항공사, 경유 횟수가 포함된 47개 항공편] 사용자 선호: 오전 출발, 최대 1회 경유"와 같이 AI에 분석을 요청합니다.
클라이언트가 샘플링 요청을 시작하면 AI는 저렴한 심야 항공편과 편리한 오전 출발편 같은 절충안을 평가할 수 있습니다. 도구는 이 분석을 사용해 상위 세 가지 추천을 제시합니다.
사용자 상호작용 모델
필수 요구 사항은 아니지만 샘플링은 사람이 과정에 개입해 통제할 수 있도록 설계되었습니다. 사용자는 여러 메커니즘을 통해 감독할 수 있습니다.
승인 제어: 샘플링 요청에 명시적 사용자 동의가 필요할 수 있습니다. 클라이언트는 서버가 분석하려는 대상과 이유를 보여 줄 수 있습니다. 사용자는 요청을 승인하거나 거부하거나 수정할 수 있습니다.
투명성 기능: 클라이언트는 정확한 프롬프트, 모델 선택, 토큰 한도를 표시하여 AI 응답을 서버에 반환하기 전에 사용자가 검토할 수 있게 합니다.
구성 옵션: 사용자는 모델 선호도를 지정하고, 신뢰하는 작업에 자동 승인을 설정하거나, 모든 작업에 승인을 요구할 수 있습니다. 클라이언트는 민감한 정보를 가리는 옵션을 제공할 수 있습니다.
보안 고려 사항: 클라이언트와 서버 모두 샘플링 중 민감한 데이터를 적절하게 처리해야 합니다. 클라이언트는 속도 제한을 구현하고 모든 메시지 내용을 검증해야 합니다. 사람 개입 방식은 서버가 요청한 AI 상호작용이 명시적 사용자 동의 없이 보안을 침해하거나 민감한 데이터에 접근하지 못하게 합니다.