프로토콜 에라

프로토콜 에라 (Protocol eras)

출처: MCP 공식 문서 — Protocol eras

2026-07-28판 MCP는 프로토콜에 상당한 변경을 가져왔어요. 그래서 Inspector는 프로토콜 에라(legacy 또는 modern, 즉 그 개정 이전 또는 이후)를 전송 방식과 무관한 일급의 서버별 설정으로 다뤄요. 같은 HTTP URL을 legacy 서버로도, modern 서버로도 검사할 수 있다는 뜻이죠. 여러 탭이 어떤 에라가 적용되는지에 따라 의미 있게 다른 UI와 트래픽을 렌더링해요.

Protocol Era 설정

각 서버는 legacy, auto, 또는 modernprotocolEra를 지녀요. 웹 클라이언트에서는 Server Settings에, 카탈로그나 설정 파일에서는 protocolEra 필드로, CLI와 TUI에서는 같은 파일에서 옵니다.

에라 연결 시 Inspector가 하는 일
legacy 기본값. 평문 initialize, 프로빙 전혀 없음.
auto 먼저 server/discover를 프로브하고, modern이 아닌 결과면 initialize로 폴백.
modern 정확히 2026-07-28로 고정. 폴백 없음, 그래서 non-modern 서버는 크게 실패.

auto가 아니라 legacy가 기본인가. 디버깅 도구는 자동 프로브를 해서는 안 돼요. server/discover 프로브는 조용한 legacy stdio 서버에서 멈추고, 여러분이 보러 온 기록된 전문을 오염시켜요. automodern에 옵트인하는 건 의도적 행위라서, Protocol 탭에 보이는 것은 여러분이 설정한 대로 행동하는 클라이언트가 서버에 보냈을 것과 같아요.

에라 선택은 세 클라이언트 모두 동일하게 동작해요.

연결되면 협상된 에라가 연결 헤더와 Connection Info에 보고돼요. modern 연결에서는 server/discovercapabilities(extensions 포함), instructions, 그리고 supportedVersions 목록도 제공해요. 서버 이름과 버전은 결과 _metaio.modelcontextprotocol/serverInfo 아래에 와요.

각 에라를 로컬에서 재현

아래 각 섹션은 Inspector 저장소에 들어 있는 조합 가능한 테스트 서버 하나의 JSON 설정을 가리키는 Reproduce with ... 포인터로 끝나요. 저장소를 클론하고 테스트 서버를 빌드한 뒤, 그 섹션이 이름 짓는 설정으로 Inspector를 열면 돼요.

git clone https://github.com/modelcontextprotocol/inspector
cd inspector && npm install && npm run build
cd clients/web && npm run test-servers:build

로깅

Legacy — 로깅은 세션 범위예요. 클라이언트가 logging/setLevel을 한 번 보내면, 서버는 세션의 나머지 동안 그 레벨 이상의 notifications/message를 내보내요. Logs 탭은 Set Active Level 선택기와 Set 버튼을 보여줘요. 레벨을 고르고 Set을 누르면 이후 서버 로그가 패널에 흘러들어와요. test-servers/configs/logging-legacy-http.json으로 재현.

Modernlogging/setLevel사라졌어요. 대신 클라이언트는 보내는 각 요청에 _meta["io.modelcontextprotocol/logLevel"]을 찍어 요청별로 옵트인해요. 서버는 옵트인하지 않은 요청에 대해 notifications/message를 내보내면 안 돼요(MUST NOT). 그래서 Logs 탭은 Log Level per Request 컨트롤을 보여줘요. 레벨을 고르면 이후 모든 요청이 그 스탬프를 지니고, Network 탭의 요청 본문에서 보여요. 요청 처리 중에 낸 로그는 그 요청의 SSE 응답 스트림을 타고 와요. 컨트롤을 Off로 하면 logLevel 키가 아예 생략돼서, 같은 도구 호출이 로그를 전혀 안 내요. 그 침묵은 버그가 아니라 올바른 동작이에요. 서버별 기본은 debug(디버깅 도구이므로 가장 장황한 레벨로 옵트인)이고, 서버에 modernLogLevel: "off"를 주면 기본으로 탈퇴해요. test-servers/configs/logging-modern-http.json으로 재현.

리소스 구독

Legacy — 리소스에서 Subscribe를 클릭하면 resources/subscribe를 보내요. Subscriptions 섹션은 스트림 장식 없이 URI를 나열해요. 리소스가 바뀌면 서버가 notifications/resources/updated를 내보내고 구독 타일의 마지막 업데이트 시각이 찍혀요. test-servers/configs/subscriptions-legacy-http.json으로 재현 — 이 설정은 update_resource 도구도 제공해서 알림 왕복을 직접 구동해볼 수 있어요.

Modern — 같은 Subscribe 버튼이 대신 subscriptions/listen 을 보내는데, 필터가 resourceSubscriptionsresourcesListChanged 옵트인을 함께 지녀요. 서버가 notifications/subscriptions/acknowledged를 보내면 구독이 확인돼요. 구독이 이제 세션 플래그가 아니라 장수 스트림이므로, Subscriptions 섹션 헤더에 Connecting...에서 Listening으로 옮겨가는 stream-status 배지가 생겨요. 스트림이 끊기면 Inspector는 subscriptions/listen을 다시 보내 재연결해요. test-servers/configs/subscriptions-modern-http.json으로 재현.

Tasks

Tasks는 프로토콜 에라 사이에서 가장 많이 바뀌는데, Inspector UI 탭이 어떻게 게이트되는지까지 포함해요.

LegacyTasks 탭은 서버가 capabilities.tasks를 광고할 때 나타나요. Run as task로 도구를 실행하면 탭이 그것을 나열하는데, tasks/list로 채우고 tasks/get으로 폴링해요. 완료된 페이로드는 블로킹 tasks/result 로 가져오고, Canceltasks/cancel을 보내요. test-servers/configs/tasks-legacy-http.json으로 재현.

Modern — Tasks는 익스텐션(io.modelcontextprotocol/tasks, SEP-2663)이라서 탭이 capabilities.tasks가 아니라 협상된 익스텐션으로 게이트돼요. 도구를 태스크로 실행하면 tools/callCreateTaskResult(resultType: "task", Protocol·Network 탭에서 보임)를 반환해요. Inspector는 tasks/get 폴링해요. tasks/list는 없으므로 Refresh가 클라이언트가 이미 아는 핸들을 다시 폴링해요. 완료된 태스크는 결과를 인라인하고, 블로킹 tasks/result 호출이 없어요. 더 많은 정보가 필요한 태스크는 input_required로 이동해서 보류-요청 모달(웹 클라이언트가 요청이 여러분을 기다릴 때마다 여는 대화상자)에 내장된 elicitation을 표면화해요. 답하면 inputResponses를 지닌 tasks/update 가 보내지고, 다음 폴링이 완료돼요. test-servers/configs/tasks-modern-http.json(도구 modern_taskmodern_input_task)으로 재현.

다중 라운드 도구 결과 (MRTR)

modern 에라에서 도구는 최종 결과 대신 input_required를 반환할 수 있는데, elicitation, sampling 요청, 또는 roots/list 요청을 내장해요. 클라이언트는 그 내장 요청에 답하고, tools/callcomplete에 도달할 때까지 새 JSON-RPC id로 재시도해요.

Inspector는 MRTR을 수동으로 구동해요. 그래서 각 라운드가 input_required로 태그된 보류-요청 모달에서 멈춰 여러분이 답하게 해요. Protocol 뷰는 전체 교환을 서로 무관한 호출이 아니라 하나의 MRTR 대화로 묶어요.

test-servers/configs/mrtr-showcase-http.json이 모든 형태를 하나의 modern 서버에 담아요.

도구 무엇을 연습하는지
mrtr_confirm 단일 elicitation 라운드.
mrtr_two_step requestState로 이어진 두 elicitation 라운드.
mrtr_sample Sampling 패널로 라우팅되는 내장 sampling 요청.
mrtr_roots 설정된 roots에서 조용히 답하는 내장 roots/list(모달 없음).
mrtr_edge inputRequests-전용 라운드, 이어서 requestState-전용 라운드.
mrtr_loop 절대 완료되지 않아 클라이언트가 MRTR_MAX_ROUNDS 한도에서 멈춤.

legacy collect_elicitation 패턴(서버가 server.elicitInput을 호출)은 2026-07-28 연결에서 오류로 처리돼요. 서버→클라이언트 요청이 거기선 허용되지 않기 때문이죠. MRTR이 그 modern 대체물이에요.

Tools: 미러링된 헤더와 제외된 도구

SEP-2243은 도구가 인자를 x-mcp-header로 어노테이션해서, Streamable HTTP 클라이언트에게 그 인자 값을 Mcp-Param-* 요청 헤더로 미러링하도록 요청하게 해요.

Inspector는 그 계약의 양쪽 절반을 Tools 탭에서 표면화해요.

  • 유효한 어노테이션을 지닌 도구는 상세 패널에 "Mirrored request headers (SEP-2243)" 섹션을 보여줘요. 예: city -> Mcp-Param-City.
  • 잘못된 어노테이션을 지닌 도구(예: 공백 때문에 RFC 9110 토큰으로 유효하지 않은 "Bad Header"라는 헤더 이름)는 사이드바에 "Excluded (SEP-2243)" 구분선 아래 취소선으로 나타나고, 호버하면 이유가 나와요. 준수 클라이언트는 그런 도구를 tools/list에서 반드시 빼야 해요. Inspector는 조용히 숨기는 대신 뺐는지 보여줘요.

test-servers/configs/xmcpheader-modern-http.json으로 재현.

Mcp-Param-* 미러링은 브라우저의 SDK에서 건너뛰어져요. 클라이언트에서 미러링된 도구를 호출하면 헤더가 빠져서, 엄격한 서버는 -32020(HeaderMismatch, 아래 오류 분류)으로 답해요. 같은 도구를 CLITUI(둘 다 Node에서 실행)에서 호출하면 올바르게 미러링돼요. 이 헤더는 Inspector 제어 밖인 SDK 내부의 환경 검사로 버려져요.

-32602 오류 패널

modern 에라에서 -32602로 거부하는 tools/call은 별개의 오류 패널로 렌더링돼요.

  • Unknown Tool: 메시지가 서버가 나열하지 않는 도구를 이름 지을 때. 서버의 tools/list에 없는 어떤 이름을 호출하면 재현돼요.
  • Invalid Parameters: 그 외의 어떤 -32602. 위 설정의 trigger_invalid_params 도구로 재현.

두 에라 모두 -32602로 거부해요. 바뀌는 건 Inspector의 표현뿐이에요. legacy 연결에서는 일반 JSON-RPC 실패 하나만 나오고, 어느 경우인지 알려면 메시지를 읽어야 해요.

Network와 Protocol: 헤더와 오류 분류

modern 에라는 Mcp-* HTTP 헤더 집합을 표준화하고 더 풍부한 JSON-RPC 오류 분류(SEP-2243 / SEP-2575)를 도입해요. 두 모니터링 탭이 작업을 나눠요.

  • Network 탭은 HTTP 뷰: 미러링된 Mcp-* 헤더가 강조되고 센티널 값이 디코딩돼요.
  • Protocol 탭은 JSON-RPC 뷰: 각 명세 오류가 일반 실패가 아니라 개별적으로 렌더링돼요.

test-servers/configs/modern-network-http.json은 클래스마다 하나씩, 실제 HTTP 상태와 JSON-RPC 오류 본문을 만드는 도구 네 개를 서빙해요.

도구 HTTP JSON-RPC 코드 의미
trigger_header_mismatch 400 -32020 필수 미러링 헤더가 없거나 틀림.
trigger_missing_capability 400 -32021 요청이 서버가 필요로 하는 클라이언트 capability를 생략함.
trigger_unsupported_version 400 -32022 지원하지 않는 버전; 지원 버전은 data.supported에.
trigger_method_not_found 404 -32601 메서드를 찾지 못함.

세션

legacy Streamable HTTP 연결은 서버가 배정한 세션 id(Mcp-Session-Id)를 지닐 수 있고, 클라이언트는 HTTP DELETE로 그것을 내려요. modern 연결은 세션리스이자 요청별이에요. 세션 id가 없으므로 클라이언트 SDK는 서버에 DELETE를 보내지 않고, 연결 끊기는 순전히 로컬이에요.

이것은 여러분의 테스트 서버에 실용적인 결과를 줘요. 요청마다 만들어지는 무상태 modern 핸들러는 호출 사이에 상태를 지닐 수 없어서, test-servers/configs/subscriptions-modern-http.json은 legacy 대응물과 달리 update_resource 도구를 생략해요. 변경이 일회용 서버 인스턴스에 대해 실행돼 다음 읽기에 보이지 않을 테니까요.

더 알아보기 (Learn more)