내 MCP 서버는 내가 신뢰하는 API와만 통신한다. 하지만 돌아오는 데이터가 믿을 만하다는 뜻은 아니다.
요약
개발자가 구축한 MCP 서버는 내부적으로 안전할 수 있지만, 반환되는 데이터 자체가 신뢰할 수 있는 정보가 아닐 수 있다는 점을 지적합니다. 특히 API의 'description' 필드처럼 출처를 알기 어려운 텍스트가 에이전트의 컨텍스트에 지침(instruction)으로 오인되어 사용될 위험성을 경고하며, 서버 검증만으로는 충분하지 않음을 강조합니다.
핵심 포인트
- 서버 구조가 안전해도 데이터 내용물은 신뢰할 수 없다.
- API 응답의 텍스트 필드(description 등)는 지침이 아닌 비활성 데이터로 처리해야 한다.
- 에이전트 설계 시, 외부 API 데이터를 '지시사항'으로 해석하는 하위 시스템 버그를 방지해야 한다.
한동안 작은 MCP 서버를 만들었었다. developer-presence라는 이름으로, GitHub REST API와 DEV.to API를 감싸는 일곱 개의 도구로 구성되어 있어서 에이전트가 채팅을 벗어나지 않고도 내 리포지토리 통계를 확인하거나, 내 아티클 목록을 보여주거나, 새 게시물을 초안 작성할 수 있게 해준다. 이건 내가 만든 것이고, 모든 줄을 직접 썼기 때문에 내부적으로 뭔가 수상한 작업을 하는 서드파티 패키지는 없다. 일반적인 'MCP 서버를 설치하기 전에 검증하라' 체크리스트로 보면 깨끗하게 통과한다. 이 체크리스트에 대한 글은 예전에 써본 적이 있다.
최근까지는 생각하지 못했던 것이, 서버를 검증한다고 해서 데이터까지 검증되는 것은 아니라는 점이었다. 그 도구들 중 두 개가 핵심을 짚는다:
@mcp.tool()
def get_repo_stats(repo: str) -> dict:
"""enjoykumawat/<repo>의 별점, 포크 수, 감시자 수, 열린 이슈를 가져온다."""
...
description은 자유 텍스트이다. 어떤 리포지토리 소유자라도 여기에 무엇이든 넣을 수 있다. 만약 내가 이 도구를 내가 통제하지 않는 리포지토리에—다른 사람의 포크, 의존성 등 무엇이든—가리킨다면, 그 필드는 신뢰할 수 있는 지침처럼 작동하는 것이 아니라, 마치 믿을 만한 지침인 것처럼 내 에이전트의 컨텍스트에 똑같이 들어간다. 즉,
응답에 포함된 모든 제목(title), 태그 목록(tag list), 본문 스니펫(body snippet)은 임의의 dev.to 사용자가 작성한 것이며, 검열되지 않았습니다. 저는 이 중 점수가 가장 높은 것들을 가져와서, 무엇에 대해 글을 쓸지 결정하고 실제로 쓰는 역할을 하는 에이전트에게 직접 공급합니다. 게시물이 기사처럼 보이기보다는 운영자 지침(operator instruction)처럼 보이도록 제목이 붙는 경우도 있으며—만약 그것이 에이전트의 컨텍스트에 들어오게 되면 지시사항처럼 읽히도록 설계된 것일 수 있습니다—점수가 충분히 높아 걸러지지 못하는 일이 발생합니다. 저는 아직 실제로 이런 시도를 해본 적은 없습니다. 바로 이것이 놓치기 쉬운 속성입니다: 실패 모드는 '서버가 손상되었다'가 아니라, '평범한 날의 데이터에 적대적인 내용이 포함되어 있었고 하위 시스템(downstream)에서 아무도 알아차리지 못했다'는 것입니다.
이것은 제가 이전 MCP 보안 게시물 두 개 모두에서 건너뛰었던 부분입니다. 하나는 오용에 대비하여 구축하는 서버를 강화하는 것에 관한 것이었고, 다른 하나는 설치하기 전에 서버를 검증하는 것—출처(provenance), 권한(permissions), 무엇을 만질 수 있는지 여부—에 관한 것이었습니다. 둘 다 '서버'를 신뢰 경계(trust boundary)로 취급합니다. 어느 것도 합법적으로 안전하고, 올바르게 범위가 지정되었으며, 완전히 검증된 서버가 완전히 낯선 사람이 작성한 문자열을 반환했을 때, 그리고 그 문자열이 실제 지침과 같은 컨텍스트 창으로 곧장 들어가는 상황에 대해서는 다루지 않습니다.
수정 사항은 아직 코드 레벨이 아니라 제가 무엇을 확인해야 하는지에 대한 변화입니다. 이전에는 '이 도구 호출이 안전한가?'라는 저의 정신 모델이 '내가 이 서버를 신뢰하는가, 그리고 이 서버가 호출하는 API를 신뢰하는가'에서 멈췄습니다. 이제는 그 후에 두 번째 질문이 생겼습니다: '응답의 _내용물_이 낯선 사람이 작성했을 법한 것인가? 그렇다면 하위 시스템(downstream)이 그것을 데이터가 아닌 지침으로 취급할까?' get_repo_stats의 경우, 솔직히 말해서 description은 비활성 텍스트(inert text)로 처리되어야 합니다. 즉, 표시되거나 로깅되거나 요약될 수는 있지만, 결코 지시사항의 원천이 되어서는 안 됩니다. 만약 제가 가져온 설명이나 기사 본문에서 발견된 '지침'에 따라 에이전트가 행동하게 만든다면, 그것은 API 응답 자체의 문제가 아니라 버그입니다. 트렌딩 토픽(trending-topics) 작업의 경우, 점수 매기기와 주제 선정 단계는 항상 _글로 작성할 주제_만을 생성해야 하며, 도구가 호출되거나 파일이 수정되는 것을 변경하는 무언가를 절대 생성해서는 안 됩니다. 이는 실제로 제가 우연히 그렇게 구축한 방식이며, 사전에 위협 모델링(threat-modeling)을 통해 설계한 것은 아닙니다.
전반적인 형태를 보면 이렇습니다: 사용자의 통제 밖에 작성된 텍스트를 포함하는 모든 도구 결과물 — 소개글(bio), 댓글, PR 설명, 트렌딩 게시물, 다른 사람이 선택한 파일 이름 등 — 은 신뢰할 수 없는 입력값입니다. 끝입니다. 얼마나 많이 API가 그것을 제공하든 상관없이 말이죠. 서버를 검증하는 것은 '파이프라인을 신뢰할 수 있는가?'라는 질문에 답합니다. 하지만 결코 '그것을 통해 흐르는 것을 신뢰할 수 있는가?'라는 질문에는 답하지 않습니다. 이 둘은 완전히 다른 질문이며, 저는 지금까지 항상 전자에 대해서만 물어보고 있었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기