코사인 유사도(Cosine Similarity)가 혼동하기 쉬운 MCP 도구들을 잡아내지 못하는 이유
요약
MCP 서버의 중복 도구 정의로 인한 LLM 에이전트의 혼동 문제를 해결하기 위한 방법론을 다룹니다. 단순한 코사인 유사도 방식의 한계를 지적하며, 스키마 대체 가능성을 먼저 검증하는 구조적 접근법을 제안합니다.
핵심 포인트
- 코사인 유사도는 도메인 어휘 중복과 동사 차이 간과로 인해 도구 혼동을 잡아내지 못함
- 텍스트 유사도 측정 전, 인자(arguments)의 스키마 호환성을 먼저 검증해야 함
- 스키마 대체 가능성 검증을 통해 불필요한 비교 쌍을 효과적으로 제거 가능
MCP (Model Context Protocol) 서버는 LLM 에이전트가 실행 시점에 무엇을 호출할지 결정하기 위해 읽는 도구 정의(이름, 설명, JSON 스키마 등)를 노출합니다. 서버가 중복되는 기능을 가진 여러 도구(read_file, read_text_file, read_media_file)를 선언할 때, 에이전트는 빈번하게 잘못된 도구를 선택하거나 유효하지 않은 인자(arguments)를 생성합니다. 도구의 수가 증가함에 따라, 배포 전에 혼동하기 쉬운 정의들을 잡아내는 것은 실제 품질 및 안전 문제로 직결됩니다.
명확한 해결책은 텍스트 유사도(text similarity)입니다. 설명을 벡터화(vectorize)하고, 코사인 유사도(cosine similarity)를 계산하여 임계값(threshold)을 넘는 항목을 표시하는 것입니다. 저는 실제 데이터를 대상으로 이를 실행해 보았으나 작동하지 않았습니다. 여기 그 이유에 대한 실증적인 사례와 대신 무엇이 효과적이었는지에 대해 설명합니다.
단순한 접근 방식 (The naive approach)
TF-IDF로 각 도구 설명을 벡터화하고, 쌍별 코사인 유사도(pairwise cosine similarity)를 계산하여 약 0.85를 초과하는 쌍을 표시합니다.
실패하는 이유
공식 @modelcontextprotocol/server-filesystem 서버의 14개 도구를 대상으로 테스트했습니다 — 총 91개의 고유한 쌍(pairs)이 존재합니다.
- 표준 임계값에서 탐지 결과가 0건입니다. 0.85 코사인 유사도에서 TF-IDF는 91개 쌍 중 단 하나도 잡아내지 못했습니다.
- 어떤 임계값도 작동하지 않습니다. 임계값을 낮추어도 도움이 되지 않습니다. 혼동하기 쉬운 쌍(
read_filevs.read_text_file)과 명확히 구분되는 쌍(read_filevs.write_file)의 유사도 분포가 서로 겹치기 때문입니다. 이들을 분리할 수 있는 절단점(cut point)이 존재하지 않습니다.
이 방식이 실패하는 두 가지 이유는 다음과 같습니다:
- 공유된 도메인 어휘(Shared domain vocabulary)가 지배적입니다. 동일한 서버의 도구들은 혼동 가능 여부와 관계없이 동일한 명사(
path,directory,file,permissions)를 반복합니다. 높은 용어 중복도는 도구의 모호성이 아니라 서버의 도메인을 반영합니다. - 반대되는 동사가 미치는 영향이 거의 없습니다.
read_file과write_file은 토큰의 80% 이상을 공유합니다. 코사인 유사도는read와write의 차이를 수많은 단어 중 단 하나의 차이로 취급합니다. 하지만 정작 중요한 것은 바로 그 차이 자체입니다.
효과적인 방법: 스키마 대체 가능성(schema substitutability)을 먼저 검증하기
텍스트 점수를 먼저 매기는 대신, 구조를 먼저 검증(gate)하십시오: 한 도구의 인자(arguments)가 다른 도구의 스키마(schema)를 충족할 수 있는가? 만약 A의 모든 필수 속성(required property)이 B에 호환 가능한 타입으로 존재하고, 어느 한 쪽도 상대방을 즉시 망가뜨릴 만한 필수 파라미터(required parameter)를 가지고 있지 않다면, 두 스키마는 대체 가능(substitutable)합니다. 스키마가 대체 가능하지 않다면, 에이전트(agent)는 말 그대로 두 호출을 혼동할 수 없습니다. 따라서 이러한 쌍들은 텍스트 비교가 일어나기 전에 폐기됩니다.
파일 시스템 서버(filesystem server)의 경우, 이 구조적 검증(structural gate)을 통해 점수 산정(scoring)이 시작되기 전 91개의 쌍 중 63개를 제거합니다.
남은 28개에 대해서는 다음 항목으로 점수를 매깁니다:
- 이름 유사도 (name affinity) (편집 거리(edit distance), 공유 접두사/접미사(shared prefix/suffix))
- 설명 유사도 (description similarity) (도메인 외 토큰 중복(non-domain token overlap))
- 이름이나 설명에 상반되는 동사(
read/write,create/delete,encrypt/decrypt)가 포함된 경우 강력한 거부(hard veto)
결과 (Results)
다음 4개의 쌍이 식별되었습니다:
read_file/read_text_fileread_file/read_media_fileread_text_file/read_media_filelist_directory/list_directory_with_sizes
이들의 점수는 0.42–0.48 사이에 위치하며, 식별되지 않은 모든 쌍(0.00–0.32)과 명확히 구분됩니다. 즉, 두 클래스 사이에 0.33–0.50의 실제 격차가 존재하며, 이는 코사인 유사도(cosine similarity)만으로는 결코 만들어낼 수 없었던 결과입니다.
91개 쌍 전체 데이터셋 — 원시 코사인 점수(raw cosine scores), 대체 가능성 결정(substitutability decisions), 유사도 점수(affinity scores), 거부 플래그(veto flags) — 은 공개되어 있습니다:
docs/data/filesystem-server-ambiguity-scan.json.
한계점 (Limitations)
- 단일 서버 (Single server). 이번 평가는 하나의 서버, 14개의 도구, 91개의 쌍(pairs)을 대상으로 합니다. 이것이 다른 MCP 서버로 일반화될 수 있는지는 테스트되지 않았습니다.
- 동사 거부(verb veto)는 휴리스틱 (heuristic)일 뿐, 증명이 아닙니다. 이는 일반적인 CRUD 반의어에 맞춰 조정되었으므로, 동사 대립 관계가 아닌 범위 기반의 모호성(예:
read_filevs 가상의read_all_files)은 놓칠 수 있습니다. - 이는 문서화의 공백을 잡아내는 것이지, 런타임 버그 (runtime bugs)를 잡는 것이 아닙니다. 플래그가 지정된 쌍은 구현상 완벽하게 안전할 수 있으며, 플래그가 지정되지 않은 쌍에 여전히 버그가 있을 수 있습니다. 이 도구는 서버가 실제로 무엇을 하는지가 아니라, 에이전트에게 무엇이 전달되는지를 감사 (audit)합니다.
사용해 보기 (Try it)
이 기능은 mcplock에 구현되어 있습니다. 이는 모든 MCP 서버를 대상으로 린트 체크 (lint check)를 수행하는 오픈 소스 CLI (pip install mcplock)이며, 사후에 드리프트 (drift)를 잡아내기 위한 별도의 해시 기반 베이스라인/디프 (baseline/diff) 모드도 제공합니다. 대체 가능성 (substitutability) 접근 방식, 특히 다른 MCP 서버에 대한 피드백은 매우 유용할 것입니다. 이것이 현재 가장 주요한 미결 과제입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기