원본 영상 보기

짧은 답: 모델에는 데이터를 주고, 렌더링은 별도 단계로

MCP 서버를 운영하면서 결과를 Claude나 ChatGPT 안에서 일반 텍스트가 아닌 실제 인터페이스로 보여 주고 싶다고 해 봅시다. 캐러셀 하나를 보여 주고 멈추는 대신, 모델이 그 결과를 보고 추론하며 계속 검색하도록 하려면 어떻게 해야 할까요? 먼저 용어 몇 가지를 정리합니다. MCP(Model Context Protocol)는 AI 채팅 클라이언트가 외부 도구를 호출하는 방식입니다. MCP 서버는 그런 도구를 제공하는 서비스입니다. MCP Apps와 ChatGPT용 OpenAI Apps SDK를 쓰면 도구가 대화 안에 나타나는 인터랙티브 인터페이스, 즉 위젯을 반환할 수 있습니다.

Indeed의 Dustin Mihalik은 세 가지 규칙으로 답합니다. 첫째, 사용자가 위젯에서 보는 모든 것은 데이터로서 모델에도 전달되어야 합니다. 둘째, 사용자가 위젯에서 하는 모든 행동은 모델에 다시 알려야 합니다. 셋째, 데이터를 가져오는 일과 인터페이스를 그리는 일은 별도의 도구가 맡아야 합니다. 그래야 모델이 작업에 필요한 만큼 검색하고, 무엇을 보여 줄지는 마지막에 고를 수 있습니다. 그는 세 번째 규칙이 나머지 두 규칙보다 우선한다고 말합니다. 모델이 한 번 검색하고 포기하는 문제를 겨냥한 규칙도 세 번째뿐입니다.

그는 이 발표를 AI Engineer 세션에서 했으며, 녹화 영상은 AI Engineer 유튜브 채널에 게시되었습니다. 세션이 언제 열렸는지는 녹화 영상에 나오지 않습니다.

교훈의 출처

Mihalik은 Indeed의 채용 검색 업무와 함께 가드레일, 게이트웨이, 컴플라이언스를 담당하는 AI 플랫폼 팀에서도 일한다고 말합니다. 그에 따르면 이 팀은 AI 벤더들과 이미 관계를 맺고 있었고, 그 덕분에 MCP 커넥터와 MCP 앱을 만들게 되었습니다.

그의 말에 따르면 Indeed는 Claude와 ChatGPT, 그리고 Career Scout용 MCP 서버와 앱을 만들었습니다. Career Scout는 그가 구직자를 위한 Indeed 자체 에이전트라고 설명하는 서비스입니다. 출시 시점이나 제공 여부는 다루지 않습니다. 그는 이 세션을 입문이 아닌 '현장에서 얻은 교훈(lessons from the trenches)'으로 소개하며, 앞선 입문 세션에서 MCP 앱의 기본은 이미 다뤘다고 말합니다.

채용 사이트가 애초에 채팅 안에 UI를 원하는 이유

그는 먼저 오스틴의 바리스타 채용 공고를 검색했을 때 Claude가 내놓은 일반 텍스트 답변을 보여 줍니다. 그는 이 답변이 유용하다고 말합니다. Claude가 시내와 인근 교외 지역의 공고를 묶어서 정리해 주기 때문입니다. 하지만 결과가 Indeed에서 왔다는 표시가 없고, 무엇이 표시될지에 퍼블리셔가 관여할 여지가 거의 없습니다.

더 큰 문제는 링크입니다. Mihalik은 Claude나 ChatGPT가 일관되게 외부 링크를 걸도록 만들기 어렵다고 말합니다. 그는 플랫폼이 사용자를 채팅 안에 머물게 하고 싶어 하기 때문이라고 추측하지만, 이는 그의 추측일 뿐 근거를 보여 주지는 않습니다. 링크 없는 채용 공고 목록은 좋지 않은 경험이라고 그는 말합니다. 그의 팀은 Claude가 안정적으로 링크를 걸게 되기까지, 그의 표현으로는 말도 안 되게 많은 시간과 eval(모델 동작을 자동으로 시험하는 테스트 실행)을 들였습니다. 구체적인 수치는 밝히지 않았습니다.

그의 설명에 따르면 위젯이 이 상황을 바꿉니다. Indeed는 각 결과에 지원 버튼을 달고, 어떤 필드를 위쪽에 보여 줄지 정할 수 있습니다. 또 '상세 보기' 버튼을 추가해 채용 공고 전문을 팝업 창, 즉 모달로 열 수 있으므로 사용자는 채팅을 떠날 필요가 없습니다. 그는 이것이 Indeed와 채팅 플랫폼 모두에 이득이라고 말합니다. 위젯은 화면으로 시연되었으며, 여기 나온 설명은 그가 말로 설명한 내용을 따른 것입니다.

단순 이식의 함정: 위젯이 모델에게 블랙박스가 된다

MCP 앱을 웹사이트를 채팅 안에 그대로 옮겨 넣는 수단으로 여기고 싶은 유혹이 있습니다. 위젯이 HTML을 불러오고, 그 HTML이 사이트에서 이미 쓰는 API를 호출하면 끝이라는 식입니다. Mihalik은 그렇게 쉽지 않다고 말하며, 실제로 바로 이런 식으로 만든 MCP 앱을 본 적이 있다고 합니다.

문제는 모델이 무엇을 아느냐입니다. 모델이 도구를 호출하고 도구가 결과를 화면에 띄우지만, 모델은 그 결과가 무엇인지 전혀 모릅니다. 그러면 '첫 번째 결과에 대해 알려 줘'나 '이 회사들 순위를 매겨 줘' 같은 평범한 후속 요청이 실패합니다. 데이터가 API에서 위젯으로 곧장 갔을 뿐 모델을 거치지 않았기 때문입니다.

규칙 1: 사용자가 보는 것은 모델도 데이터로 받는다

그의 첫 번째 규칙은 인터페이스에 표시되는 모든 정보를 데이터로서 모델에도 제공해야 한다는 것입니다.

그가 설명하는 MCP 및 MCP Apps 스펙에 따르면 도구 응답에는 두 가지가 담깁니다. 첫째는 구조화된 콘텐츠(structured content)로, 모델이 읽는 기계 판독용 결과이며 텍스트 전용 MCP 도구라면 원래 반환했을 내용입니다. 둘째는 리소스 URI로, 채팅 클라이언트가 위젯의 HTML을 불러올 때 쓰는 포인터입니다. 둘 다 반환해야 하며, 그는 둘을 동기화해야 한다고 말합니다. 위젯 뒤의 API에 급여 범위 같은 새 필드가 생기면, 모델이 읽는 구조화된 콘텐츠에도 같은 필드가 추가되어야 합니다. 그렇지 않으면 사용자는 볼 수 있는데 모델은 언급할 수 없는 정보가 생깁니다.

위젯이 이미 보여 주는 내용을 모델이 다시 쓰지 않게 하기

규칙 1에는 부작용이 있습니다. 데이터를 받은 모델은 여느 도구 출력을 다룰 때처럼 결과 목록 전체를 텍스트로 써 내려가는데, 그 목록을 이미 보여 주고 있는 위젯 바로 아래에 씁니다. 사용자는 모든 내용을 두 번 보게 됩니다.

그의 해법은 도구 설명(모델이 도구를 어떻게 쓸지 판단할 때 읽는 텍스트) 맨 앞에 한 줄을 넣는 것입니다. 결과가 UI 컴포넌트로 사용자에게 자동으로 표시되었다는 내용입니다. 그의 말에 따르면 이 줄이 있으면 모델은 짧은 요약만 쓰고 목록은 위젯에 맡깁니다. 그는 인터페이스가 보여 주는 것과 모델이 쓰는 것 사이에 일종의 줄다리기가 있다고 설명하며, 이 한 줄이 '상당히 많은 경우를 해결한다'고 말합니다.

규칙 2: 사용자가 무엇을 클릭했는지 모델에 알린다

위젯이 정보를 가리는 경우는 또 있습니다. 검색 결과로 채용 공고 10개가 나왔고 사용자가 그중 하나의 상세 정보를 열었다고 해 봅시다. 모델은 그것이 어느 공고인지 모릅니다. 그러면 '이 공고에 맞춰 자기소개서를 써 줘'나 '이 직무 설명을 요약해 줘' 같은 요청이 실패합니다. 공고 전문은 위젯에만 로드되었을 뿐 모델에게는 전달되지 않았기 때문입니다.

Mihalik의 규칙은 사용자가 위젯에서 하는 행동에 관한 정보도 모델에 보내야 한다는 것입니다. 그가 '규칙 2'라고 직접 말하지는 않지만, 설명 순서상 두 번째이며 그는 이후 데이터/렌더링 분리를 규칙 3이라고 부릅니다.

그는 MCP Apps가 이를 위한 메서드를 제공한다고 말하며, 이를 update model context라고 부릅니다. 그에 따르면 이 메서드는 문자열 하나만 받기 때문에, 시간에 따라 여러 이벤트를 알리려면 그 문자열 하나에 계속 이어 붙여야 합니다. 그는 MCP Apps 문서에 있다고 설명하는 장바구니 예제를 언급합니다. 이 앱은 장바구니에 담긴 상품과 총액을 모델에 전달하므로, 사용자는 자기 장바구니에 대해 질문할 수 있습니다.

전환점: UI 도구가 다단계 검색을 중간에 끊는다

규칙 1과 2를 적용하면 모델은 무슨 일이 일어나는지 대략 파악할 수 있습니다. 그래도 Mihalik은 앱이 아직 좋지 않다고 말합니다. 사람들이 Claude에게 쉬운 문제를 가져오지 않기 때문입니다. 검색 한 번이면 될 일이라면 웹사이트로 가면 된다고 그는 말합니다. Claude에게는 어려운 문제를 가져온다는 것입니다.

그의 예는 이주도 고려하는 사용자입니다. 이 사용자는 하나의 직무명으로 여러 도시를 검색하고, 가장 급여가 높은 선택지를 골라내고, 특정 업종은 제외하고 싶어 합니다. 그는 일반 텍스트 MCP 검색 도구라면 Claude가 이를 잘 처리한다고 말합니다. 10~15회쯤 검색하고, 결과를 걸러 관련 세부 정보를 뽑아낸 뒤 요약 표로 마무리합니다. 이 횟수는 대략적인 예시일 뿐 벤치마크가 아닙니다.

이제 그 검색 도구가 위젯도 렌더링하게 하고, 도구 설명에 결과가 사용자에게 표시된다고 적어 봅시다. Mihalik은 Claude가 한 번 호출하고 멈춘다고 말합니다. 결과가 이미 화면에 있으니 더 파고들 필요가 없다고 판단하는 것 같다는 것입니다. 그는 현실적인 이유도 덧붙입니다. 캐러셀 열 개가 연달아 나오길 원하는 사람은 없고, Claude도 이미 무언가를 표시했다는 점을 인식하는 것 같다는 것입니다. 결국 경험을 개선하려던 UI가 사용자가 원하던 다단계 작업을 중간에 끊어 버립니다. 그는 이것을 Claude에 한정된, 자기 팀의 관찰 결과로 전합니다.

규칙 3: 데이터 처리와 UI 렌더링을 분리한다

Mihalik의 세 번째 규칙은 데이터 처리와 UI 렌더링을 분리하라는 것이며, 그는 이 규칙이 나머지 두 규칙보다 우선한다고 말합니다. 이 표현은 OpenAI Apps SDK 문서에서 가져온 것이며, 문서 몇 군데에 이 내용이 나온다고 그는 말합니다.

Indeed의 방식은 이렇습니다. 그가 search jobs라고 부르는 도구는 인터페이스 없는 표준 텍스트 전용 MCP 도구가 되며, Claude는 이를 원하는 만큼 호출할 수 있습니다. 별도의 render-jobs 위젯은 채용 공고 ID 목록을 받습니다. Claude는 검색으로 후보 공고를 100개가량 모은 뒤 5개로 걸러 내고, 그 5개의 ID만 렌더링 도구에 넘길 수 있습니다. 그러면 사용자는 모델이 고른 최종 후보가 담긴 위젯 하나를 보게 됩니다. 100개에서 5개라는 수치는 그가 든 예시입니다.

그는 렌더링 도구가 모델이 보여 주려는 데이터 전체를 받을 수도 있고, 그 데이터에 대한 참조를 받을 수도 있다고 말합니다. Indeed는 참조, 즉 ID를 택했습니다. 어느 쪽이든 렌더링 도구의 설명에는 데이터가 어디서 오는지, 어떤 형식이어야 하는지, 그리고 그 데이터를 얻으려면 데이터 도구 중 하나를 먼저 호출해야 한다는 점을 적어야 합니다. 그는 이것이 도구 설명을 꽤 간단히 바꾸는 일이라고 말합니다.

Mihalik이 설명한 두 가지 도구 구성. 동작은 그가 Claude에서 관찰한 내용이며 측정 결과가 아닙니다.
검색과 렌더링을 함께 하는 단일 도구텍스트 검색 도구 + 별도 렌더링 도구
모델의 검색 횟수그의 설명으로는 한 번. 표시된 결과를 완성된 답으로 여깁니다작업에 필요한 만큼. 여러 도시에 걸친 요청에서 10~15회 검색한다고 설명합니다
모델이 볼 수 있는 것규칙 1을 따랐다면 반환된 데이터무엇이든 표시되기 전에 모든 검색 결과를 데이터로 봅니다
사용자가 보는 것단일 쿼리로 만든 위젯모델이 고른 최종 후보가 담긴 위젯 하나(그의 예: 후보 약 100개를 5개로 압축)
렌더링 단계가 받는 것단일 쿼리가 반환한 결과 그대로모델이 고른 채용 공고 ID 목록

다른 분야에서의 같은 분리, 그리고 모델의 추론을 담는 렌더링 도구

Mihalik은 대부분의 업계에서 비슷한 분리 방식을 찾을 수 있다고 말합니다. 모델이 데이터를 탐색하게 한 다음, 무엇을 렌더링할지 고르게 하는 것입니다. 그는 전자상거래 상품 검색 결과와, 모델이 고른 주소 다섯 개를 받는 지도 위젯을 예로 듭니다.

이어 그는 렌더링 도구가 ID 이상을 받을 수 있다고 제안합니다. 텍스트 전용 답변에서 모델은 흔히 각 결과를 고른 이유를 설명한다고 그는 지적합니다. 렌더링 도구가 ID와 함께 그 공고가 적합한 이유를 짧게 받거나, ID와 함께 직무 설명에서 강조할 구절을 받을 수도 있습니다. 그러면 모델의 추론이 별도 문장이 아니라 위젯 안에 나타납니다. 그는 Indeed가 이를 '잠재적으로' 추가할 수 있다고 말하는 데 그치므로, 이는 Indeed가 이미 출시한 기능이 아니라 설계 아이디어입니다.

내 MCP 앱을 위한 설계 체크리스트

Mihalik은 두 가지 요점으로 마무리합니다. 첫째, 인터페이스보다 데이터를 먼저 설계하라는 것입니다. 그는 이것이 MCP 앱을 ChatGPT에 UI를 넣는 수단으로 보는 일반적인 시각과 어긋난다는 점을 인정합니다. 모델이 어떤 데이터를 가져야 하고 그 데이터로 무엇을 할 수 있어야 하는지 정한 다음, 렌더링은 모델이 그 데이터를 탐색한 결과로 따라오게 하라는 것입니다. 둘째, 작고 조합 가능한 도구를 만들라는 것입니다. 그의 예는 채용 공고를 찾는 방식별 검색 도구 두세 개와 렌더링 도구 한두 개입니다. 렌더링 도구는 예컨대 공고 목록용 하나와 공고 하나를 강조해 보여 주는 용도 하나일 수 있습니다. 각 도구에 간단한 설명을 붙이면 모델에 과부하를 주지 않으면서도 어떻게 탐색하고 무엇을 보여 줄지는 모델이 고를 수 있습니다.

그의 조언을 종합하면 개발자를 위한 짧은 체크리스트가 됩니다.

  • 데이터 일치: 위젯이 보여 주는 모든 것은 구조화된 데이터로 모델에도 돌아가야 하며, 둘은 동기화되어야 합니다.
  • 설명을 통한 유도: 도구 설명에 결과가 이미 표시되었다고 적어, 모델이 결과를 반복하지 않고 요약하게 합니다.
  • 상호작용 컨텍스트: 위젯 안에서의 클릭과 선택을 모델에 알려, 후속 요청이 맥락에 맞게 처리되도록 합니다.
  • 데이터/렌더링 분리: 검색은 모델이 여러 번 호출할 수 있는 텍스트 전용 도구로 만들고, 최종 선택만 별도 도구로 렌더링합니다. 이 도구의 설명에는 어떤 데이터 도구를 먼저 호출해야 하는지 적습니다.

아직 입증되지 않은 것

이 내용은 약 15분짜리 발표에서 나온 한 팀의 경험이며, 지표도, eval 결과도, 전후 비교 수치도, 질의응답도 없습니다. Claude가 언제 검색을 멈추는지에 관한 그의 주장은 모델 동작에 대한 관찰입니다. 이는 새 모델에서 달라질 수 있고, 그가 같은 방식으로 설명하지 않은 ChatGPT나 다른 클라이언트에서는 성립하지 않을 수도 있습니다.

스펙 용어, update model context 메서드와 그 단일 문자열 제한, 문서 예제는 모두 그의 설명에서 나온 것입니다. 저희는 이를 MCP Apps나 Apps SDK 문서와 대조하지 않았고, 이 동작을 재현하기 위한 앱도 만들지 않았습니다. 정확한 필드명과 메서드명은 최신 문서에서 확인하고, 이 체크리스트는 검증된 레시피가 아니라 자기 서버에서 시험해 볼 만한, 논리가 탄탄한 출발점으로 받아들이는 것이 좋습니다.

출처

AI Engineer · @aiDotEngineer

함께 본 출처

자료 및 작성 기준

약 15분 분량의 AI Engineer 녹화 영상에 대해 자기소개부터 마무리 발언까지 영어 자동 생성 자막 전체를 읽었습니다. 질의응답은 없습니다. 화면의 슬라이드와 스크린숏은 확인할 수 없었으며, 발표자가 말로 설명한 내용을 통해서만 묘사했습니다. 알아듣기 어려운 자막 조각은 보수적으로 해석하거나 제외했습니다. 공식 MCP, MCP Apps, OpenAI Apps SDK 문서는 참고하지 않았으며, 이 기사를 위해 MCP 앱을 만들거나 테스트하지 않았습니다.