
MCP 앱에 WebSocket 기반 실시간 스트리밍을 추가하는 방법
요약
Goose 오픈 소스 AI Agent 환경에서 MCP 앱에 WebSocket을 활용하여 실시간 데이터 스트리밍을 구현하는 방법을 다룹니다. 기존 폴링 방식의 지연 시간 문제를 해결하기 위해 connectedDomains를 사용하여 백엔드에서 UI로 데이터를 직접 푸시하는 푸시 모델 구축 과정을 설명합니다.
핵심 포인트
- 폴링 방식의 지연 시간 및 오버헤드 문제 분석
- WebSocket을 이용한 실시간 데이터 푸시 모델 구현
- MCP 앱의 connectedDomains를 활용한 실시간 스트리밍
- Sales Dashboard를 위한 라이브 KPI 및 트랜잭션 피드 업데이트
요약 (TL;DR): Goose 오픈 소스 AI Agent에서 WebSocket과 connectedDomains를 사용하여 폴링 (Polling) 방식에서 벗어나 Sales Dashboard MCP 앱으로 라이브 데이터를 직접 푸시하는 방법을 배워보세요.
이 기사를 위한 코드 저장소 - 여기
이 기사는 MCP 앱에 관한 저의 시리즈 기사 중 일부입니다:
- MCP 앱의 기초 (The Foundations of MCP Apps)
- Sales Analytics Agentic UI 기반 MCP 앱 구축 및 Amazon Bedrock AgentCore 배포 (Building MCP Apps based Sales Analytics Agentic UI & deploying it on Amazon Bedrock AgentCore)
- MCP 앱에 WebSocket 기반 실시간 스트리밍 추가하기 (본 기사)
이전 기사에서 우리는 MCP 앱을 사용하여 완전한 영업 분석 채팅 흐름 (Chatflow)을 구축했습니다. 대화형 양식, 차트 시각화, PDF 보고서가 모두 AI Agent 채팅창 내에서 렌더링되었습니다. 전체 채팅 흐름은 요청-응답 (Request-Response) 패턴에 의존했습니다: MCP 앱이 도구 (Tool)를 호출하면, 서버가 데이터를 반환하고, UI가 이를 렌더링하는 방식입니다.
하지만 **라이브 데이터 (Live Data)**가 필요한 경우에는 어떻게 될까요? 실시간 KPI, 라이브 트랜잭션 피드, 그리고 새로운 판매가 발생함에 따라 변하는 주(State) 단위 순위를 보여주기 위해 몇 초마다 업데이트되는 대시보드가 필요하다면 말입니다.
가장 단순한 접근 방식은 폴링 (Polling)입니다: setInterval을 통해 MCP 도구를 호출하고, 결과를 렌더링하고, 이를 반복하는 것입니다. 매 2초마다, 샌드박스 처리된 iframe은 postMessage JSON-RPC 브릿지를 통해 get-realtime-sales-snapshot으로 tools/call을 실행하게 됩니다:
작동은 했습니다! 하지만 매 왕복 (Round-trip)마다 지연 시간 (Latency)이 추가되며, 호스트는 UI가 직접 받을 수 있는 데이터를 전달하느라 불필요한 작업을 수행하게 됩니다.
우리가 진정으로 원하는 것은 **푸시 모델 (push model)**입니다. 즉, 백엔드에서 데이터가 준비되는 즉시 새로운 데이터를 밀어주는 지속적인 연결(persistent connection)입니다.
그 역할을 바로 connectedDomains가 수행합니다.
MCP Apps CSP에서의 connectedDomains
MCP Apps는 샌드박스 처리된 iframe (sandboxed iframes) 내부에서 실행됩니다. 기본적으로 이들은 외부 네트워크 요청을 보낼 수 없습니다. 즉, fetch, XMLHttpRequest, WebSocket 모두 사용할 수 없습니다. 이는 설계 의도에 따른 것으로, 샌드박스가 앱을 외부 세계로부터 격리하기 때문입니다.
하지만 MCP Apps 명세(spec)는 리소스의 _meta.ui.csp에 선언된 콘텐츠 보안 정책 (CSP, Content Security Policy) 필드를 통해 탈출구(escape hatch)를 제공합니다. Part 1에서는 CDN에서 Chart.js를 로드하기 위해 resourceDomains를 사용했습니다. 이제 우리는 다른 필드를 사용할 것입니다.
resourceDomains— 스크립트, 스타일시트, 이미지 로드를 허용합니다 (CDN 자산에 사용됨)connectedDomains— 외부 연결을 허용합니다:fetch,XMLHttpRequest, 그리고 WebSocket
이것이 바로 우리 MCP App의 실시간 스트리밍을 가능하게 하는 단 한 줄의 설정입니다.
아키텍처 (Architecture)
변경 후 (WebSocket 푸시):
직접 연결되며, 호스트 중계(host relay) 없이 서버가 데이터를 푸시합니다!
MCP App은 여전히 호스트와 ui/initialize 핸드셰이크(handshake)를 수행하지만 (이는 iframe 통합을 위해 필수적입니다), 모든 데이터는 별도의 경량 백엔드로 직접 연결된 WebSocket을 통해 흐릅니다.
1단계: 리소스에 connectedDomains 선언하기
첫 번째 변경 사항은 MCP 서버의 리소스 등록 부분입니다. 대시보드 HTML을 반환할 때, CSP 메타데이터에 connectedDomains를 포함합니다.
// index.ts — 리소스 등록
server.registerResource(
"realtime-sales-dashboard-ui",
...
그 단 하나의 추가 사항 — `connectedDomains: [
function onMetricChange(value) {
currentMetric = value;
resetKpiTraces();
...
더 이상의 callTool은 필요 없습니다. 더 이상의 postMessage 중계도 필요 없습니다. UI가 데이터 소스와 직접 통신합니다.
메시지 프로토콜 (Message Protocol)
WebSocket 통신은 단순한 JSON 프로토콜을 사용합니다:
클라이언트 → 서버 (Upstream):
{ "type": "filter", "metric": "orders", "state": "MH" }
{ "type": "pause" }
{ "type": "resume" }
서버 → 클라이언트 (Downstream):
{
"generatedAt": "2026-06-10T07:00:00Z",
"metric": "orders",
...
실행하기
# 터미널 1: Python WebSocket 서버 시작
pip3 install websockets
python3 ws_server.py
...
우리의 AI 클라이언트로 Goose를 사용해 보겠습니다.
aaif-goose / goose
코드 제안을 넘어 설치, 실행, 편집 및 테스트를 수행하는 오픈 소스 기반의 확장 가능한 AI 에이전트 - 모든 LLM과 함께 사용 가능
🦆 goose가 이동했습니다! 이 프로젝트는
block/goose에서 Linux Foundation의 Agentic AI Foundation (AAIF)로 이동했습니다. 일부 링크와 참조가 아직 업데이트 중입니다 — 전환 기간 동안 양해 부탁드립니다.
goose
코드, 워크플로 및 그 사이의 모든 것을 위한 당신의 네이티브 오픈 소스 AI 에이전트 — 데스크톱 앱, CLI 및 API 제공
goose는 사용자의 머신에서 실행되는 범용 AI 에이전트입니다. 단순히 코드만을 위한 것이 아닙니다 — 연구, 글쓰기, 자동화, 데이터 분석 또는 완수해야 하는 어떤 작업에도 사용할 수 있습니다.
macOS, Linux, Windows를 위한 네이티브 데스크톱 앱을 제공합니다. 터미널 워크플로를 위한 완전한 CLI를 제공합니다. 어디에나 임베딩할 수 있는 API를 제공합니다. 성능과 이식성을 위해 Rust로 구축되었습니다.
goose는 Anthropic, OpenAI, Google, Ollama, OpenRouter, Azure, Bedrock 등 15개 이상의 제공업체(Providers)와 함께 작동합니다. API 키를 사용하거나 ACP를 통해 기존의 Claude, ChatGPT 또는 Gemini 구독을 사용할 수 있습니다. ...를 통해 70개 이상의 확장 기능(Extensions)에 연결하세요.
Goose는 다양한 AI 제공업체를 지원합니다:
우리는 LLM 제공업체(LLM Provider)로 Amazon Bedrock을 사용할 것입니다.
show dashboard 프롬프트를 사용하여 show-realtime-sales-dashboard 도구(Tool)를 실행합니다. 대시보드는 WebSocket을 통해 연결되며, KPI, 차트, 활동 피드가 실시간으로 업데이트되는 것을 볼 수 있습니다. 이때 스파크라인(Sparkline) 추적 데이터가 시간이 지남에 따라 누적됩니다.
이 패턴을 사용해야 하는 경우
모든 MCP 앱에 WebSocket이 필요한 것은 아닙니다. 이전 기사에서 다룬 판매 시각화나 PDF 보고서와 같이 앱이 일회성 데이터 가져오기(Data fetch)를 수행한다면, tools/call 패턴이 더 간단하고 충분합니다.
다음과 같은 경우에는 WebSocket + connectedDomains를 사용하세요:
- 데이터가 빈번하게 변경되는 경우 — 라이브 대시보드, 모니터링, 실시간 피드
- 서버가 푸시 주기 (push cadence)를 제어해야 하는 경우 — 클라이언트가 임의의 간격으로 폴링 (polling)하는 대신, 서버가 업데이트 전송 시점을 결정하기를 원하는 경우
- 호스트 부하를 줄이고 싶은 경우 — MCP 도구 (tools)를 통한 폴링은 호스트가 모든 요청을 중계해야 함을 의미하지만, WebSocket은 이를 우회합니다
- 양방향 통신 (Bidirectional communication)이 필요한 경우 — 클라이언트가 필터 변경, 일시 중지/재개 신호 또는 기타 명령을 데이터 소스로 다시 보내야 하는 경우
결론
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기


