MCP 책 쓰자 Part 1
1부. MCP 이해하기 – 개념에서 출발
1장. 프롤로그: 왜 MCP인가?
1. 생성형 에이전트 시대의 도래
2022년 11월 OpenAI가 공개한 ChatGPT는 단기간 내에 수억 명의 사용자를 확보하며 전 세계적으로 큰 반향을 일으켰다. 출시 후 두 달 만에 월간 사용자 수는 1억 명을 돌파했고, 이는 Instagram(약 2.5년), TikTok(약 9개월)과 비교할 때 훨씬 빠른 속도였다. ChatGPT는 출시 후 단 2개월 만에 월간 사용자 1억 명을 확보하여, 당시까지 가장 빠른 성장 속도를 보인 소비자용 애플리케이션으로 기록되었다. 소셜 미디어와 언론에서는 "인류 역사상 가장 빠르게 성장한 소비자 기술"로 평가하며 그 잠재력을 주목했다.
ChatGPT는 기존의 단순한 규칙 기반 챗봇과 달리, 대규모의 언어 데이터를 기반으로 문맥을 이해하고 자연스럽게 텍스트를 생성할 수 있었다. 예를 들어, 사용자가 "퇴근하고 나서 뭐 하면 좋을까?"라고 물었을 때 단순히 "산책하세요"라고 대답하는 것이 아니라, 사용자의 질문 맥락을 이해하고 "오늘 하루 고생하셨어요. 기분 전환이 필요하실 것 같네요. 근처 공원에서 가볍게 산책하거나 좋아하는 음악을 들으며 휴식해보세요."처럼 감정과 상황을 반영한 응답을 제공했다.
이처럼 자연스러운 문장 생성과 컨텍스트 기반 응답 능력은 교육, 고객 응대, 코딩 보조, 콘텐츠 생성 등 다양한 분야에서 빠르게 도입되었고, 특히 개발자 커뮤니티에서는 ChatGPT를 통한 코드 생성 및 디버깅 도우미로 활발히 활용되기 시작했다. 또한 Claude와 같은 LLM이 등장한 이후에는 보다 복합적인 지식 검색 수요가 늘어나면서, 기존의 키워드 기반 검색 엔진 대신 LLM을 활용한 질의 기반 검색 솔루션이 주목받기 시작했다.
이러한 흐름 속에서 등장한 대표적인 서비스가 Perplexity AI이다. 사용자는 자연어로 질문을 입력하면, Perplexity는 LLM을 이용해 관련된 웹 문서를 검색하고, 그 내용을 기반으로 요약된 답변과 출처를 제공한다. 이는 단순한 웹 크롤링 결과가 아니라, 사용자의 의도를 이해하고 관련 지식을 재구성한 결과라는 점에서 기존 검색 방식과 차별화되며, 실제로 기술 분야나 의학, 법률 등 전문성이 요구되는 질문에서 강점을 보인다. 최근에는 oo.ai와 같은 신규 검색 서비스도 등장하여, 최신 논문, 개발 문서, 커뮤니티 기반 Q&A 등을 통합 검색하고 LLM 기반 응답을 제공하는 방식을 실험하고 있다. 이는 검색이라는 행위 자체가 정보 수집을 넘어 '의미 해석'과 '컨텍스트 요약'을 포함하는 방향으로 진화하고 있음을 보여준다.
다음은 위에서 언급한 LLM 기반 서비들의 공식 사이트다. 각 플랫폼의 기능을 직접 체험할 수 있으니 처음 보는 사이트는 직접 방문하길 권장한다.
- ChatGPT: https://chat.openai.com
- Claude: https://claude.ai
- Perplexity AI: https://www.perplexity.ai
- Gemini (Google): https://gemini.google.com
- oo.ai: https://oo.ai
하지만 당시의 ChatGPT를 포함한 초기 LLM 서비스들은 기본적으로 단일 턴 기반의 문답을 수행하는 대화형 언어 모델로, 복잡한 작업 지시나 외부 도구와의 통합에는 제한이 있었다. Claude, Perplexity, oo.ai 등 다양한 LLM 기반 서비스들이 등장하면서 질의응답을 넘어 문맥 추론, 실시간 검색, 멀티도구 사용 등의 기능을 시도하고 있지만, 당시에는 이러한 기능들이 본격적으로 구현되기 이전이었다.
2023년 이후에는 LLM이 단순히 텍스트를 생성하는 수준에서 벗어나 다단계 작업을 수행하고 외부 시스템과 상호작용할 수 있는 '에이전트(Agent)'로 진화하기 시작했다. 대표적으로 OpenAI는 2023년 6월 이후 'Function Calling' 기능을 도입하여, 예를 들어 사용자가 "서울의 날씨를 알려줘"라고 입력하면 LLM은 자체적으로 getWeather
함수의 JSON 스펙을 인식하고, 해당 도구를 호출한 뒤 결과를 요약해 사용자에게 제공할 수 있게 되었다.
Anthropic은 Claude 2부터 문서 분석, 툴 사용 등 복합적 기능을 포함하기 시작했으며, Claude 3에서는 'Tool Use' 기능을 통해 LLM이 상황에 따라 적절한 툴을 선택하고 호출하는 구조를 도입하였다. 예를 들어 Claude 3는 사용자가 업로드한 PDF 문서에서 요점을 추출하고, 이를 바탕으로 이메일 응답을 자동으로 작성하는 시나리오를 구현할 수 있다.
Perplexity는 웹 검색 도구와 결합된 질의응답 에이전트로서, 사용자가 "최신 AI 트렌드를 알려줘"라고 물으면 LLM이 자체적으로 검색을 수행하고, 여러 문서에서 요점을 추출해 하나의 요약 응답을 생성한다. 이는 기존 검색엔진과 차별화되는 LLM 기반 지식 탐색 방식의 대표 사례다.
oo.ai는 LLM을 백엔드로 둔 실시간 프로그래밍 질문 플랫폼으로, 사용자가 "JavaScript에서 클로저란?"이라고 물을 경우, 관련 개념 설명과 함께 예제 코드, 실행 결과까지 단계적으로 제공해준다. 나아가 GitHub, StackOverflow, 논문 등 다양한 출처를 통합해 도구처럼 활용하는 방식까지 확장되고 있다.
Google의 Gemini 1.5 Pro는 최대 100만 토큰이라는 초장문의 문맥을 다룰 수 있어, 수십 개의 논문이나 대형 코드베이스를 한 번에 입력하고 복합적인 질의응답을 수행할 수 있다. 예를 들어, 논문 전체를 넣고 '이 문서에서 저자의 핵심 주장을 요약하고 반론이 무엇인지 정리해줘'와 같은 요청이 가능하며, 긴 문맥을 잃지 않고 정확하게 응답할 수 있는 것이 특징이다. 또한 멀티모달 입력(이미지, 오디오 등)을 처리할 수 있어, 복합 입력 기반 에이전트에 적합한 플랫폼으로 자리 잡고 있다.
Meta의 LLaMA 3는 오픈 모델로서의 확장성과 경량화된 구조를 중심으로 설계되었으며, 에이전트 프레임워크와의 통합을 염두에 둔 아키텍처를 제공한다. 특히 연구 및 개발 커뮤니티에서의 재학습(finetuning)과 커스터마이징이 용이하게 되어 있어, 도메인 특화 에이전트 구축에 유리하다. LLaMA 3 기반 모델은 다양한 오픈소스 에이전트 프레임워크(LangChain, CrewAI 등)와의 호환성이 뛰어나, 프라이빗 환경에서의 독립적 에이전트 시스템 개발이 가능하다는 점에서도 주목받고 있다.
즉, 생성형 AI의 흐름은 단순 생성 모델에서 툴을 사용할 수 있는 에이전트 모델로 확장되고 있으며, 이 변화의 핵심에는 LLM이 다양한 컨텍스트와 외부 시스템을 이해하고 활용할 수 있는 능력을 갖추는 방향으로 진화하고 있다는 점이 있다.
에이전트란 단순히 텍스트를 생성하는 것을 넘어, 사용자의 질의를 이해하고 이를 해결하기 위해 외부 도구와 시스템을 적극적으로 활용하는 지능형 시스템이다. 텍스트 생성은 하나의 수단일 뿐, 목표는 사용자의 목적을 완수하는 것이다. 이를 위해 에이전트는 다음과 같은 복합적인 기능을 수행할 수 있어야 한다:
- 외부 API 호출: 사용자가 "오늘 서울 날씨 알려줘"라고 말했을 때, 에이전트는 이 요청을 이해하고 적절한 API, 예를 들어
getWeather(city="Seoul")
를 호출한다. 단순 호출이 아니라, 요청을 분석하여 필요한 파라미터를 추출하고, 호출 결과를 재가공하여 응답으로 제공해야 한다. 예를 들어 "서울의 기온은 현재 18도이며, 흐림입니다. 우산을 챙기시는 것이 좋겠습니다."와 같이 사용자 친화적인 형태로 정보를 변환하는 과정이 포함된다. 또한 오류가 발생했을 경우, 재시도나 오류 메시지 안내까지 포함한 흐름 설계가 요구된다. - 파일 업로드 및 다운로드 처리: 사용자가 계약서 PDF를 업로드하면, 에이전트는 해당 문서의 포맷과 구조를 파악하여 의미 있는 정보를 추출한다. 예를 들어 문서의 표나 목록에서 핵심 조항만을 선별하거나, 전체 내용을 요약하여 주요 문단을 제공하는 작업이 가능해야 한다. Claude와 같은 모델은 PDF의 텍스트 영역을 분석해 '청구 금액', '결제일자', '계약 상대방' 등 키 정보를 인식하고 표 형태로 정리해주는 기능을 제공한다. 다운로드 처리의 경우, 사용자가 요청한 정보를 정해진 형식(예: Excel, JSON, PDF)으로 다시 변환하여 내려받을 수 있도록 파일 생성 및 전송 기능이 포함되어야 하며, 보안과 포맷 정합성까지 함께 고려해야 한다.
- 멀티모달 입력의 해석: 사용자가 이미지를 업로드했을 때, 에이전트는 단순히 해당 이미지를 보여주는 수준이 아니라, 그 내용을 분석할 수 있어야 한다. 예를 들어 음식 사진이 업로드되면, 이를 분석해 "김치찌개"라는 결과를 도출하거나, 배경 속 간판 글자를 OCR로 인식해 장소를 추정하거나, 사진 속 여러 객체를 구분하여 사용자가 의도한 질문(예: '가장 눈에 띄는 물건이 무엇인가요?')에 맞게 해석해야 한다. 이를 위해 이미지 분류 모델, 물체 인식 모델, OCR 엔진, 장면 이해 모듈 등을 통합적으로 연계하는 구조가 필요하다. 분석 결과는 단순 나열이 아니라, 자연어로 요약되어 사용자에게 제공되어야 한다. 예: "사진 속에는 김치찌개, 밥, 물컵이 있으며, 배경에는 한식당 간판이 보입니다."
- 데이터베이스 질의 및 저장: 사용자 요청이 "지난주에 주문한 내역 보여줘"라면, 에이전트는 사용자의 ID 또는 인증 토큰을 이용해 데이터베이스에서 관련 데이터를 조회한다. 이때 단순 SQL 쿼리가 아니라, 시간 필터, 상태 조건(예: 배송 완료), 결과 정렬 기준 등을 복합적으로 고려한 쿼리를 생성하고 실행한다. 그 결과로 나온 주문 목록을 다시 사용자 친화적인 응답 형태로 가공하여, 예를 들어 "지난주에 총 3건의 주문이 있었고, 가장 최근 주문은 무선 이어폰이며 4월 10일에 배송되었습니다."처럼 정리해서 전달한다. 필요한 경우 후속 질문(예: "이 중에서 아직 도착하지 않은 건 뭐야?")에 대비해 컨텍스트를 유지한다.
이러한 기능을 위해서는 LLM이 단순히 텍스트를 생성하는 수준을 넘어, 사용자의 목표를 파악하고 그에 따라 도구를 능동적으로 선택하고 실행하는 능력, 즉 에이전트화된 행동력이 필요하다.
에이전트가 이러한 능력을 갖추기 위해서는 다음의 사이클을 따르는 구조가 필요하다:
- 이해 (Understanding): 사용자의 발화를 분석해 목적을 파악한다. 예: "계약서 핵심만 알려줘"라는 요청에서 문서 요약이라는 목적을 인식.
- 계획 (Planning): 목적을 달성하기 위한 도구와 실행 순서를 계획한다. 예: PDF 문서를 분석할 도구를 선택하고 요약기를 연결.
- 실행 (Execution): 선택한 도구들을 호출해 작업을 수행한다. 실제로 MCP나 function calling 기능을 이용해 외부 API를 호출함.
- 응답 (Response): 결과를 사용자에게 자연어로 정리하여 응답한다. 필요한 경우, 후속 작업을 유도할 수도 있음.
OpenAI는 이러한 구조를 기반으로 function calling
, tool use
, GPTs
기능을 도입해 도구 사용 능력을 확장하고 있으며, 사용자가 도구를 구성해 하나의 GPT Agent로 만들 수 있는 인터페이스도 제공하고 있다.
Anthropic은 Claude 3에서 복수의 툴을 동시에 선택하고, 중간결과를 문맥에 반영하여 후속 추론에 활용하는 구조를 도입했다. 이는 단순한 API 호출이 아닌, 일종의 상호작용적인 의사결정 체계에 가깝다.
구글의 Gemini는 초장문 문맥과 멀티모달 입력 처리를 기반으로, 복잡한 질의에서도 적절한 분석 루틴을 구성하고 실행할 수 있게 설계되었으며, Meta의 LLaMA 시리즈는 커스터마이징과 경량화에 특화되어 다양한 에이전트 프레임워크와의 통합을 고려한 구조를 지닌다.
이 모든 변화는 LLM이 단순한 텍스트 생성 모델에서 벗어나, 다양한 도구와 시스템을 유연하게 조합하는 컨텍스트 중심의 실행 주체로 진화하고 있음을 의미한다.
2. 기존 LLM 호출의 한계
2023년 기준으로 가장 널리 사용되는 LLM API 서비스는 OpenAI의 ChatGPT API, Anthropic Claude API, Google PaLM/Gemini API, Cohere, Mistral API 등이다. 이들 모두 LLM을 통해 자연어 질의에 응답할 수 있지만, 실질적인 도구 사용 및 시스템 제어는 다음과 같은 한계를 지닌다.
2.1 단일 함수 호출로 제한된 기능성
OpenAI의 function calling
기능은 LLM이 외부 툴(API 등)을 명시적으로 호출하고, 그 결과를 자연어 응답에 반영할 수 있도록 해주는 강력한 확장 기능이다. 이 기능은 2023년 6월 13일에 공식 발표되었으며, 같은 날부터 API를 통해 본격적으로 제공되기 시작했다. 특히 툴 기반 에이전트 구조 구현의 가능성을 크게 넓혔으며, 복잡한 작업 흐름의 자동화를 위한 첫걸음으로 간주되었다. 그러나 이 기능은 설계적으로 단일 호출 기반(single-turn, single-call)에 머물러 있어, 보다 복잡한 사용자 요청을 처리하는 데 여러 제약이 존재한다.
OpenAI Function Calling은 2023년 6월 13일에 공식 출시되었으며, 자세한 내용은 다음 페이지에서 확인할 수 있다.
https://openai.com/blog/function-calling-and-other-api-updates
구조적 제약
- 단일 함수 제한: 한 번의 응답 사이클에서 단 하나의 함수만 호출할 수 있다. 즉, LLM이 여러 도구를 조합해 사용하는 복합적인 작업을 자동으로 수행하기 어렵다.
- 컨텍스트 손실: 호출 간의 상태나 이전 함수 결과가 LLM 내부 컨텍스트에 완전히 반영되지 않거나, 후속 호출에 자연스럽게 전달되지 않는다. 각 요청은 기본적으로 stateless하므로 툴 체인을 구성하려면 수동으로 중간결과를 관리해야 한다.
다단계 및 조건 기반 요청 처리의 제약
사용자가 "이 이미지를 분석해서 어떤 음식인지 알려주고, 그 지역의 날씨도 알려줘"라고 말했을 때, 내부적으로 analyze_image()
, extract_location()
, get_weather()
같은 여러 함수를 순서대로 호출해야 한다. 하지만 function calling은 하나의 함수만 호출할 수 있으므로, 이와 같은 다단계 체인을 자동으로 수행하려면 별도 래퍼 코드가 필요하며, 결과를 수동으로 중계하는 과정이 필수적이다.
또한 사용자의 요청이 도구 선택에 영향을 줄 수 있는 복합적인 의미를 담고 있을 때, 예를 들어 "이미지에 글자가 보이면 텍스트를 추출하고, 그렇지 않으면 색상만 알려줘"와 같은 표현은 LLM이 요청의 의도를 파악한 후 어떤 도구를 사용할지 결정해야 한다. 하지만 현재 OpenAI의 tool_choice: auto
기능은 구조적으로 한 번의 호출에서 하나의 도구만 자동 선택하도록 설계되어 있어, 이처럼 논리적 판단이나 상황 인식에 따라 동적으로 도구를 선택하는 데에는 적합하지 않다. 실제 사용자들로부터도 이러한 구조가 명확한 선택 로직을 만들기 어렵고, 예상과 다른 결과로 이어지는 경우가 보고되고 있다. 복잡한 판단 흐름이 필요한 경우에는 외부 오케스트레이션 로직의 개입이 필요하다.
함수 선택과 체인 구성의 어려움
- 함수 선택 불확실성: 사용자가 "날씨 알려줘"라고 했을 때,
get_weather()
,get_forecast()
,get_air_quality()
중 어떤 함수를 호출할지 명확하지 않다. 툴 간의 목적과 입력 요구 조건이 유사한 경우, LLM은 명확한 선택을 내리기 어렵고 잘못된 호출을 시도할 수 있다. - 자동 체인 구성 불가: 사용자가 "이 문서에서 장소 이름을 추출하고 해당 장소의 뉴스를 요약해줘"라고 했을 때,
extract_entities()
→fetch_news()
→summarize()
흐름이 필요하지만, LLM은 일련의 함수 호출을 계획하고 자동 실행하는 기능을 내장하고 있지 않다. 이 역시 수작업 오케스트레이션을 필요로 한다.
복잡한 JSON 스키마의 한계
각 함수의 입력/출력은 JSON Schema로 명시되지만, 다음과 같은 문제가 자주 발생한다:
- 스키마 구조가 깊거나 선택지가 많을 경우, LLM이 올바른 입력 구조를 생성하지 못하거나 일부 속성을 누락한다.
- context token 제한으로 인해 schema 일부가 잘리면, LLM은 누락된 정보를 기반으로 잘못된 응답을 생성한다.
- 예:
location
항목에latitude
와longitude
가 별도로 요구되는데, LLM이 "서울"과 같은 문자열로 응답할 경우, 호출 자체가 실패하게 된다.
2.2 언어와 플랫폼의 제약
이러한 구조적 제약을 해결하기 위한 프레임워크로는 LangChain, AutoGen, CrewAI, Flowise 등이 있다. 이들은 LLM과 툴 간의 연계를 워크플로우로 구성하거나, Agent 기반 대화를 구성하는 방식으로 발전해 왔다.
-
LangChain은 2022년 중반에 개발이 시작된 Python 생태계를 중심으로 구축된 대표적인 오케스트레이션 프레임워크다. LLM 호출, 툴 연동, 체인 구성, 에이전트 기반 구조 등을 지원하며, 다양한 외부 도구와 통합할 수 있는 인터페이스를 제공한다. 가장 큰 장점은 유연한 체인 구성과 풍부한 예제이지만, 체인 구성이 복잡하고 추상화 레이어가 깊어 디버깅이 어렵고 러닝커브가 존재한다.
-
AutoGen은 2023년 상반기에 Microsoft에서 개발한 프레임워크로, 여러 LLM 인스턴스를 협업 가능한 에이전트로 구성해 대화와 작업을 분산시킬 수 있도록 설계되었다. 멀티 에이전트 협력 구조, 자동 메시지 라우팅, 오토루프 기반 task resolution을 지원하지만, 설정이 복잡하고 사용자가 원하는 대로 에이전트를 설계하거나 디버깅하기 어렵다는 한계가 있다.
-
CrewAI는 2023년 하반기에 등장한 오픈소스 프레임워크로, 최근 커뮤니티에서 활발히 사용되고 있다. 역할 기반 에이전트들(예: 리서처, 라이터 등)을 팀 단위로 구성해 일괄적으로 태스크를 수행하게 한다. 간결한 구성, 역할 기반 분업, 단순화된 API가 장점이나, 에이전트 간 복잡한 상호작용이나 조건 제어가 필요한 시나리오에서는 한계가 있다.
-
Flowise는 2023년 초에 개발된 시각적 노드 기반 UI를 제공하는 no-code/low-code 플랫폼으로, LangChain 기반 백엔드를 사용해 LLM 워크플로우를 손쉽게 구성할 수 있도록 돕는다. 비개발자 접근성이 뛰어나고 빠른 프로토타이핑이 가능하나, 복잡한 분기 구조나 다단계 툴 체인 구성에는 여전히 제약이 있다.
각 프레임워크의 공식 사이트를 통해 최신 문서와 예제를 직접 확인할 수 있다.
- LangChain: https://www.langchain.com
- AutoGen: https://github.com/microsoft/autogen
- CrewAI: https://docs.crewai.com
- Flowise: https://flowiseai.com
이 프레임워크들은 각각의 장점에도 불구하고 다음과 같은 공통적인 어려움을 여전히 포함하고 있다:
-
플랫폼 종속성과 환경 제약: 대부분의 프레임워크가 Python에 강하게 의존하고 있으며, Node.js, Rust, Go 등의 다른 언어 생태계와의 통합은 복잡하거나 공식적으로 지원되지 않는 경우가 많다. 이는 다양한 시스템 환경에 프레임워크를 적용하거나 기존 애플리케이션과 통합하는 데 있어 장벽으로 작용한다.
-
조건 분기, 병렬 처리, 중간결과 연계 같은 고난도 시나리오 처리의 한계: 복잡한 조건 분기(if/else), 툴 간 의존성 처리, 중간 출력 재사용, 병렬 실행 등이 필요한 시나리오에서는 별도의 래퍼 로직이나 외부 스케줄러, 상태 관리 시스템이 필요하다. 이로 인해 코드 복잡도가 높아지고 테스트 및 유지보수 비용이 상승한다.
-
체계적 에이전트 구성이나 도구 호출 흐름 설계를 위한 반복적 수작업 필요: 각 프레임워크가 다양한 구성 옵션을 제공하더라도, 실무에서는 여전히 JSON schema 작성, 프롬프트 설계, 에이전트 행동 정의, 도구 매핑 규칙 설정 등 많은 작업이 수작업으로 이루어진다. 이로 인해 개발자와 운영자의 부담이 크며, 재사용성과 일관성을 확보하기 어렵다.
결론적으로, 현재의 function-calling 중심 LLM API와 LangChain 등 워크플로우 프레임워크는 에이전트의 자율성과 툴 선택 유연성에 제한이 있다. 특히 다단계 조건 분기, 병렬 툴 호출, 사용자 입력 흐름의 동적 제어 같은 기능을 구현하기 위해서는 개발자가 복잡한 래퍼 로직을 직접 구현해야 하며, 이는 유지보수성 및 확장성 측면에서도 부담이 크다.
3. MCP가 열어주는 가능성
MCP(Model Context Protocol)는 LLM을 진정한 에이전트로 만들기 위해 고안된 프로토콜이다. 다음과 같은 핵심 장점을 갖는다:
3.1 LLM 중심의 오케스트레이션 구조
기존 LLM 호출 방식은 사람이 프롬프트에 직접 함수 설명이나 예시를 삽입하고, 도구 호출 결과도 수동으로 복사해 재사용해야 하는 비효율적인 구조였다. 반면 MCP에서는 LLM이 오케스트레이션의 중심에 위치하며, 대화 흐름 안에서 도구 선택과 실행, 결과 해석까지 주도적으로 수행할 수 있는 구조로 바뀐다.
-
도구 선택의 주체가 LLM: MCP는 LLM에게 현재 사용 가능한 도구 목록을
tools
배열에 담아 제공하고, 각 도구는name
,description
,inputSchema
를 포함하는 명세를 따른다. LLM은 사용자의 질의와 대화 흐름을 해석해 가장 적합한 MCPTool을 자동으로 선택하고, 필요한 입력값을 구성하여 호출한다. 예를 들어 "계약서를 요약해줘"라는 질의에 대해 LLM은summarize_contract_pdf
라는 툴을 선택하고,fileUrl
,language
값을 포함한 입력을 구성한다. -
입력 스키마의 표준화: 최신 MCP 스펙에서는 각 MCPTool의 입력은
inputSchema
라는 JSON Schema로 정의되며, 출력은 명세하지 않는다. MCP는 툴 실행 결과를 자동으로 LLM 입력에 통합하고, LLM은 해당 결과를 반영해 다음 응답을 구성한다. 이는 function calling처럼 하나의 함수에서 입력/출력을 모두 명세하는 방식과 달리, 단방향성 입력 구조에 집중하며 시스템 복잡도를 낮춘다. -
자동 컨텍스트 연계와 흐름 유지: 도구 호출 결과는 자동으로 다음 LLM 호출 컨텍스트에 통합되며, 별도의 상태 관리나 메모리 구현 없이도 연속된 흐름을 구현할 수 있다. 예를 들어 계약서 요약 결과를 바탕으로 "이 문서에 위약금 조항이 있는지 알려줘"라는 후속 질의가 이어질 경우, LLM은 앞선 요약 결과를 기억하고 그 문맥에 맞춰 응답을 구성한다.
-
모델 중심 설계의 확장성: MCP는 GPT, Claude, Gemini 등 다양한 LLM 모델에서 동일한 방식으로 MCPTool을 해석하고 사용할 수 있도록 표준화된 인터페이스를 제공한다. 이는 기존의 프레임워크 중심 호출 방식과 비교해 모델 간 도구 사용의 일관성을 높이고, 여러 모델을 동시에 사용하는 멀티에이전트 시나리오 구성도 유리하게 만든다.
MCP의 이 구조는 LLM이 단순히 문장을 생성하는 역할을 넘어, 목표 지향적 행동 주체로서 역할을 수행할 수 있도록 진화시키는 핵심 동력이 된다. 사용자의 목적을 이해하고, 그에 필요한 도구를 선택하고, 실행 결과를 바탕으로 후속 응답을 구성하는 일련의 과정이 모두 LLM 중심에서 자연스럽게 이어지며, 이는 기존 프롬프트 기반 설계보다 훨씬 유연하고 확장 가능한 방식이다.
다음은 MCPTool이 사용하는 최신 JSON Schema 형식의 예시이다:
{
"name": "summarize_contract_pdf",
"description": "계약서 PDF 문서를 요약합니다.",
"inputSchema": {
"type": "object",
"properties": {
"fileUrl": {
"type": "string",
"description": "분석할 PDF 파일의 URL"
},
"language": {
"type": "string",
"enum": ["ko", "en"],
"default": "ko",
"description": "요약 결과의 언어 설정"
}
},
"required": ["fileUrl"]
}
}
이처럼 MCP는 도구 명세를 간단하고 표준화된 방식으로 표현함으로써, 다양한 플랫폼과 모델에서 일관되게 작동하는 도구 중심 LLM 오케스트레이션을 가능하게 만든다.
위 JSON 예시는 2025년 기준 MCP의 최신 스펙(
inputSchema
기반)에 따르고 있다. MCP는 계속해서 발전 중이며, 이전 버전에서는parameters
와output
필드를 함께 사용했지만 최근 스펙에서는inputSchema
중심으로 단순화되었다. 최신 구조 및 변경 이력은 다음 공식 사이트를 통해 확인할 수 있다:
3.2 언어/플랫폼 독립적 구조
MCP의 또 하나의 핵심 설계 철학은 언어와 플랫폼으로부터의 독립성이다. 기존의 LLM 연동 프레임워크나 툴 구성 시스템은 대부분 Python을 중심으로 구현되며, Node.js, Rust, Go 등의 언어를 사용하는 개발자들은 직접 RPC 연동이나 API 래핑을 통해 도구를 연결해야 했다. 하지만 MCP는 이러한 제약을 제거하고, 어떤 언어로 구현된 도구라도 MCPTool로 등록하여 사용할 수 있도록 설계되었다.
이러한 플랫폼 독립성은 다음과 같은 세 가지 구조적 특징을 기반으로 한다:
-
언어에 구애받지 않는 Tool 인터페이스: MCP는 MCPTool이 어떤 언어로 구현되었는지와 무관하게 동일한 방식으로 등록되고 호출될 수 있도록 설계되었다. Python, Node.js, Rust, Go, Java 등 다양한 언어로 작성된 툴들이 MCPServer에 연결될 수 있으며, MCPClient는 이 도구들을
tools
목록으로 받아들여 일관된 방식으로 호출할 수 있다. 이러한 일관성은 MCP가 도구 실행을 위한 전송 계층(transport layer)으로 표준입출력(stdin/stdout) 또는 SSE 기반 Web API를 지원하기 때문에 가능하다. 이를 통해 개발자는 도구의 실행 방식에 구애받지 않고, 동일한 방식으로 툴을 선언하고 호출할 수 있다. -
유연한 실행 구조: Stdio와 Web 기반 Transport: MCPServer는 다양한 언어 환경에서 작성된 MCPTool을 일관되게 실행하기 위해 두 가지 전송 계층을 지원한다. 첫 번째는
stdio 기반 실행 구조
로, 각 MCPTool을 CLI 프로그램처럼 취급하여 JSON 입력을 표준 입력(stdin)으로 전달하고 결과를 표준 출력(stdout)으로 수신하는 방식이다. 이 구조는 운영체제 수준의 입출력 구조를 활용하기 때문에, Python, Go, Rust, C++ 등 거의 모든 언어에서 손쉽게 구현할 수 있다.두 번째는
Web 기반 실행 구조
로, HTTP API 또는 SSE(Server-Sent Events) 방식으로 동작하는 MCPTool을 등록하는 방식이다. 이 구조에서는 MCPServer가 HTTP POST 요청을 통해 JSON 데이터를 도구에 전달하고, 응답을 일반 JSON 또는 스트리밍 형식으로 수신한다. 특히 SSE를 활용하면 LLM이 실시간으로 도구 출력을 받아볼 수 있어, 대용량 결과나 점진적 출력이 필요한 시나리오에 적합하다. 이 방식은 클라우드 기반 마이크로서비스, 컨테이너 환경, 외부 API와의 통합 등에서 매우 유용하다. -
복수 MCPServer 병렬 호출을 지원하는 Client 구조: MCP는 클라이언트-서버 구조를 기반으로 하며, 단일 LLM 기반 MCPClient는 여러 개의 MCPServer에 병렬로 연결해 MCPTool을 동시에 호출할 수 있다. 예를 들어
이미지 설명 MCPServer
,날씨 정보 MCPServer
,계약서 분석 MCPServer
가 각각 독립적으로 존재하더라도, MCPClient는 각 서버의 도구를 하나의 통합된 인터페이스에서 받아들이고, LLM은 그 중 가장 적절한 도구를 선택하여 사용할 수 있다. 이 구조는 로컬 서버와 원격 API 서버를 자유롭게 조합할 수 있는 이기종 분산 환경에서도 강력한 확장성을 제공한다.다음은 이를 활용한 간단한 예시이다:
"이 이미지에 무엇이 보이는지 설명하고, 현재 날씨와 계약서의 핵심 조항을 요약해줘"
위 요청에 따라 MCPClient는 아래와 같이 병렬적으로 도구를 호출할 수 있다:
image-docent-server
→ 이미지 분석 도구 호출weather-info-server
→ 위치 기반 날씨 데이터 조회contract-summarizer-server
→ PDF 계약서 요약 수행
각 서버는 독립적으로 실행되며, LLM은 세 결과를 받아 하나의 응답으로 통합해 사용자에게 제공한다. 실제 구현에서는 MCPClient 내부에서 Node.js 환경의
Promise.all()
혹은 Python의asyncio.gather()
를 사용해 각 MCPServer에 대한 병렬 호출을 처리할 수 있다. 이러한 병렬 실행 방식은 MCP의 공식 예제나 커뮤니티 구현에서도 흔히 활용되며, 병렬성 확보와 지연 시간 최소화에 실질적인 효과를 발휘한다.
이러한 구조 덕분에 MCP는 Python 기반 LangChain이나 AutoGen과 달리 특정 언어나 실행환경에 종속되지 않고, 도구 정의는 독립적으로, 호출은 일관되게 구성할 수 있다. 백엔드가 Rust로 작성된 시스템, 프론트엔드가 Node.js로 구성된 도구, 데이터 파이프라인이 Go 기반인 경우에도 문제 없이 LLM을 통해 통합 제어가 가능하다.
또한 이 구조는 도구의 재사용성과 유지보수성 측면에서도 매우 유리하다. 전체 프레임워크를 수정하지 않고도 개별 MCPTool만 교체하거나 업그레이드하면 되며, 모든 도구가 동일한 inputSchema
구조를 따르기 때문에 새로운 도구를 추가하거나 기존 도구를 변경하는 데 드는 비용도 크게 줄어든다.
MCP는 이렇게 단일 언어나 플랫폼에 얽매이지 않도록 설계된 구조를 통해, 다양한 기술 환경에서도 일관된 방식으로 도구를 조합하고 LLM 기반 에이전트를 구성할 수 있게 한다. 이러한 설계는 에이전트를 구성하는 도구 생태계를 언어나 런타임의 경계 없이 연결하는 진정한 프로토콜 수준의 접근이라고 할 수 있다.
3.3 도구 중심이지만 언어 기반으로 작동하는 구조
MCP(Model Context Protocol)는 '모든 도구 중심의 설계'를 전제로 하지만, 동시에 '언어적 상호작용'에 강력하게 반응하는 프로토콜로 진화하고 있다. 이는 단순히 함수 호출과 응답을 연결하는 API 설계 수준이 아니라, 도구의 메타정보를 언어적으로 이해하고 활용하는 구조를 말한다. 다시 말해, LLM이 구조화된 도구 정의를 단순 매핑 정보가 아닌, 언어 기반 추론의 맥락에서 해석할 수 있도록 한다.
이러한 설계는 다음과 같은 구조적 특징으로 구체화된다.
1. Tool 선언은 구조적, 호출은 언어적으로 유도됨
MCP에서는 모든 도구가 JSON 기반의 명세 구조로 정의된다. 대표적인 필드는 다음과 같다:
name
: 도구의 식별자 (예:generate_summary
)description
: 자연어로 작성된 도구의 기능 설명inputSchema
: 도구에 전달되어야 할 입력값의 구조
이 중에서 특히 중요한 것은 description
이다. LLM은 이 필드를 기반으로, 현재 대화 맥락에서 어떤 도구가 가장 적합한지 추론하게 된다. 예를 들어 사용자가 “계약서를 요약해줘”라고 요청하면, description
에 “PDF 문서를 요약합니다”라고 쓰여 있는 summarize_contract_pdf
가 높은 확률로 선택된다.
즉, 도구 호출은 구조적으로 명세되지만, 선택은 언어적 유사성과 의미 기반 추론에 의존한다. 이로 인해 개발자는 도구의 이름보다 description
의 문장 설계에 더 많은 주의를 기울이게 되며, 이는 결국 문장 설계가 API 설계의 일부가 되는 새로운 프로그래밍 패턴을 유도한다.
2. Description은 LLM의 추론 핵심으로 작동한다
MCP는 모든 도구를 구조화된 JSON 스키마로 선언하지만, 그 중 어떤 도구를 호출할지는 전적으로 LLM이 'description'을 해석한 결과에 의존한다. 이 점에서 description은 단순한 주석(comment)이 아니라 행동 유도 명령(hint) 역할을 한다.
예를 들어 아래와 같은 두 개의 툴이 존재한다고 하자:
{
"name": "extract_keywords",
"description": "문장에서 키워드를 추출합니다."
}
{
"name": "summarize_text",
"description": "문장을 요약합니다."
}
사용자가 "이 텍스트의 핵심 내용을 알려줘"라고 말했을 때, LLM은 단어 선택의 뉘앙스를 고려해 summarize_text
를 선택하게 된다. 이때 문장의 뉘앙스가 “핵심 키워드”에 가까울 경우에는 extract_keywords
가 선택될 수도 있다. 이처럼 도구의 선택은 description과 사용자 발화 간의 의미적 일치도를 기반으로 한다.
따라서 도구 정의 시 description은 단순한 기능 설명이 아닌, LLM이 정확하게 선택할 수 있도록 도와주는 언어적 트리거로 작동해야 한다.
3. Schema는 LLM이 이해할 수 있는 언어적 구조로 정돈되어야 한다
MCP에서 도구의 입력 구조는 inputSchema
로 정의된다. 이는 JSON Schema의 기본 규격을 따르며, 다음과 같은 요소를 포함할 수 있다:
{
"type": "object",
"properties": {
"topic": {
"type": "string",
"description": "요약할 주제"
},
"length": {
"type": "string",
"enum": ["short", "medium", "long"],
"description": "요약의 길이 설정"
}
},
"required": ["topic"]
}
여기서 중요한 점은 각 파라미터에 description
을 제공하는 것이다. 이 설명이 없을 경우, LLM은 파라미터 이름만으로 의미를 추론해야 하며, 이는 의도와 다른 결과를 만들 수 있다. 반대로 description이 존재하면, LLM은 해당 필드가 어떤 값을 받아야 하는지 문맥적으로 이해할 수 있다.
예를 들어 위 스키마에서 사용자가 “축구 경기 요약해줘”라고 요청했다면, topic
은 “축구 경기”, length
는 명시되지 않았으므로 기본값이 적용된다. 이처럼 MCP의 schema는 구조적이지만, 그 해석은 언어 기반 추론의 일부로 작동한다.
4. Tool 설계는 Prompt 설계와 합쳐지는 방향으로 진화 중
기존에는 API 문서와 프롬프트 설계가 분리되어 있었다. 하지만 MCP에서는 도구의 description과 스키마가 곧 LLM의 행동을 유도하는 요소가 되기 때문에, 이 둘은 긴밀히 연결된다. 이는 “프롬프트가 곧 API 설계의 일부”라는 새로운 설계 패턴을 의미한다.
실제 MCP 도구 설계 시, 많은 개발자는 다음과 같은 사항을 고민하게 된다:
- 어떤 문장 구조로 description을 작성해야 LLM이 정확하게 선택할까?
- 명사형으로 표현해야 하나? 아니면 동사형이 더 낫나?
- 동의어나 비슷한 개념이 여러 개일 때, 가장 대표적인 표현은 무엇인가?
이러한 질문들은 전통적인 API 설계에서는 고려하지 않던 요소지만, MCP에서는 매우 중요한 요소가 된다. 결국 도구 설계는 기술적 명세와 언어적 설계를 동시에 다루는 이중 설계 행위가 된다.
5. 예제 기반 유도 학습 (Few-shot Prompting)과의 결합
MCP는 도구의 입력 스키마와 description을 기반으로 LLM이 도구를 선택하도록 유도하지만, 복잡한 시나리오에서는 도구 사용 예제를 함께 제공해야 정확도가 높아진다. 이를 위해 일부 MCP 클라이언트는 각 도구에 대한 examples
필드를 함께 제공할 수 있도록 설계되어 있으며, LLM은 해당 예시를 바탕으로 보다 정밀한 호출을 할 수 있게 된다.
예를 들어, 다음과 같은 예제를 포함하면:
{
"name": "search_paper",
"description": "논문 주제를 입력받아 관련 논문을 검색합니다.",
"examples": [
{
"user": "최근 생성형 AI에 대한 논문 찾아줘",
"arguments": {
"query": "generative AI"
}
}
]
}
LLM은 유사한 문장이 입력되었을 때 이 예제를 참조하여 보다 정확하게 query
값을 추론하고, 호출 실패 확률을 낮출 수 있다. 이는 MCP가 추구하는 정적 명세와 언어적 예시의 결합이라는 이상을 잘 보여주는 부분이다.
3.4 예측 가능성과 제어 가능성
앞서 3.3에서는 도구 중심의 MCP 구조가 언어 기반 추론과 결합하여 얼마나 유연하고 강력한 에이전트 설계를 가능하게 하는지 살펴보았다. 그러나 이처럼 유연한 구조일수록 시스템의 동작을 예측하고 오류 발생 시 제어할 수 있는 메커니즘이 더욱 중요해진다. 특히 운영 환경에서는 에이전트가 자율적으로 도구를 선택하고 실행하되, 그 과정과 결과는 언제든 추적 가능하고 통제할 수 있어야 한다.
MCP(Model Context Protocol)의 설계는 단순히 기능을 구현하는 것에 그치지 않고, 실질적인 운영의 안정성과 개발 생산성을 담보할 수 있도록 '예측 가능성과 제어 가능성'을 핵심 목표로 삼고 있다. 이는 특히 실제 현업 환경에서 LLM 기반 시스템을 활용할 때 필수적으로 요구되는 요소들이다.
1. 명세 기반 도구 설계로 오류 가능성 최소화
MCP는 모든 도구를 inputSchema
라는 JSON 기반의 구조적 명세로 정의한다. 이 구조는 다음과 같은 이점을 제공한다.
- 정형화된 인터페이스: 도구가 받는 입력의 타입, 필수 여부, 허용 값 등이 명시되어 있어, LLM이 올바른 입력값을 생성하도록 유도한다.
- 자동화된 유효성 검사: LLM이 생성한 인풋이 JSON Schema에 부합하는지 확인할 수 있어, 잘못된 호출을 사전에 차단할 수 있다.
- 예상 가능한 행동 패턴: 어떤 입력이 들어왔을 때 어떤 출력이 나올지를 명세로 파악할 수 있기 때문에, 테스트와 검증이 용이하다.
이로 인해 개발자는 각 도구의 정의를 코드와 문서 수준에서 동시에 관리할 수 있으며, 명세 변경이 곧 기능 변경이라는 일관성을 유지할 수 있다. 이는 오픈소스 환경이나 기업 내부 툴 개발 시 GitHub 등의 코드 저장소를 통한 협업과 리뷰에도 매우 효과적이다.
💡 팁: 모든 도구의 스키마를
/tools/
폴더 아래 JSON 파일로 저장하고, 변경 이력을 Git으로 관리하면 전체 시스템의 변경 추적과 롤백이 쉬워진다.
2. 대화 기반 리플레이 가능성 – 사용 내역의 트래킹과 복원
MCP는 LLM이 중심이 되는 구조이지만, 결국 이 구조는 대화의 흐름에 따라 시스템이 어떻게 반응했는지를 파악하고 재현할 수 있어야 한다. 이를 위해 MCPClient는 다음과 같은 기록 방식을 지원하도록 설계된다.
- 요청-응답 로그: 사용자의 질의, 선택된 MCPTool, 인풋 파라미터, 툴의 출력, LLM의 최종 응답까지 모든 과정이 로그로 기록된다.
- 세션 기반 스냅샷: 하나의 사용자 세션 단위로 상태를 저장해두면, 이후 언제든 동일한 대화를 다시 불러와 복원(replay)할 수 있다.
- 리플레이 테스트: 특정 시점의 입력을 다시 재현해 도구 선택과 LLM 응답이 변경되었는지 확인하는 테스트를 자동화할 수 있다.
💡 리플레이 기능은 디버깅, 회귀 테스트(regression test), 품질 검증 등에서 매우 강력한 도구가 된다.
예를 들어, 사용자가 "이 이미지에 대해 설명해줘"라고 말했을 때 다음과 같은 흐름이 리플레이 가능하다:
{
"userMessage": "이 이미지에 대해 설명해줘",
"selectedTool": "generate_docent_from_file_upload",
"inputArguments": {
"file": "https://example.com/photo.jpg"
},
"toolOutput": {
"description": "이 이미지는 해변에서 노을을 배경으로 한 남성과 아이가 함께 걷는 모습이 담겨 있습니다."
},
"finalResponse": "이 사진은 해질 무렵 해변에서 산책하는 부자(父子)의 따뜻한 장면을 보여줍니다."
}
3. 툴 사용 제약과 허용 범위 설정
예측 가능성을 확보하는 또 다른 방법은, LLM이 사용할 수 있는 도구의 범위를 명시적으로 제한하는 것이다. 이는 보안성 확보와 의도하지 않은 행동 방지 측면에서 중요한 기능이다.
MCP에서는 다음과 같은 방식으로 제어가 가능하다:
- 툴 화이트리스트 제공: LLM에 전달되는
tools
목록을 제어함으로써 사용 가능한 도구만 노출한다. - 역할 기반 툴 노출: 사용자의 권한(Role)에 따라 사용할 수 있는 도구 집합을 달리 구성할 수 있다.
- 컨텍스트 조건 제어: 대화의 특정 조건이 충족되었을 때만 특정 도구를 노출하는 방식도 구현 가능하다.
예: 사용자가 "계약서 분석 결과를 PDF로 내려받고 싶어요"라고 했을 때,
export_to_pdf
도구는 이전에analyze_contract
결과가 존재할 때만 노출되도록 구성할 수 있다.
4. 툴 호출 실패에 대한 명확한 핸들링
실제 시스템에서는 항상 예외 상황이 발생할 수 있다. 이때, 에러 발생 시의 동작을 예측 가능하게 설계하는 것이 중요하다. MCP는 다음과 같은 실패 처리 전략을 도입할 수 있다:
- 입력 검증 실패: JSON Schema와 일치하지 않는 입력은 LLM 호출 이전에 즉시 차단
- 툴 실행 실패: 툴의 stderr 출력을 감지하거나 예외 메시지를 받아 LLM에게 전달
- 재시도 정책 설정: 동일한 인풋으로 N회까지 재시도 후 실패로 간주
- 사용자 친화적인 에러 설명 제공: 예외 메시지를 해석하여 "요청한 파일이 손상된 것 같습니다"와 같은 형태로 응답
MCPClient는 이러한 실패 상황을 로그로 저장함으로써, 동일한 오류가 반복되지 않도록 분석할 수 있는 기반을 제공한다.
5. 시나리오 기반 테스트 자동화
MCP 기반 에이전트는 단순한 프롬프트 테스트를 넘어, 복잡한 툴 체인과 조건 분기를 포함한 시나리오 수준의 테스트가 필요하다. 이를 위해 다음과 같은 자동화 도구가 활용될 수 있다:
- tool 호출 시퀀스 단위 테스트: 각 MCPTool을 독립적으로 실행하는 테스트
- 컨텍스트 기반 대화 흐름 테스트: LLM이 이전 툴 결과를 기억하고 후속 작업을 수행하는지 검증
- 예측 응답 검증: 동일한 입력에 대해 일관된 응답을 제공하는지 여부를 정기적으로 점검
MCP 운영 시스템에서는
test-cases.json
파일을 따로 정의하여, 정기적인 CI 테스트에 포함하는 방식으로 자동화할 수 있다.
6. 변경 이력과 버전 관리 체계
에이전트 시스템은 지속적으로 변화한다. 새로운 도구가 추가되거나, 기존 도구의 입력 구조가 변경될 수 있다. 이때 MCP는 버전 관리를 통해 이전 상태로의 롤백이나 변경 추적이 가능하도록 돕는다.
- 툴 명세의 버저닝: 각 MCPTool의 명세에
version
필드를 포함해 버전 히스토리 관리 (권장 패턴) - 도구 명 변경 없이 기능 변경을 가능하게 함: 동일한
name
을 유지하면서 schema를 점진적으로 업그레이드 - 호환성 검증 도구와 결합 가능: 기존 입력과 호환되지 않는 변경은 배포 전 자동 검증
예시:
{
"name": "summarize_contract_pdf",
"version": "2.1.0",
"inputSchema": { ... }
}
7. 정책 기반 운영과 관찰 가능성 (Observability)
운영 단계에서 중요한 또 하나의 요소는 시스템의 가시성이다. MCP는 다음과 같은 방식으로 관찰 가능성을 강화할 수 있다:
- 사용자별 도구 사용 빈도 집계: 어떤 툴이 많이 사용되고 있는지를 분석
- 에이전트 선택 툴 로그 기록: 어떤 문장에 어떤 도구가 선택되었는지를 기록
- 지연 시간, 오류율 등 메트릭 수집: 도구 호출의 평균 응답 시간, 실패율 등 수집 가능
이러한 데이터를 기반으로 대시보드를 구성하면, LLM 에이전트의 상태를 실시간으로 모니터링하고, 병목 구간이나 비정상 사용 패턴을 조기에 탐지할 수 있다.