Elicitation

Elicitation

서버가 상호작용 중 클라이언트를 통해 사용자에게 추가 정보를 요청하는 표준화된 방법을 설명하는 페이지예요. 이 흐름은 클라이언트가 사용자 상호작용과 데이터 공유에 대한 통제를 유지하면서, 서버가 필요한 정보를 동적으로 수집할 수 있게 해 줘요.

출처: 문서

본문

Model Context Protocol (MCP)은 서버가 상호작용 중 클라이언트를 통해 사용자에게 추가 정보를 요청하는 표준화된 방법을 제공해요. 이 흐름은 클라이언트가 사용자 상호작용과 데이터 공유에 대한 통제를 유지하면서, 서버가 필요한 정보를 동적으로 수집할 수 있게 해 줘요.

Elicitation은 두 가지 모드를 지원해요:

  • Form 모드: 서버가 사용자에게 구조화된 데이터를 요청하며, 응답 검증용 선택적 JSON 스키마를 포함할 수 있어요
  • URL 모드: 서버가 사용자를 외부 URL로 안내해, MCP 클라이언트를 통과해서는 안 되는 민감한 상호작용을 처리해요

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

MCP의 Elicitation은 사용자 입력 요청이 다른 MCP 서버 기능 안에 *중첩(nested)*되어 일어나도록 해서, 서버가 대화형 워크플로우를 구현할 수 있게 해요.

구현체는 자신의 필요에 맞는 어떤 인터페이스 패턴으로든 elicitation을 노출할 자유가 있어요. 프로토콜 자체는 특정 사용자 상호작용 모델을 강제하지 않아요.

경고 (Warning): 신뢰·안전과 보안을 위해:

  • 서버는 MUST NOT form 모드 elicitation으로 비밀번호, API 키, 접근 토큰, 지불 자격 증명 같은 민감한 정보를 요청해서는 안 된다
  • 서버는 MUST 그러한 민감한 정보가 포함된 상호작용에는 URL 모드를 사용해야 한다

여기서 "민감한 정보"란 접근을 허가하거나 트랜잭션을 승인하는 비밀(secrets)과 자격 증명을 말해요. 일반적인 연락처나 프로필 정보(이름, 이메일 주소, 사용자 이름 같은)는 범주적으로 금지되지는 않아요. 그런 데이터를 form 모드로 요청할지는 서버의 재량이며, 사용자가 검토하고 거절할 수 있는 능력에 따라 달라요.

MCP 클라이언트는 MUST:

  • 어떤 서버가 정보를 요청하는지 명확히 하는 UI를 제공한다
  • 사용자 프라이버시를 존중하고 명확한 거절·취소 옵션을 제공한다
  • form 모드에서 사용자가 보내기 전에 응답을 검토·수정할 수 있게 한다
  • URL 모드에서 대상 도메인/호스트를 명확히 표시하고, 대상 URL로 이동하기 전에 사용자 동의를 받는다

기능 (Capabilities)

elicitation을 지원하는 클라이언트는 MUST 각 요청의 _meta.io.modelcontextprotocol/clientCapabilities에 elicitation 기능을 선언해야 해요:

{
  "_meta": {
    "io.modelcontextprotocol/clientCapabilities": {
      "elicitation": {
        "form": {},
        "url": {}
      }
    }
  }
}

하위 호환성을 위해, 빈 기능 객체는 form 모드만 지원을 선언하는 것과 동등해요:

{
  "_meta": {
    "io.modelcontextprotocol/clientCapabilities": {
      "elicitation": {}, // Equivalent to { "form": {} }
    },
  },
}

elicitation 기능을 선언하는 클라이언트는 MUST 최소 하나의 모드(form 또는 url)를 지원해야 해요.

서버는 MUST NOT 클라이언트가 지원하지 않는 모드로 elicitation 요청을 보내서는 안 돼요.

프로토콜 메시지 (Protocol Messages)

Elicitation 요청 (Elicitation Requests)

서버는 MAY 클라이언트 요청 처리 중에, elicitation/create 요청을 담은 InputRequiredResult를 보내 사용자에게 정보를 요청할 수 있어요.

모든 elicitation 요청은 MUST 다음 파라미터를 포함해야 해요:

Name Type Options Description
mode string form, url The mode of the elicitation. Optional for form mode (defaults to "form" if omitted).
message string A human-readable message explaining why the interaction is needed.

mode 파라미터는 elicitation의 유형을 지정해요:

  • "form": 선택적 스키마 검증이 있는 인밴드(in-band) 구조화 데이터 수집. 데이터는 클라이언트에 노출된다.
  • "url": URL 탐색을 통한 대역 외(out-of-band) 상호작용. 데이터(URL 자체는 제외)는 클라이언트에 노출되지 않는다.

하위 호환성을 위해, 서버는 MAY form 모드 elicitation 요청에서 mode 필드를 생략할 수 있어요. 클라이언트는 MUST mode 필드가 없는 요청을 form 모드로 취급해야 해요.

Form 모드 Elicitation 요청 (Form Mode Elicitation Requests)

Form 모드 elicitation은 서버가 MCP 클라이언트를 통해 직접 구조화된 데이터를 수집할 수 있게 해요.

Form 모드 elicitation 요청은 MUST mode: "form"을 지정하거나 mode 필드를 생략하고, 다음 추가 파라미터를 포함해야 해요:

Name Type Description
requestedSchema object A JSON Schema defining the structure of the expected response.

요청된 스키마 (Requested Schema)

requestedSchema 파라미터는 서버가 JSON Schema의 제한된 부분집합을 사용해 기대되는 응답의 구조를 정의하게 해요.

클라이언트 사용자 경험을 단순화하기 위해, form 모드 elicitation 스키마는 원시(primitive) 속성만 가진 평면 객체(flat objects)로 제한돼요.

스키마는 다음 원시 타입으로 제한돼요:

  1. 문자열 스키마 (String Schema)

    {
      "type": "string",
      "title": "Display Name",
      "description": "Description text",
      "minLength": 3,
      "maxLength": 50,
      "format": "email",
      "default": "[email protected]"
    }
    

    지원되는 형식: email, uri, date, date-time

  2. 숫자 스키마 (Number Schema)

    {
      "type": "number", // or "integer"
      "title": "Display Name",
      "description": "Description text",
      "minimum": 0,
      "maximum": 100,
      "default": 50
    }
    
  3. 불리언 스키마 (Boolean Schema)

    {
      "type": "boolean",
      "title": "Display Name",
      "description": "Description text",
      "default": false
    }
    
  4. 열거형 스키마 (Enum Schema)

    단일 선택 열거형 (타이틀 없음):

    {
      "type": "string",
      "title": "Color Selection",
      "description": "Choose your favorite color",
      "enum": ["Red", "Green", "Blue"],
      "default": "Red"
    }
    

    단일 선택 열거형 (타이틀 포함):

    {
      "type": "string",
      "title": "Color Selection",
      "description": "Choose your favorite color",
      "oneOf": [
        { "const": "#FF0000", "title": "Red" },
        { "const": "#00FF00", "title": "Green" },
        { "const": "#0000FF", "title": "Blue" }
      ],
      "default": "#FF0000"
    }
    

    다중 선택 열거형 (타이틀 없음):

    {
      "type": "array",
      "title": "Color Selection",
      "description": "Choose your favorite colors",
      "minItems": 1,
      "maxItems": 2,
      "items": {
        "type": "string",
        "enum": ["Red", "Green", "Blue"]
      },
      "default": ["Red", "Green"]
    }
    

    다중 선택 열거형 (타이틀 포함):

    {
      "type": "array",
      "title": "Color Selection",
      "description": "Choose your favorite colors",
      "minItems": 1,
      "maxItems": 2,
      "items": {
        "anyOf": [
          { "const": "#FF0000", "title": "Red" },
          { "const": "#00FF00", "title": "Green" },
          { "const": "#0000FF", "title": "Blue" }
        ]
      },
      "default": ["#FF0000", "#00FF00"]
    }
    

클라이언트는 이 스키마를 다음에 사용할 수 있어요:

  1. 적절한 입력 폼 생성
  2. 보내기 전에 사용자 입력 검증
  3. 사용자에게 더 나은 안내 제공

모든 원시 타입은 합리적인 시작점을 제공하는 선택적 기본값을 지원해요. 기본값을 지원하는 클라이언트는 SHOULD 폼 필드를 이 값들로 미리 채워야 해요.

복잡한 중첩 구조, 객체 배열(열거형은 제외), 기타 고급 JSON Schema 기능은 클라이언트 사용자 경험을 단순화하기 위해 의도적으로 지원하지 않는다는 점을 기억하세요.

예시: 단순 텍스트 요청 (Example: Simple Text Request)

입력 요청 (InputRequiredResult.inputRequests 안에 전달됨):

{
  "method": "elicitation/create",
  "params": {
    "mode": "form",
    "message": "Please provide your GitHub username",
    "requestedSchema": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": ["name"]
    }
  }
}

클라이언트 결과 (재시도된 요청의 inputResponses 안에 반환됨):

{
  "action": "accept",
  "content": {
    "name": "octocat"
  }
}

예시: 구조화 데이터 요청 (Example: Structured Data Request)

입력 요청 (InputRequiredResult.inputRequests 안에 전달됨):

{
  "method": "elicitation/create",
  "params": {
    "mode": "form",
    "message": "Please provide your contact information",
    "requestedSchema": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Your full name"
        },
        "email": {
          "type": "string",
          "format": "email",
          "description": "Your email address"
        },
        "age": {
          "type": "number",
          "minimum": 18,
          "description": "Your age"
        }
      },
      "required": ["name", "email"]
    }
  }
}

클라이언트 결과 (재시도된 요청의 inputResponses 안에 반환됨):

{
  "action": "accept",
  "content": {
    "name": "Monalisa Octocat",
    "email": "[email protected]",
    "age": 30
  }
}

URL 모드 Elicitation 요청 (URL Mode Elicitation Requests)

참고 (Note): 새 기능: URL 모드 elicitation은 MCP 사양 2025-11-25 버전에서 도입됐어요. 그 설계와 구현은 향후 프로토콜 개정에서 바뀔 수 있어요.

URL 모드 elicitation은 서버가 사용자를 MCP 클라이언트를 통과해서는 안 되는 대역 외 상호작용을 위한 외부 URL로 안내할 수 있게 해 줘요. 이는 인증 흐름, 지불 처리, 기타 민감하거나 안전한 작업에 필수적이에요.

URL 모드 elicitation 요청은 MUST mode: "url", message를 지정하고 다음 추가 파라미터를 포함해야 해요:

Name Type Description
url string The URL that the user should navigate to.

url 파라미터는 MUST 유효한 URL을 담아야 해요.

참고 (Note): 중요: URL 모드 elicitation은 MCP 서버에 대한 MCP 클라이언트의 접근을 승인하기 위한 것이 아니에요(그건 MCP authorization이 담당). 대신, MCP 서버가 사용자를 대신해 민감한 정보나 제3자 승인을 얻어야 할 때 사용돼요. MCP 클라이언트의 bearer 토큰은 그대로 유지돼요. 클라이언트의 유일한 책임은 사용자에게 서버가 열길 원하는 elicitation URL에 대한 컨텍스트를 제공하는 것이에요.

예시: 민감 데이터 요청 (Example: Request Sensitive Data)

이 예시는 사용자를 민감한 정보(예: API 키)를 제공할 수 있는 보안 URL로 안내하는 URL 모드 elicitation 요청을 보여줘요. 같은 요청이 사용자를 OAuth 승인 흐름 또는 지불 흐름으로 안내할 수도 있어요. 유일한 차이는 URL과 메시지예요.

입력 요청 (InputRequiredResult.inputRequests 안에 전달됨):

{
  "method": "elicitation/create",
  "params": {
    "mode": "url",
    "url": "https://mcp.example.com/ui/set_api_key",
    "message": "Please provide your API key to continue."
  }
}

클라이언트 결과 (재시도된 요청의 inputResponses 안에 반환됨):

{
  "action": "accept"
}

action: "accept"가 담긴 응답은 사용자가 상호작용에 동의했음을 나타내요. 상호작용이 완료됐다는 뜻은 아니에요. 상호작용은 대역 외에서 일어나고 클라이언트는 그 결과를 직접 통보받지 않아요. 클라이언트가 원래 요청을 재시도하면, 서버는 반향된(echoed) requestState(또는 자체 저장 상태)에서 대역 외 상호작용이 완료됐는지 판단해, 최종 결과를 반환하거나 또 다른 InputRequiredResult로 응답해요. 클라이언트는 SHOULD 사용자가 원래 요청을 재시도하거나 취소(또는 클라이언트와 상호작용을 재개)할 수 있는 수동 컨트롤을 제공해야 해요.

메시지 흐름 (Message Flow)

Form 모드 흐름 (Form Mode Flow)

sequenceDiagram
    participant User
    participant Client
    participant Server

    Client->>Server: tools/call(id: 1)
    note over Server: Server needs more info
    Server-->>Client: InputRequiredResult(elicitation/create (mode: form))

    Note over User,Client: Present elicitation UI
    User-->>Client: Provide requested information

    Note over Server,Client: Retry request with new information
    Client->>Server: tools/call(id: 2, user response)
    Server-->>Client: Result(id: 2, result)

URL 모드 흐름 (URL Mode Flow)

sequenceDiagram
    participant UserAgent as User Agent (Browser)
    participant User
    participant Client
    participant Server

    Client->>Server: tools/call(id: 1)
    Note over Server: Server needs more info <br/> Server creates requestState encoding url info.
    Server-->>Client: InputRequiredResult(elicitation/create (mode: url), requestState)

    Client->>User: Present consent to open URL
    User-->>Client: Provide consent

    Client->>UserAgent: Open URL
    Client->>Server: tools/call(id: 2, Accept Response, requestState))
    Note over Server: Server uses requestState to discover url info. <br/> It may need to block until the request is fulfilled.

    Note over User,UserAgent: User interaction
    UserAgent-->>Server: Interaction complete

    Note over Server: Continue processing with new information
    Server-->Client: Result(id: 2, result)

응답 액션 (Response Actions)

Elicitation 응답은 서로 다른 사용자 액션을 명확히 구분하기 위해 세 가지 액션 모델을 사용해요. 이 액션들은 form과 URL elicitation 모드 모두에 적용돼요.

{
  "action": "accept", // or "decline" or "cancel"
  "content": {
    "propertyName": "value",
    "anotherProperty": 42
  }
}

세 가지 응답 액션은:

  1. 수락 (Accept) (action: "accept"): 사용자가 명시적으로 승인하고 데이터와 함께 제출

    • Form 모드: content 필드는 요청된 스키마와 일치하는 제출 데이터를 담음
    • URL 모드: content 필드는 생략됨
    • 예시: 사용자가 "제출", "OK", "확인" 등을 클릭
  2. 거절 (Decline) (action: "decline"): 사용자가 명시적으로 요청을 거절

    • content 필드는 일반적으로 생략됨
    • 예시: 사용자가 "거부", "거절", "아니요" 등을 클릭
  3. 취소 (Cancel) (action: "cancel"): 사용자가 명시적 선택 없이 닫음

    • content 필드는 일반적으로 생략됨
    • 예시: 사용자가 대화상자를 닫거나, 바깥을 클릭하거나, Escape를 누르거나, 브라우저가 로드에 실패함

서버는 각 상태를 적절히 처리해야 해요:

  • 수락 (Accept): 제출된 데이터 처리
  • 거절 (Decline): 명시적 거절 처리 (예: 대안 제시)
  • 취소 (Cancel): 닫힘 처리 (예: 나중에 다시 요청)

구현 고려 사항 (Implementation Considerations)

상태 유지 (Statefulness)

Elicitation은 다중 왕복 요청 메커니즘으로 서버가 사용자에 대한 상태를 유지할 것을 요구하지 않아요.

하지만 상태를 저장한다면, elicitation을 구현하는 서버는 MUST 보안 모범 사례 문서의 지침에 따라 이 상태를 개별 사용자와 안전하게 연관시켜야 해요. 구체적으로:

  • 상태 저장소는 MUST 무단 접근으로부터 보호되어야 한다
  • 원격 MCP 서버의 경우, 사용자 식별은 가능할 때 MCP authorization으로 획득한 자격 증명(예: sub 클레임)에서 MUST 파생되어야 한다

참고 (Note): 이 섹션의 예시는 비규범적(non-normative)이며 elicitation의 잠재적 용도를 보여줘요. 구현자는 보안 모범 사례를 유지하면서 자신의 특정 요구사항에 맞게 이 패턴을 조정해야 해요.

민감 데이터를 위한 URL 모드 Elicitation (URL Mode Elicitation for Sensitive Data)

민감 정보(예: 자격 증명, 지불 정보)를 요구하는 외부 API와 상호작용하는 서버의 경우, URL 모드 elicitation은 사용자가 이 정보를 MCP 클라이언트에 노출하지 않고 제공할 수 있는 안전한 메커니즘을 제공해요.

이 패턴에서:

  1. 서버는 사용자를 보안 웹 페이지(HTTPS로 제공)로 안내한다
  2. 페이지는 사용자가 신뢰하는 도메인에 브랜드화된 폼 UI를 제시한다
  3. 사용자는 민감한 자격 증명을 보안 폼에 직접 입력한다
  4. 서버는 자격 증명을 사용자 신원에 바인딩해 안전하게 저장한다
  5. 이후 MCP 요청은 이 저장된 자격 증명을 API 접근에 사용한다

이 접근 방식은 민감한 자격 증명이 LLM 컨텍스트, MCP 클라이언트 또는 중간 MCP 서버를 절대 통과하지 않도록 보장해서, 클라이언트 측 로깅이나 다른 공격 벡터를 통한 노출 위험을 줄여요.

OAuth 흐름을 위한 URL 모드 Elicitation (URL Mode Elicitation for OAuth Flows)

URL 모드 elicitation은 MCP 서버가 제3자 리소스 서버에 대한 OAuth 클라이언트로 동작하는 패턴을 가능하게 해요. URL 모드 elicitation으로 가능해진 외부 API와의 승인은 MCP authorization과 분리돼요. MCP 서버는 MUST NOT URL 모드 elicitation에 의존해 사용자가 서버 자신에게 승인되게 해서는 안 돼요.

구분 이해하기 (Understanding the Distinction)

  • MCP Authorization: MCP 클라이언트와 MCP 서버 사이의 필수 OAuth 흐름 (authorization 사양에 있음)
  • 외부 (제3자) Authorization: MCP 서버와 제3자 리소스 서버 사이의 선택적 승인. URL 모드 elicitation으로 시작됨

외부 승인에서 서버는 둘 다로 동작해요:

  • OAuth 리소스 서버 (MCP 클라이언트에게)
  • OAuth 클라이언트 (제3자 리소스 서버에게)

예시 시나리오:

  • MCP 클라이언트가 MCP 서버에 연결한다
  • MCP 서버가 다양한 제3자 서비스와 통합한다
  • MCP 클라이언트가 제3자 서비스 접근이 필요한 도구를 호출하면, MCP 서버는 그 서비스의 자격 증명이 필요하다

핵심 보안 요구사항은:

  1. 제3자 자격 증명은 MCP 클라이언트를 통과해선 안 된다: 클라이언트는 보안 경계를 보호하기 위해 제3자 자격 증명을 절대 볼 수 없어야 한다
  2. MCP 서버는 제3자 서비스에 클라이언트의 자격 증명을 사용해선 안 된다: 그건 token passthrough이며 금지된다
  3. 사용자는 MCP 서버를 직접 승인해야 한다: 상호작용은 MCP 클라이언트를 포함하지 않고 MCP 프로토콜 밖에서 일어난다
  4. 토큰은 MCP 서버의 책임이다: MCP 서버는 URL 모드 elicitation으로 얻은 제3자 토큰을 저장하고 관리할 책임이 있다 (즉, MCP 서버는 상태를 유지해야 한다)

URL 모드 elicitation으로 얻은 자격 증명은 MCP 클라이언트가 사용하는 MCP 서버 자격 증명과 구별돼요. MCP 서버는 MUST NOT URL 모드 elicitation으로 얻은 자격 증명을 MCP 클라이언트에게 전송해서는 안 돼요.

참고 (Note): 추가 배경은 Security Best Practices 문서의 token passthrough 섹션을 참조해, MCP 서버가 패스스루 프록시로 동작할 수 없는 이유를 이해하세요.

구현 패턴 (Implementation Pattern)

URL 모드 elicitation으로 외부 승인을 구현할 때:

  1. MCP 서버는 제3자 서비스에 대한 OAuth 클라이언트로 동작하며 승인 URL을 생성한다
  2. MCP 서버는 elicitation 요청을 사용자의 신원과 연관(바인딩)시키는 내부 상태를 저장한다
  3. MCP 서버는 승인 흐름을 시작할 수 있는 URL과, 필요하다면 elicitation 요청과 사용자에 대한 정보를 인코딩한 선택적 requestState를 담아 클라이언트에게 URL 모드 elicitation 요청을 보낸다
  4. 사용자는 제3자 승인 서버와 직접 OAuth 흐름을 완료한다
  5. 제3자 승인 서버는 MCP 서버로 다시 리다이렉트한다
  6. MCP 서버는 제3자 토큰을 사용자 신원에 바인딩해 안전하게 저장한다
  7. 이후 MCP 요청은 제3자 리소스 서버에 대한 API 접근에 이 저장된 토큰을 활용할 수 있다

이 패턴이 구현될 수 있는 방법의 비규범적 예시는 다음과 같아요:

sequenceDiagram
    participant User
    participant UserAgent as User Agent (Browser)
    participant 3AS as 3rd Party AS
    participant 3RS as 3rd Party RS
    participant Client as MCP Client
    participant Server as MCP Server

    Client->>Server: tools/call
    Note over Server: Needs 3rd-party authorization for user
    Note over Server: Store state (bind the elicitation request to the user)
    Note over Server: generate requestState that encodes information about the original request and user.
    Server->>Client: InputRequiredResult<br/>(mode: "url", url: "https://mcp.example.com/connect?...", requestState)

    Client->>User: Present consent to open URL
    User->>Client: Provide consent
    Client->>UserAgent: Open URL
    Client->>Server: Accept response
    UserAgent->>Server: Load connect route

    Note over Server: Confirm: user is logged into MCP Server or MCP AS<br>Confirm: elicitation user matches session user
    Server->>UserAgent: Redirect to third-party authorization endpoint
    UserAgent->>3AS: Load authorize route
    Note over 3AS,User: User interaction (OAuth flow):<br>User consents to scoped MCP Server access
    3AS->>UserAgent: redirect to MCP Server's redirect_uri
    UserAgent->>Server: load redirect_uri page
    Note over Server: Confirm: redirect_uri belongs to MCP Server
    Server->>3AS: Exchange authorization code for  OAuth tokens
    3AS->>Server: Grants tokens
    Note over Server: Bind tokens to MCP user identity
    Client->>Server: tools/call (ElicitResults, requestState)
    Note over Server: Retrieve token bound to user identity
    Server->>3RS: Call 3rd-party API

이 패턴은 명확한 보안 경계를 유지하면서 사용자 승인이 필요한 제3자 서비스와의 풍부한 통합을 가능하게 해요.

오류 처리 (Error Handling)

서버는 SHOULD NOT elicitation 요청이 항상 성공할 것이라 가정하면 안 되고, 사용자가 elicitation을 거절하거나 취소하거나 클라이언트가 요청을 처리하지 못하는 경우를 MUST 처리해야 해요.

보안 고려 사항 (Security Considerations)

  1. 서버는 MUST elicitation 요청을 클라이언트와 사용자 신원에 바인딩해야 한다
  2. 클라이언트는 MUST 어떤 서버가 정보를 요청하는지 명확한 표시를 제공해야 한다
  3. 클라이언트는 SHOULD 사용자 승인 통제를 구현해야 한다
  4. 클라이언트는 SHOULD 사용자가 언제든 elicitation 요청을 거절할 수 있게 해야 한다
  5. 클라이언트는 SHOULD 어떤 정보가 왜 요청되는지 명확히 하는 방식으로 elicitation 요청을 제시해야 한다

안전한 URL 처리 (Safe URL Handling)

elicitation을 요청하는 MCP 서버는:

  1. MUST NOT URL elicitation 요청에서 클라이언트에게 보내는 URL에 자격 증명, 개인 식별 정보 등 최종 사용자에 대한 민감한 정보를 포함해서는 안 된다.
  2. MUST NOT 보호된 리소스에 접근하기 위해 사전 인증된(pre-authenticated) URL을 제공해서는 안 된다. 그런 URL은 악의적인 클라이언트가 사용자를 가장(impersonate)하는 데 사용될 수 있기 때문이다.
  3. SHOULD NOT form 모드 elicitation 요청의 어떤 필드에도 클릭 가능하도록 의도된 URL을 포함해서는 안 된다.
  4. SHOULD 개발 환경이 아닌 환경에서는 HTTPS URL을 사용해야 한다.

이 서버 요구사항은 클라이언트 구현체가 언제 URL을 사용자에게 제시할지에 대한 명확한 규칙을 갖도록 보장해서, 아래의 클라이언트 측 규칙을 일관되게 적용할 수 있게 해요.

URL 모드 elicitation을 구현하는 클라이언트는 MUST 사용자가 악의적인 링크를 모르고 클릭하지 않도록 URL을 신중히 처리해야 해요.

URL 모드 elicitation 요청을 처리할 때 MCP 클라이언트는:

  1. MUST NOT URL 또는 그 메타데이터를 자동으로 사전 fetch해서는 안 된다.
  2. MUST NOT 사용자의 명시적 동의 없이 URL을 열어서는 안 된다.
  3. MUST 동의 전에 검토할 수 있도록 전체 URL을 사용자에게 보여줘야 한다.
  4. MUST 클라이언트나 LLM이 콘텐츠나 사용자 입력을 검사할 수 없게 하는 안전한 방식으로 서버가 제공한 URL을 열어야 한다. 예를 들어 iOS에서는 SFSafariViewController가 좋지만 WkWebView는 아니다.
  5. SHOULD 서브도메인 스푸핑을 완화하려고 URL의 도메인을 강조해야 한다.
  6. SHOULD 모호하거나 의심스러운 URI(예: Punycode 포함)에 대한 경고를 가져야 한다.
  7. SHOULD NOT URL elicitation 요청의 url 필드(위에 명시된 제한 사항 포함)를 제외하고, elicitation 요청의 어떤 필드에도 URL을 클릭 가능하게 렌더링해서는 안 된다.

사용자 식별 (Identifying the User)

서버는 MUST NOT 서버 검증 없이 클라이언트 제공 사용자 식별에 의존해서는 안 된다. 이는 위조될 수 있기 때문이다. 대신 서버는 SHOULD 보안 모범 사례를 따라야 한다.

비규범적 예시:

  • 잘못됨: "I am [email protected]" 같은 사용자 입력을 권위 있는 것으로 취급
  • 올바름: 사용자를 식별하려면 authorization에 의존

Form 모드 보안 (Form Mode Security)

  1. 서버는 MUST NOT form 모드로 민감한 정보(비밀번호, API 키 등)를 요청해서는 안 된다
  2. 클라이언트는 SHOULD 제공된 스키마에 대해 모든 응답을 검증해야 한다
  3. 서버는 SHOULD 받은 데이터가 요청된 스키마와 일치하는지 검증해야 한다

피싱 (Phishing)

URL 모드 elicitation은 공격자가 피해자에게 보낼 수 있는 URL을 반환해요. MCP 서버는 MUST 정보를 받아들이기 전에 URL을 연 사용자의 신원을 검증해야 해요.

일반적으로 신원 검증은 MCP authorization server를 활용해 사용자를 식별하고, 브라우저의 세션 쿠키 또는 그에 상응하는 것으로 처리해요.

예를 들어, URL 모드 elicitation은 서버가 다른 리소스 서버의 OAuth 클라이언트로 동작하는 OAuth 흐름을 수행하는 데 사용될 수 있어요. 적절한 완화 없이는 다음 피싱 공격이 가능해요:

  1. 악의적인 사용자(Alice)가 정상 서버에 연결되어 elicitation 요청을 트리거한다
  2. 정상 서버는 제3자 승인 서버의 OAuth 클라이언트로 동작하며 승인 URL을 생성한다
  3. Alice의 클라이언트는 URL을 표시하고 동의를 요청한다
  4. 링크를 클릭하는 대신, Alice는 같은 정상 서버의 피해자 사용자(Bob)를 속여 클릭하게 한다
  5. Bob은 자신의 정상 서버 접속을 승인한다고 생각하고 링크를 열어 승인을 완료한다
  6. 정상 서버는 제3자 승인 서버로부터 콜백/리다이렉트를 받고, 그것이 Alice의 요청이라고 가정한다
  7. 제3자 서버에 대한 토큰이 Bob이 아니라 Alice의 세션과 신원에 바인딩되어, 계정 탈취로 이어진다

이 공격을 막으려면 서버는 MUST elicitation 요청을 시작한 사용자(MCP 클라이언트를 통해 서버에 접근하는 최종 사용자)가 승인 흐름을 완료하는 사용자와 같도록 보장해야 해요.

이를 달성하는 방법은 많고, 가장 좋은 방법은 특정 구현에 따라 달라져요.

일반적이고 비규범적인 예시로, MCP 서버가 웹으로 접근 가능하고 제3자 승인 코드 흐름을 수행하려는 경우를 생각해 보세요. 피싱 공격을 막기 위해 서버는 제3자 승인 엔드포인트 대신 https://mcp.example.com/connect?...로 URL 모드 elicitation을 만들 거예요. 이 "connect URL"은 페이지를 연 사용자가 elicitation이 생성된 사용자와 같도록 보장해야 해요. 예를 들어, 사용자가 유효한 세션 쿠키를 갖고 있고 그 세션 쿠키가 URL 모드 elicitation을 생성하는 데 MCP 클라이언트를 사용하던 사용자와 같은 사용자용인지 확인할 거예요. 이는 MCP 서버의 승인 서버에서 나온 권위 있는 subject(sub 클레임)를 세션 쿠키의 subject와 비교해서 수행할 수 있어요. 그 페이지가 같은 사용자임을 확인하면, 정상적인 OAuth 흐름을 완료할 수 있는 https://example.com/authorize?...의 제3자 승인 서버로 사용자를 보낼 수 있어요.

다른 경우, 서버는 웹으로 접근할 수 없고 세션 쿠키로 사용자를 식별하지 못할 수도 있어요. 이 경우 서버는 elicitation URL을 여는 사용자가 elicitation이 생성된 사용자와 같다는 것을 식별하기 위한 다른 메커니즘을 사용해야 해요.

모든 구현에서 서버는 MUST 사용자 신원을 결정하는 메커니즘이 공격자가 elicitation URL을 수정할 수 있는 공격에 대해 탄력적이도록 보장해야 해요.

더 알아보기 (Learn more)