-
[OpenAI][Realtime] MCP approval request가 뜰 때 mcp_approval_response와 require_approval을 같이 읽는 법기타개발지식/풀스택개발 2026. 6. 25. 20:13
IT 리서치 노트
[OpenAI][Realtime] MCP approval request가 뜰 때 mcp_approval_response와 require_approval을 같이 읽는 법
Realtime MCP를 붙인 음성 세션에서 가장 먼저 막히는 지점은 도구 호출 자체보다 승인 이벤트 처리다. 2026년 6월 25일 기준 OpenAI 공식 문서는 approval이 필요한 도구 호출이 들어오면
mcp_approval_requestitem을 conversation에 넣고, 클라이언트가mcp_approval_response를 별도 이벤트로 보내야 다음 단계로 진행된다고 설명한다. 이 글은 음성 세션에서 이 흐름을 어디서 끊어 읽고,require_approval을 어떤 필터로 잡아야 운영이 덜 꼬이는지 정리한 것이다.1. 개요
결론부터 말하면 Realtime MCP approval은 도구 호출에 대한 부가 옵션이 아니라, 세션 상태를 중단하고 다시 이어 붙이는 제어 흐름이다. 그래서
mcp_approval_request를 받으면 사용자 확인 UI 또는 음성 확인 단계가 필요하고, 승인 결과는mcp_approval_response로 명시적으로 되돌려줘야 한다. 여기서require_approval은 전체 on/off가 아니라 read-only 또는 특정 tool 이름으로 좁히는 편이 안전하다.이미 session.tools와 response.tools를 나누는 글이 세션 노출 범위를 설명했다면, 이번 글은 그 다음 단계인 승인 흐름을 다룬다. 또 approval 정책과 감사 로그를 나누는 글은 팀 규칙 관점이라면, 이번 글은 Realtime 이벤트 관점의 구현 순서라고 보면 된다.
2. 어디서 실제로 막히는가
실무에서는 보통 세 가지 증상으로 막힌다. 첫째, 모델이 tool을 부르려다 세션이 멈춘 것처럼 보이는데 실제 원인은
mcp_approval_request가 왔는데도 클라이언트가 응답을 안 보낸 경우다. 둘째, 어떤 도구는 승인 없이 지나가고 어떤 도구는 멈추는데, 세션 정책에서require_approval을 어떻게 걸었는지 로그가 남지 않아 원인을 좁히지 못한다. 셋째, 승인 UI는 띄웠는데 approval request id와 실제 응답이 서로 엇갈려 사용자가 승인한 작업이 실행되지 않거나, 반대로 다른 요청이 실행된다.특히 음성 세션은 사용자가 화면을 오래 보지 않을 수 있다는 점이 더 까다롭다. 브라우저 챗 UI라면 팝업을 눌러 보겠지만, 음성 에이전트는 확인 질문을 말로 다시 읽고, 사용자의 응답을 구조화하고, 결과를 이벤트로 다시 보내야 한다. 이 단계가 없으면 서버는 pending approval 상태를 쌓고, 사용자는 에이전트가 멈췄다고 느낀다.
또
require_approval을 전체always로만 두면 read-only 조회도 매번 멈춘다. 반대로 전체never로 두면 write 계열이나 외부 전송 계열이 무방비로 열릴 수 있다. 결국 tool surface를 줄이는 post 37의 축과 승인 범위를 자르는 이번 축을 같이 가져가야 한다.- 증상: 음성 세션이 멈춘 것처럼 보이지만 실제로는 approval 대기 상태다.
- 실패:
mcp_approval_requestitem id와 사용자 승인 결과를 연결하지 않는다. - 막힘:
require_approval필터가 read-only와 write 도구를 제대로 구분하지 않는다. - 누락: 승인 로그와 실제 tool 실행 로그를 같은 trace로 묶지 않는다.
증상 먼저 볼 곳 판단 기준 세션이 멈춘 것처럼 보인다 conversation item 로그 mcp_approval_request가 왔는지 먼저 본다승인했는데 실행이 안 된다 approval request id와 response payload 같은 request id를 응답에 다시 보냈는지 본다 조회도 매번 확인을 묻는다 require_approval필터read-only와 tool_names 조건을 다시 본다 3. 실무에서 적용하는 순서
구현 순서는 다섯 단계가 가장 안정적이다. 먼저 세션 기본값에서 어떤 도구가 승인 대상인지
require_approval필터를 정의한다. 다음으로mcp_approval_request를 conversation item으로 받아 request id와 tool 정보를 저장한다. 세 번째로 사용자에게 읽어 줄 승인 문구를 만들고, 승인을 받으면mcp_approval_response를 보낸다. 네 번째로 실제 tool 실행 결과를 approval request id와 같은 trace에 묶는다. 마지막으로 reject, timeout, disconnect 세 경우를 별도 종료 코드로 남긴다.require_approval을 read-only와 write 도구 기준으로 먼저 자른다.mcp_approval_request를 수신하면 request id와 tool 이름을 저장한다.- 사용자 확인을 받은 뒤
mcp_approval_response를 보낸다. - 실제 tool 실행 로그를 approval trace와 연결한다.
- reject, timeout, disconnect를 별도 상태로 남긴다.
실무에서는 approval 메시지 자체를 너무 길게 만들지 않는 편이 좋다. 사용자에게는 어떤 작업이 실행될지, 어떤 계정 또는 대상에 영향을 주는지, 취소하면 무엇이 보존되는지만 읽어 주고, 상세 정책은 서버 로그와 UI 카드에 남기는 편이 낫다. 음성 세션에서 장황한 설명은 승인 실패율만 높인다.
이렇게 나누면 세션 기본값, 승인 대기, 실제 실행이 서로 다른 레벨이라는 점이 드러난다. 이미 post 24에서 OAuth와 tool 범위를 줄였다면, 이번 단계는 그 좁은 범위를 실제 사용자 승인과 묶는 구현이라고 보면 된다.
4. 공식 문서와 예시 화면으로 확인하기
첫 화면은 Realtime with tools 문서의 승인 처리 구간이다. 여기서는 approval이 필요한 MCP 도구를 모델이 바로 실행하지 못하고, 클라이언트가 approve 또는 reject를 명시적으로 보내야 다음 단계로 진행된다는 점을 먼저 확인해야 한다.
즉 approval은 UI 위젯 하나를 붙이는 문제가 아니라, 세션 상태를 멈춤과 재개가 가능한 이벤트 흐름으로 설계해야 한다는 뜻이다. 음성 세션에서 이 흐름을 무시하면 사용자는 말했는데 작업은 멈춰 있고, 서버는 왜 멈췄는지 설명하지 못하는 상태가 생긴다.
두 번째 자료는 문서가
mcp_approval_request를 어떻게 설명하는지 보여 준다. 중요한 점은 이것이 단순 로그 문자열이 아니라 conversation 안에 들어오는 item이라는 점이다.그래서 서버 로그에서 승인 대기만 보고 끝내면 부족하다. 실제 클라이언트는 이 item의 id와 tool 정보, 사용자가 본 승인 문구, 승인 결과를 한 세트로 보관해야 재현이 된다.
세 번째 화면은 Realtime client events reference의
require_approval설명이다. 여기서 approval은 무조건 전체 on 또는 off가 아니라, read-only 여부나 특정 tool 이름으로 좁힐 수 있다는 점을 읽어야 한다.이 필터를 잘 쓰면 read-only 조회는 빠르게 유지하고, 외부 전송이나 상태 변경만 승인 대상으로 남길 수 있다. 오전에 발행한 session.tools와 response.tools 분리 글이 세션 노출 범위를 설명했다면, 이번 구간은 승인 범위를 따로 자르는 레이어라고 보면 된다.
승인 응답은 conversation item으로 다시 보내는 편이 가장 명확하다. 실제 구현에서는 approval item id와 approve 또는 reject 결과가 짝이 맞아야 하므로, 프론트엔드와 서버가 같은 필드를 기준으로 움직이게 만들어야 한다.
이 예시처럼 request item id를 명시하지 않으면 나중에 어떤 승인 요청에 대한 응답인지 로그에서 분리하기 어려워진다. 팀 정책 글인 post 41에서 말한 감사 로그 기준도 결국 이 상관관계를 남길 수 있느냐에 달려 있다.
승인 처리의 핵심은 이벤트 순서를 고정하는 것이다. 음성 세션에서는 모델 응답, approval request, 사용자 확인, approval response, 실제 tool 실행이 서로 다른 레이어에서 벌어지므로 순서가 흔들리면 중복 실행이나 미실행 둘 다 생긴다.
특히
mcp_approval_request가 온 뒤 사용자가 침묵하거나 연결이 끊겼을 때 어떤 timeout으로 세션을 닫을지 미리 정해 두는 편이 좋다. 그렇지 않으면 pending approval만 쌓이고 실제 작업은 하나도 끝나지 않는다.마지막 자료는 운영 로그 예시다. 세션 id, approval request id, 사용자 결정, 실제 tool 실행 id를 한 줄 메모로 남기면 나중에 음성 재생 없이도 장애를 좁힐 수 있다.
이 정도 로그가 있어야 '승인을 받았는데 실행이 안 됐다'와 '승인 전에 실행됐다'를 구분할 수 있다. post 37의 allowed_tools 축과 합치면, 어떤 tool이 들어왔고 왜 승인되었는지까지 설명할 수 있다.
5. 주의사항과 리스크
첫 번째 리스크는 approval request가 왔는데도 사용자에게 아무 신호를 주지 않는 것이다. 두 번째 리스크는
require_approval을 너무 넓게 잡아 모든 조회가 멈추게 만들거나, 반대로 너무 좁게 잡아 write 작업이 무심코 통과하게 만드는 것이다. 세 번째 리스크는 request id와 tool 실행 id를 분리 저장해 감사 로그에서 어떤 승인이 어떤 실행으로 이어졌는지 설명하지 못하는 것이다.운영 전에는 최소한 approve, reject, timeout, disconnect 네 가지 케이스를 각각 재현해 보는 편이 좋다. 특히 timeout과 disconnect를 안 만들면 approval pending이 무기한 남고, 다음 턴의 도구 호출 해석까지 꼬일 수 있다.
- approval request는 사용자 확인 단계와 로그 저장 단계를 함께 가진다.
require_approval은 전체 on/off보다 read-only 또는 tool 이름 필터가 실용적이다.- request id와 tool 실행 결과를 같은 trace로 남겨야 운영 감사가 된다.
6. 결론
Realtime MCP approval 흐름을 안정적으로 운영하려면
mcp_approval_request를 conversation item으로 받아 처리하고,mcp_approval_response를 별도 이벤트로 되돌리는 구조를 분명히 가져가야 한다. 여기에require_approval필터를 read-only와 write 도구 기준으로 자르면, 음성 세션에서도 조회 속도와 변경 통제를 같이 가져갈 수 있다.- approval은 로그 문자열이 아니라 세션 제어 이벤트로 본다.
- request id와 응답 id를 맞춰야 승인 결과가 재현된다.
- read-only와 write 도구를 같은 승인 정책에 넣지 않는다.
7. 참고 링크
'기타개발지식 > 풀스택개발' 카테고리의 다른 글