티스토리 뷰

개요
MCP에 대해서는 어느 정도 알고는 있지만 좀더 체계적으로 이해하고 정리해두고 싶었다. 그래서 클로드 데스크탑과 꼬리를 무는 질문과 답변을 나눈 다음에 다음과 같이 정리를 했다.
목차
- MCP란 무엇인가?
- MCP 아키텍처와 구성요소
- 통신 메커니즘: 파이프와 JSON-RPC
- MCP 작동 과정 상세 분석
- Transport 계층과 다양한 전송 방식
- JSON-RPC 선택 이유와 장점
- Claude의 도구 선택 알고리즘
- 참고 자료
MCP란 무엇인가?
Model Context Protocol(MCP)는 AI 애플리케이션이 외부의 애플리케이션과 소통하는 방법을 표준화한 오픈 프로토콜이다.
핵심 개념
- USB-C for AI: MCP는 AI 애플리케이션을 위한 USB-C 포트와 같은 역할
- Language Server Protocol (LSP) 영감: 개발 도구 생태계를 표준화한 LSP에서 영감을 받아 AI 생태계를 표준화
- 양방향 통신: AI와 외부 시스템 간의 실시간 상호작용
MCP의 가치
기존에는 AI가 각각의 서비스들에 대해 각각의 다른 소통 방법을 정의해야 했지만, 이제는 모두 표준화된 MCP로 소통을 하면 된다.
MCP 아키텍처와 구성요소
1. 기본 구조
- MCP Client는 Claude Desktop, Cursor와 같은 Host Application 내부에 구현되어 있다고 보면 된다. 앞으로는 Claude Desktop을 Host application + MCP Client를 대표하여 언급하겠다.
- Claude Desktop등에 MCP 서버와의 연결방법을 설정해두면 소통을 하게 된다(JSON-RPC over Transport)
Host Application (Claude Desktop)
↓
MCP Client
↓ (JSON-RPC over Transport)
MCP Server
↓
External System (파일, DB, API 등)
2. 주요 구성요소
Host Application
- Claude Desktop 등 AI 애플리케이션
- 사용자 인터페이스 제공
- 여러 MCP Client 관리
MCP Client
- Host 애플리케이션 내부에서 실행
- 특정 MCP Server와 1:1 연결
- JSON-RPC 통신 관리
MCP Server
- 외부 시스템과 MCP 프로토콜 간의 브리지 역할
- 다양한 언어로 구현 가능 (Python, TypeScript, Java, Rust 등)
- 세 가지 주요 기능 제공(다음 참고)
3. MCP Server가 제공하는 기능
Tools
AI가 결정하여 호출하는 함수이며 실제 작업 수행한다. 다음과 같이 MCP Client에게 tool 정보를 제공한다.
{
"name": "print_memo",
"description": "간단한 메모를 프린터로 출력합니다",
"inputSchema": {
"type": "object",
"properties": {
"text": {"type": "string"}
}
}
}
Resources
AI가 접근할 수 있는 데이터 소스이며 읽기 전용이라 안전하다. 컨텍스트 정보를 제공하는 것이다. 다음과 같이 MCP Client에게 Resources 정보를 제공한다.
{
"name": "user_documents",
"description": "사용자 문서 폴더의 파일들",
"mimeType": "text/plain"
}
Prompts
사전 정의된 템플릿으로 Toos와 Resources를 최적으로 활용하는 방법을 미리 정의해둔 것이다. 정확한 이름을 명시해서 써야 한다. 예를 들어 code_review 를 사용해서 다음 코드를 리뷰해줘 와 같이 사용해야 한다.
{
"name": "code_review",
"description": "코드 리뷰를 위한 최적화된 프롬프트",
"arguments": {
"language": "프로그래밍 언어",
"code": "검토할 코드"
}
}
통신 메커니즘: Pipe와 JSON-RPC
TCP와 HTTP를 예로 들면 TCP는 데이터가 오고가는 통로라고 한다면, HTTP는 오고가는 데이터를 어떤 규칙으로 주고받을지를 정의한 것이다. 마찬가지로 로컬 PC에서 Claude Desktop(의 MCP Client)와 MCP Server는 Pipe로 연결이 되어 통신을 하고, 그 주고받는 데이터의 형식은 JSON-RPC를 사용한다.
파이프(Pipe) 통신
조금 어려운 이야기일 수 있겠다. Claude Desktop은 설정대로 MCP server를 자식 프로세스로 만들어 실행시킨다. 그리고 동시에 자식프로세스와 파이프로 연결한다.
이후에 각각의 stdout 출력은 서로의 stdin으로 입력되어 통신을 하게 된다.
데이터 전송 형태 예시
Claude Desktop → MCP Server
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"print_memo","arguments":{"text":"우유 사기"}}}\\\\n
MCP Server → Claude Desktop
{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"메모가 출력되었습니다"}]}}\\\\n
중요 구현 포인트
- flush()를 필수 사용해야 한다. 그렇지 않으면 버퍼가 찰때까지 전송이 되지 않는다.
# MCP 서버에서 응답 전송 시
print(json.dumps(response), flush=True) # flush=True 필수!
# 또는 명시적으로
sys.stdout.write(json.dumps(response) + '\\\\n')
sys.stdout.flush()
- 줄 단위로 전송이 된다.
- 각 JSON 메시지는 한 줄로 전송이 되며 \\\\n으로 메시지를 구분한다. 따라서 메시지 내부에 개행 문자는 포함할 수 없다.
MCP 작동 과정 상세 분석
1단계: 초기화 (Initialization)
Claude Desktop 시작 시:
- claude_desktop_config.json 파일 읽기
- mcpServers 섹션 파싱
- 각 MCP 서버 설정 정보를 메모리에 로드
- 설정 검증 (경로 존재, 권한 확인)
2단계: 서버 실행 (Server Execution)
Claude Desktop 측:
- 자식 프로세스로 MCP 서버 실행
- stdin/stdout 파이프 설정
- 프로세스 생명주기 관리 시작
MCP 서버 측:
- 내부에서 MCP server 실행. 메시지 수신대기
3단계: 통신 (Communication)
- 초기 핸드셰이크
// Claude Desktop→ MCP 서버
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {"listChanged": true}
}
}
}
// MCP 서버 → Claude Desktop
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {"listChanged": true}
},
"serverInfo": {
"name": "todo-printer",
"version": "1.0.0"
}
}
}
- 도구 목록 조회: Claude Desktop는 자신이 사용할 수 있는 Tools, Resources, Prompts 정보를 서버에 요청하여 받게 된다.
// Claude Desktop → MCP 서버
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}
// MCP 서버 → Claude Desktop
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "print_memo",
"description": "간단한 메모를 프린터로 출력합니다",
"inputSchema": {
"type": "object",
"properties": {
"text": {"type": "string"}
}
}
}
]
}
}
- 도구 실행
// Claude Desktop → MCP 서버
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "print_memo",
"arguments": {
"text": "우유 사기"
}
}
}
// MCP 서버 → Claude Desktop
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "메모가 성공적으로 출력되었습니다."
}
]
}
}
4단계: 기능 제공 (Feature Provision)
실제 사용 과정을 예시를 들어 좀더 들여다보자.
- 사용자 요청: "장보기 메모를 출력해줘"
- Claude Desktop 분석: 요청을 분석하고 적절한 도구 선택
- 도구 호출: print_memo 도구 실행 결정
- 실제 실행: MCP 서버에서 프린터 출력 수행
- 결과 반환: 실행 결과를 Claude Desktop이 사용자에게 전달
Transport 계층과 다양한 전송 방식
1. 통신 계층 구조
- 응용 계층: JSON-RPC 2.0 (메시지 형식/프로토콜)
- 전송 계층: Transport (데이터 전송 방식)
2. MCP 공식 지원 Transport
- stdio (Standard Input/Output) - Claude Desktop 기본값
{
"mcpServers": {
"server-name": {
"command": "/path/to/executable",
"args": ["arg1", "arg2"]
}
}
}
- 클라이언트는 가능한 한 stdio를 지원해야 함 (SHOULD support)
- 프로세스 간 파이프 통신
- 로컬 환경에 최적화
- Streamable HTTP (Server-Sent Events 포함)
{
"mcpServers": {
"http-server": {
"transport": "streamable_http",
"url": "<https://example.com/mcp>"
}
}
}
- 2025-03-26 버전에서 HTTP+SSE transport를 대체
- HTTP POST/GET 요청 사용
- 선택적으로 Server-Sent Events 지원
- 원격 서버에 적합
3. 다양한 Transport에서의 JSON-RPC
공식지원을 하지 않을 뿐이지 어떠한 전송계층에서건 JSON-PRC로만 통신을 하면 된다. 다시 말해서 MCP는 양방향 메시지 교환을 지원하는 모든 통신 채널에서 구현이 가능하다.
- 네트워크 기반: TCP Socket, WebSocket, UDP, gRPC, MQTT
- 로컬 IPC: Named Pipes, Unix Domain Socket, Message Queues, Shared Memory
- 클라우드/분산: Message Brokers, Cloud Functions, Container Communication
4. Claude Desktop이 stdio를 선택한 이유
- 단순함
- 네트워크 설정, 포트 관리, 방화벽 설정이 모두 불필요하다.
- 보안
- 로컬 프로세스 간 통신만 하여 네트워크 노출이 없다.
- 권한 상속(부모 프로세스 → 자식 프로세스)
- 생명주기 관리
- 부모 프로세스 종료 시 자식도 자동 정리한다(Claude Desktop 종료시 MCP 서버도 함께 종료)
- 프로세스 상태 모니터링 용이
- 재시작 제어 간단
JSON-RPC 선택 이유와 장점
1. Language Server Protocol의 성공 사례
MCP는 LSP에서 영감을 받았으며, LSP의 JSON-RPC 사용 성공 사례를 따름:
- 개발 도구 생태계 전반에 프로그래밍 언어 지원 표준화
- 다양한 에디터와 언어 서버 간의 원활한 통신
- 검증된 아키텍처 패턴
2. JSON-RPC의 고유한 장점
- 요청-응답 매칭 내장: id 필드로 요청과 응답을 매칭할 수 있는데 이는 비동기 환경에서 필수이다. 따라서 여러 요청을 동시에 처리 가능하다. 요청에 대한 응답을 기다리지 않고 마구 보내도, 응답의 id를 통해 어떤 요청에 대한 응답인지 알 수 있다는 것이다.
// 요청
{"jsonrpc": "2.0", "id": 42, "method": "tools/call", "params": {...}}
// 응답
{"jsonrpc": "2.0", "id": 42, "result": {...}}
- 표준화된 에러 처리: 에러 코드가 표준화되어 있다.
{
"jsonrpc": "2.0",
"id": 42,
"error": {
"code": -32601,
"message": "Method not found",
"data": {...}
}
}
- 배치 요청 지원이 가능하다.
[
{"jsonrpc": "2.0", "id": 1, "method": "tools/list"},
{"jsonrpc": "2.0", "id": 2, "method": "resources/list"}
]
3. 다른 프로토콜과의 비교
- REST API의 한계
- URL 경로 설계 복잡성
- 에러 코드 표준화 어려움
- 요청-응답 매칭 없음
- RPC 스타일에 부자연스러움
- GraphQL의 한계
- 스키마 정의 복잡성
- 동적 도구 추가 어려움
- 오버헤드 크기
- RPC 패턴에 맞지 않음
- gRPC의 한계
- 바이너리 프로토콜 (디버깅 어려움)
- Proto 스키마 관리 복잡
- 웹 환경 지원 제한
4. AI/LLM 환경에 최적화된 이유
- 자연스러운 함수 호출 패러다임
# AI가 생각하는 방식
"사용자가 메모를 출력하고 싶어한다. print_memo 함수를 호출해야겠다."
# JSON-RPC로 직접 번역
{
"method": "tools/call",
"params": {"name": "print_memo", "arguments": {"text": "사용자 메모"}}
}
- 스키마 없는 유연성
- 새로운 도구를 런타임에 동적으로 추가 가능
- 스키마 수정 없이 즉시 사용
- Transport 독립성
- 동일한 JSON-RPC 메시지를 다양한 Transport로 전송
- 프로토콜과 전송 방식의 분리
- 확장성과 호환성 보장
Claude Desktop의 도구 선택 알고리즘
Claude Desktop에 많은 MCP server가 설정되어 있고, 각각의 server가 수많은 Tools를 제공한다고 할때 어떤 기준으로 도구를 선택할 지 궁금했다.
1. 도구 메타데이터 기반 선택
- MCP 서버가 제공하는 도구의 name, description 정보들에서 매칭을 한다.
{
"name": "print_memo",
"description": "간단한 메모를 프린터로 출력합니다",
"inputSchema": {
"properties": {
"text": {
"type": "string",
"description": "출력할 메모 내용"
}
}
}
}
Claude의 매칭 과정:
- 사용자: "장보기 메모를 출력해줘"
- 키워드 매칭: "출력" → "프린터로 출력"
- 의미 분석: "메모" → print_memo
- 입력 스키마 호환성 검사
{
"name": "send_email",
"inputSchema": {
"properties": {
"to": {"type": "string"},
"subject": {"type": "string"},
"body": {"type": "string"}
},
"required": ["to", "subject", "body"]
}
}
Claude의 판단:
- 필수 매개변수 확인(required)
- 사용자 요청에서 정보 추출 가능성 평가
- 누락된 정보에 대한 추가 질문 필요성 판단
2. 컨텍스트 기반 가중치로 선택
최근에 사용한 도구에 가중치를 둔다. 방금 앞에 짧은 메모를 프린터 출력해달라는 요청을 했다면, 다음에는 사용자가 그냥 “숙제하기” 라고만 쳐도 프린터 출력을 하라는 것으로 이해했다.
1번과 2번에서 알 수 있듯이 많은 MCP server가 등록되어 사용할 수 있는 도구가 많고 유사한 도구들이 있다면 선택의 오류가 많아질 수 있다.
3. 도구 설명 최적화 권장사항
- 명확하고 구체적인 설명
// ❌ 나쁜 예
{
"name": "tool1",
"description": "유용한 기능"
}
// ✅ 좋은 예
{
"name": "print_receipt",
"description": "영수증을 열감지 프린터로 출력합니다. 쇼핑 목록, 메모, 영수증 등 간단한 텍스트 출력에 사용하세요."
}
- 관련 키워드 포함
{
"name": "send_email",
"description": "이메일을 전송합니다. 메일, 편지, 메시지 보내기, 연락하기 등에 사용하세요."
}
참고 자료
공식 문서
- MCP 공식 사이트: https://modelcontextprotocol.io/
- MCP 사양: https://modelcontextprotocol.io/specification/2025-06-18
- Transport 사양: https://modelcontextprotocol.io/specification/2
'develop-and-AI' 카테고리의 다른 글
| 영수증 프린터로 할 일 관리 - 프린터 준비 (0) | 2025.07.11 |
|---|---|
| 영수증 프린터로 할 일 관리 - 시작 (0) | 2025.07.11 |
| Claude Code: Hooks 간단 실습 (0) | 2025.07.03 |
| NotebookLM 언어를 한국어로 하면 아쉬운 두 가지 (0) | 2025.05.25 |
| NotebookLM으로 테크뉴스 소화하기 (0) | 2025.05.20 |
- Total
- Today
- Yesterday
- 독서후기
- go
- ChatGPT
- 영화
- middleware
- 잡학툰
- 독서
- agile
- 클린 애자일
- MCP
- 인텔리제이
- API
- Gin
- websocket
- postgres
- OpenAI
- gocore
- notion
- github
- 체호프
- 오블완
- golang
- 티스토리챌린지
- clean agile
- bun
- intellij
- Echo
- solid
- strange
- backend
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |