아키텍처 및 작동 원리 심층 분석 (Under the Hood)
단순한 비유를 넘어, 소프트웨어 엔지니어링 관점에서 MCP가 어떻게 설계되었고 작동하는지 세밀하게 파헤쳐 보겠습니다.
1. 전체 구조와 데이터 흐름
MCP 아키텍처는 클라이언트-서버 모델을 엄격하게 따릅니다. 여기서 혼동하지 말아야 할 점은, ‘클라이언트’가 보통 우리가 쓰는 AI 애플리케이션(호스트) 내부에 위치한다는 것입니다.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
flowchart LR
AiHostApp["AI 애플리케이션 (Host)"]
McpClientNode["MCP 클라이언트"]
JsonRpcProtocol["JSON-RPC 계층"]
McpServerNode["MCP 서버"]
ExternalSystem["외부 데이터 및 API"]
AiHostApp --> McpClientNode
McpClientNode --> JsonRpcProtocol
JsonRpcProtocol --> McpServerNode
McpServerNode --> ExternalSystem
- AI 애플리케이션(예: Claude Desktop)은 사용자의 입력을 받아들입니다.
- 애플리케이션 내부에 내장된 MCP 클라이언트는 등록된 MCP 서버들에게 “너희들은 어떤 기능을 가지고 있니?”라고 질의합니다.
- 클라이언트와 서버는 JSON-RPC라는 가볍고 표준화된 포맷을 통해 메시지를 주고받습니다.
- MCP 서버는 외부 시스템(예: 로컬 폴더, 사내 Jira 시스템 등)과 직접 통신하여 데이터를 가져오거나 동작을 수행합니다.
서버가 AI 클라이언트에게 제공할 수 있는 기능은 크게 세 가지로 분류됩니다. 이 세 가지 요소의 목적과 차이점을 정확히 이해하는 것이 핵심입니다.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
erDiagram
McpServerEntity ||--o{ McpResourceEntity : "provides"
McpServerEntity ||--o{ McpToolEntity : "exposes"
McpServerEntity ||--o{ McpPromptEntity : "offers"
McpResourceEntity {
string uri
string name
string mimeType
}
McpToolEntity {
string name
string description
object inputSchema
}
McpPromptEntity {
string name
string template
}
| 컴포넌트 명칭 | 주요 목적 및 특징 | 일상적인 비유 | 구체적인 사용 예시 |
|---|
| Resources | 읽기 전용 데이터 제공. 정적이거나 동적인 데이터를 URI 형태로 노출합니다. | 웹 브라우저로 정보성 웹페이지를 읽는 것 | 특정 로그 파일 읽기, 데이터베이스 스키마 조회, API 응답 가져오기 |
| Tools | 실행 가능한 작업 노출. 상태를 변경하거나 부수 효과(Side Effect)를 일으키는 작업을 정의합니다. | 버튼을 눌러 온라인 폼을 제출하고 작업을 실행하는 것 | GitHub에 새 이슈 생성하기, DB에 UPDATE 쿼리 실행하기, 특정 코드 라인 수정하기 |
| Prompts | 재사용 가능한 지시문 템플릿 제공. 사용자가 자주 하는 요청을 템플릿화하여 제공합니다. | 복잡한 검색 조건이 미리 입력된 즐겨찾기 북마크 | “이 코드베이스의 스타일 가이드에 맞춰 코드를 리뷰해줘”라는 사전 정의된 템플릿 |
특히 Tools 기능은 AI가 스스로 행동하는 에이전트(Agent)로 진화하는 데 결정적인 역할을 합니다. 서버는 도구의 입력 형식을 JSON Schema로 명확히 정의하여 클라이언트에 전달하며, AI 모델은 이 스키마를 바탕으로 정확한 인자(Arguments)를 생성하여 서버로 호출 요청을 보냅니다.
3. 클라이언트-서버 통신 방식 및 프로토콜
통신은 철저히 비동기적이며 JSON-RPC 2.0 규격을 따릅니다. 사용자가 AI에게 “내 로컬 프로젝트의 main.py 파일을 읽어서 버그를 찾아줘”라고 요청했을 때 내부적으로 일어나는 통신 과정을 살펴보겠습니다.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
sequenceDiagram
participant AiModel as AI 애플리케이션
participant McpClient as MCP 클라이언트
participant McpServer as 파일시스템 MCP 서버
AiModel->>McpClient: main.py 분석 요청
McpClient->>McpServer: tools/call 요청 (읽기 도구)
Note right of McpClient: {"method": "tools/call", "params": {"name": "read_file", "arguments": {"path": "main.py"}}}
McpServer-->>McpServer: 파일 시스템에서 main.py 읽기
McpServer-->>McpClient: 성공 응답 및 파일 내용 반환
Note left of McpServer: {"result": {"content": [{"type": "text", "text": "def main():..."}]}}
McpClient-->>AiModel: 컨텍스트에 파일 내용 주입
AiModel-->>AiModel: LLM 추론 진행 (버그 탐색)
AiModel->>McpClient: 분석 결과 출력
위 시퀀스에서 보듯, 프로토콜 계층은 매우 얇고 투명합니다. 클라이언트는 단순히 서버가 정의한 메서드를 호출하고, 그 결과를 텍스트 혹은 바이너리 형태의 배열로 반환받을 뿐입니다. 복잡한 파일 I/O나 권한 관리는 전적으로 서버가 책임집니다.
4. 서버의 상태 전이와 생명주기
MCP 연결은 무상태(Stateless) REST API와 달리, 지속적인 연결(Stateful)을 유지하며 초기 협상 과정을 거칩니다.
%%{init: {"theme":"base","themeVariables":{"primaryColor":"#F0EEE9","primaryBorderColor":"#2a78d6","primaryTextColor":"#2b2926","secondaryColor":"#e8f0fb","secondaryBorderColor":"#4a3aa7","secondaryTextColor":"#2b2926","tertiaryColor":"#eafaf3","tertiaryBorderColor":"#1baf7a","tertiaryTextColor":"#2b2926","lineColor":"#8a8578","textColor":"#2b2926","edgeLabelBackground":"#F0EEE9","noteBkgColor":"#F0EEE9","noteTextColor":"#2b2926","noteBorderColor":"#8a8578","clusterBkg":"#faf9f6","clusterBorder":"#d8d4c8","fontFamily":"Pretendard, sans-serif"}}}%%
stateDiagram-v2
[*] --> UninitializedState
UninitializedState --> NegotiatingState : 초기화 (Initialize) 요청 전송
NegotiatingState --> InitializedState : 기능(Capabilities) 및 권한 정보 교환 완료
InitializedState --> ConnectedState : Ping 테스트 및 정상 작동
ConnectedState --> DisconnectedState : 종료 요청 혹은 네트워크 타임아웃
DisconnectedState --> [*]
가장 중요한 단계는 NegotiatingState(기능 협상 단계)입니다. 이 시점에 서버는 자신이 어떤 기능(예: “나는 Tools만 지원하고 Resources는 지원하지 않아”)을 가졌는지 클라이언트에게 알립니다. 이를 통해 서로 다른 버전의 SDK나 클라이언트-서버 조합에서도 유연하게 호환성을 유지할 수 있습니다.