콘텐츠로 이동

클라이언트 개념 (Client Concepts)

MCP 클라이언트는 호스트 애플리케이션이 특정 MCP 서버와 통신하기 위해 만드는 구성 요소입니다. 호스트 애플리케이션(예: Claude.ai, IDE)은 사용자 경험 전체를 관리하고 여러 클라이언트를 조율합니다. 반면 각 클라이언트는 하나의 서버와의 직접 통신 한 건을 담당하죠. 이 구분을 이해하는 게 중요해요. 호스트(host)는 사용자가 실제로 마주하는 애플리케이션이고, 클라이언트(client)는 서버 연결을 가능하게 하는 프로토콜 수준의 구성 요소라는 뜻입니다.

핵심 클라이언트 기능 (Core Client Features)

클라이언트는 서버가 제공하는 컨텍스트를 활용할 뿐 아니라, 서버 쪽에 여러 기능을 제공하기도 합니다. 이런 클라이언트 기능 덕분에 서버 작성자는 더 풍부한 상호작용을 만들 수 있어요.

기능 설명 예시
Elicitation 서버가 상호작용 중에 사용자에게 특정 정보를 요청할 수 있게 해줍니다. 서버가 필요할 때 정보를 수집하는 구조화된 방법을 제공하죠. 여행 예약 서버가 예약을 확정하기 위해 비행기 좌석, 객실 타입, 연락처 등 사용자 선호도를 물어볼 수 있어요.
Roots 클라이언트가 서버가 집중해야 할 디렉터리를 지정할 수 있게 해줍니다. 조정(coordination) 메커니즘을 통해 의도된 범위를 전달하죠. Roots는 프로토콜 버전 2026-07-28부터 폐기(deprecated)되었습니다. 여행 예약 서버에 특정 디렉터리 접근 권한을 주고, 그 디렉터리에서 사용자 달력을 읽게 할 수 있어요.
Sampling 서버가 클라이언트를 통해 LLM 완성을 요청할 수 있게 해줘서, 에이전틱(agentic) 워크플로를 가능하게 합니다. 이 방식은 사용자 권한과 보안 조치를 온전히 클라이언트가 관리하게 하죠. Sampling은 프로토콜 버전 2026-07-28부터 폐기되었습니다. 여행 예약 서버가 항공편 목록을 LLM에 보내고, 사용자에게 가장 좋은 항공편을 고르도록 요청할 수 있어요.

Elicitation

Elicitation은 서버가 상호작용 중에 사용자에게 특정 정보를 요청할 수 있게 해주는 기능으로, 더 역동적이고 반응적인 워크플로를 만들어 줍니다.

개요 (Overview)

Elicitation은 서버가 필요할 때 필요한 정보를 수집하는 구조화된 방법을 제공합니다. 모든 정보를 처음부터 요구하거나 데이터가 없어서 실패하는 대신, 서버는 작업을 잠시 멈추고 사용자에게 특정 입력을 요청할 수 있어요. 덕분에 서버가 고정된 패턴을 따르기보다는 사용자의 필요에 맞춰 적응하는 유연한 상호작용이 가능해집니다.

Elicitation은 두 가지 모드를 지원합니다.

  • 폼 모드(Form mode): 서버가 클라이언트에게 사용자로부터 구조화된 데이터를 수집하도록 요청합니다. 요청에는 스키마(schema)가 포함되고, 클라이언트는 그 스키마로 입력 폼을 만들고 응답을 검증합니다.
  • URL 모드(URL mode): 서버가 사용자가 열어볼 URL을 제공합니다. 상호작용은 대역 외(out of band)로 일어나고, 그 데이터는 클라이언트를 거치지 않습니다. 그래서 자격증명 입력이나 타사 OAuth 인증처럼 민감한 흐름에 적합해요.

Elicitation은 다중 왕복 요청(Multi Round-Trip Requests, MRTR) 패턴을 따릅니다. tools/call 같은 요청을 처리하다가 서버가 사용자 입력이 필요해지면, InputRequiredResult로 응답하는데, 그 inputRequests 필드에 하나 이상의 elicitation/create 요청을 실어 보냅니다. 클라이언트는 입력을 모은 뒤 원래 요청을 재시도하면서, 수집한 inputResponses를 붙이고 서버가 포함했던 requestState를 그대로 되돌려 보냅니다.

Elicitation 흐름: 이 흐름은 동적인 정보 수집을 가능하게 합니다. 서버는 필요할 때 특정 데이터를 요청하고, 사용자는 적절한 UI로 정보를 제공하며, 서버는 새로 얻은 컨텍스트와 함께 재시도된 요청을 완료합니다.

Elicitation 요청 예시 (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"]
    }
  }
}

예시: 휴가 예약 승인 (Example: Holiday Booking Approval)

여행 예약 서버는 최종 예약 확정 과정에서 elicitation의 힘을 보여줍니다. 사용자가 바르셀로나 여행 패키지를 골랐다면, 서버는 다음 단계로 진행하기 전에 최종 승인과 빠진 세부 정보를 모아야 합니다. 서버는 여행 요약(바르셀로나 항공편 6월 15~22일, 해변가 호텔, 총 $3,000)과 좌석 선택·객실 타입·여행 보험 같은 추가 선호 항목을 담은 구조화된 요청으로 예약 확정을 elicitation 하죠.

예약이 진행되면서 서버는 예약을 완료하는 데 필요한 연락처 정보도 elicitation 합니다. 항공 예약을 위한 여행자 정보, 호텔을 위한 특별 요청, 비상 연락처 같은 것을 물어볼 수 있겠죠.

사용자 상호작용 모델 (User Interaction Model)

Elicitation 상호작용은 명확하고 맥락에 맞으며 사용자의 자율성을 존중하도록 설계됩니다.

  • 요청 표시(Request presentation): 클라이언트는 어느 서버가 왜 묻는지, 정보가 어떻게 쓰일지에 대한 명확한 맥락과 함께 elicitation 요청을 표시합니다. 요청 메시지는 목적을 설명하고, 스키마는 구조와 검증을 제공하죠.
  • 응답 옵션(Response options): 사용자는 텍스트 필드, 드롭다운, 체크박스 같은 적절한 UI 컨트롤로 요청된 정보를 제공하거나, 선택적 설명과 함께 제공을 거절하거나, 전체 작업을 취소할 수 있어요. 클라이언트는 응답을 서버로 돌려보내기 전에 제공된 스키마에 맞춰 검증합니다.
  • URL 처리(URL handling): URL 모드에서는 클라이언트가 전체 URL을 보여주고 사용자의 명시적 동의를 얻은 뒤에야 열며, URL을 자동으로 가져오지(fetch) 않습니다. 클라이언트는 사용자가 동의했는지만 알 수 있고, 상호작용 자체는 사용자와 대상 사이트 사이에서만 일어나요.
  • 개인정보 고려사항(Privacy considerations): 서버는 폼 모드로 비밀번호, API 키, 액세스 토큰, 결제 자격증명 같은 민감한 정보를 요청해서는 안 됩니다. 그런 상호작용은 데이터가 대역 외로 유지되어 클라이언트나 LLM 컨텍스트를 통과하지 않는 URL 모드에 속하죠. 클라이언트는 의심스러운 요청에 대해 경고하고, 사용자가 전송 전에 폼 데이터를 검토할 수 있게 합니다.

Roots

Roots는 프로토콜 버전 2026-07-28부터 폐기되어 제거가 예정되어 있습니다. 새 구현은 디렉터리나 파일을 도구 파라미터, 리소스 URI, 또는 서버 설정으로 전달하는 방식을 사용해야 합니다.

Roots는 서버 작업의 파일시스템 경계를 정의해서, 클라이언트가 서버가 집중해야 할 디렉터리를 지정할 수 있게 해줍니다.

개요 (Overview)

Roots는 클라이언트가 서버에 파일시스템 접근 경계를 전달하는 메커니즘입니다. 서버가 작업할 수 있는 디렉터리를 가리키는 파일 URI로 구성되어, 서버가 이용 가능한 파일과 폴더의 범위를 이해하도록 돕죠. Roots는 의도된 경계를 전달하지만, 보안 제한을 강제하지는 않습니다. 실제 보안은 파일 권한이나 샌드박싱을 통해 운영체제 수준에서 강제해야 해요.

Root 구조:

{
  "uri": "file:///Users/agent/travel-planning",
  "name": "Travel Planning Workspace"
}

Roots는 오직 파일시스템 경로만 사용하며 항상 file:// URI 스킴을 씁니다. 서버가 프로젝트 경계, 워크스페이스 구성, 접근 가능한 디렉터리를 이해하는 데 도움을 주죠. 사용자가 서로 다른 프로젝트나 폴더를 다룰 때 roots 목록은 바뀔 수 있습니다. 서버는 다음에 roots 목록을 요청할 때 갱신된 경계를 받아갑니다.

예시: 여행 기획 워크스페이스 (Example: Travel Planning Workspace)

여러 고객 여행을 다루는 여행 에이전트라면 roots로 파일시스템 접근을 구성하는 게 유용합니다. 여행 기획의 여러 측면을 위한 서로 다른 디렉터리를 가진 워크스페이스를 생각해볼까요. 클라이언트는 파일시스템 roots를 여행 기획 서버에 제공합니다.

  • file:///Users/agent/travel-planning — 모든 여행 파일이 담긴 메인 워크스페이스
  • file:///Users/agent/travel-templates — 재사용 가능한 일정 템플릿과 리소스
  • file:///Users/agent/client-documents — 고객 여권과 여행 서류

에이전트가 바르셀로나 일정을 만들 때, 잘 동작하는(well-behaved) 서버는 이 경계를 존중합니다. 지정된 roots 안에서 템플릿에 접근하고, 새 일정을 저장하고, 고객 서류를 참조하죠. 서버는 보통 root 디렉터리에서의 상대 경로를 사용하거나, root 경계를 존중하는 파일 검색 도구를 이용해 roots 안의 파일에 접근합니다.

에이전트가 file:///Users/agent/archive/2023-trips 같은 보관 폴더를 열면, 클라이언트는 그 폴더를 roots 목록에 추가하고, 서버는 다음 roots/list 요청에서 새 경계를 확인합니다. Roots를 존중하는 서버의 전체 구현은 공식 servers 리포지토리의 filesystem server에서 볼 수 있어요.

설계 철학 (Design Philosophy)

Roots는 클라이언트와 서버 사이의 조정(coordination) 메커니즘이지, 보안 경계가 아닙니다. 스펙은 서버가 root 경계를 "SHOULD respect(존중해야 한다)"라고 요구하지, "MUST enforce(강제해야 한다)"라고 하지 않아요. 서버는 클라이언트가 통제할 수 없는 코드를 실행하기 때문입니다.

Roots는 서버를 신뢰하거나 검증했을 때, 사용자가 그 권고적(advisory) 성격을 이해하고 있을 때, 그리고 의도를 막기보다 사고를 방지하는 게 목적일 때 가장 잘 작동합니다. 컨텍스트 범위 지정(서버가 어디에 집중해야 하는지 알려주기), 사고 방지(잘 동작하는 서버가 경계 안에 머물도록), 워크플로 구성(예: 프로젝트 경계를 자동으로 관리)에 탁월하죠.

사용자 상호작용 모델 (User Interaction Model)

Roots는 주로 사용자 동작에 따라 호스트 애플리케이션에 의해 자동으로 관리되지만, 일부 애플리케이션은 수동 관리를 노출하기도 합니다.

  • 자동 root 감지(Automatic root detection): 사용자가 폴더를 열면 클라이언트가 자동으로 그 폴더를 root로 노출합니다. 여행 워크스페이스를 열면 클라이언트가 그 디렉터리를 root로 노출해서, 서버가 현재 작업 범위에 어떤 일정과 문서가 들어있는지 이해하도록 돕죠.
  • 수동 root 구성(Manual root configuration): 고급 사용자는 설정으로 root를 지정할 수 있습니다. 예를 들어 재사용 가능한 리소스를 위해 /travel-templates를 추가하면서, 재무 기록이 담긴 디렉터리는 제외하는 식이에요.

Sampling

Sampling은 프로토콜 버전 2026-07-28부터 폐기되어 제거가 예정되어 있습니다. 새 구현은 LLM 제공자 API와 직접 통합하는 방식을 사용해야 합니다.

Sampling은 서버가 클라이언트를 통해 언어 모델 완성을 요청할 수 있게 해줍니다. 에이전틱 동작을 가능하게 하면서도 보안과 사용자 통제를 유지하죠.

개요 (Overview)

Sampling은 서버가 AI 모델과 직접 통합하거나 비용을 지불하지 않고도 AI 의존 작업을 수행할 수 있게 해줍니다. 대신 서버는 이미 AI 모델 접근 권한을 가진 클라이언트에게 그 작업을 대신 처리해 달라고 요청할 수 있어요. 이 방식은 사용자 권한과 보안 조치를 온전히 클라이언트가 관리하게 합니다. Sampling 요청은 도구가 데이터를 분석하는 것 같은 다른 작업의 컨텍스트 안에서 일어나고, 별도의 모델 호출로 처리되기 때문에 서로 다른 컨텍스트 사이의 경계가 명확하게 유지되어, 컨텍스트 창을 더 효율적으로 쓸 수 있죠.

Sampling도 elicitation에서 설명한 것과 같은 다중 왕복 요청(MRTR) 흐름을 따르며, 그때는 InputRequiredResultsampling/createMessage 요청을 담습니다.

서버는 sampling 중에 요청에 tools 배열과 선택적인 toolChoice 필드를 포함해 도구 사용을 요청할 수도 있어요. 도구 정의는 그 sampling 요청에 범위가 한정되며, 서버가 노출하는 도구와 일치할 필요는 없습니다. 클라이언트는 sampling.tools 기능(capability)으로 지원을 선언하고, 서버는 이를 선언하지 않은 클라이언트에게 도구가 활성화된 sampling 요청을 보내서는 안 됩니다. 자세한 내용은 스펙의 sampling을 참고하세요.

Sampling 흐름: 이 흐름은 여러 인간 개입(human-in-the-loop) 체크포인트를 통해 보안을 보장합니다. 사용자는 클라이언트가 원래 요청을 재시도하기 전에 초기 요청과 생성된 응답을 모두 검토하고 수정할 수 있어요.

요청 파라미터 예시:

{
  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
}

예시: 항공편 분석 도구 (Example: Flight Analysis Tool)

findBestFlight라는 도구를 가진 여행 예약 서버를 생각해 보죠. 이 도구는 sampling으로 이용 가능한 항공편을 분석해 최적의 선택을 추천합니다. 사용자가 "다음 달 바르셀로나로 가는 최고의 항공편을 예약해 줘"라고 요청하면, 도구는 복잡한 트레이드오프를 평가하기 위해 AI 지원이 필요해요.

도구는 항공사 API를 조회해 47개의 항공편 옵션을 모읍니다. 그런 다음 이 옵션들을 분석하도록 AI 지원을 요청합니다. "이 항공편 옵션들을 분석해 최선의 선택을 추천해 줘: [가격, 시간, 항공사, 경유가 있는 47개 항공편] 사용자 선호: 오전 출발, 경유 최대 1회." 클라이언트가 sampling 요청을 시작하고, AI가 더 저렴한 새벽(red-eye) 항공편과 편리한 오전 출발 같은 트레이드오프를 평가하게 하죠. 도구는 이 분석으로 상위 세 가지 추천을 제시합니다.

사용자 상호작용 모델 (User Interaction Model)

요구 사항은 아니지만, sampling은 인간 개입(human-in-the-loop) 통제를 허용하도록 설계되었습니다. 사용자는 여러 메커니즘을 통해 감독을 유지할 수 있어요.

  • 승인 통제(Approval controls): Sampling 요청은 명시적인 사용자 동의를 요구할 수 있습니다. 클라이언트는 서버가 무엇을 왜 분석하려는지 보여줄 수 있고, 사용자는 요청을 승인하거나 거절하거나 수정할 수 있어요.
  • 투명성 기능(Transparency features): 클라이언트는 정확한 프롬프트, 모델 선택, 토큰 제한을 표시해서, 사용자가 AI 응답이 서버로 돌아가기 전에 검토할 수 있게 합니다.
  • 구성 옵션(Configuration options): 사용자는 모델 선호도를 설정하고, 신뢰하는 작업에는 자동 승인을 설정하거나, 모든 것에 승인을 요구하도록 설정할 수 있어요. 클라이언트는 민감한 정보를 가리기(redact) 위한 옵션을 제공할 수도 있습니다.
  • 보안 고려사항(Security considerations): 클라이언트와 서버 모두 sampling 중 민감한 데이터를 적절히 다뤄야 합니다. 클라이언트는 rate limiting을 구현하고 모든 메시지 내용을 검증해야 하죠. 인간 개입 설계 덕분에 서버가 요청한 AI 상호작용이 사용자의 명시적 동의 없이 보안을 위협하거나 민감한 데이터에 접근할 수 없습니다.