stdio vs HTTP — MCP transport 고르기

MCP·에이전트 만들기 2026-07-15 17:02:23 mcptransport

글 목록 →

앞선 글에서 MCP가 무엇인지, 그리고 Tools·Resources·Prompts라는 세 가지 primitive를 살펴봤다. 그런데 클라이언트와 서버가 실제로 “어떤 통로로” 메시지를 주고받는지는 아직 다루지 않았다. 이 통로를 MCP에서는 transport라고 부른다. 표준으로 정해진 방식은 두 가지, stdio와 HTTP다.

메시지는 어차피 JSON-RPC

transport를 고르기 전에 알아둘 것이 하나 있다. 어떤 통로를 쓰든 오가는 메시지의 형식은 동일하다. MCP는 JSON-RPC 2.0을 쓴다. 도구를 호출하는 요청은 이렇게 생겼다.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": { "name": "get_weather", "arguments": { "city": "Seoul" } }
}

transport는 이 JSON 덩어리를 어디로 흘려보낼지만 결정한다. 그래서 서버 로직을 짤 때 transport를 크게 신경 쓰지 않아도 되고, 나중에 바꾸기도 쉽다.

stdio — 표준 입출력으로 연결

stdio transport는 클라이언트가 서버를 자식 프로세스로 직접 실행한다. 그리고 그 프로세스의 표준 입력(stdin)으로 요청을 써 넣고, 표준 출력(stdout)으로 응답을 읽는다. 우리가 터미널에서 cat 같은 명령에 입력을 파이프로 넘기는 것과 원리가 같다.

클라이언트 ──(stdin)──▶ 서버 프로세스
클라이언트 ◀──(stdout)── 서버 프로세스

여기서 중요한 규칙 하나. 로그를 절대 stdout에 찍으면 안 된다. stdout은 JSON-RPC 메시지 전용 통로라, console.log로 아무거나 출력하면 프로토콜이 깨진다. 디버그 출력은 stderr로 보내야 한다.

// 안 됨 — 프로토콜 채널을 오염시킨다
console.log("서버 시작됨");

// 이렇게 — stderr는 안전하다
console.error("서버 시작됨");

stdio는 네트워크가 필요 없고, 클라이언트와 서버가 같은 기계에서 돈다. Claude Desktop 같은 로컬 앱이 내 컴퓨터의 파일이나 도구에 붙을 때 쓰는 방식이 바로 이것이다. 설정도 단순하다. “이 명령어를 실행해라” 한 줄이면 된다.

HTTP — 원격 서버로 연결

HTTP transport는 서버가 독립적으로 떠 있고, 클라이언트가 네트워크 너머로 요청을 보낸다. 서버를 한 번 배포해두면 여러 사용자가 각자의 클라이언트로 접속할 수 있다.

  • 서버를 클라우드에 올려 팀 전체가 공유하고 싶을 때
  • 서버가 무거운 리소스(DB, 사내 API)에 붙어 있어 한 곳에서 관리하고 싶을 때
  • 인증·권한 제어를 서버 쪽에 두고 싶을 때

대신 stdio에는 없던 고민이 따라온다. 누가 접근할 수 있는지(인증), 어떻게 배포하고 살아있는지 확인할지(운영)를 직접 챙겨야 한다.

무엇을 고를까

stdioHTTP
실행 위치같은 기계, 자식 프로세스원격, 독립 서버
설정명령어 한 줄배포 + 인증
적합한 경우로컬 도구, 개인용공유 서버, 팀·서비스

처음 MCP 서버를 만든다면 stdio로 시작하는 것을 권한다. 배포나 인증 없이 로직에만 집중할 수 있고, 로컬에서 곧바로 붙여 테스트할 수 있다. 서버가 쓸 만해지고 여럿이 공유할 필요가 생기면 그때 HTTP로 옮기면 된다. 메시지 형식은 그대로이니 옮기는 비용도 크지 않다.

댓글

이 글에 대한 의견은 아래 댓글로 남겨주세요 (GitHub 계정 필요). 로그인 없이 남기고 싶다면