기술 · 약 8분 읽기

기술 가이드

OpenAI Tunnel로 사내 MCP를 ChatGPT 커넥터로 연결한 방법

OpenAI Tunnel로 ChatGPT와 사내 MCP를 잇는 연결 일러스트
그림 1. ChatGPT에서 배포 서버의 사내 MCP까지 이어지는 연결 경로 개념도

ChatGPT에서 "최신 블로그 글 목록 보여줘"라고 물었을 때, 회사 블로그 데이터를 직접 읽고 답해주면 좋겠다는 필요가 생깁니다. MCP(Model Context Protocol)는 AI 앱이 외부 도구와 데이터를 표준화된 방식으로 주고받게 하는 프로토콜입니다.[1] 우리는 블로그와 뉴스 콘텐츠를 검색·조회·생성하는 15개 도구를 MCP 서버로 이미 배포해 두었어요. 남은 것은 ChatGPT가 이 서버를 찾아가는 길이었습니다.

이 글은 그 길을 여는 과정에서 실제로 막혔던 지점과 푼 방법을 순서대로 정리합니다. 순서는 이렇습니다. 터널 생성 → 사이트 키 발급 → 터널 클라이언트 실행 위치 결정 → ChatGPT 플러그인 등록 → 연결 확인.

브라우저와 배포 서버 백엔드를 잇는 터널 구성 일러스트

왜 공개 URL을 그냥 쓰지 않았나

가장 단순한 방법은 ChatGPT 커넥터 모달에 공개 주소(https://data-sketchers.com/mcp)를 넣는 것이지만, 이 방법은 두 가지 문제를 만납니다.

첫째, 사내 도구를 인터넷에 그대로 노출하는 문제입니다. 키 인증이 있더라도 엔드포인트 자체가 공개 검색 대상에 들어가고, 공격 표면이 넓어져요. 둘째, 실제로 존재하는 차단 문제입니다. 사이트 앞단의 Cloudflare가 비브라우저 User-Agent(기본 Python·Go HTTP 클라이언트)의 요청을 봇으로 보고 403으로 막습니다. ChatGPT의 터널 클라이언트도 이 규칙의 대상이 되어, 로컬 PC에서 클라이언트를 돌리면 터널이 만들어지지 않았어요.

여기서 선택한 구조가 OpenAI Tunnel입니다. 터널은 배포 서버 안쪽에서 ChatGPT 쪽으로 아웃바운드 연결을 만들고, ChatGPT는 이 터널을 통해 사내 MCP에 접근합니다. 공개 URL 노출 없이, Cloudflare 앞단을 거치지 않고, 배포 서버에서 바로 백엔드로 들어가는 길이 생기는 거죠.

터널 생성부터 커넥터 연결까지 단계 일러스트

1단계: OpenAI 콘솔에서 터널을 만든다

OpenAI 콘솔(platform.openai.com)의 Tunnels 메뉴에서 Create tunnel을 누르고 이름을 붙이면 터널 ID(tunnel_로 시작하는 문자열)가 발급됩니다. 이 ID가 ChatGPT 커넥터와 터널 클라이언트를 잇는 열쇠예요.

ChatGPT 플러그인 디렉터리 화면

2단계: MCP 서버 키를 발급받는다

우리 MCP 서버는 발급된 키(Bearer 토큰)가 붙은 요청만 받습니다. 관리자 엔드포인트에서 키를 발급하면 스코프(읽기·쓰기·미디어 권한)와 유효기간(365일), 요청 속도 제한이 함께 정해집니다. 키 값은 화면에 다시 표시되지 않으므로 발급 시점에 안전한 곳에 저장해야 해요. ChatGPT 쪽 설정이 아니라 터널 클라이언트가 이 키를 붙여서 보내는 구조라, ChatGPT 커넥터 모달의 인증은 "인증 없음"으로 두는 것이 맞습니다.

사용자 지정 MCP 서버 추가 모달에 터널 ID 입력

3단계: 터널 클라이언트는 배포 서버에서 돌린다

처음에는 로컬 Windows PC에서 OpenAI의 tunnel-client를 돌렸습니다. 연결은 만들어지는데 헬스체크가 계속 실패했고, 원인은 앞서 말한 Cloudflare의 봇 차단이었습니다. tunnel-client는 자체 User-Agent를 바꿀 방법이 없어서, 이 규칙을 우회할 수 없었어요.

해법은 실행 위치를 옮기는 것. tunnel-client를 배포 서버에서 systemd user service로 상시 구동하면 Cloudflare 앞단을 아예 거치지 않습니다. 서버 안에서는 백엔드 컨테이너의 사내 주소로 직접 붙고요. 설치 순서는 이렇습니다.

  1. GitHub releases에서 서버용 바이너리(linux amd64)를 받아 ~/tunnel-client/bin/에 둔다.
  2. ~/.config/tunnel-client/<프로필이름>.yaml에 MCP 서버 주소와 인증 헤더(extra_headers: env:CONTENT_MCP_AUTHORIZATION)를 적는다. --profile 인자에는 파일 경로가 아니라 이름만 들어간다는 점을 여기서 배웠어요.
  3. 키·터널 ID를 담은 env 파일을 두고 systemd user service로 등록한다.

서비스 기동 후 127.0.0.1:9080/healthz가 ready를 반환하고, 로그에 mcp session initialized와 mcp channel route resolved가 찍히면 터널이 살아 있는 것입니다.

4단계: ChatGPT 플러그인으로 등록한다

ChatGPT 설정 → 플러그인 → 추가 → "사용자 지정 MCP 서버 추가" 모달에서 이름과 설명을 채우고, 연결 방식 토글을 터널로 바꾼 뒤 터널 ID를 붙여 넣습니다. 인증은 "인증 없음"을 선택해요. 이유는 2단계에서 말한 구조 때문입니다. 키는 터널 클라이언트가 붙이므로 ChatGPT가 별도 인증을 할 필요가 없어요.

플러그인 이름 입력 화면

플러그인 설명 입력 화면

연결 방식 토글에서 터널 선택

모달 입력 완료 화면

등록이 끝나면 플러그인 목록에서 상태를 확인합니다. 초록 점과 "연결됨" 표시가 보이면 ChatGPT가 터널을 통해 사내 MCP에 닿을 수 있는 상태예요.

DataSketchers Content 연결됨 화면

실제로 막혔던 지점 세 가지

Cloudflare 봇 차단은 터널 클라이언트의 실행 위치를 바꿔 해결했습니다. 로컬에서 사이트 앞단을 통과시키려는 시도(User-Agent 우회 포함)는 구조적으로 한계가 있어요. 프로필 경로 오류는 --profile에 파일 경로가 아니라 이름을 넣는 규칙으로 정리됐고, 환경변수 전달은 값에 공백이 있는 Bearer 헤더 때문에 셸 따옴표 문제가 여러 겹 겹쳤습니다. 결국 로컬에서 파일을 base64로 인코딩해 전송한 뒤 원격에서 디코딩하는 방식으로 안전하게 넘겼어요.

ChatGPT 모달 UI 자체도 만만치 않았습니다. 드롭다운 클릭이 모달을 닫아 버려서 여러 번 다시 열었고, 추천 칩을 잘못 클릭해 터널 ID가 다른 터널로 바뀌기도 했어요(화면 자동화로 입력하다 보면 이런 실수가 생깁니다). 터널 ID는 입력 후 화면을 확대해서 한 글자씩 확인하는 게 안전합니다.

연결되면 무엇이 달라지나

ChatGPT 채팅에서 "최신 블로그 글 목록 보여줘", "이 주제로 블로그 초안 만들어줘" 같은 요청이 사내 데이터를 기반으로 동작합니다. 15개 도구가 블로그·뉴스의 조회, 검색, 생성, 예약 확인을 커버하고요. 사내 도구가 인터넷에 노출되지 않으면서 ChatGPT의 자연어 인터페이스에 붙는다는 점이 이 구조의 실익입니다.

같은 구조는 다른 사내 MCP에도 그대로 적용할 수 있어요. 터널을 하나 더 만들고, 배포 서버에 서비스를 하나 더 등록하고, ChatGPT에 커넥터를 추가하면 됩니다. 내부 지식·문서 시스템을 ChatGPT에 연결할 때 같은 절차를 반복하면 됩니다.

참고자료

[1] Model Context Protocol · Introducing MCP

https://modelcontextprotocol.io/

MCP의 개념과 AI 앱이 도구·데이터를 연결하는 표준 방식

[2] OpenAI Docs · MCP

https://platform.openai.com/docs/mcp

ChatGPT 커넥터와 MCP 서버 연결 방식, 원격 서버 요구사항

자료 확인: 2026-10-10. 본문의 스크린샷 중 터널 ID가 보이는 부분은 흐림 처리했고, 서버 주소·키 값은 본문에 적지 않았습니다.


시리즈 이어 읽기

이전 글: 식품 규정과 내부 기준을 위한 RAG 설계에서 자주 놓치는 6가지

#MCP#OpenAI#Tunnel#ChatGPT#인프라