MCP Python SDK 2.3.0 업그레이드 전 서버·클라이언트 점검

MCP Python SDK 2.3.0의 헤더 검증, 요청 필드 생략, OAuth 타임아웃 변경을 기준으로 서버와 클라이언트의 업그레이드 점검 항목을 정리한다.

2026-10-09

의존성과 도구 등록부터 확인한다

MCP Python SDK 2.3.0에서는 잘못된 x-mcp-header 선언이 도구 등록을 실패시킨다. 이전에 서버가 시작됐다는 사실만으로는 업그레이드 후에도 같은 도구를 등록할 수 있다고 판단할 수 없다.

이 글의 점검 기준은 mcp (python-sdk) v2.3.0 (2026-10-02), 직전 v2.2.0, httpx2>=2.10.0이다. v2.3.0 릴리스노트에 나온 동작 변경을 서버·클라이언트의 확인 항목으로 바꿔 정리한다.

릴리스노트가 안내하는 업데이트 명령은 다음과 같다.

pip install -U mcp

실행 전에 httpx2를 별도로 고정하고 있는지 확인한다. 요구 하한이 >=2.5.0에서 >=2.10.0으로 바뀌었으며, 새 max_sse_event_size 옵션이 이 의존성을 필요로 한다. 2.10 미만으로 고정하지 않았다면 이 항목 때문에 별도로 할 일은 없다.

의존성을 확인한 뒤에는 실제 도구 등록 경로를 실행한다. @mcp.tool(), add_tool, Tool.from_function 모두 잘못된 헤더 선언에 대해 InvalidSignature를 발생시키며, 오류에는 도구 이름과 문제가 포함된다.

헤더 선언 오류를 등록 경로에서 찾는다

이전에는 잘못된 x-mcp-header 선언이 있어도 서버가 시작됐고, 2026-07-28 클라이언트가 해당 도구를 목록에서 조용히 제외했다. 이제 오류가 등록 시점에 드러난다. 도구 목록만 확인하던 검증에 등록 성공 여부와 오류 내용을 포함해야 하는 이유다.

거부되는 선언은 다음과 같다.

  • 일반 str, int, bool 이외의 파라미터 타입. str | None, float, 리스트, enum도 포함된다.
  • 유효한 토큰이 아닌 헤더 이름.
  • 대소문자만 다른 헤더 이름의 중복.

아래 그림은 같은 선언 오류가 이전에는 클라이언트의 도구 목록에서 드러났지만, 이제는 등록 경로에서 실패하는 차이를 보여 준다.

⤢✕잘못된 x-mcp-header 선언이전 동작v2.3.0서버 시작2026-07-28 클라이언트가 도구목록에서 제외도구 등록 시 InvalidSignature도구 이름과 문제 확인

선택적 헤더를 사용한다면 str | None이라는 타입 표기만 확인해서는 부족하다. 릴리스노트는 스키마를 직접 제공하는 다음 파라미터 선언을 제시한다.

Annotated[str | None, WithJsonSchema({"type": "string", "x-mcp-header": "Region"})] = None

기존 선택적 헤더 선언을 이 예시와 대조하고, 실제 등록 경로에서 허용되는지 확인한다. 타입뿐 아니라 헤더 이름과 대소문자 중복도 함께 확인해야 등록 오류의 원인을 놓치지 않는다. 관련 문서는 Header parameters에 연결돼 있다.

레거시 연결에서는 빈 객체 대신 누락과 None을 처리한다

2025-11-25 및 그 이전 연결에서 2.x가 매 요청에 보내던 "_meta": {}는 더 이상 전송되지 않는다. 일부 서버가 이 빈 객체를 거부했으며, v2.3.0은 v1처럼 해당 필드를 생략한다. 2026-07-28 연결의 동작은 바뀌지 않는다.

ping과 커서 없는 목록 요청도 params 멤버 없이 전송된다. 수신 측에서는 ctx.meta가 {} 대신 None이 되고, 파라미터 없는 요청을 받은 미들웨어는 ctx.params를 None으로 보게 된다.

따라서 레거시 연결을 운영한다면 요청의 직렬화 결과와 수신 코드를 함께 확인한다. 항상 빈 객체가 존재한다고 가정하는 코드, 빈 객체와 필드 누락을 구분하는 검사, ctx.params를 바로 읽는 미들웨어가 점검 대상이다.

initialize 응답도 확인해야 한다. experimental을 설정하지 않았다면 이전의 "experimental": {}가 생략된다. server/discover는 이미 이를 생략하고 있었다. 레거시 연결에서 capabilities.experimental을 읽는 클라이언트는 None을 처리해야 한다.

아래 비교는 요청에서 생략되는 필드와 응답에서 생략되는 필드를 나누고, 수신 코드가 처리할 값을 연결한다.

⤢✕ 빈 객체 생략과 수신 코드의 처리 MCP Python SDK v2.3.0 · 행별 변경 전 → v2.3.0 → 확인할 수신 값 항목 변경 전 v2.3.0 확인할 수신 값 요청 필드 _meta 2025-11-25 및 그 이전 연결 매 요청에 "_meta": {} 전송 빈 _meta 생략 ctx.meta {} 대신 None params — ping · 커서 없는 목록 요청 params 멤버 없이 전송 파라미터 없는 요청의 미들웨어 ctx.params는 None initialize 응답의 capability experimental initialize가 미설정 시 "experimental": {} 전송 미설정 experimental 생략 레거시 클라이언트 capabilities.experimental 의 None 처리 적용 범위 2026-07-28 연결의 빈 _meta 및 params 처리 동작은 변경 없음 변경 전 v2.3.0 확인할 수신 값 요청 필드 initialize 응답의 capability MCP Python SDK 2.3.0 업그레이드 전 서버·클라이언트 점검 | ai-agents

점검할 때는 연결 버전을 결과에 함께 기록한다. 2026-07-28 연결에서 확인한 요청만으로 레거시 연결의 필드 생략과 None 처리를 검증했다고 볼 수는 없다.

tools/list 미들웨어와 헤더 검증의 관계를 다시 확인한다

Mcp-Param-* 검증은 이제 도구 이름으로 등록된 스키마를 조회한다. MCPServer가 매 tools/call마다 tools/list를 실행하던 동작이 없어져, 미들웨어도 그 추가 요청을 보지 않게 된다.

특히 tools/list를 필터링하거나 다시 작성하는 미들웨어를 사용한다면 영향을 확인해야 한다. 이제 그 변경은 헤더 검증에 반영되지 않는다. 검증 기준은 등록된 스키마다.

점검 대상 이전 동작 v2.3.0 동작 확인할 내용
tools/call의 미들웨어 관측 호출마다 추가 tools/list 요청이 보임 추가 요청이 없어짐 추가 요청을 전제로 한 미들웨어 검사가 있는지
tools/list 필터링·수정 목록 처리 결과가 헤더 검증에 영향을 줌 등록된 스키마로 검증 목록 수정에 검증 동작을 의존했는지
저수준 서버의 스키마 제공 검증을 위해 tools/list 핸들러를 실행하는 경로 Server(get_tool_input_schema=...)로 스키마 제공 가능 목록 핸들러 없이 검증용 스키마를 제공할 필요가 있는지

저수준 서버라면 새 Server(get_tool_input_schema=...) 옵션이 적용 대상인지 살핀다. 이 옵션은 tools/list 핸들러를 실행하지 않고도 헤더 검증에 사용할 도구 스키마를 공급할 수 있게 한다.

클라이언트 측에서는 HeaderMismatch도 점검한다. Client.call_tool은 HeaderMismatch(-32020) 거부를 받으면 도구 목록을 다시 조회하고 한 번 재시도한다. 해당 오류를 재현하는 검증에서는 최초 거부뿐 아니라 목록 재조회와 재시도 결과까지 확인한다. 릴리스노트가 명시한 재시도 범위는 이 오류에 대한 한 번의 재시도다.

OAuth 로그인 대기 제한을 요청 타임아웃과 분리한다

대화형 OAuth 로그인은 이제 요청 타임아웃을 소모하지 않는다. OAuthClientProvider가 redirect_handler와 callback_handler를 기다리는 동안 타임아웃이 일시정지된다.

이 변경은 로그인이 10초보다 오래 걸렸을 때 Client(mode="auto")가 2025-11-25로 결정되던 문제를 수정한다. 자동 모드에서 로그인 시간이 길어지는 상황을 재현하고, 그 결과로 연결이 어떻게 결정되는지 확인할 필요가 있다.

동시에 기존 운영 코드의 대기 제한도 다시 확인해야 한다. 요청 타임아웃은 이제 아무도 완료하지 않는 로그인을 종료하지 않는다. 로그인 대기에 제한이 필요하다면 callback_handler 내부에 둬야 한다.

아래 그림은 SDK가 일시정지하는 요청 타임아웃과, 운영 코드가 필요에 따라 제한해야 하는 로그인 대기의 경계를 보여 준다.

⤢✕callback_handlerredirect_handlerOAuthClientProvidercallback_handlerredirect_handlerOAuthClientProvider핸들러를 기다리는 동안 요청 타임아웃 일시정지로그인 대기 제한이 필요하면 내부에 둠redirect_handler 대기반환callback_handler 대기반환

검증에서는 로그인이 오래 걸리지만 완료되는 경우와 완료되지 않는 경우를 구분한다. 전자는 자동 모드의 연결 결정 문제를 확인하는 상황이고, 후자는 callback_handler의 대기 제한 필요성을 확인하는 상황이다. 같은 요청 타임아웃으로 둘을 처리하던 코드는 이번 변경의 영향을 받는다.

큰 결과와 구독 기능은 필요한 설정만 조정한다

큰 도구 결과를 SSE로 받는 클라이언트에는 max_sse_event_size=가 추가됐다. 적용 위치는 streamable_http_client와 StreamableHttpParameters이며, 기본값은 SSE 이벤트당 1 MiB로 유지된다.

큰 결과를 받아야 한다면 한도를 올리거나 None을 전달할 수 있다. 판단 기준은 SSE 이벤트 크기다. 업그레이드만으로 기본 한도가 커지는 것은 아니므로, 해당 상황을 실제 결과로 확인한 뒤 옵션을 조정한다.

구독 기능을 제공하지 않을 서버에는 MCPServer(subscriptions=False)가 추가됐다. 이 설정은 subscriptions/listen 제공을 중단하고, listChanged와 subscribe를 false로 알린다. 설정을 적용했다면 요청 처리 여부와 광고되는 capability를 함께 확인한다.

운영 상황 관련 옵션·동작 확인할 결과
큰 SSE 도구 결과 수신 max_sse_event_size= 기본 1 MiB 또는 지정한 한도가 해당 이벤트에 맞는지
구독 기능을 제공하지 않는 서버 MCPServer(subscriptions=False) subscriptions/listen 중단과 listChanged, subscribe의 false 광고
저수준 서버의 헤더 검증 Server(get_tool_input_schema=...) 목록 핸들러 실행 없이 필요한 도구 스키마가 제공되는지

수정 항목을 기존 검증에 연결한다

나머지 수정은 해당 기능을 사용하는 경로에서 확인하면 된다. 릴리스 항목마다 새 검증을 만드는 대신, 기존 시나리오에서 기대 결과가 바뀌는 지점을 찾는다.

사용 경로 v2.3.0의 수정 검증할 기대 결과
프롬프트·리소스 템플릿 ctx: Context[AppState]가 도구 외에도 동작 해당 핸들러에서 Context 사용이 동작하는지
도구 출력 스키마 명시적인 "structuredContent": null도 스키마 검증 null을 누락으로 취급하지 않고 출력 스키마에 따라 검사하는지
인프로세스 Client(server) 예외를 발생시키는 progress_callback이 호출을 실패시키지 않음 진행 콜백 예외와 도구 호출 결과를 구분하는지
클라이언트 OpenTelemetry JSON-RPC 오류 응답을 span에 기록 오류 응답의 기록 여부와 자동 모드 탐색 span
Windows stdio_client 실행 파일을 이벤트 루프 밖에서 해석 해당 실행 경로가 동작하는지

OpenTelemetry를 사용한다면 자동 모드의 탐색도 확인한다. server/discover가 없는 서버에 mode="auto"로 연결할 때는 탐색에 대해 하나의 ERROR span이 표시된다. 이 span을 관측했을 때는 어떤 요청에서 발생했는지 확인해야 한다.

업그레이드 검증 결과에는 등록 오류, 레거시 연결의 필드 누락, 미들웨어가 관측하는 요청, OAuth 대기 동작을 각각 남긴다. 이들은 서로 다른 경계에서 발생하는 변경이다. 서버 시작 성공이나 도구 호출 성공만으로는 나머지 경로의 검증을 대신할 수 없다.

MCPPythonSDKOAuth미들웨어