← 목록으로

MCP 서버를 배포해도 툴 설명은 갱신되지 않는다

  • MCP 서버가 클라이언트에 넘기는 건 크게 셋이다. 툴 설명(tools/list), 서버 지침(initialize의 instructions), 툴 호출 결과(tools/call). 이 중 배포하는 순간 반영되는 건 세 번째뿐이다. 앞의 둘은 연결 시점에 한 번 건네지고 그 뒤로는 클라이언트가 들고 있다.
  • 두 필드의 처지도 다르다. 툴 목록은 notifications/tools/list_changed로 갱신을 알릴 수 있지만 스펙 문구가 MUST가 아니라 SHOULD다. 반면 instructions는 initialize 응답에만 실리고, 라이프사이클 스펙 어디에도 "instructions가 바뀌었다"는 알림이 정의되어 있지 않다. 재연결 외에 갱신 경로가 없다.
  • 서버리스라면 그 알림조차 실질적으로 못 보낸다. 알림을 보내려면 해당 세션으로 열린 스트림이 필요한데, 배포하면 인스턴스가 통째로 교체되어 기존 세션을 들고 있던 쪽이 사라진다.
  • 결과적으로 3주 전에 커넥터를 붙인 사용자의 세션은 3주 전 툴 설명을 읽으면서 오늘 배포된 코드를 호출한다. 에러가 나지 않고, 타입도 안 깨지고, 응답 코드는 200이다. 모델이 조용히 조금 다른 판단을 내릴 뿐이다.
  • 실제 사고 사례. 가계부 항목 분류 정의를 고쳐 배포했는데, 배포 전에 연결된 세션이 살아 있었다. 그 세션의 모델은 옛 정의를 들고 있었고 사용자 데이터는 이미 새 정의로 정리되어 있어서, 모델이 "분류가 잘못됐다"고 판단하고 되돌리려 했다. 버그가 아니다. 양쪽이 서로 다른 시점의 계약을 성실하게 지킨 것이다.
  • 대응은 계약을 산문에서 코드로 옮기는 것이었다. 지켜져야만 하는 규칙은 툴 설명에 문장으로 쓰지 않고 응답 경로에서 거절로 강제한다. 거절 로직은 코드라 배포하면 즉시 반영되고, 오래전에 연결한 사용자에게도 곧바로 적용된다.
  • 흔한 클라이언트 버전 스큐와 결정적으로 다른 점은, 낡은 코드는 시그니처가 안 맞으면 터지지만 낡은 지시문은 절대 안 터진다는 것이다.
그냥 목록으로
원문 보기 ↗