MCP로 사용자에게 되묻기 — elicitation은 언제?

에이전트가 정보가 부족할 때 추측으로 툴을 재호출하면, 잘못된 인자·중복 부작용·사용자 신뢰 하락이 이어집니다. MCP elicitation은 서버가 클라이언트에게 elicitation/create를 보내 사용자 입력을 정식으로 요청하는 패턴입니다. 클라이언트가 elicitation 능력을 선언했을 때만 쓸 수 있고, UI 경로명은 제품마다 달라도 **동작(메시지·스키마·응답 액션)**은 스펙이 고정합니다.

이 글의 축은 셋입니다. 툴 실패와 되묻기의 차이 · 최소 질문 설계 · 타임아웃·취소. 요금·플랜·제휴·창작 후기는 없습니다.

근거는 Model Context Protocol 스펙의 elicitation(폼/URL 모드, message·requestedSchema, 응답 action: accept / decline / cancel)입니다. 제품별 메뉴 이름은 적지 않고 동작만 설명합니다.

툴 실패와 되묻기의 차이는?

한 줄 답: 툴 실패는 tools/call이 에러·불완전 결과로 끝난 상태이고, elicitation은 처리 도중에 서버가 사용자에게 구조화된 입력을 요구하는 별도 요청입니다. 같은 “정보가 없다”라도, 전자는 재시도·스키마 수정 쪽이고 후자는 사용자 확인 쪽입니다.

구분툴 실패 (tools/call)Elicitation (elicitation/create)
주체보통 클라이언트→서버 툴 호출의 결과서버→클라이언트로 사용자 입력 요청
신호JSON-RPC 에러 또는 실패 콘텐츠message + (폼이면) requestedSchema
사용자 개입에이전트가 추측·재호출할 수 있음클라이언트가 UI로 묻고, 사용자가 응답
전제툴·인자 스키마클라이언트가 elicitation capability 선언

언제 되묻기가 맞나:

  • 선택·확인이 필요한 값(대상 브랜치, 삭제 여부, 프로젝트 ID)인데 컨텍스트에 없음.
  • 툴 인자로 넣기엔 민감하지 않지만 추측하면 위험한 값(표시 이름, 이메일 형식의 연락처 등—폼 모드).
  • 비밀번호·API 키·결제 자격처럼 클라이언트/LLM을 거쳐선 안 되는 값 → 스펙상 URL 모드(폼 금지).

언제 툴 실패/재설계가 맞나:

  • 필수 인자가 툴 inputSchema에 있는데 에이전트가 비워 호출한 경우 → 스키마·설명을 고치거나, 호출 전에 에이전트 규칙을 보강.
  • 서버/네트워크/권한 오류 → elicitation이 아니라 에러 처리·재시도 정책.
  • 클라이언트가 elicitation을 선언하지 않음 → 서버는 해당 모드로 요청을내면 안 됩니다(스펙: 미지원 모드 금지).

폼 모드 예(개념):

{
  "method": "elicitation/create",
  "params": {
    "mode": "form",
    "message": "배포 대상 환경을 선택해 주세요.",
    "requestedSchema": {
      "type": "object",
      "properties": {
        "env": {
          "type": "string",
          "title": "환경",
          "enum": ["staging", "production"]
        }
      },
      "required": ["env"]
    }
  }
}

에이전트가 env를 추측해 deploy 툴을 두 번 치는 것보다, 한 번 묻고 accept의 content로 이어가는 편이 안전합니다.

최소 질문 설계는?

한 줄 답: 한 번의 elicitation에 flat object + 소수 필수 필드만 둡니다. message로 “왜 필요한지”를 쓰고, requestedSchema는 스펙이 허용하는 원시 타입(string / number / boolean / enum)만 사용합니다. 중첩 객체·객체 배열은 폼 모드에서 의도적으로 막혀 있습니다.

설계 체크리스트:

  1. 필수(required)를 최소화 — 지금 툴 한 번에 꼭 필요한 키만. “나중에 쓸지도” 필드는 빼기.
  2. message는 한 문장으로 동기 — “무엇을 / 왜” (예: “스토리지 버킷 이름을 확인합니다. 잘못된 버킷에 쓰면 데이터가 섞입니다.”).
  3. 필드 title·description·enum/format — 클라이언트가 폼을 그릴 때 힌트. email·uri·date 등 지원 format을 쓰면 검증이 쉬워집니다.
  4. 기본값(default) — 안전한 기본이 있으면 스키마에 넣고, 클라이언트가 지원하면 미리 채웁니다. 위험한 기본(production 배포 등)은 두지 않습니다.
  5. 민감 정보는 폼 금지 — 비밀번호·토큰·결제 정보는 URL 모드. 폼으로 받으면 클라이언트/로그에 노출될 수 있습니다.

하지 말 것:

  • 한 화면에 프로필 전체·설정 수십 개를 몰아넣기(이탈·오입력↑).
  • “전부 optional”인 거대 스키마로 책임 전가(에이전트가 다시 추측).
  • 폼 모드 URL을 클릭 유도 문구로 숨기기(스펙: 폼 필드에 클릭용 URL을 넣지 않는 편이 안전).

최소 스키마 예:

{
  "type": "object",
  "properties": {
    "confirm": {
      "type": "boolean",
      "title": "삭제 진행",
      "description": "이 작업을 되돌리기 어렵습니다."
    }
  },
  "required": ["confirm"]
}

질문에 답이 두 갈래면 boolean/enum 하나가, 자유 서술 장문보다 재현·자동화에 유리합니다.

타임아웃·취소는?

한 줄 답: 스펙 응답은 accept / decline / cancel 세 액션입니다. 명시적 거절은 decline, 닫기·Esc·이탈처럼 선택 없이 닫힌 경우는 cancel에 가깝습니다. 타임아웃은 스펙에 별도 action 이름이 없으므로, 클라이언트·서버 구현이 취소에 가깝게 처리하거나 JSON-RPC 오류로 끊는 경우가 많습니다—제품 UI 경로는 달라도, 서버는 세 갈래(+미응답)를 모두 가정해야 합니다.

action의미(스펙)서버 쪽 권장 처리
accept사용자가 제출·동의content(폼)로 진행. URL 모드는 content 없이 동의만
decline명시적 거절대안 제안·해당 툴 중단. 같은 질문 즉시 재폭격 금지
cancel선택 없이 닫힘나중에 다시 묻거나, 안전한 기본 경로로 폴백

운영 메모:

  • 미응답/타임아웃 — UI가 일정 시간 후 닫히면 보통 cancel 또는 요청 실패로 보입니다. 서버는 “수락으로 간주”하면 안 됩니다.
  • URL 모드 — accept는 “URL로 가도 된다”는 동의이지, 외부 절차 완료가 아닙니다. 완료는 선택적 notifications/elicitation/complete일 수 있고, 클라이언트가 알림을 못 받아도 수동 재시도·취소를 남겨 두는 것이 스펙 권고에 가깝습니다.
  • 능력 불일치 — 클라이언트가 선언하지 않은 모드로 elicitation/create를내면 Invalid params(-32602) 쪽이 됩니다. 초기화 때 capability를 확인하세요.
  • 상태 — 실무 elicitation은 사용자별로 “이미 받았는지”를 서버가 안전하게 묶어야 합니다. 세션 ID만으로 묶지 말라는 보안 가이드가 있습니다.
{
  "result": {
    "action": "cancel"
  }
}

취소·타임아웃 뒤에는 같은 message로 무한 재질문하지 말고, 채팅에 한 줄 요약(“환경 선택이 취소되었습니다. staging으로만 진행할까요?”) 후 다음 턴으로 넘기는 편이 사용자 부담이 적습니다.

자주 묻는 질문

Q. elicitation 없이 채팅으로 “뭐로 할까요?”만 물어보면 안 되나요?
A. 가능하지만, 구조화·검증·decline/cancel 구분이 약합니다. 폼 스키마가 있으면 클라이언트가 입력 검증을 돕고, 서버는 content 키를 신뢰 가능하게 읽습니다.

Q. 툴 인자 스키마와 requestedSchema를 똑같이 복제해야 하나요?
A. 아닙니다. 툴 스키마는 호출 계약이고, elicitation은 사용자에게 확인할 최소 부분집합이면 됩니다. 확인 후 서버/에이전트가 툴 인자로 매핑합니다.

Q. 제품 화면에서 버튼 이름이 다른데 괜찮은가요?
A. 괜찮습니다. 스펙은 UI 위젯을 강제하지 않고 요청/응답 의미를 정의합니다. 구현체는 Submit/Reject/닫기를 각각 accept/decline/cancel에 매핑하면 됩니다.

정리

정보가 없을 때 툴을 더 때리는 것과 사용자에게 되묻는 것은 다릅니다. MCP elicitation은 elicitation/create로 메시지와(폼이면) 최소 스키마를 보내고, accept·decline·cancel(및 미응답)을 구분해 이어가면 됩니다. 민감 정보는 폼이 아니라 URL 모드로 두고, 타임아웃을 수락으로 간주하지 마세요. 추측보다 한 번의 짧은 확인이 에이전트 부작용을 줄입니다.