2026년 4월 2일 | 개발 공부
요즘 에이전트 시스템 이야기를 보다 보면 MCP라는 단어를 자주 보게 된다. 처음에는 나도 이걸 거의 "도구를 표준 방식으로 연결하는 어댑터" 정도로 이해했다. 실제로 겉으로 보기에는 맞는 말이다. 서버 하나 열고, 함수 몇 개 노출하고, 클라이언트가 그걸 호출하면 되니까 구조가 단순해 보인다. 그런데 조금 더 들여다보니 내가 진짜 배우게 된 건 프로토콜 이름보다 도구 계약을 얼마나 명확하게 정의하느냐 쪽이었다.
왜 이런 생각을 하게 됐냐면, 에이전트가 도구를 잘 쓰는지 못 쓰는지는 단순히 연결 여부보다도 "이 도구를 언제 호출해야 하는지", "어떤 입력이 들어오면 실패로 봐야 하는지", "응답이 돌아왔을 때 다음 행동을 어떻게 결정해야 하는지"에서 갈렸기 때문이다. MCP는 이 연결을 깔끔하게 해 주지만, 그 위에 올라가는 계약이 흐리면 시스템은 생각보다 금방 흔들린다. 나는 이 지점을 한동안 API 문서 품질 문제 정도로 봤는데, 지금은 에이전트 동작을 좌우하는 인터페이스 설계 문제에 더 가깝다고 느낀다.
1. MCP를 도입한다고 해서 도구 사용이 자동으로 좋아지지는 않는다
MCP가 주는 장점은 분명하다. 도구를 노출하는 방식이 정리되고, 클라이언트 쪽에서 여러 서버를 비교적 일관되게 다룰 수 있고, 메타데이터를 함께 전달하기도 쉽다. 문제는 여기서 끝이 아니라는 점이다. 에이전트 입장에서 중요한 건 단순히 "호출할 수 있다"가 아니라 올바른 순간에, 올바른 입력으로, 기대한 범위 안에서 호출할 수 있다는 확신이다.
예를 들어 검색 도구 하나만 있어도 실제로는 꽤 많은 계약이 숨어 있다. 빈 문자열은 허용할지, 너무 넓은 질의는 어떻게 다룰지, 결과가 0건이면 실패인지 정상인지, 시간 초과가 나면 재시도할지 그냥 다른 경로로 갈지 같은 것들이다. 사람이 직접 버튼을 누를 때는 애매한 부분을 눈치로 넘길 수 있지만, 에이전트는 그런 빈칸에서 바로 이상한 행동을 시작한다. 그러니까 MCP는 배선을 정리해 주는 층이고, 실제 품질은 그 위의 행동 규약이 좌우한다.
- 도구 설명이 모호하면 에이전트는 호출 시점을 자주 잘못 고른다.
- 입력 제약이 느슨하면 실패를 도구가 아니라 모델 쪽 추론 문제로 오해하기 쉽다.
- 응답 의미가 불분명하면 다음 액션이 흔들리고, 체감상 "에이전트가 멍청하다"는 인상만 남는다.
2. 내가 보게 된 핵심은 함수 시그니처보다 실패 경계였다
예전에는 도구 설계를 볼 때 입력 필드 이름과 타입을 먼저 봤다. 물론 그것도 중요하다. 그런데 실제 운영 감각에 가까운 부분은 오히려 실패 경계를 어떻게 잡았는지였다. 도구 호출에서 제일 위험한 순간은 성공과 실패가 섞여 보일 때다. JSON은 정상적으로 왔는데 내용은 비어 있거나, HTTP는 200인데 사실상 사용할 수 없는 응답이 돌아오거나, 부분 성공인데 그 사실이 구조 안에 드러나지 않는 경우가 그렇다.
에이전트는 이런 애매한 상태를 사람처럼 읽어내지 못한다. 성공처럼 보이면 다음 단계로 넘어가고, 실패처럼 보이면 불필요하게 루프를 돌거나 다른 도구를 마구 부른다. 그래서 나는 MCP 도구를 설계할 때 이제 함수 이름보다 어떤 경우를 명시적으로 실패로 표기할지, 재시도 가능한 실패와 아닌 실패를 어떻게 구분할지를 먼저 보는 편이다. 이 기준이 서 있으면 모델이 조금 덜 똑똑해도 시스템은 덜 무너진다.
{
"ok": false,
"error_type": "validation_error",
"message": "query must be at least 3 characters",
"retryable": false
}
나는 요즘 이런 식의 응답이 훨씬 낫다고 느낀다. 단순히 에러 문자열 하나를 던지는 것보다, 실패 종류와 재시도 가능 여부를 같이 주는 편이 다음 행동을 설계하기 쉽다. 이건 거창한 이론이라기보다, 에이전트 시스템을 덜 피곤하게 만드는 실무 감각에 가깝다.
3. 도구 계약이 선명하면 프롬프트도 오히려 짧아진다
많은 경우 도구 사용 품질이 안 나올 때 프롬프트를 계속 길게 쓰게 된다. "이럴 때는 이 도구를 쓰고, 저럴 때는 쓰지 말고, 결과가 비어 있으면 다시 시도하고" 같은 규칙을 전부 프롬프트에 몰아 넣는 식이다. 나도 한동안 그렇게 풀려고 했는데, 어느 순간부터는 프롬프트가 길어질수록 오히려 유지보수가 더 어려워졌다. 규칙이 많아질수록 모델이 매번 안정적으로 지키리라는 보장도 약했다.
반대로 도구 계약이 명확하면 프롬프트는 꽤 짧아져도 된다. 입력 스키마가 선명하고, 실패 타입이 구조화돼 있고, 설명 문구가 "이 도구는 언제 쓸지"까지 포함하면 모델은 훨씬 덜 헤맨다. 결국 프롬프트는 불명확한 인터페이스를 임시로 메우는 층이 되기 쉽고, 인터페이스가 좋아질수록 프롬프트는 더 압축된다. 나는 이걸 보면서 에이전트 품질 문제의 일부는 프롬프트 엔지니어링 문제가 아니라 인터페이스 엔지니어링 문제라고 정리하게 됐다.
- 도구 설명에는 기능 소개보다 호출 조건과 금지 조건이 더 중요할 때가 많다.
- 응답 포맷이 안정적이면 후속 추론 체인도 짧아진다.
- 프롬프트로 막던 예외 처리를 계약으로 옮기면 재사용성이 높아진다.
4. 이 감각은 MCP 바깥에서도 그대로 통한다
내가 이 개념을 흥미롭게 보는 이유는, 사실 이 얘기가 MCP에만 갇혀 있지 않기 때문이다. 내부 마이크로서비스 API를 설계할 때도 비슷하고, 배치 작업 파이프라인을 나눌 때도 비슷하고, 프론트엔드와 백엔드의 경계를 정할 때도 비슷하다. 인터페이스가 있다는 말은 호출 경계가 있다는 뜻이고, 호출 경계가 있다는 말은 실패를 어떻게 표현할지 같이 정해야 한다는 뜻이다.
그래서 요즘 나는 새 도구를 붙일 때 "연결됐는가"보다 먼저 "이 경계를 다른 사람이 읽었을 때도 같은 행동을 하게 만들 수 있는가"를 본다. 이 질문이 통과되지 않으면, 프로토콜이 아무리 세련돼도 결국 운영 단계에서 사람 손으로 계속 보정하게 된다. 반대로 계약이 좋으면 구현체를 바꾸거나 모델을 바꿔도 흔들림이 적다. 내가 최근에 배운 건 결국 이것이다. 좋은 도구 연결은 배선이 아니라 행동 기대치를 설계하는 일에 더 가깝다.
5. 그래서 도구를 볼 때 내가 먼저 체크하는 것들
요즘은 새 도구를 보면 기능 설명보다 먼저 몇 가지를 체크한다. 첫째, 이 도구가 풀려는 일이 한 문장으로 말이 되는가. 둘째, 입력값을 잘못 넣었을 때 실패가 구조적으로 드러나는가. 셋째, 결과가 비어 있거나 애매할 때 다음 행동을 결정할 실마리를 주는가. 넷째, 같은 호출을 다시 해도 되는지, 아니면 부작용이 있는지 분명한가. 이런 질문이 명확할수록 에이전트는 덜 흔들리고, 사람도 나중에 디버깅할 때 훨씬 편하다.
특히 마지막 항목이 의외로 중요했다. 조회성 도구와 변경성 도구를 같은 감각으로 설명해 두면, 모델은 생각보다 쉽게 위험한 호출을 반복한다. 그래서 단순히 schema를 예쁘게 쓰는 것보다 이 호출이 안전한지, 재실행 가능한지, 확인 단계를 거쳐야 하는지를 설명에 박아 두는 편이 훨씬 실전적이었다. 나는 이걸 한 번 체감한 뒤로 도구 설명을 거의 사용자 설명서가 아니라 운영 규정처럼 보게 됐다.
- 이 도구는 언제 호출해야 하는가.
- 어떤 입력은 아예 거부해야 하는가.
- 실패 시 다른 경로로 우회할 수 있는가.
- 반복 호출이 안전한가, 아니면 확인이 필요한가.
결국 도구 통합은 연결 작업처럼 보이지만, 실제로는 행동 설계와 운영 설계가 한꺼번에 들어온다. 그래서 에이전트 품질을 높이고 싶다면 모델에게 더 많은 지시를 넣기 전에, 도구가 어떤 약속을 하고 있는지부터 먼저 다듬는 편이 낫다. 이 순서를 바꾸면 노력 대비 개선 폭이 꽤 커진다.
6. 짧게 남겨 두고 싶은 결론
MCP는 분명 유용한 표준이지만, 그 이름만으로 도구 사용 품질이 해결되지는 않는다. 실제 차이는 도구 설명, 입력 제약, 실패 타입, 재시도 가능 여부, 응답 의미 같은 계약 층에서 나온다. 나는 그래서 이제 "무슨 프로토콜을 썼는가"보다 "이 도구가 어떤 약속을 하고 있는가"를 먼저 본다. 결국 에이전트 시스템을 덜 흔들리게 만드는 건 연결 그 자체보다 계약을 얼마나 명확하게 써 두었는가였다.
'[개발 공부]' 카테고리의 다른 글
| Reranker를 검색 마지막 미세조정보다 순서 복구 단계로 이해하게 된 이유 (0) | 2026.04.06 |
|---|---|
| Speculative Decoding, 작은 모델의 초안이 큰 모델의 속도로 이어지는 방식 (0) | 2026.04.04 |
| HNSW를 벡터 DB보다 그래프 탐색으로 읽게 된 이유 (0) | 2026.04.03 |
| 웹소켓을 붙일 때 HTTP 감각을 그대로 가져가면 자꾸 꼬이는 이유 (0) | 2026.04.01 |
| 브라우저 자동화에서 세션을 복원하는 두 가지 감각 (1) | 2026.04.01 |