MCP 클라이언트는 호스트 애플리케이션이 특정 MCP 서버와 통신하기 위해 생성하는 구성 요소입니다. Claude.ai나 IDE 같은 호스트 애플리케이션은 전체 사용자 경험을 관리하고, 여러 클라이언트를 조율합니다. 각 클라이언트는 하나의 서버와 1:1로 직접 통신합니다.
이 구분은 중요합니다. 호스트는 사용자가 상호작용하는 애플리케이션이고, 클라이언트는 서버 연결을 가능하게 하는 프로토콜 수준의 구성 요소입니다.
클라이언트는 서버가 제공하는 컨텍스트를 활용하는 것 외에도, 서버에게 여러 기능을 제공할 수 있습니다. 이러한 기능 덕분에 서버 작성자는 더 풍부한 상호작용을 설계할 수 있습니다.
| 기능 | 설명 | 예시 |
|---|---|---|
| Elicitation | 서버가 사용자에게 특정 정보를 요청할 수 있게 해 주는 구조화된 방식 | 여행 예약 서버가 좌석 선호, 객실 유형, 연락처를 요청 |
| Roots | 서버가 집중해야 할 디렉터리를 클라이언트가 지정하는 메커니즘 | 여행 예약 서버에 특정 폴더(캘린더)를 접근 범위로 제공 |
| Sampling | 서버가 클라이언트를 통해 LLM 완성을 요청할 수 있게 함 | 항공편 목록을 LLM에 보내 최적 옵션을 고르게 함 |
Elicitation은 서버가 사용자에게 필요한 정보를 요청할 수 있게 해, 더 동적이고 반응적인 워크플로를 만들게 합니다.
서버는 필요한 정보가 없을 때 중단하거나 처음부터 모두 요구하는 대신, 필요한 시점에 사용자에게 정보를 요청할 수 있습니다. 그 결과 보다 유연한 상호작용이 가능해집니다.
Elicitation 흐름:
sequenceDiagram
participant User
participant Client
participant Server
Note over Server,Client: Server initiates elicitation
Server->>Client: elicitation/create
Note over Client,User: Human interaction
Client->>User: Present elicitation UI
User-->>Client: Provide requested information
Note over Server,Client: Complete request
Client-->>Server: Return user response
Note over Server: Continue processing with new information
Elicitation 구성 요소 예시:
{
method: "elicitation/requestInput",
params: {
message: "Please confirm your Barcelona vacation booking details:",
schema: {
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"]
}
}
}
여행 예약 서버는 최종 승인과 누락된 세부 정보를 얻기 위해 elicitation을 사용합니다. 예: 바르셀로나 여행 패키지(6/15~6/22, 해변 호텔, 총 $3,000)에 대한 승인 요청.
예약 진행 중에는 항공권 발권에 필요한 여행자 정보, 호텔 특이사항, 비상 연락처 등도 추가로 요청할 수 있습니다.
클라이언트는 “어떤 서버가 왜 이 정보를 요청하는지”를 명확히 보여주고, 스키마를 통해 구조와 검증을 제공합니다.
사용자는 다음과 같이 응답할 수 있습니다.
클라이언트는 스키마에 맞는지 검증한 뒤 서버에 반환합니다.
프라이버시: Elicitation은 비밀번호나 API 키를 요청하지 않습니다. 클라이언트는 의심스러운 요청을 경고하고 사용자에게 재확인 기회를 제공합니다.
Roots는 서버가 작업할 파일 시스템 경계를 정의합니다. 클라이언트가 서버에게 집중해야 할 디렉터리를 알려 주는 협업 메커니즘입니다.
Roots는 파일 URI로 구성되며, 서버가 접근 가능한 범위를 알려주는 힌트입니다. 실제 보안은 OS 권한 또는 샌드박싱이 담당합니다.
Root 구조:
{
"uri": "file:///Users/agent/travel-planning",
"name": "Travel Planning Workspace"
}
Roots는 항상 file:// URI를 사용합니다.
사용자가 다른 폴더를 열면 클라이언트는 roots/list_changed로 변경을 알릴 수 있습니다.
file:///Users/agent/travel-planning – 주요 작업 공간file:///Users/agent/travel-templates – 일정 템플릿file:///Users/agent/client-documents – 여권/문서서버는 이 범위 안에서 파일을 탐색/저장하는 것이 기대됩니다. 전체 구현 예시는 filesystem 서버를 참고하세요.
Roots는 보안 경계가 아니라 협업 경계입니다. 사양은 서버가 루트 경계를 존중해야 한다고 말하지만, 강제해야 한다고 요구하지는 않습니다. 이는 서버 코드가 클라이언트 통제 밖에 있기 때문입니다.
Roots는 신뢰된 서버, 사용자가 인지하는 환경, 사고 방지 목적에 특히 효과적입니다. 컨텍스트 범위를 좁히고, 실수를 줄이며, 워크플로 조직에 도움을 줍니다.
Sampling은 서버가 클라이언트를 통해 LLM 완성을 요청할 수 있게 하여 모델 종속성과 비용 문제를 줄이면서도 사용자 통제와 보안을 유지합니다.
서버는 AI 작업을 직접 수행하지 않고, 클라이언트에 모델 호출을 요청합니다. 이는 클라이언트가 권한 및 보안을 완전히 통제하도록 합니다.
Sampling 흐름:
sequenceDiagram
participant LLM
participant User
participant Client
participant Server
Note over Server,Client: Server initiates sampling
Server->>Client: sampling/createMessage
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 Server,Client: Complete request
Client-->>Server: Return approved response
요청 파라미터 예시:
{
messages: [
{
role: "user",
content: "Analyze these flight options and recommend the best choice:\n" +
"1) Airline A - $1,200 - 2 stops\n" +
"2) Airline B - $1,450 - 1 stop\n" +
"3) Airline C - $1,100 - 3 stops"
}
],
maxTokens: 400,
temperature: 0.2
}