이 장의 목표는 Apps SDK 예제 프로젝트를 한 번 끝까지 실행해 보는 것입니다. 처음 세팅은 조금 번거롭지만, 한 번 제대로 준비해 두면 이후 장에서 도구, JSON Schema, 위젯 UI, window.openai 브릿지를 빠르게 반복 실습할 수 있습니다.
Apps SDK 개발 환경은 일반적인 React 웹앱 하나를 띄우는 구조와 다릅니다. 보통 세 가지가 동시에 움직입니다.
위젯 UI를 빌드한 정적 자산 서버
도구와 컴포넌트를 노출하는 MCP 서버
그 MCP 서버를 호출하는 ChatGPT 개발자 환경
이 구조를 머릿속에 넣고 시작하면 에러가 나도 어디를 봐야 할지 빨리 알 수 있습니다.

필요한 도구부터 준비하기
공식 예제 저장소를 실행하려면 기본적으로 다음이 필요합니다.1
| 도구 | 권장 버전 | 쓰임 |
|---|---|---|
| Node.js | 18 이상 | 예제 위젯 빌드, Node MCP 서버 실행 |
| pnpm | 권장 패키지 매니저 | 워크스페이스 의존성 설치와 스크립트 실행 |
| Python | 3.10 이상 | Python MCP 서버 실행 |
| Git | 최신 안정 버전 | 예제 저장소 클론 |
| ChatGPT 개발자 모드 | 활성화 필요 | 로컬 MCP 서버를 ChatGPT에 연결 |
| ngrok 같은 터널링 도구 | 선택이지만 권장 | 로컬 MCP 서버를 공개 HTTPS 주소로 노출 |
Node.js는 LTS 버전을 설치하는 편이 안전합니다. 설치 후 터미널에서 다음처럼 확인합니다.
node -v
pnpm -v
python --versionpnpm이 없다면 Node.js의 Corepack을 사용할 수 있습니다.
corepack enable
corepack prepare pnpm@latest --activatePython 서버를 실행할 예정이라면 가상환경 사용에 익숙해지는 것이 좋습니다. 가상환경은 프로젝트마다 Python 패키지를 분리해 주는 폴더입니다. 한 프로젝트의 의존성이 다른 프로젝트를 망가뜨리는 일을 줄여 줍니다.
예제의 UI는 React 기반 컴포넌트로 구성되어 있고, 빌드 과정에서 스타일과 함께 독립 실행 가능한 HTML, JavaScript, CSS 자산으로 묶입니다. 공식 저장소는 Vite 기반 빌드 스크립트를 통해 assets/ 폴더에 버전이 붙은 정적 파일을 생성합니다.1 즉, 이 장에서 React 앱을 새로 만들 필요는 없습니다. 저장소 안에 이미 준비된 위젯을 빌드해서 사용합니다.
예제 저장소 클론과 의존성 설치
먼저 공식 예제 저장소를 내려받습니다.
git clone https://github.com/openai/openai-apps-sdk-examples.git
cd openai-apps-sdk-examples
pnpm install공식 README에는 포맷팅 도구를 위한 pre-commit install도 안내되어 있습니다.1 코드를 수정해 기여하거나 팀 프로젝트로 확장할 계획이라면 설치해 두면 좋습니다.
pre-commit install실습만 할 때는 필수는 아닙니다. 핵심은 pnpm install이 루트 워크스페이스 의존성을 제대로 설치하는 것입니다. 중간에 실패하면 Node 버전, pnpm 버전, 회사 프록시나 방화벽 설정을 먼저 확인합니다.
UI 위젯 빌드와 정적 서버 실행
Apps SDK 예제의 위젯은 MCP 서버 코드 안에 그대로 들어 있는 것이 아닙니다. 먼저 UI 컴포넌트를 빌드해서 assets/ 폴더에 정적 파일로 만들어야 합니다.
pnpm run build이 명령은 여러 위젯 엔트리포인트를 빌드하고, 결과물을 assets/에 생성합니다. 그다음 정적 파일 서버를 띄웁니다.
pnpm run serve공식 예제에서는 이 정적 자산 서버가 http://localhost:4444에서 실행됩니다.1 대부분의 MCP 서버는 이 서버에서 위젯 HTML, JS, CSS를 가져오는 것을 전제로 합니다. 따라서 MCP 서버만 실행하고 pnpm run serve를 빼먹으면 도구 호출은 되는데 UI가 비어 보일 수 있습니다.
실습 중에는 터미널을 최소 두 개 열어 두는 편이 좋습니다.
터미널 1: pnpm run serve # assets 정적 서버, 보통 4444 포트
터미널 2: MCP 서버 실행 # 보통 8000 포트
터미널 3: ngrok http 8000 # ChatGPT 연결이 필요할 때개발 중 UI만 빠르게 수정해 보고 싶다면 pnpm run dev로 Vite 개발 서버를 사용할 수도 있습니다. 하지만 ChatGPT와 연결하는 표준 흐름을 확인할 때는 pnpm run build 후 pnpm run serve를 기준으로 잡는 것이 좋습니다.
첫 실행은 Pizzaz Node 서버로 시작하기
가장 먼저 실행해 볼 예제는 Pizzaz입니다. 피자 목록, 캐러셀, 지도, 쇼핑 흐름 같은 여러 UI 패턴을 보여 주기 때문에 Apps SDK의 감을 잡기에 좋습니다.
정적 서버가 이미 켜져 있다는 전제에서 새 터미널을 열고 다음을 실행합니다.
cd pizzaz_server_node
pnpm start서버가 정상적으로 실행되면 보통 로컬 8000 포트에서 MCP 엔드포인트가 열립니다. 여기서 중요한 점은 Pizzaz Node 서버가 단순한 웹 서버가 아니라 MCP 서버라는 것입니다. 이 서버는 ChatGPT에 도구 목록을 알려 주고, 도구가 호출되면 결과와 위젯 리소스 정보를 반환합니다.
흐름을 단순화하면 다음과 같습니다.
ChatGPT
→ MCP 서버에 도구 목록 요청
→ 사용자의 말에 맞는 도구 호출
→ MCP 서버가 structuredContent와 UI 메타데이터 반환
→ ChatGPT가 위젯 iframe 렌더링앞 장에서 본 원칙을 그대로 확인하는 단계입니다. 모델은 판단하고, MCP 서버는 실행하고, 위젯은 보여줍니다.
Python 예제 서버 실행하기
공식 예제 저장소는 Node 서버뿐 아니라 Python 서버도 제공합니다. Python 예제를 실행할 때는 가상환경을 만든 뒤 필요한 패키지를 설치합니다.
macOS나 Linux에서는 다음 흐름을 사용합니다.
python -m venv .venv
source .venv/bin/activate
pip install -r pizzaz_server_python/requirements.txt
uvicorn pizzaz_server_python.main:app --port 8000Windows PowerShell에서는 활성화 명령이 다릅니다.
python -m venv .venv
.venvScriptsActivate.ps1
pip install -r pizzaz_server_python/requirements.txt
uvicorn pizzaz_server_python.main:app --port 8000다른 Python 예제도 구조는 비슷합니다.
| 예제 | 실행 목적 | 대표 명령 |
|---|---|---|
| Pizzaz Python | Pizzaz 위젯을 Python MCP 서버로 제공 | uvicorn pizzaz_server_python.main:app --port 8000 |
| Solar System | 3D 태양계 위젯 제공 | uvicorn solar-system_server_python.main:app --port 8000 |
| Kitchen Sink Python | window.openai 흐름 확인 | uvicorn kitchen_sink_server_python.main:app --port 8000 |
| Shopping Cart | 장바구니 상태 동기화 확인 | uvicorn shopping_cart_python.main:app --port 8000 |
Python Pizzaz 서버는 위젯 HTML을 캐시할 수 있습니다. 공식 README는 assets/를 다시 빌드하거나 수동으로 수정했다면 Python MCP 서버를 재시작하라고 안내합니다.1 UI를 바꿨는데 ChatGPT에 예전 화면이 계속 보이면 정적 서버와 MCP 서버를 모두 재시작해 보세요.
예제별로 무엇을 보면 좋은가
처음부터 모든 코드를 깊게 읽을 필요는 없습니다. 예제마다 확인할 포인트만 잡으면 됩니다.
Pizzaz는 가장 넓은 UI 패턴을 보여 줍니다. 목록, 캐러셀, 지도, 쇼핑 흐름처럼 실제 앱에서 자주 쓰는 화면을 확인할 수 있습니다. 나중에 상품 추천, 매장 검색, 예약 앱을 만들 때 참고하기 좋습니다.
Kitchen Sink는 작지만 중요합니다. 이 예제는 window.openai 브릿지의 여러 기능을 한꺼번에 보여 줍니다. 호스트 상태를 읽고, setWidgetState로 위젯 상태를 저장하고, 위젯에서 다시 도구를 호출하고, 표시 모드 변경이나 외부 링크 열기 같은 호스트 기능을 사용합니다.1 뒤의 window.openai 장에서 다시 자세히 다룹니다.
Solar System은 시각화가 강한 앱의 예입니다. 단순 텍스트 답변보다 3D 뷰어가 더 적합한 경우, Apps SDK 위젯이 어떤 가치를 주는지 확인할 수 있습니다.
Shopping Cart는 상태 동기화가 핵심입니다. 사용자가 위젯에서 수량을 바꾸면 그 상태가 다음 도구 호출과 대화 맥락에 반영되어야 합니다. 이 예제는 widgetSessionId와 위젯 상태를 활용해 모델과 UI가 같은 장바구니 상태를 보도록 만드는 방식을 보여 줍니다.1
이 네 가지를 실행해 보면 Apps SDK 앱이 단순한 응답 카드가 아니라, 대화와 서버 실행과 UI 상태가 함께 움직이는 앱이라는 점이 분명해집니다.
ChatGPT 개발자 모드에서 연결하기
로컬 서버가 실행되었다고 해서 ChatGPT가 바로 접근할 수 있는 것은 아닙니다. ChatGPT에서 테스트하려면 개발자 모드를 켜고 커넥터로 MCP 서버를 등록해야 합니다.
기본 흐름은 다음과 같습니다.
ChatGPT 설정으로 이동합니다.
Connectors또는Apps & Connectors메뉴를 엽니다.개발자 모드를 활성화합니다.
새 커넥터 또는 앱을 추가합니다.
MCP 서버 URL을 입력합니다.
예제에서는 인증 방식을
No authentication으로 선택합니다.새 대화에서
More옵션으로 앱을 대화에 추가합니다.
ChatGPT가 연결할 URL은 보통 MCP 엔드포인트까지 포함해야 합니다. ngrok을 사용했다면 다음과 같은 형태가 됩니다.
https://your-endpoint.ngrok-free.app/mcp등록 후 새 대화에서 Pizzaz 앱을 선택하고 다음처럼 물어봅니다.
What are the best pizzas in town?도구가 정상적으로 발견되고 호출되면 ChatGPT 응답과 함께 위젯 UI가 표시됩니다. 만약 앱이 보이지 않거나 도구가 호출되지 않는다면 URL 끝의 /mcp, 터널 실행 상태, MCP 서버 로그를 먼저 확인합니다.
ngrok으로 로컬 MCP 서버 노출하기
ChatGPT가 로컬 PC의 localhost:8000에 직접 접근할 수 없는 환경에서는 터널링 도구가 필요합니다. 가장 흔한 선택은 ngrok입니다.
MCP 서버가 8000 포트에서 실행 중이라면 다음을 실행합니다.
ngrok http 8000ngrok은 공개 HTTPS 주소를 발급합니다. 이 주소 뒤에 /mcp를 붙여 ChatGPT 커넥터에 등록합니다.
https://your-endpoint.ngrok-free.app/mcpPython MCP 서버를 터널링할 때는 추가로 주의할 점이 있습니다. 공식 예제 README는 Python MCP SDK가 DNS rebinding 보호를 적용하므로, 터널 도메인을 허용 목록에 넣고 서버를 시작하라고 안내합니다.1
export MCP_ALLOWED_HOSTS=your-endpoint.ngrok-free.app
export MCP_ALLOWED_ORIGINS=https://your-endpoint.ngrok-free.app
uvicorn pizzaz_server_python.main:app --port 8000이 환경 변수는 서버를 시작하기 전에 설정해야 합니다. 이미 서버를 켠 뒤에 설정했다면 서버를 종료하고 다시 시작합니다. 이 값을 잘못 설정하면 브라우저나 ChatGPT 쪽에서는 연결이 되는 것처럼 보여도 서버가 호스트나 오리진 검증 단계에서 요청을 거부할 수 있습니다.
Node 예제와 Python 예제를 번갈아 실행할 때는 같은 8000 포트를 동시에 사용할 수 없습니다. 하나를 종료한 뒤 다른 서버를 실행하거나, 포트를 바꾸고 ngrok 명령도 함께 바꿔야 합니다.
Chrome 142 이상에서 UI가 안 보일 때
서버 로그는 정상이고 도구 호출도 된 것 같은데 위젯 UI만 비어 있다면 브라우저 보안 정책을 확인해야 합니다. 공식 예제 저장소는 Chrome 142 이상에서 로컬 네트워크 접근 검사 때문에 위젯 UI가 보이지 않을 수 있으며, 로컬 개발 중에는 관련 플래그를 비활성화해야 할 수 있다고 안내합니다.1
확인 순서는 다음과 같습니다.
Chrome 주소창에
chrome://flags/를 입력합니다.#local-network-access-check또는 Local Network Access 관련 항목을 찾습니다.값을
Disabled로 변경합니다.Chrome을 완전히 재시작합니다.
이 설정은 로컬 개발 편의를 위한 우회입니다. 보안 정책을 무시해도 된다는 뜻이 아닙니다. 운영 환경에서는 위젯 자산과 MCP 서버를 공개 HTTPS 도메인에서 안정적으로 제공하고, CORS와 CSP를 명확히 설정해야 합니다.
자주 막히는 지점 점검표
예제 실행 중 문제가 생기면 아래 순서대로 확인합니다.
| 증상 | 먼저 볼 곳 |
|---|---|
pnpm install 실패 | Node 18 이상인지, pnpm이 활성화됐는지 확인 |
| MCP 서버가 시작되지 않음 | 8000 포트 충돌, 의존성 설치 누락 확인 |
| 도구는 호출되는데 UI가 안 뜸 | pnpm run build, pnpm run serve, 4444 포트 확인 |
| ChatGPT에서 커넥터 등록 실패 | 공개 HTTPS URL인지, /mcp까지 입력했는지 확인 |
| Python 서버가 터널 요청을 거부 | MCP_ALLOWED_HOSTS, MCP_ALLOWED_ORIGINS 설정 확인 |
| Chrome에서 위젯이 빈 화면 | local network access 플래그와 브라우저 재시작 확인 |
| UI 수정이 반영되지 않음 | 다시 빌드 후 정적 서버와 MCP 서버 재시작 |
Apps SDK 실습은 처음에 실행 프로세스가 많아 보입니다. 하지만 실제로는 정적 자산 서버, MCP 서버, ChatGPT 연결이라는 세 축만 기억하면 됩니다.
다음 장을 위한 기준 상태
이 장을 마쳤다면 다음 상태가 되어야 합니다.
공식 예제 저장소가 로컬에 클론되어 있다.
pnpm install이 완료되어 있다.pnpm run build로assets/가 생성된다.pnpm run serve로 위젯 자산 서버가 실행된다.Pizzaz, Kitchen Sink, Solar System, Shopping Cart 중 하나 이상의 MCP 서버를 실행해 보았다.
ngrok URL을 ChatGPT 개발자 모드 커넥터에 등록해 도구 호출을 확인했다.
UI가 안 보일 때 브라우저 보안 정책과 정적 서버 상태를 점검할 수 있다.
여기까지가 Apps SDK 개발의 반복 가능한 기본 환경입니다. 다음 장에서는 이 기반 위에서 첫 번째 ChatGPT 앱을 직접 만들며, 도구 등록과 위젯 연결을 더 작은 단위로 분해해 보겠습니다.
참고
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.