MCP 기초 — Primitives, Lifecycle, JSON-RPC Base

MCP 이전의 모든 통합(integration)은 일회성이었습니다. 모델 컨텍스트 프로토콜(Model Context Protocol; MCP)은 2024년 11월에 Anthropic이 처음 공개했고, 지금은 리눅스 재단(Linux Foundation)의 Agentic AI Foundation이 관리하고 있습니다. MCP는 도구의 발견(discovery)과 호출(invocation)을 표준화해서 어떤 클라이언트(client)든 어떤 서버(server)와도 대화할 수 있게 만듭니다. 2025-11-25 사양(spec)은 여섯 가지 기본 요소(primitives, 서버 측 셋·클라이언트 측 셋), 세 단계 생애주기(lifecycle), 그리고 JSON-RPC 2.0 와이어 포맷(wire format)을 정의합니다. 이 세 가지만 익히면, 이 phase의 나머지 MCP 장은 대부분 "그저 읽기만 하면 되는" 내용으로 줄어듭니다.

유형: Learn 언어: Python (표준 라이브러리, JSON-RPC 파서) 선수 지식: Phase 13 · 01~05 (도구 인터페이스와 함수 호출(function calling)) 예상 시간: 약 45분

학습 목표

  • MCP의 여섯 기본 요소(primitive)를 모두 말할 수 있습니다. 서버 측의 도구(tools), 자원(resources), 프롬프트(prompts)와 클라이언트 측의 루트(roots), 샘플링(sampling), 일레시테이션(elicitation)을 각각 하나의 사용 사례(use case)와 함께 설명합니다.
  • 세 단계 생애주기(initialize, operation, shutdown)를 따라가며 각 단계에서 누가 어떤 메시지를 보내는지 말합니다.
  • JSON-RPC 2.0의 요청(request), 응답(response), 알림(notification) 봉투(envelope)를 파싱하고 직접 만들어 봅니다.
  • initialize 단계의 능력 협상(capability negotiation)이 무엇인지, 이것이 없으면 무엇이 깨지는지 설명합니다.

문제

MCP 이전에는 도구를 사용하는 에이전트(tool-using agent)마다 자체적인 프로토콜이 있었습니다. Cursor에는 MCP와 비슷해 보이지만 호환되지는 않는 도구 시스템이 있었습니다. Claude Desktop은 또 다른 방식을 제공했습니다. VS Code의 Copilot 확장(extension)에는 세 번째 방식이 있었습니다. "Postgres 쿼리(query)" 도구를 만드는 팀은 같은 도구를 세 번 작성해야 했고, 매번 각 호스트(host)의 API에 맞춰 다시 만들어야 했습니다. 재사용하려면 코드를 그대로 복사해 옮겨 붙이는 수밖에 없었습니다.

그 결과는 일회성 통합의 캄브리아기 대폭발이었고, 생태계 발전 속도(ecosystem velocity)에는 분명한 천장이 생겼습니다.

MCP는 이 문제를 와이어 포맷을 표준화해서 해결합니다. 하나의 MCP 서버는 모든 MCP 클라이언트에서 그대로 동작합니다. Claude Desktop, ChatGPT, Cursor, VS Code, Gemini, Goose, Zed, Windsurf 등 2026년 4월 기준 300개가 넘는 클라이언트가 있습니다. SDK 월간 다운로드는 1억 1천만 건, 공개 서버는 10,000개를 넘습니다. 리눅스 재단은 2025년 12월에 새로 만들어진 Agentic AI Foundation 아래에서 MCP의 관리(stewardship)를 맡았습니다.

이 phase에서 사용하는 사양 리비전(spec revision)은 2025-11-25입니다. 이 리비전은 비동기 작업(async Tasks; SEP-1686), URL 모드 일레시테이션(URL-mode elicitation; SEP-1036), 도구를 사용하는 샘플링(sampling with tools; SEP-1577), 점진적 범위 동의(incremental scope consent; SEP-835), OAuth 2.1의 자원 표시자 의미 체계(resource-indicator semantics)를 추가했습니다. Phase 13 · 09부터 16까지가 이러한 확장을 다루며, 이 lesson은 그 기반(base)에서 멈춥니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.MCP 기초가 해결하는 핵심 과제는?

2.MCP 기초 이전의 주요 한계는?

0/2 답변 완료

개념

서버 측 세 가지 기본 요소

  1. 도구(Tools). 호출 가능한 행동입니다. Phase 13 · 01에서 본 것과 같은 네 단계 루프(loop)를 그대로 사용합니다.
  2. 자원(Resources). 외부에 노출하는 데이터입니다. URI로 주소를 매길 수 있는 읽기 전용 콘텐츠이며, file:///path, db://query/... 같은 표준 스킴이나 직접 정의한 커스텀 스킴(custom scheme)을 사용할 수 있습니다.
  3. 프롬프트(Prompts). 재사용 가능한 템플릿입니다. 호스트(host) UI에서는 슬래시 명령(slash command)으로 노출되며, 서버가 템플릿을 제공하고 클라이언트가 인자(argument)를 채워 넣습니다.

클라이언트 측 세 가지 기본 요소

  1. 루트(Roots). 서버가 접근해도 되는 URI의 집합입니다. 클라이언트가 선언하고, 서버는 이를 지켜야 합니다.
  2. 샘플링(Sampling). 서버가 클라이언트의 모델에게 텍스트 생성(completion)을 요청합니다. 이 덕분에 서버 쪽에 별도의 API 키 없이도 서버에서 호스팅되는 에이전트 루프(server-hosted agent loop)를 구성할 수 있습니다.
  3. 일레시테이션(Elicitation). 서버가 실행 도중에 클라이언트의 사용자에게 구조화된 입력을 요청합니다. 폼(form)이나 URL 형태(SEP-1036)가 될 수 있습니다.

MCP의 모든 능력(capability)은 이 여섯 가지 중 정확히 하나에 속합니다. Phase 13 · 10부터 14까지가 각각을 깊이 있게 다룹니다.

와이어 포맷: JSON-RPC 2.0

모든 메시지는 다음 필드를 가진 JSON 객체(JSON object)입니다.

  • 요청(Requests): {jsonrpc: "2.0", id, method, params}
  • 응답(Responses): {jsonrpc: "2.0", id, result | error}
  • 알림(Notifications): {jsonrpc: "2.0", method, params}. id가 없고 응답을 기대하지도 않습니다.

기반 사양(base spec)에는 기본 요소(primitive)별로 묶인 약 15개의 메서드가 정의되어 있습니다. 그중 중요한 것은 다음과 같습니다.

  • initialize / initialized (핸드셰이크(handshake))
  • tools/list, tools/call
  • resources/list, resources/read, resources/subscribe
  • prompts/list, prompts/get
  • sampling/createMessage (서버에서 클라이언트로 보내는 메시지)
  • notifications/tools/list_changed, notifications/resources/updated, notifications/progress

세 단계 생애주기

1단계: initialize.

클라이언트는 자신의 capabilitiesclientInfo를 담은 initialize 요청을 보냅니다. 서버는 자신의 capabilities, serverInfo, 그리고 자신이 따르는 사양 버전(spec version)을 응답으로 돌려줍니다. 클라이언트는 응답을 충분히 해석한 뒤 notifications/initialized 알림을 보냅니다. 이때부터는 협상된 능력(capability)의 범위 안에서 양쪽 모두 요청을 보낼 수 있습니다.

2단계: operation.

양방향으로 동작합니다. 클라이언트는 도구 발견을 위해 tools/list를 호출하고, 도구 호출을 위해 tools/call을 호출합니다. 서버는 자신이 선언한 능력에 따라 sampling/createMessage를 보낼 수 있고, 도구 목록이 바뀌면 notifications/tools/list_changed를 보낼 수 있습니다. 클라이언트는 사용자가 루트 범위(root scope)를 바꾸면 notifications/roots/list_changed를 보낼 수 있습니다.

3단계: shutdown.

어느 쪽이든 전송 계층(transport)을 닫습니다. MCP에는 별도로 정의된 구조화된 종료 메서드가 없습니다. 종료 신호는 전송 계층, 즉 stdio 또는 Streamable HTTP(Phase 13 · 09)가 직접 전달합니다.

능력 협상(Capability Negotiation)

initialize 핸드셰이크 안의 capabilities 객체가 양쪽 사이의 계약 역할을 합니다. 서버 예시는 다음과 같습니다.

{
  "tools": {"listChanged": true},
  "resources": {"subscribe": true, "listChanged": true},
  "prompts": {"listChanged": true}
}

서버는 tools/list_changed 알림을 보낼 수 있고 resources/subscribe도 지원한다고 선언합니다. 클라이언트는 자신의 능력 선언으로 화답합니다.

{
  "roots": {"listChanged": true},
  "sampling": {},
  "elicitation": {}
}

만약 클라이언트가 sampling을 선언하지 않았다면, 서버는 sampling/createMessage를 호출해서는 안 됩니다. 대칭적으로, 서버가 resources.subscribe를 선언하지 않았다면, 클라이언트는 구독을 시도해서는 안 됩니다.

바로 이 메커니즘이 생태계 분화(ecosystem drift)를 막아줍니다. 샘플링을 지원하지 않는 클라이언트도 여전히 유효한 MCP 클라이언트이고, sampling을 호출하지 않는 서버도 여전히 유효한 MCP 서버입니다. 단지 그 둘이 그 기능을 함께 쓰지 않을 뿐입니다.

구조화된 콘텐츠와 오류 형태

tools/call은 타입이 지정된 블록(typed block)의 content 배열을 반환합니다. 타입(type)은 text, image, resource입니다. Phase 13 · 14에서는 여기에 MCP 앱(MCP Apps), 즉 ui://로 식별되는 상호작용형 UI(interactive UI)가 추가됩니다.

오류(error)는 JSON-RPC 오류 코드를 사용합니다. 사양에서 추가로 정의된 코드로는 -32002 "Resource not found"와 -32603 "Internal error"가 있고, MCP에 특화된 오류 데이터는 error.data 필드에 담깁니다.

클라이언트 능력과 도구 호출 결정의 차이

자주 헷갈리는 부분이 있습니다. capabilities.tools는 클라이언트가 "도구 목록 변경 알림(tool-list-changed notification)을 지원하는가"를 나타냅니다. 클라이언트가 특정 도구를 실제로 호출할지 말지는 클라이언트가 사용하는 모델이 실행 시점에 내리는 결정이지, 능력 플래그(capability flag)가 아닙니다. 능력 플래그는 사양 수준의 계약(spec-level contract)이고, 모델의 도구 선택은 그것과 직교(orthogonal)하는 별개의 문제입니다.

왜 REST가 아니라 JSON-RPC인가?

JSON-RPC 2.0(2010)은 가벼운 양방향 프로토콜입니다. 반면 REST는 클라이언트 쪽에서 시작하는 방식(client-initiated)입니다. MCP는 서버에서 시작하는 메시지, 즉 샘플링이나 알림 같은 흐름이 필요했고, 그 때문에 요청과 응답의 형태가 대칭(symmetric)인 JSON-RPC가 자연스럽게 잘 맞았습니다. JSON-RPC는 stdio 위에서나 WebSocket/Streamable HTTP 위에서도 HTTP 요청 형태를 다시 만들어 내지 않고 깔끔하게 얹을 수 있다는 장점도 있습니다.

사용해보기

code/main.py는 최소한의 JSON-RPC 2.0 파서와 메시지 생성기를 먼저 제공한 뒤, initialize -> tools/list -> tools/call -> shutdown 흐름을 한 줄 한 줄 손으로 따라갑니다. 실제 전송 계층은 없고, 메시지 형태만 보여줍니다. 아래 "더 읽을거리"에 있는 사양 문서와 비교하면서 각 봉투의 형태를 직접 확인해 봅니다.

확인해 볼 지점은 다음과 같습니다.

  • initialize는 양쪽의 능력을 함께 선언합니다. 응답에는 serverInfoprotocolVersion: "2025-11-25"가 들어 있습니다.
  • tools/listtools 배열을 반환합니다. 각 항목에는 name, description, inputSchema가 있습니다.
  • tools/callparams.nameparams.arguments를 사용합니다.
  • 응답의 content{type, text} 형태 블록의 배열입니다.

산출물 만들기

이 lesson에서는 outputs/skill-mcp-handshake-tracer.md를 만듭니다. MCP 클라이언트-서버 상호작용을 패킷 캡처처럼 기록한 트랜스크립트(pcap-style transcript)가 주어지면, 이 skill은 각 메시지에 어떤 기본 요소(primitive)에 속하는지, 어떤 생애주기 단계에 해당하는지, 어떤 능력에 의존하는지를 주석으로 달아 줍니다.

연습문제

  1. (쉬움) code/main.py를 실행합니다. 능력 협상이 일어나는 줄을 찾고, 만약 서버가 tools.listChanged를 선언하지 않았다면 어떤 점이 달라질지 설명합니다.

  2. (중간) 파서를 확장해서 notifications/progress를 처리하도록 만듭니다. 메시지 형태는 {method: "notifications/progress", params: {progressToken, progress, total}}입니다. 오래 걸리는 tools/call이 진행되는 동안 이 알림을 발생시키고, 클라이언트 핸들러(handler)가 진행 바(progress bar)를 표시할 수 있을지 확인합니다.

  3. (어려움) MCP 2025-11-25 사양을 처음부터 끝까지 읽습니다. 전체 문서는 약 80쪽 분량입니다. 대부분의 서버에는 굳이 필요하지 않은 능력 플래그를 하나 찾아냅니다. 힌트: 자원 구독(resource subscription)과 관련이 있습니다.

  4. (중간) 가상의 "크론 잡(cron job)" 기능이 어떤 기본 요소에 속할지 종이에 스케치해 봅니다. 힌트: 서버는 클라이언트가 예약된 시점(scheduled time)에 자신을 호출해 주기를 원합니다. 현재의 여섯 기본 요소로는 잘 맞지 않습니다. MCP의 2026 로드맵에는 이 주제에 대한 초안 SEP가 들어 있습니다.

  5. (어려움) GitHub에 공개되어 있는 MCP 서버 세션 로그 하나를 골라 직접 파싱합니다. 요청, 응답, 알림 메시지의 개수를 세어 보고, 전체 트래픽에서 생애주기와 운영(operation) 단계의 비중이 어떻게 나뉘는지 계산합니다.

핵심 용어

용어흔한 설명실제 의미
MCP(Model Context Protocol)"모델 컨텍스트 프로토콜"모델과 도구 사이의 발견과 호출을 표준화하는 공개 프로토콜
서버 기본 요소(Server primitive)"서버가 노출하는 것"도구(tools, 행동), 자원(resources, 데이터), 프롬프트(prompts, 템플릿)
클라이언트 기본 요소(Client primitive)"클라이언트가 서버에게 허용하는 것"루트(roots, 범위), 샘플링(sampling, LLM 콜백), 일레시테이션(elicitation, 사용자 입력)
JSON-RPC 2.0"와이어 포맷"대칭적인 요청/응답/알림 봉투 구조
initialize 핸드셰이크"능력 협상"첫 메시지 쌍. 서버와 클라이언트가 지원 기능을 선언한다
tools/list"발견(Discovery)"클라이언트가 서버의 현재 도구 목록을 요청한다
tools/call"호출(Invocation)"클라이언트가 서버에게 인자와 함께 도구 실행을 요청한다
notifications/*_changed"변경 이벤트(Mutation event)"기본 요소 목록이 바뀌었음을 서버가 클라이언트에게 알리는 메시지
콘텐츠 블록(Content block)"타입이 지정된 결과"도구 결과 안의 `{type: "text"
SEP(Spec Evolution Proposal)"사양 진화 제안"SEP-1686 async Tasks처럼 이름이 붙은 초안 제안

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

mcp-handshake-tracer

Given a pcap-style transcript of an MCP client-server conversation, annotate every message with its primitive, lifecycle phase, and capability dependency.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.프로덕션에서 MCP 기초의 가장 중요한 설계 원칙은?

2.MCP 기초가 올바른 선택이 아닌 경우는?

3.MCP 기초는 AI 생태계에 어떻게 들어맞나요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다