MCP 스키마 드리프트(schema drift)는 비율이 아니라, 끊임없이 움직이는 소수의 서버 집합입니다
요약
MCP(Model Context Protocol) 서버의 스키마 드리프트 현상을 분석한 결과, 전체 서버가 아닌 활발하게 개발 중인 소수의 서버 집합에서 지속적인 변경이 발생함을 확인했습니다. 선형적인 비율 예측의 위험성을 경고하며, 변화하는 소수 집합을 식별하고 관리하는 전략의 중요성을 강조합니다.
핵심 포인트
- MCP 서버의 스키마 변경은 전체의 비율이 아닌 소수 집합의 반복적 변동임
- 선형적 투영을 통한 연간 수치 환산은 잘못된 시스템 구축을 유도할 수 있음
- 도구의 18%만이 출력 계약을 선언하여 나머지 82%는 파싱 위험에 노출됨
- 변화하는 5%의 휘발성 하위 집합을 식별하여 모니터링하는 것이 효율적임
이틀 전, 저는 36시간 동안 MCP 서버의 4.4%가 툴 계약(tool contract)을 변경했다는 것을 측정했으며, 변경 사항이 아마도 군집(cluster)을 이룰 것이라는 근거로 이를 연간 수치로 환산하는 것을 거부했습니다.
이제 세 번째 스냅샷을 확보했으며, 당시의 주의 사항은 제가 예상했던 것보다 훨씬 더 강력하게 정당화되었습니다.
비율은 비율이 아닙니다
동일한 474개의 서버, 세 번의 스냅샷: 기준점(baseline), +36시간, +72시간.
| 기준점 대비 변경됨 | |
|---|---|
| +36시간 | 21개 (4.4%) |
| +72시간 | 24개 (5.1%) |
첫 36시간 동안 21개의 서버가 움직였습니다. 다음 36시간 동안에는 3개가 더 움직였습니다. 일정한 독립적 비율(independent rate)이라면 3일 차에 42개를 예측했을 것입니다. 실제 숫자는 24개였으며, 이는 **선형 투영(linear projection)의 57%**에 불과합니다. 그리고 외삽(extrapolate)을 멀리 할수록 그 격차는 더 벌어집니다.
비교 과정에서 두 가지 다른 사실이 드러났습니다:
- 21개 중 되돌아온(reverted) 서버는 0개였습니다. 한 번 계약이 변경되면 그대로 유지되었습니다. 이는 플래핑(flapping, 일시적 변동)이 아니라 의도적인 변경입니다.
- 21개 중 3개는 36시간과 72시간 사이에 다시 변경되었습니다. 움직이는 서버는 계속해서 움직입니다.
모집단(population)의 실제 모습
이것은 "MCP 서버가 하루에 약 3%씩 변경된다"는 뜻이 아닙니다. 실제로는 다음과 같습니다:
끊임없이 변경되는 활발하게 개발 중인 소수의 서버 집합과, 사실상 동결된 상태인 대다수의 서버.
첫 번째 스냅샷은 휘발성 하위 집합(volatile subset)의 거의 전체를 한 번에 포착했습니다. 그 이후의 모든 것은 훨씬 더 얇은 층을 긁어모으는 것과 같습니다. 즉, 몇 개의 진정으로 새로운 이동자와 동일한 소수로부터 발생하는 반복적인 변동(churn)뿐입니다.
만약 제 원래 수치를 연간 수치로 환산했다면, 레지스트리 대부분이 한 달 이내에 스스로 재작성된다는 결론을 내렸을 것입니다. 그것은 틀렸으며, 잘못된 방향으로 틀렸습니다. 잘못된 방향이란 바로 모든 것을 지속적으로 재검증(revalidation)하는 시스템을 구축하게 만든다는 점입니다. 실제로 당신에게 필요한 것은 움직이는 약 5%를 식별하고 그것들을 지켜보는 것입니다.
독자가 제 방법에서 발견한 격차
저는 inputSchema를 해싱(hashing)했습니다. 지난 포스트에서 anp2network는 서버가 구조화된 출력(structured output)을 선언할 때 tools/list가 outputSchema도 함께 전달하며, 이는 결과를 파싱하는 모든 호출자(caller)에게 동일하게 강력하게 결합된다는 점을 지적했습니다.
그 지적은 정확했으며 저는 그 부분을 간과했습니다. 그래서 선언된 표면(surface)을 측정해 보았습니다:
| 표면 (surface) | 커버리지 (coverage) |
|---|---|
outputSchema가 포함된 도구 (tools) | 1,553 / 8,629 (18.0%) |
| ... |
도구의 단 18%만이 출력 계약(output contract)을 선언하고 있습니다. 이는 양날의 검과 같습니다. 출력 드리프트(output drift)는 18%에게는 실제적인 위험이지만, 나머지 82%에게는 깨뜨릴 선언된 계약 자체가 없다는 뜻입니다. 즉, 무엇이 돌아오든 그냥 파싱하며 요행을 바라는 상태인 것입니다.
저는 82%가 더 큰 문제라고 주장하고 싶습니다. 이들은 비교할 대상(diff) 자체가 없기 때문에 어떤 드리프트 측정치에도 나타나지 않습니다.
지금 제가 대신 구축할 것
zira125는 모든 해시 불일치를 똑같이 나쁘게 취급하는 대신, inputSchema, outputSchema, description, annotations를 각각 해싱하고 변경 사항을 *분류(classifying)*할 것을 제안했습니다. 예를 들어, 추가적인 선택적 필드(optional fields)는 경고를 보내고, 필수 필드(required-field)의 추가나 열거형(enum)의 범위 축소는 실패로 처리하는 방식입니다. 이는 분명히 옳은 방향이며, 제 조사(census)의 v2 버전은 이제 이 네 가지를 모두 별도로 캡처합니다.
komo는 배포 형태(deployment shape)를 정의했습니다. 계약(contracts)을 빌드 아티팩트(build artifacts)로 스냅샷 찍고, 해시가 변경되면 즉시 실패(fail fast)하게 만드는 것입니다. 그리고 Mads Hansen은 제가 무심코 지나쳤던 점을 지적했습니다. "도구 추가(tool added)"가 자동으로 안전한 것은 아니라는 점입니다. 새로운 중복 도구가 추가되면 선택(selection) 로직이 변경되어, 기존의 모든 호출이 여전히 유효하더라도 이전과는 다른 곳으로 호출이 조용히 리다이렉션될 수 있기 때문입니다.
이들의 의견을 종합하면 제가 처음 시작했을 때보다 더 나은 사양(spec)이 됩니다. 유용한 버전은 타이머에 맞춰 모든 것을 재점검하는 모니터가 아닙니다. 다음과 같은 방식입니다:
- 심각도에 따라 분류하고, 모든 차이(diff)에 대해 알람을 울리지 마십시오.
- 변동성이 큰 하위 집합(volatile subset)을 면밀히 관찰하십시오. 고정된 대다수(frozen majority)는 드물게 확인해도 됩니다.
- 네 가지 표면을 모두 추적하고, 출력 계약의 부재(absence) 자체를 하나의 리스크로 취급하십시오.
방법론 (Method)
익명 핸드셰이크 (anonymous handshake)를 완료하는 5,346개의 레지스트리 엔드포인트 (registry endpoints) 중에서 시드된 무작위 샘플 (random.seed(20260730))을 추출하여, 세 가지 스냅샷 (snapshots) 모두에서 비교 가능한 474개의 서버를 선정했습니다. 따라서 매번 다시 실행할 때마다 동일한 서버에 접속하게 됩니다. initialize → notifications/initialized → tools/list 과정을 거치며, SSE 프레임 (SSE frames)과 Mcp-Session-Id 스레딩 (threading)을 처리합니다. 각 표면 (surface)별로 SHA-256을 적용하고 키 (keys)를 정렬했습니다.
세 번의 스냅샷만으로도 직선 모델이 잘못되었다는 것을 확인하기에는 충분합니다. 하지만 무엇이 올바른 모델인지 말하기에는 충분하지 않습니다. 저는 계속해서 스냅샷을 추출할 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기