MCP Elicitation은 왜 ‘추가 질문’이 아니라 사용자 입력 경계일까
MCP 서버가 작업 중간에 사용자에게 정보를 더 달라고 할 때, AI 앱은 그것을 어떻게 안전한 제품 흐름으로 설계해야 할까?
MCP Elicitation은 왜 ‘추가 질문’이 아니라 사용자 입력 경계일까
- 카테고리: ai_dev
- 예상 읽기 시간: 10분
- 오늘의 질문: MCP 서버가 작업 중간에 사용자에게 정보를 더 달라고 할 때, AI 앱은 그것을 어떻게 안전한 제품 흐름으로 설계해야 할까?
- 핵심 출처:
- Elicitation - Model Context Protocol - 2025-06-18 사양, 2026-06-21 확인
- Lifecycle - Model Context Protocol - 2025-06-18 사양, 2026-06-21 확인
- MCP and Connectors - OpenAI API - 게시일 미표기, 2026-06-21 확인
- Combine built-in tools and function calling - Google AI for Developers - Interactions API Beta/Preview 문서, 2026-06-21 확인
1. 왜 지금 봐야 하나
에이전트 앱을 만들다 보면 “모델이 알아서 필요한 걸 물어보면 되지 않을까?”라는 유혹이 생긴다. 예를 들어 일정 예약 MCP 서버가 날짜가 빠졌다는 사실을 발견하면 사용자에게 날짜를 물어보고, CRM MCP 서버가 고객 구분이 애매하면 담당자를 물어보고, 사내 문서 MCP 서버가 검색 범위를 좁히기 위해 프로젝트명을 물어보는 식이다.
문제는 이 순간이 단순한 대화가 아니라 사용자 입력 경계라는 점이다. MCP 서버는 모델 바깥의 별도 시스템이다. 서버가 “추가 정보가 필요하다”고 말할 때, 클라이언트는 다음 네 가지를 동시에 판단해야 한다.
- 이 서버가 지금 사용자에게 물어볼 자격이 있는가?
- 어떤 정보가 서버로 전달되는가?
- 사용자가 수락, 거절, 취소했을 때 워크플로가 어떻게 이어지는가?
- 이 입력이 민감정보, 결제, 권한 승인 같은 더 강한 경계를 우회하지 않는가?
MCP 2025-06-18 사양은 이 문제를 위해 elicitation을 도입했다. Elicitation은 MCP 서버가 클라이언트를 통해 사용자에게 구조화된 정보를 요청하는 표준 흐름이다. 중요한 점은 “서버가 마음대로 사용자와 대화한다”가 아니라, 클라이언트가 사용자 인터랙션과 데이터 공유를 통제하는 방식으로 서버의 질문을 중개한다는 것이다.
최근 OpenAI Responses API의 MCP/Connectors 문서도 같은 방향을 보여준다. 원격 MCP 서버와 커넥터를 모델에 붙일 수 있지만, 신뢰하지 않는 원격 서버는 모델 컨텍스트에 들어간 민감 데이터를 유출할 수 있으므로 승인, allowlist, 검토 로그가 필요하다고 경고한다. Google Gemini의 tool context circulation 문서도 내장 도구와 커스텀 함수가 섞일 때 도구 호출 id, signature, context 전달을 명확히 보존해야 한다고 설명한다. 즉, 이제 AI 앱의 중요한 설계 포인트는 “도구를 호출할 수 있나?”에서 “도구 호출 중간의 사용자 입력과 컨텍스트를 어떤 계약으로 주고받나?”로 이동하고 있다.
오늘의 핵심은 이것이다.
MCP Elicitation은 편리한 추가 질문 기능이 아니라, 외부 도구 서버가 사용자 입력을 요청하는 순간을 제품·보안·상태 관리 관점에서 명시하는 경계다.
2. 핵심 개념
Elicitation의 기본 흐름은 간단하다.
- MCP 서버가 작업 중 추가 정보가 필요하다고 판단한다.
- 서버가 클라이언트에
elicitation/create요청을 보낸다. - 클라이언트가 사용자에게 UI를 보여준다.
- 사용자는
accept,decline,cancel중 하나로 응답한다. - 클라이언트가 응답을 서버로 돌려주고, 서버는 그 상태에 맞게 작업을 계속하거나 중단한다.
여기서 개발자가 봐야 할 설계 포인트는 세 가지다.
2-1. 질문은 자연어가 아니라 스키마가 붙은 요청이다
MCP Elicitation 요청에는 사용자에게 보여줄 message와 기대 응답 형태를 나타내는 requestedSchema가 들어간다. 사양은 클라이언트 구현을 단순하게 만들기 위해 스키마를 “중첩 없는 flat object + primitive property”로 제한한다. 문자열, 숫자, 불리언, enum 같은 기본 타입 중심이다.
이 제약은 약점이 아니라 안전장치다. 서버가 복잡한 폼 전체를 마음대로 밀어 넣기보다, “지금 이 작업을 이어가기 위해 필요한 최소 입력”을 선언하게 만든다. 클라이언트는 이 스키마를 기반으로 UI를 만들고, 검증하고, 로그를 남길 수 있다.
2-2. 응답 상태는 성공/실패 두 가지가 아니다
Elicitation 응답은 accept, decline, cancel 세 가지 action을 구분한다.
accept: 사용자가 정보를 제출했다.decline: 사용자가 요청을 명시적으로 거절했다.cancel: 사용자가 닫거나 중단했지만 명시적 거절은 아니다.
이 구분은 제품 품질에 중요하다. 예를 들어 “배송 주소를 알려주세요”라는 요청에서 decline이면 “주소 없이는 주문을 만들 수 없습니다”가 맞을 수 있다. cancel이면 “나중에 이어서 작성할 수 있습니다”가 더 자연스럽다. 권한·결제·삭제 같은 고위험 작업에서는 decline과 cancel 모두 안전하게 중단해야 하지만, 분석용 필터 입력처럼 선택적인 값은 cancel 후 기본 범위로 계속할 수도 있다.
2-3. Capability negotiation 없이는 기능이 아니다
MCP lifecycle 사양에 따르면 클라이언트와 서버는 초기화 단계에서 프로토콜 버전과 capability를 협상한다. 클라이언트가 Elicitation을 지원한다면 elicitation capability를 선언해야 한다. 서버도 이 전제를 보고 상호작용을 설계한다.
이 말은 “모델이 대화로 물어보면 되잖아”와 다르다. 모델의 임의 질문은 프로토콜 상태가 아니다. 반면 Elicitation은 서버 요청, 클라이언트 UI, 사용자 action, 서버 후속 처리까지 추적 가능한 프로토콜 이벤트다. 운영에서는 이 차이가 크다. 장애 분석, 감사 로그, 권한 리뷰, UX 개선 모두 “어느 서버가, 어떤 스키마로, 어떤 이유를 들어, 사용자가 어떻게 응답했는가”를 필요로 한다.
3. 최신 이슈와 연결
AI 앱의 도구 연결 방식은 빠르게 표준화되고 있다. OpenAI Responses API는 type: "mcp"로 원격 MCP 서버나 커넥터를 붙이고, server_url, authorization, allowed_tools, require_approval 같은 설정으로 도구 노출과 승인 정책을 조절한다. 문서가 특히 강조하는 부분은 신뢰 경계다. 원격 MCP 서버는 모델 컨텍스트의 데이터를 볼 수 있으므로, 개발자는 어떤 데이터가 공유되는지 검토하고 필요한 경우 승인을 요구해야 한다.
Google의 Interactions API 문서도 비슷한 흐름을 다른 용어로 보여준다. 내장 도구와 커스텀 함수가 섞이면 도구 context circulation이 필요하고, Gemini 3 계열에서는 function call id와 signature를 통해 도구 호출과 결과의 연결성을 유지한다. 세부 구현은 다르지만 메시지는 같다. 에이전트 시스템에서 “중간 단계”는 그냥 문자열 로그가 아니라, 다음 단계의 판단과 권한에 영향을 주는 상태다.
MCP Elicitation은 이 중간 단계에 “사용자 입력”이 끼어드는 경우를 다룬다. 검색 결과나 함수 결과를 모델에 돌려주는 것보다 더 조심해야 한다. 사용자는 서버가 누구인지, 왜 묻는지, 어떤 값이 전달되는지 알아야 한다. 서버는 민감정보를 요청하면 안 되고, 클라이언트는 사용자가 거절하거나 취소할 수 있는 경로를 제공해야 한다.
여기서 실패하기 쉬운 패턴은 세 가지다.
첫째, Elicitation을 인증이나 결제 입력 창처럼 쓰는 것이다. 2025-06-18 Elicitation 사양은 서버가 Elicitation으로 민감정보를 요청해서는 안 된다고 명시한다. 비밀번호, API 키, 카드 번호, OAuth 토큰 같은 값은 별도 인증/보안 흐름으로 처리해야 한다.
둘째, 서버 메시지를 그대로 믿고 UI에 표시하는 것이다. 서버가 “작업을 계속하려면 회사 전체 데이터 접근을 승인하세요”라고 보낼 수 있다면, 클라이언트는 서버 이름, 요청 이유, 전달 필드, 위험도를 함께 보여줘야 한다. 메시지 자체도 정책 검토 대상이다.
셋째, decline과 cancel을 같은 에러로 뭉개는 것이다. 그러면 사용자는 “거절했는데 왜 다시 묻지?”, “잠깐 닫았는데 작업이 삭제됐네?” 같은 경험을 하게 된다. 에이전트 UX는 모델 응답 품질만이 아니라 이런 상태 전이가 결정한다.
4. 개발자 관점 해석
Elicitation을 잘 쓰려면 “질문을 만드는 기능”이 아니라 “입력 경계 컴포넌트”로 봐야 한다.
작은 팀의 기본 아키텍처
가장 단순한 구조는 다음과 같다.
User request
-> Agent runtime
-> MCP server tool call
-> MCP server needs input
-> elicitation/create
-> Client Elicitation UI
-> accept/decline/cancel
-> MCP server continues or exits
-> Agent runtime resumes
여기서 클라이언트는 최소한 다음 정보를 로그로 남기는 것이 좋다.
server_label또는 서버 식별자- 요청된
message requestedSchema의 필드 이름과 타입- 사용자 action: accept/decline/cancel
- accept인 경우 실제 값은 마스킹하거나 정책에 맞게 저장
- 원래 실행 중이던 workflow/run/trace id
- 이 입력 이후 호출된 도구와 최종 결과
이 로그는 나중에 “왜 에이전트가 이 값을 사용했는가?”를 설명해준다. LLM 앱에서 재현 가능한 디버깅은 모델 프롬프트만 저장해서는 부족하다. 도구 서버가 중간에 어떤 사용자 입력을 요구했는지까지 기록해야 한다.
보안 경계
Elicitation UI에는 최소 세 가지 문장이 필요하다.
- “어느 서버가 요청하는가”
- “왜 필요한가”
- “어떤 값이 전달되는가”
예를 들어 “crm_server가 고객사를 찾기 위해 회사명을 요청합니다. 입력한 회사명은 crm_server로 전달됩니다.”처럼 표시한다. 사용자가 보기에는 귀찮아 보일 수 있지만, 원격 MCP 서버와 사내 데이터가 연결될수록 이 투명성이 사고를 줄인다.
또한 서버별 정책을 둬야 한다.
- 공개·저위험 서버: 단순 필터 값만 허용
- 사내 서버: tenant/project/user context를
_meta나 런타임 context로 제한 - 쓰기 작업 서버: Elicitation과 별도로 승인/confirmation 단계 필요
- 외부 SaaS 커넥터: OAuth scope, tool allowlist, audit log 필수
Elicitation은 권한 승인이 아니다. 사용자가 “서울”이라는 값을 입력했다고 해서 서버가 캘린더를 수정할 권한을 얻는 것은 아니다. 값 입력, tool approval, OAuth authorization, destructive action confirmation은 서로 다른 경계로 분리해야 한다.
UX 실패 모드
개발자가 자주 놓치는 실패 모드는 다음과 같다.
- 너무 자주 묻는다: 서버가 작은 애매함마다 Elicitation을 던지면 사용자는 agent fatigue를 느낀다.
- 너무 늦게 묻는다: 여러 도구 호출을 한 뒤 마지막에 필수 값이 없다고 묻는다면 비용과 지연이 낭비된다.
- 질문이 불투명하다: “추가 정보가 필요합니다”만 표시하면 사용자는 무엇이 전달되는지 모른다.
- 기본값이 위험하다: 사용자가 cancel했는데 전체 조직 범위로 검색하면 데이터 노출 위험이 커진다.
- 모델이 임의로 보완한다: 사용자가 decline했는데 모델이 추측으로 값을 채우면 신뢰성이 무너진다.
좋은 Elicitation 설계는 질문 수를 늘리는 것이 아니라, 질문해야 할 때만 명확하게 묻고, 묻지 않아도 되는 값은 안전한 기본값이나 검색 후보로 처리하는 것이다.
5. 내 프로젝트에 적용할 체크포인트
AI 앱에 MCP 서버나 커스텀 도구를 붙이고 있다면 아래 질문을 점검해보자.
- 우리 agent runtime은 중간 사용자 입력 요청을 프로토콜 이벤트로 기록하는가?
- 어떤 서버가 Elicitation을 요청할 수 있는지 allowlist가 있는가?
- Elicitation으로 절대 받을 수 없는 필드 목록이 있는가? 예: password, api_key, token, card_number
accept,decline,cancel을 서로 다른 상태로 처리하는가?- 사용자가 입력한 값이 어느 서버로 전달되는지 UI에 표시하는가?
- Elicitation 이후 이어지는 tool call이 읽기인지 쓰기인지 구분하는가?
- 쓰기·삭제·결제·외부 전송은 별도 승인 단계를 요구하는가?
- trace나 audit log에서 “서버 질문 -> 사용자 응답 -> 후속 도구 호출”을 연결해 볼 수 있는가?
- 테스트 케이스에 “사용자가 거절했을 때”, “사용자가 취소했을 때”, “서버가 민감정보를 요청했을 때”가 포함되어 있는가?
특히 마지막 항목이 중요하다. Elicitation은 정상 경로보다 거절·취소·악성 요청에서 품질이 드러난다. 사용자가 협조해주는 happy path만 테스트하면 실제 운영에서 가장 민감한 경계를 놓친다.
6. 오늘 10분 액션
오늘은 새 라이브러리를 붙이지 말고, 지금 만들고 있는 AI 기능 하나를 골라 “중간 사용자 입력 요청” 표를 만들어보자.
기능: ______________________
1. 도구/서버가 추가로 물어볼 수 있는 값 3개
- 값 A:
- 값 B:
- 값 C:
2. 각 값의 민감도
- 공개/저위험:
- 사내/중간위험:
- 민감/금지:
3. 사용자 action별 처리
- accept:
- decline:
- cancel:
4. 별도 승인이 필요한 후속 작업
- 쓰기:
- 삭제:
- 결제/외부 전송:
5. 로그로 남길 것
- server id:
- schema fields:
- action:
- trace id:
10분 안에 표만 채워도 충분하다. 이 표를 만들면 “모델이 알아서 물어보겠지”라는 흐릿한 설계가 “어떤 서버가 어떤 값을 어떤 상태로 요청할 수 있는가”라는 계약으로 바뀐다.
7. 더 볼 자료
- Elicitation - Model Context Protocol: MCP 서버가 클라이언트를 통해 사용자에게 구조화된 입력을 요청하는 사양. flat schema, accept/decline/cancel, 민감정보 금지 규칙을 먼저 보자.
- Lifecycle - Model Context Protocol: capability negotiation과 초기화 흐름. Elicitation이 “그냥 대화”가 아니라 협상된 capability임을 이해하는 데 필요하다.
- MCP and Connectors - OpenAI API: 원격 MCP 서버와 커넥터를 Responses API에서 사용할 때 approval, allowed tools, 원격 서버 신뢰 경계를 어떻게 설명하는지 확인하자.
- Combine built-in tools and function calling - Google AI for Developers: 벤더는 다르지만 도구 호출 id, signature, context circulation을 통해 중간 도구 상태를 보존해야 한다는 관점을 참고할 수 있다.
중복 회피 메모
최근 ai_dev 글은 에이전트 권한 계약, Tool Search, Guardrail 체크포인트, Structured Outputs, reasoning effort, prompt caching, RAG 검색 품질을 다뤘다. 이번 글은 도구 권한을 승인하는 방법이나 도구 목록을 줄이는 문제가 아니라, MCP 서버가 작업 중간에 사용자 입력을 요청하는 elicitation을 제품 UI·프로토콜 상태·보안 경계로 설계하는 방법에 집중한다.
핵심 출처
로그인하면 이 글을 북마크하고, 나만 보는 한 줄 메모를 남길 수 있어요.
댓글 0
최신순 ▾혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)