무엇인가
MCP(Model Context Protocol)는 언어 모델 앱이 외부 도구와 데이터에 붙는 방법을 하나로 정한 공개 규격입니다. Anthropic이 2024년 11월 오픈소스로 공개했고, 2025년 12월 리눅스 재단 산하 에이전틱 AI 재단(AAIF)에 기증했습니다. Anthropic·Block·OpenAI가 공동 창립사입니다.
규격이 없을 때는 모델 N개와 도구 M개를 잇는 연동 코드가 N×M개 필요했습니다. MCP가 있으면 도구 쪽은 MCP 서버 하나, 앱 쪽은 MCP 클라이언트 하나만 만들면 되므로 N+M개로 줄어듭니다. 흔히 'AI 세계의 USB-C'라고 부르는 이유입니다.
2026년 7월 28일 개정판은 출시 이후 가장 큰 변화입니다. initialize 핸드셰이크와 Mcp-Session-Id 헤더가 사라졌고, 서버가 클라이언트에게 먼저 요청을 보내던 방식도 없어졌습니다. 요청 하나하나가 스스로를 설명하므로, 로드밸런서 뒤의 어느 인스턴스가 받아도 처리할 수 있습니다.
어떻게 동작하나
구성은 세 층입니다. 사용자가 쓰는 앱이 호스트(Claude Desktop, Cursor 등), 호스트 안에서 서버 하나와 1:1로 통신하는 것이 클라이언트, 실제 도구·데이터를 가진 프로그램이 서버입니다. 서버는 세 가지를 내놓습니다 — 모델이 호출하는 도구(tools), 읽기 전용 리소스(resources), 미리 만든 작업 템플릿인 프롬프트(prompts). 메시지는 JSON-RPC 2.0이고, 통로는 로컬 하위 프로세스를 띄우는 stdio와 원격용 Streamable HTTP 두 가지입니다.
2026-07-28 개정에서 무엇이 바뀌었는지는 아래 표가 요약합니다.
| 항목 | 2025-11-25까지 | 2026-07-28 |
|---|---|---|
| 연결 시작 | initialize → 응답 → notifications/initialized | 핸드셰이크 없음. 매 요청의 _meta에 프로토콜 버전·클라이언트 기능을 싣는다. 서버 정보는 server/discover로 조회 |
| 상태 | Mcp-Session-Id 헤더로 세션 유지 | 세션 없음. 상태가 필요하면 서버가 발급한 핸들(basket_id 같은 문자열)을 도구 인자로 주고받는다 |
| 라우팅 | 게이트웨이가 JSON 본문을 열어 봐야 했다 | 필수 헤더 Mcp-Method·Mcp-Name. 스키마에 x-mcp-header를 단 인자는 Mcp-Param-* 헤더로 복사된다 |
| 서버가 되묻기 | 열린 스트림으로 서버가 요청을 밀어 넣었다 | MRTR — 서버가 질문을 결과로 돌려주고 클라이언트가 답을 붙여 원 요청을 다시 보낸다 |
| 목록 캐시 | 세션마다 tools/list가 달라질 수 있어 캐시 불가 | 목록이 연결과 무관. 결과에 ttlMs·cacheScope |
| 변경 알림 | HTTP GET 스트림, resources/subscribe | subscriptions/listen 요청 하나가 긴 스트림을 연다. Last-Event-ID 재개는 삭제 |
세션을 없앤 이유는 확장성만이 아닙니다. SEP-2567의 진단은 세션이 클라이언트마다 다른 뜻이었다는 것입니다. ChatGPT는 도구 호출마다 세션을 새로 만들었고, 데스크톱 클라이언트는 앱 실행 동안 하나를 유지했고, 웹 클라이언트는 페이지를 새로 고칠 때마다 잃었습니다. 로컬에서 잘 되던 상태 유지는 프로토콜이 아니라 stdio 프로세스 수명 덕분이었습니다.
MRTR(Multi Round-Trip Requests)의 흐름은 이렇습니다.
tools/call을 보낸다.resultType: "input_required"인 결과를 돌려준다. inputRequests에 묻고 싶은 것을, requestState에 지금까지의 진행을 봉인해 담는다.inputResponses와 봉인을 붙여 다시 보낸다. 서버는 아무것도 기억하지 않았으므로 어느 인스턴스든 이어받는다.빠른 시작
Python 공식 SDK(mcp)는 2.x에서 고수준 서버 클래스 이름을 FastMCP에서 MCPServer로 바꿨습니다. 아래는 코어닷투데이 튜토리얼의 메모 서버를 현재 API로 옮긴 것입니다.
pip install "mcp[cli]"
from mcp.server import MCPServer
mcp = MCPServer("MemoServer")
memos: dict[str, str] = {}
@mcp.tool()
def save_memo(title: str, content: str) -> str:
"""메모를 저장합니다."""
memos[title] = content
return f"메모 '{title}'이 저장되었습니다."
@mcp.tool()
def search_memo(keyword: str) -> str:
"""키워드로 메모를 검색합니다."""
hits = [f"- {k}: {v}" for k, v in memos.items() if keyword in k or keyword in v]
return "\n".join(hits) or "일치하는 메모가 없습니다."
@mcp.resource("memo://list")
def list_memos() -> str:
"""저장된 모든 메모 제목."""
return "\n".join(f"- {t}" for t in memos) or "저장된 메모가 없습니다."
if __name__ == "__main__":
mcp.run() # 인자가 없으면 stdio
타입 힌트가 곧 입력 스키마이고, docstring이 도구 설명이 됩니다. uv run mcp dev server.py로 MCP Inspector에서 바로 호출해 볼 수 있고, 원격 배포는 mcp.run(transport="streamable-http")처럼 전송 방식을 run()에 넘깁니다. 같은 서버가 2025년식 클라이언트의 initialize와 2026년식 요청을 함께 받습니다.
TypeScript는 v2에서 패키지가 나뉘었습니다. 서버는 npm install @modelcontextprotocol/server로 설치하고 server.registerTool(이름, { description, inputSchema }, 핸들러)로 도구를 등록합니다.
언제 쓰고, 언제 피하나
| 상황 | MCP가 잘 맞는다 | 다른 방법을 먼저 본다 |
|---|---|---|
| 연결 대상 | 같은 도구를 여러 호스트(Claude, ChatGPT, IDE)에 붙인다 | 앱 하나·모델 하나에서만 쓰는 함수 몇 개 |
| 통신 상대 | 에이전트 ↔ 도구·데이터 | 에이전트 ↔ 에이전트 협업 — A2A가 그 층을 맡는다 |
| 통제 | 셸을 통째로 주기보다 감사 가능한 도구 경계가 필요하다 | 도구 설명·인자를 모델 문맥에 넣는 것 자체가 위험한 환경 |
| 상태 | 상태가 없거나 ID로 표현된다(이슈 번호, PR 번호) | 연결마다 서버 메모리에 상태를 쥐고 있어야 한다 — 핸들 설계로 바꿔야 함 |
이미 있는 서버라면 대부분 할 일이 적습니다. SEP-2567이 오픈소스 서버 1,000개를 무작위로 조사했더니 90.0%는 세션 ID를 아예 참조하지 않았고, 6.3%는 SDK 보일러플레이트뿐이었습니다. 손이 가는 쪽은 세션에 애플리케이션 상태를 둔 2.5%, 게이트웨이 스티키 라우팅 0.7%, 인증 정보를 세션에 묶은 0.5%입니다.
한계와 주의
- 두 시대가 한동안 공존한다. Python SDK 문서는 아직 대부분의 클라이언트가 2025년식이라고 적었다. 그 클라이언트들은 여전히 세션을 열므로 기존 스티키 라우팅을 바로 걷어내면 안 된다.
requestState는 공격자가 조작할 수 있는 입력이다. 인가나 비즈니스 로직에 영향을 주면 HMAC·AEAD로 무결성을 지키고 인증 주체·짧은 만료·원 요청 식별자를 넣어야 한다. 그래도 1회용은 보장되지 않는다. Python SDK는 봉인 키를 프로세스마다 만들므로, 여러 대로 늘릴 때는RequestStateSecurity(keys=[...])로 키를 공유한다.- 핸들은 공짜가 아니다. 모델이 ID를 계속 들고 다녀야 해 토큰을 쓰고, SEP도 컨텍스트 압축이 어려워지는 경우를 인정한다.
- 폐기 예고된 기능이 있다. 샘플링·루트·로깅은 최소 12개월 유예 뒤 제거 대상이고,
ping은 이미 삭제됐다. 동적 클라이언트 등록(DCR)은 CIMD로, 실험적 태스크는 공식 확장으로 옮겨 가며tasks/list가 사라졌다. - 3월 튜토리얼과 지금 SDK는 다르다. 당시 Python 예제는 공식 SDK가 아니라 별도 프로젝트인
fastmcp패키지를, TypeScript 예제는 v1(@modelcontextprotocol/sdk의server.tool())을 썼다. 위 빠른 시작은 공식 SDK 2.x 기준이다. v1 TypeScript SDK는 v2 출시(2026-07-27) 뒤 최소 6개월 동안 버그·보안 수정을 받는다. - 표준이 되자 공급망이 됐다. 도구 설명에 지시문을 숨기는 도구 설명 오염(2025년 4월 Invariant Labs 시연), 이메일을 몰래 BCC로 빼돌린 악성 서버 postmark-mcp(2025년 9월)가 있었다. 모르는 서버는 설치 전에 코드와 도구 설명을 읽는다.
- SDK 대응에 격차가 있다. Tier 1(TypeScript·Python·Go·C#)은 발표 당일 새 명세를 지원했지만 Rust는 베타, Java는 Tier 2라 기한이 더 길다.
- 명세 저장소 라이선스는 MIT에서 Apache-2.0으로 넘어가는 중이다. 새 기여는 Apache-2.0, 명세가 아닌 문서는 CC-BY-4.0이고, 재허락을 받지 못한 기존 기여는 MIT로 남는다.





