MCP 2026-07-28 스펙 마이그레이션: 무상태 전환으로 바뀐 것과 기존 서버 점검 순서

세션·초기화 절차 제거, server/discover, 다중 왕복 요청, 폐기 예정 기능까지 공식 변경 이력 기준 정리

MCP 무상태 스펙 마이그레이션 썸네일

핵심 요약

  1. 2026-07-28은 initialize 절차와 Mcp-Session-Id를 없애고 요청마다 _meta에 버전을 싣는 무상태 구조다.
  2. 서버는 server/discover를 반드시 구현하고 모든 결과에 resultType을 넣어야 한다.
  3. 서버가 클라이언트에 보내던 요청은 InputRequiredResult를 쓰는 다중 왕복 요청(MRTR)으로 바뀌었다.
  4. 구버전 클라이언트는 새 전용 서버에 연결할 수 없으므로 전환 기간에는 dual-era 운영이 현실적이다.

MCP의 현재 프로토콜 버전은 2026-07-28이다. 버전 정책상 버전 날짜는 하위 호환이 깨지는 변경이 마지막으로 있었던 날을 뜻하는데, 이번 버전은 이름 그대로 호환이 깨지는 변경을 여럿 담고 있다. 핵심은 연결마다 세션을 맺던 구조를 없애고, 모든 요청이 스스로 버전과 기능 정보를 싣는 무상태 구조로 바꾼 것이다. 이 글은 공식 변경 이력을 기준으로 무엇이 바뀌었는지, 기존 서버를 옮길 때 어디부터 확인할지를 정리한다.

주요 변경 사항 한눈에 보기

이전(2025-11-25)2026-07-28
initialize/notifications/initialized 초기화 절차제거. 요청마다 _meta에 프로토콜 버전·클라이언트 기능 포함
Streamable HTTP의 Mcp-Session-Id 세션제거. 호출 간 상태는 서버가 발급한 핸들을 도구 인자로 주고받음
초기화 응답으로 기능 교환서버가 server/discover를 반드시 구현
서버가 클라이언트에 요청(sampling/createMessage, elicitation/create 등)다중 왕복 요청(MRTR): 서버가 InputRequiredResult를 반환하고 클라이언트가 정보를 담아 원 요청을 재시도
HTTP GET 스트림, resources/subscribesubscriptions/listen 하나로 통합
ping, logging/setLevel제거. 로그 수준은 요청의 _meta로 지정
SSE 재개(Last-Event-ID)제거. 끊긴 요청은 새 ID로 다시 보냄

그 밖에 모든 결과에 resultType 필드가 필수가 됐고("complete" 또는 "input_required"), Streamable HTTP POST 요청에 Mcp-Method, Mcp-Name 헤더가 필수가 됐다. 목록 조회 결과에는 캐시 힌트인 ttlMs와 cacheScope가 추가됐다. 실험 기능이던 tasks는 코어에서 빠져 공식 확장으로 옮겨졌다.

요청은 이렇게 달라진다

// 2026-07-28: 초기화 없이 바로 요청하되, 버전을 _meta에 싣는다
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

// 서버가 해당 버전을 지원하지 않으면
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32022,
    "message": "Unsupported protocol version",
    "data": { "supported": ["2026-07-28", "2025-11-25"], "requested": "1900-01-01" }
  }
}

버전 오류 코드는 이번 버전에서 새 오류 코드 할당 정책에 따라 -32022로 정해졌고, 리소스를 찾지 못한 경우의 코드도 -32002에서 -32602로 바뀌었다. 오류 코드를 숫자로 비교하는 클라이언트 코드가 있다면 함께 수정해야 한다.

구버전과 섞여 있을 때의 동작

호환성 문서는 초기화 절차를 쓰는 2025-11-25 이하를 legacy, 새 방식을 modern, 둘 다 지원하는 구현을 dual-era로 부른다. 새 클라이언트가 구버전 서버에 붙거나 구버전 클라이언트가 새 전용 서버에 붙으면 연결이 실패한다. 구버전 클라이언트에는 새 버전으로 넘어갈 방법이 없으므로, 사용자가 많은 서버는 한동안 두 방식을 모두 지원하는 dual-era로 운영하는 것이 현실적이다. dual-era 서버는 요청에 새 방식의 _meta가 있으면 무상태로, initialize 요청이 오면 기존 방식으로 응답한다.

기존 서버를 옮길 때 점검 순서

  1. 사용 중인 SDK의 지원 버전 확인: 직접 프로토콜을 구현하지 않았다면 SDK가 2026-07-28과 dual-era를 지원하는지부터 본다.
  2. 세션에 기대는 코드 찾기: 세션 ID로 사용자 상태를 저장했다면, 서버가 발급한 핸들을 도구 인자로 받는 방식으로 바꾼다. 이때 핸들은 인증된 사용자에 서버 쪽에서 묶어야 한다.
  3. 서버 발 요청을 MRTR로 바꾸기: 샘플링이나 사용자 입력 요청을 보내던 부분을 InputRequiredResult 반환으로 바꾼다.
  4. 제거된 메서드 정리: ping, logging/setLevel, SSE 재개 처리 코드를 걷어낸다.
  5. server/discover 구현과 resultType 추가: 모든 결과에 resultType을 넣는다.
  6. 폐기 예정 기능 계획: Roots, Sampling, Logging 기능과 HTTP+SSE 전송, 동적 클라이언트 등록이 Deprecated로 분류됐다. 폐기 예정 기능은 최소 12개월 유지되지만 새 구현에는 쓰지 않는다.
# 옮길 대상 코드 위치를 먼저 찾아 두기
grep -rnE "Mcp-Session-Id|initialize|logging/setLevel|\"ping\"|Last-Event-ID|sampling/createMessage|elicitation/create|roots/list" src/

세션이 사라진 뒤의 보안 포인트

세션이 없어지면 여러 요청에 걸친 상태를 서버가 발급한 핸들로 주고받게 된다. MCP 보안 문서는 핸들을 가지고 있다는 사실만으로 인증된 것으로 취급하지 말고, 추측할 수 없는 난수로 만들고, 인증된 사용자와 서버 쪽에서 묶으라고 권한다. 인가 쪽에서도 인가 응답의 iss 검증 의무 등이 추가됐는데, 이 부분은 MCP 서버 OAuth 구현 항목에 정리했다. MCP 구조 자체를 먼저 이해하려면 MCP 개념 정리를 참고한다.

초보자가 자주 실수하는 포인트

  • 세션 ID 대신 쓰는 핸들을 인증 수단처럼 취급하는 경우
  • 오류 코드를 숫자로 비교하던 코드를 새 코드 번호에 맞게 고치지 않는 경우
  • 폐기 예정인 Sampling이나 HTTP+SSE 전송을 새 구현에 도입하는 경우

체크리스트

  • 사용 중인 SDK가 2026-07-28과 dual-era를 지원하는지 확인했는가
  • 세션에 의존하던 상태를 사용자에 묶인 핸들로 바꿨는가
  • server/discover와 resultType을 구현했는가
  • 제거된 메서드와 SSE 재개 코드를 정리했는가
  • 폐기 예정 기능의 대체 계획을 세웠는가

자주 묻는 질문

당장 옮기지 않으면 기존 클라이언트가 끊기나요?

서버가 기존 방식(2025-11-25)을 계속 지원하는 한 기존 클라이언트는 그대로 동작한다. 문제는 새 방식만 쓰는 클라이언트가 늘어날 때로, 그 클라이언트는 구버전 서버에 연결하지 못한다. 전환 기간에는 두 방식을 모두 지원하는 것이 안전하다.

참고 자료 · 검증 기준

위 자료와 내용을 대조한 날짜: . 도구·서비스 정책은 이후 바뀔 수 있으므로 적용 전 공식 문서를 다시 확인하세요.

이 글은 위 참고 자료를 바탕으로 정리했으며, 내용은 운영 과정에서 순차적으로 보완될 수 있습니다.