MCP 아키텍처 (Architecture)¶
Model Context Protocol(MCP)의 개요 입니다. MCP가 다루는 범위와 핵심 개념을 살펴보고, 각 핵심 개념을 보여 주는 예시를 함께 다룹니다. MCP SDK가 많은 부분을 추상화해 주기 때문에, 대부분의 개발자는 데이터 레이어 프로토콜 부분이 가장 유용할 것입니다. 그 부분은 MCP 서버가 AI 애플리케이션에 맥락(context)을 어떻게 제공하는지를 다룹니다. 구체적인 구현 세부 사항은 언어별 SDK 문서를 참고하세요.
범위 (Scope)¶
Model Context Protocol은 다음 프로젝트들을 포함합니다.
- MCP 명세 (Specification): 클라이언트와 서버의 구현 요구 사항을 정리한 MCP 명세입니다.
- MCP SDK: MCP를 구현한 다양한 프로그래밍 언어용 SDK입니다.
- MCP 개발 도구 (Development Tools): MCP 서버와 클라이언트를 개발하기 위한 도구로, MCP Inspector를 포함합니다.
- MCP 레퍼런스 서버 구현 (Reference Server Implementations): MCP 서버의 레퍼런스 구현입니다.
MCP는 맥락 교환을 위한 프로토콜에만 집중합니다. AI 애플리케이션이 LLM을 어떻게 사용하는지, 제공받은 맥락을 어떻게 관리하는지를 규정하지는 않습니다.
MCP의 개념 (Concepts of MCP)¶
참여자 (Participants)¶
MCP는 클라이언트-서버 아키텍처를 따릅니다. MCP 호스트(host)는 Claude Code나 Claude Desktop 같은 AI 애플리케이션으로, 하나 이상의 MCP 서버에 연결을 맺습니다. MCP 호스트는 MCP 서버마다 MCP 클라이언트 하나를 만들어 이 일을 처리합니다. 각 MCP 클라이언트는 대응하는 MCP 서버와 전용 연결을 유지합니다. STDIO 트랜스포트를 사용하는 로컬 MCP 서버는 대개 단일 MCP 클라이언트만 서비스하는 반면, Streamable HTTP 트랜스포트를 사용하는 원격 MCP 서버는 보통 많은 MCP 클라이언트를 서비스합니다. MCP 아키텍처의 핵심 참여자는 다음과 같습니다.
- MCP 호스트 (Host): 하나 이상의 MCP 클라이언트를 조정하고 관리하는 AI 애플리케이션
- MCP 클라이언트 (Client): MCP 서버에 대한 연결을 유지하고, 호스트가 사용할 맥락을 MCP 서버로부터 얻는 구성 요소
- MCP 서버 (Server): MCP 클라이언트에게 맥락을 제공하는 프로그램
예시: Visual Studio Code가 MCP 호스트 역할을 합니다. Visual Studio Code가 Sentry MCP 서버 같은 MCP 서버에 연결하면, Visual Studio Code 런타임은 Sentry MCP 서버와의 연결을 유지하는 MCP 클라이언트 객체를 생성합니다. 그리고 Visual Studio Code가 나중에 로컬 파일시스템 서버 같은 또 다른 MCP 서버에 연결하면, 런타임은 이 연결을 위해 추가적인 MCP 클라이언트 객체를 생성합니다. MCP 서버는 맥락 데이터를 서비스하는 프로그램을 말하며, 어디에서 실행되든 상관없습니다. MCP 서버는 로컬이나 원격 어디서든 실행될 수 있습니다. 예를 들어 Claude Desktop이 파일시스템 서버를 실행하면, 서버는 STDIO 트랜스포트를 사용하기 때문에 같은 머신에서 로컬로 실행됩니다. 이를 보통 "로컬" MCP 서버라고 부릅니다. 공식 Sentry MCP 서버는 Sentry 플랫폼에서 실행되며, Streamable HTTP 트랜스포트를 사용합니다. 이를 보통 "원격" MCP 서버라고 부릅니다.
레이어 (Layers)¶
MCP는 두 개의 레이어로 구성됩니다.
- 데이터 레이어 (Data layer): 클라이언트-서버 통신을 위한 JSON-RPC 기반 프로토콜을 정의합니다. capability와 버전 발견(discovery), 그리고 tools, resources, prompts, notifications 같은 핵심 프리미티브(primitive)를 포함합니다.
- 트랜스포트 레이어 (Transport layer): 클라이언트와 서버 사이의 데이터 교환을 가능하게 하는 통신 메커니즘과 채널을 정의합니다. 트랜스포트별 연결 수립, 메시지 프레이밍, 인증을 포함합니다.
개념적으로 데이터 레이어는 안쪽 레이어이고, 트랜스포트 레이어는 바깥쪽 레이어입니다.
데이터 레이어 (Data layer)¶
데이터 레이어는 메시지 구조와 의미(semantics)를 정의하는 JSON-RPC 2.0 기반 교환 프로토콜을 구현합니다. 이 레이어는 다음을 포함합니다.
- 발견 (Discovery): 클라이언트가 서버의 지원 프로토콜 버전, capability, 정체성을
server/discover요청을 통해 조회할 수 있게 합니다. - 서버 기능 (Server features): 서버가 핵심 기능을 제공할 수 있게 합니다. AI 액션을 위한 tools, 맥락 데이터를 위한 resources, 대화 템플릿을 위한 prompts를 포함하며, 클라이언트에서 서버로 향하는 것과 서버에서 클라이언트로 향하는 것 모두를 다룹니다.
- 클라이언트 기능 (Client features): 서버가 사용자로부터 입력을 이끌어 낼 수 있게 합니다. Sampling은 프로토콜 버전
2026-07-28부터 deprecated 되었습니다. - 유틸리티 기능 (Utility features): 실시간 업데이트를 위한 notifications과 장시간 실행 작업을 위한 진행 추적(progress tracking) 같은 추가 capability를 지원합니다.
트랜스포트 레이어 (Transport layer)¶
트랜스포트 레이어는 클라이언트와 서버 사이의 통신 채널과 인증을 관리합니다. 연결 수립, 메시지 프레이밍, MCP 참여자 간의 안전한 통신을 처리합니다. MCP는 두 가지 트랜스포트 메커니즘을 지원합니다.
- Stdio 트랜스포트: 표준 입력/출력 스트림을 사용해 같은 머신의 로컬 프로세스 간 직접 통신을 합니다. 네트워크 오버헤드가 없어 최적의 성능을 제공합니다.
- Streamable HTTP 트랜스포트: 클라이언트→서버 메시지에 HTTP POST를 사용하고, 스트리밍 기능에는 선택적으로 Server-Sent Events를 사용합니다. 원격 서버 통신을 가능하게 하며 bearer token, API key, custom headers를 포함한 표준 HTTP 인증 방식을 지원합니다. MCP는 인증 토큰을 얻기 위해 OAuth 사용을 권장합니다.
트랜스포트 레이어는 통신 세부 사항을 프로토콜 레이어로부터 추상화하므로, 모든 트랜스포트 메커니즘에서 동일한 JSON-RPC 2.0 메시지 형식을 사용할 수 있습니다.
데이터 레이어 프로토콜 (Data Layer Protocol)¶
MCP의 핵심은 MCP 클라이언트와 MCP 서버 사이의 스키마와 의미를 정의하는 것입니다. 개발자는 아마 데이터 레이어, 특히 프리미티브 집합이 MCP에서 가장 흥미로운 부분일 것입니다. 바로 서버에서 클라이언트로 맥락을 공유하는 방법을 정의하는 부분이기 때문입니다. MCP는 하부 RPC 프로토콜로 JSON-RPC 2.0을 사용합니다. 클라이언트와 서버는 서로에게 요청을 보내고 그에 응답합니다. 응답이 필요 없을 때는 notifications을 사용할 수 있습니다.
무상태성과 발견 (Statelessness and discovery)¶
MCP는 (무상태) 프로토콜입니다. 모든 요청은 프로토콜 버전과 해당 요청에 관련된 정보를 _meta 필드에 담아 전달하므로, 서버는 각 요청을 독립적으로 처리할 수 있습니다. 클라이언트는 별도로 설정하지 않는 한 같은 필드에 자신의 정체성도 명시해야 합니다. 서버는 필수 요청인 server/discover를 통해 지원 버전과 capability를 광고하며, 클라이언트는 다른 어떤 요청보다 먼저 이 요청을 보낼 수 있습니다. 자세한 내용은 명세에서, 요청별 메타데이터와 발견 시퀀스는 예시에서 확인할 수 있습니다.
프리미티브 (Primitives)¶
MCP 프리미티브는 MCP에서 가장 중요한 개념입니다. 클라이언트와 서버가 서로에게 무엇을 제공할 수 있는지를 정의하기 때문입니다. 이 프리미티브들은 AI 애플리케이션과 공유할 수 있는 맥락 정보의 유형과 수행할 수 있는 액션의 범위를 지정합니다. MCP는 서버가 노출할 수 있는 세 가지 핵심 프리미티브를 정의합니다.
- Tools: AI 애플리케이션이 액션을 수행하기 위해 호출할 수 있는 실행 가능한 함수입니다 (예: 파일 연산, API 호출, 데이터베이스 쿼리).
- Resources: AI 애플리케이션에 맥락 정보를 제공하는 데이터 소스입니다 (예: 파일 내용, 데이터베이스 레코드, API 응답).
- Prompts: 언어 모델과의 상호작용을 구조화하는 데 도움을 주는 재사용 가능한 템플릿입니다 (예: 시스템 프롬프트, few-shot 예시).
각 프리미티브 유형에는 발견(*/list), 조회(*/get), 그리고 일부의 경우 실행(tools/call)을 위한 메서드가 연관되어 있습니다. MCP 클라이언트는 */list 메서드를 사용해 사용 가능한 프리미티브를 발견합니다. 예를 들어 클라이언트는 먼저 사용 가능한 모든 tools를 나열하고(tools/list) 그다음 실행할 수 있습니다. 이 설계 덕분에 목록이 동적일 수 있습니다. 구체적인 예로, 데이터베이스에 대한 맥락을 제공하는 MCP 서버를 생각해 봅시다. 이 서버는 데이터베이스를 쿼리하는 tool을 노출하고, 데이터베이스의 스키마를 담은 resource를 제공하며, tools와 상호작용하기 위한 few-shot 예시를 포함하는 prompt를 제공할 수 있습니다. 서버 프리미티브의 자세한 내용은 server concepts에서 확인하세요.
MCP는 클라이언트가 노출할 수 있는 프리미티브도 정의합니다. 이 프리미티브들은 MCP 서버 작성자가 더 풍부한 상호작용을 만들 수 있게 해 줍니다.
- Elicitation: 서버가 사용자에게 추가 정보를 요청할 수 있게 합니다. 서버 작성자가 사용자에게 더 많은 정보를 얻고 싶거나, 액션에 대한 확인을 요청하고 싶을 때 유용합니다. 서버는
elicitation/create메서드로 사용자 입력을 요청합니다.
Elicitation 요청은 Multi Round-Trip Requests 패턴을 통해 전달되며, 자세한 내용은 elicitation overview에서 확인할 수 있습니다.
Deprecated: 다음 클라이언트 프리미티브는 프로토콜 버전 2026-07-28부터 deprecated 되었습니다.
- Sampling: 서버가 클라이언트의 AI 애플리케이션에 언어 모델 완성(completion)을 요청할 수 있게 합니다. 서버 작성자가 언어 모델에 접근하고 싶지만 모델에 독립적이고 싶고, MCP 서버에 언어 모델 SDK를 포함하고 싶지 않을 때 유용합니다. 서버는
sampling/createMessage메서드로 완성을 요청하며, 이것도 Multi Round-Trip Requests 패턴을 통해 전달됩니다. 새 구현은 LLM 제공자 API에 직접 통합해야 합니다. - Logging: 서버가 디버깅과 모니터링 목적으로 클라이언트에 로그 메시지를 보낼 수 있게 합니다. 새 구현은
stderr(stdio 트랜스포트)로 로그를 남기거나 OpenTelemetry를 사용해야 합니다.
클라이언트 프리미티브의 자세한 내용은 client concepts에서 확인하세요. 서버/클라이언트 프리미티브 외에도, 프로토콜은 핵심 프로토콜 위에 구축되는 선택적 확장(extensions)을 지원합니다. 예를 들어 Tasks 확장은 서버가 장시간 실행되는 요청에 대한 지속적인 핸들(durable handle)을 반환할 수 있게 해 주므로, 클라이언트는 상태를 폴링하고 나중에 결과를 조회할 수 있습니다.
Notifications¶
프로토콜은 서버와 클라이언트 사이의 동적 업데이트를 가능하게 하는 실시간 notifications을 지원합니다. 예를 들어 서버의 사용 가능한 tools가 바뀌면(새 기능이 추가되거나 기존 tools가 수정되는 등), 서버는 연결된 클라이언트에게 이러한 변경을 알리기 위해 tool 업데이트 notification을 보낼 수 있습니다. Notifications은 응답을 기대하지 않는 JSON-RPC 2.0 notification 메시지로 전송됩니다. 변경 알림은 opt-in 방식입니다. 클라이언트는 받고 싶은 notification 유형을 명명하는 장기(long-lived) subscriptions/listen 스트림을 열고, 서버는 그 스트림에서 일치하는 notifications을 전달합니다.
예시 (Example)¶
데이터 레이어 (Data Layer)¶
이 섹션은 MCP 클라이언트-서버 상호작용을 단계별로 안내하며, 데이터 레이어 프로토콜에 초점을 맞춥니다. JSON-RPC 2.0 메시지를 사용해 발견(discovery), tool 연산, notifications을 시연합니다.
1. 발견 (Discovery)¶
앞서 무상태성과 발견 섹션에서 설명했듯이, 모든 MCP 요청은 _meta 필드에 프로토콜 버전과 클라이언트 capability를 담고, 클라이언트는 그곳에 자신의 정체성도 포함해야 합니다. 다른 요청을 보내기 전에 서버가 무엇을 지원하는지 알고 싶은 클라이언트는 server/discover 요청을 보냅니다. 이 요청은 모든 서버가 구현해야 합니다. 발견 응답은 보통 캐시 가능하므로, 발견 흐름을 매 요청마다 수행하지 않고 재사용할 수 있습니다.
발견 교환 이해하기 (Understanding the Discovery Exchange)¶
_meta 필드와 발견 응답은 함께 여러 목적을 제공합니다.
- 프로토콜 버전 선택:
io.modelcontextprotocol/protocolVersion필드는 이 요청에서 클라이언트가 사용하는 버전을 선언하고, 응답의supportedVersions는 서버가 수용하는 버전을 나열합니다. 서버가 요청된 버전을 지원하지 않으면, 지원하는 버전을 나열한UnsupportedProtocolVersionError로 요청을 거부하고, 클라이언트는 서로 지원하는 버전으로 재시도합니다. - Capability 발견: 클라이언트는 매 요청에서
io.modelcontextprotocol/clientCapabilities로 자신의 capability를 선언하고, 서버는server/discover로 자신의capabilities객체를 반환합니다. 이를 통해 각 당사자가 상대가 처리할 수 있는 프리미티브(tools, resources, prompts)와 변경 notification 사용 가능 여부를 알 수 있으므로, 지원되지 않는 연산은 시도되지 않습니다. - 정체성 교환: 요청
_meta의io.modelcontextprotocol/clientInfo필드와 결과_meta의io.modelcontextprotocol/serverInfo필드는 디버깅과 호환성 목적의 식별·버전 정보를 제공합니다.
이 예시에서, 교환은 MCP capability가 어떻게 선언되는지 보여 줍니다.
클라이언트 capability:
"elicitation": {}— 클라이언트는 서버가 요청할 때 사용자로부터 추가 입력을 수집할 수 있음을 선언합니다.
서버 capability:
"tools": {"listChanged": true}— 서버는 tools 프리미티브를 지원하며,subscriptions/listen에서toolsListChanged필터를 지킬 수 있습니다. 이 필터를 요청한 클라이언트는 tool 목록이 바뀔 때notifications/tools/list_changed를 받습니다."resources": {}— 서버는 resources 프리미티브도 지원합니다 (resources/list와resources/read메서드를 처리할 수 있음).
server/discover 호출은 선택 사항입니다. 모든 요청이 같은 _meta 필드를 담기 때문에, 클라이언트는 어떤 요청이든 직접 보내고 버전 오류가 오면 처리할 수 있습니다. 발견은 서버의 정체성, capability, 지원 버전을 단일 요청으로 가져오는 편리한 방법입니다.
AI 애플리케이션에서 어떻게 동작하는가 (How This Works in AI Applications)¶
AI 애플리케이션의 MCP 클라이언트 매니저는 설정된 서버에 연결하고, 이후 사용을 위해 발견된 capability를 저장합니다. 애플리케이션은 이 정보를 사용해 어떤 서버가 특정 유형의 기능(tools, resources, prompts)을 제공할 수 있는지, 실시간 업데이트를 지원하는지 판단합니다. Python SDK에서는 클라이언트가 연결하는 동안 발견이 일어나며, 결과는 클라이언트 객체에서 사용할 수 있습니다.
AI 애플리케이션 발견을 위한 의사 코드(pseudo-code):
# Pseudo Code
async with Client(stdio_client(server_config)) as client:
if client.server_capabilities.tools:
app.register_mcp_server(client, supports_tools=True)
app.set_server_ready(client)
2. Tool 발견 (프리미티브) (Tool Discovery)¶
클라이언트는 tools/list 요청을 보내 사용 가능한 tools를 발견할 수 있습니다. 이 요청은 MCP의 tool 발견 메커니즘의 기본입니다. 클라이언트가 tools를 사용하기 전에 서버에 어떤 tools가 있는지 이해할 수 있게 해 줍니다.
Tool 발견 요청 이해하기 (Understanding the Tool Discovery Request)¶
tools/list 요청은 모든 MCP 요청에 수반되는 표준 _meta 필드 외에 매개변수를 필요로 하지 않습니다. 또한 페이지네이션을 위한 선택적 cursor 매개변수를 받지만, 위 예시에서는 생략했습니다.
Tool 발견 응답 이해하기 (Understanding the Tool Discovery Response)¶
응답은 사용 가능한 각 tool에 대한 종합적인 메타데이터를 제공하는 tools 배열을 포함합니다. 이 배열 기반 구조 덕분에 서버는 서로 다른 기능 간에 명확한 경계를 유지하면서 여러 tools를 동시에 노출할 수 있습니다. 응답의 각 tool 객체는 몇 가지 핵심 필드를 포함합니다.
name: 서버 네임스페이스 안에서 tool을 식별하는 고유 식별자입니다. tool 실행의 기본 키 역할을 하며, 명확한 명명 패턴을 따라야 합니다 (예: 그냥calculate보다는calculator_arithmetic).title: 클라이언트가 사용자에게 보여줄 수 있는 사람이 읽을 수 있는 표시 이름입니다.description: tool이 무엇을 하고 언제 사용하는지에 대한 상세 설명입니다.inputSchema: 기대되는 입력 매개변수를 정의하는 JSON Schema로, 타입 검증을 가능하게 하고 필수·선택 매개변수에 대한 명확한 문서를 제공합니다.
결과는 "resultType": "complete"로 표시되며 두 개의 캐싱 필드를 갖습니다. ttlMs는 밀리초 단위의 신선도(freshness) 힌트이므로, 이 tool 목록은 5분 동안 캐시될 수 있습니다. cacheScope는 누가 응답을 재사용할 수 있는지를 나타냅니다. 명세의 caching 유틸리티가 전체 규칙을 정의합니다.
AI 애플리케이션에서 어떻게 동작하는가 (How This Works in AI Applications)¶
AI 애플리케이션은 연결된 모든 MCP 서버에서 사용 가능한 tools를 가져와, 언어 모델이 접근할 수 있는 통합 tool 레지스트리로 결합합니다. 이 덕분에 LLM은 어떤 액션을 수행할 수 있는지 이해하고, 대화 중에 적절한 tool 호출을 자동으로 생성할 수 있습니다.
AI 애플리케이션 tool 발견을 위한 의사 코드:
# Pseudo-code using MCP Python SDK patterns
available_tools = []
for client in app.mcp_clients():
tools_response = await client.list_tools()
available_tools.extend(tools_response.tools)
conversation.register_available_tools(available_tools)
많은 서버를 연합(federate)하는 클라이언트는 모든 tool을 미리 로드하는 대신 점진적 tool 발견(progressive tool discovery)을 사용할 수 있습니다.
3. Tool 실행 (프리미티브) (Tool Execution)¶
이제 클라이언트는 tools/call 메서드를 사용해 tool을 실행할 수 있습니다. 이는 MCP 프리미티브가 실제로 어떻게 사용되는지 보여 줍니다. 사용 가능한 tools를 발견한 후, 클라이언트는 적절한 인자로 그들을 호출할 수 있습니다.
Tool 실행 요청 이해하기 (Understanding the Tool Execution Request)¶
tools/call 요청은 클라이언트와 서버 사이에 타입 안전성과 명확한 통신을 보장하는 구조화된 형식을 따릅니다. 여기서는 발견 응답의 실제 tool 이름(weather_current)을 단순화된 이름 대신 사용하고 있습니다.
Tool 실행의 핵심 요소 (Key Elements of Tool Execution)¶
요청 구조는 몇 가지 중요한 구성 요소를 포함합니다.
name: 발견 응답의 tool 이름(weather_current)과 정확히 일치해야 합니다. 이는 서버가 어떤 tool을 실행할지 정확히 식별할 수 있게 합니다.arguments: tool의inputSchema에 정의된 입력 매개변수를 포함합니다. 이 예시에서는:location: "San Francisco" (필수 매개변수)units: "imperial" (선택 매개변수, 지정하지 않으면 기본값 "metric")_meta: 모든 MCP 요청이 포함해야 하는 표준 요청별 필드, 즉 프로토콜 버전과 클라이언트 capability를 담고, 별도로 설정하지 않는 한 포함해야 하는 클라이언트 정체성도 담습니다.- JSON-RPC 구조: 요청-응답 상관관계를 위한 고유
id를 가진 표준 JSON-RPC 2.0 형식을 사용합니다.
Tool 실행 응답 이해하기 (Understanding the Tool Execution Response)¶
응답은 MCP의 유연한 콘텐츠 시스템을 보여 줍니다.
content배열: Tool 응답은 콘텐츠 객체의 배열을 반환하므로, 풍부하고 다중 형식의 응답(텍스트, 이미지, resources 등)이 가능합니다.- 콘텐츠 유형: 각 콘텐츠 객체는
type필드를 갖습니다. 이 예시에서"type": "text"는 평문 콘텐츠를 나타내지만, MCP는 다양한 사용 사례를 위한 여러 콘텐츠 유형을 지원합니다. - 구조화된 출력: 응답은 AI 애플리케이션이 언어 모델 상호작용을 위한 맥락으로 사용할 수 있는 실행 가능한 정보를 제공합니다.
이 실행 패턴은 AI 애플리케이션이 서버 기능을 동적으로 호출하고, 언어 모델과의 대화에 통합할 수 있는 구조화된 응답을 받을 수 있게 해 줍니다.
AI 애플리케이션에서 어떻게 동작하는가 (How This Works in AI Applications)¶
대화 중 언어 모델이 tool을 사용하기로 결정하면, AI 애플리케이션은 그 tool 호출을 가로채 적절한 MCP 서버로 라우팅하고, 실행한 뒤 결과를 대화 흐름의 일부로 LLM에 돌려줍니다. 이 덕분에 LLM은 실시간 데이터에 접근하고 외부 세계에서 액션을 수행할 수 있습니다.
AI 애플리케이션 tool 실행을 위한 의사 코드:
# Pseudo-code for AI application tool execution
async def handle_tool_call(conversation, tool_name, arguments):
client = app.find_mcp_client_for_tool(tool_name)
result = await client.call_tool(tool_name, arguments)
conversation.add_tool_result(result.content)
4. 실시간 업데이트 (Notifications)¶
MCP는 서버가 폴링을 하지 않아도 클라이언트에게 변경을 알릴 수 있는 실시간 notifications을 지원합니다. 이 섹션은 클라이언트를 동기화되고 반응적으로 유지하는 핵심 기능인 notification 시스템을 보여 줍니다.
변경 구독하기 (Subscribing to Changes)¶
변경 알림은 opt-in 방식입니다. 이를 받으려면 클라이언트가 받고 싶은 이벤트 유형을 명명하는 notifications 필터를 가진 subscriptions/listen 요청을 보내 장기 notification 스트림을 엽니다. 여기서 클라이언트는 tool 목록 변경을 요청합니다.
Listen 요청:
{
"jsonrpc": "2.0",
"id": 4,
"method": "subscriptions/listen",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
},
"notifications": {
"toolsListChanged": true
}
}
}
모든 클라이언트 요청은 _meta에 io.modelcontextprotocol/protocolVersion과 io.modelcontextprotocol/clientCapabilities 필드를 담고, 보통 io.modelcontextprotocol/clientInfo도 담으므로, 서버는 연결 상태에 의존하지 않고 클라이언트를 식별할 수 있습니다. 서버는 구독을 notifications/subscriptions/acknowledged로 확인하며, 이것이 그 구독의 ID를 _meta에 담는 첫 번째 메시지입니다 (그 전에는 서버가 그 구독에 대한 다른 notification을 보내지 않습니다). 그 notifications 필드는 서버가 지키기로 동의한 요청 필터의 부분집합을 반영하며, 지원되지 않는 notification 유형은 생략됩니다.
확인(Acknowledgment):
{
"jsonrpc": "2.0",
"method": "notifications/subscriptions/acknowledged",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 4
},
"notifications": {
"toolsListChanged": true
}
}
}
Tool 목록 변경 notification 이해하기 (Understanding Tool List Change Notifications)¶
확인 이후, 서버의 사용 가능한 tools가 바뀌면(새 기능이 추가되거나, 기존 tools가 수정되거나, tools가 일시적으로 사용 불가능해지는 등), 서버는 그 스트림에서 notification을 전달합니다.
Notification:
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 4
}
}
}
MCP Notifications의 핵심 특징 (Key Features of MCP Notifications)¶
- 응답 불필요: notification에
id필드가 없다는 점에 주목하세요. 이는 응답이 기대되거나 전송되지 않는 JSON-RPC 2.0 notification 의미를 따릅니다. - Opt-in 방식: 이 notification은
subscriptions/listen필터에서"toolsListChanged": true를 요청한 클라이언트에게만 전송되며, tools capability에서"listChanged": true를 선언한 서버에서만 사용할 수 있습니다 (1단계에서 볼 수 있듯이). - 구독 ID 태깅: 스트림의 모든 notification은
_meta에io.modelcontextprotocol/subscriptionId를 담습니다. 값은 스트림을 연subscriptions/listen요청의 JSON-RPC ID(이 예시에서는4)이므로, 클라이언트는 각 notification을 이를 생성한 구독과 연결할 수 있습니다. - 이벤트 기반: 서버는 내부 상태 변경에 따라 notification을 보낼 시점을 결정하므로, MCP 연결은 동적이고 반응적입니다.
- Best Effort: 특히 트랜스포트 재연결 시에는 모든 notification이 전송·수신된다는 보장이 없습니다. 클라이언트는 결과의 신선함을 유지하기 위해 폴링에도 의존해야 합니다.
Notifications에 대한 클라이언트 응답 (Client Response to Notifications)¶
이 notification을 받으면, 클라이언트는 보통 업데이트된 tool 목록을 요청함으로써 반응합니다. 이는 클라이언트가 사용 가능한 tools에 대한 이해를 최신으로 유지하는 갱신 주기를 만듭니다.
Request:
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
}
}
}
Notifications이 중요한 이유 (Why Notifications Matter)¶
이 notification 시스템은 여러 이유로 중요합니다.
- 동적 환경: tools는 서버 상태, 외부 의존성, 사용자 권한에 따라 사라지거나 나타날 수 있습니다.
- 효율성: 클라이언트는 변경을 위해 폴링할 필요 없이, 업데이트가 발생하면 알림을 받습니다.
- 일관성: 클라이언트가 사용 가능한 서버 capability에 대해 항상 정확한 정보를 갖도록 보장합니다.
- 실시간 협업: 변화하는 맥락에 적응할 수 있는 반응형 AI 애플리케이션을 가능하게 합니다.
이 notification 패턴은 tools를 넘어 다른 MCP 프리미티브로도 확장되어, 클라이언트와 서버 사이의 포괄적인 실시간 동기화를 가능하게 합니다.
AI 애플리케이션에서 어떻게 동작하는가 (How This Works in AI Applications)¶
AI 애플리케이션은 자신이 신경 쓰는 변경을 위한 notification 스트림을 열어 둡니다. notification이 도착하면 즉시 tool 레지스트리를 갱신하고 LLM의 사용 가능한 capability를 업데이트합니다. 이 덕분에 진행 중인 대화가 항상 가장 최신의 tool 집합에 접근할 수 있고, LLM은 새 기능이 사용 가능해지면 동적으로 적응할 수 있습니다.
AI 애플리케이션 notification 처리를 위한 의사 코드:
# Pseudo-code for AI application notification handling
async def follow_tool_changes(client):
async with client.listen(tools_list_changed=True) as sub:
async for _event in sub:
tools_response = await client.list_tools()
app.update_available_tools(client, tools_response.tools)
if app.conversation.is_active():
app.conversation.notify_llm_of_new_capabilities()