Model Context Protocol (MCP) 개요
MCP가 등장한 이유
섹션 제목: “MCP가 등장한 이유”AI 에이전트가 외부 시스템(데이터베이스, API, 파일 시스템)과 통합될 때, 기존에는 각 LLM 제공자마다 서로 다른 방식으로 도구를 정의해야 했습니다. OpenAI 방식으로 작성한 도구는 Anthropic 모델에서 그대로 쓸 수 없고, 새 모델이 나올 때마다 통합 코드를 다시 작성해야 했습니다.
**MCP(Model Context Protocol)**는 Anthropic이 2024년 11월 공개한 오픈 표준입니다. LLM과 외부 도구 사이의 공통 언어를 정의하여, 한 번 만든 MCP 서버를 모든 호환 클라이언트에서 사용할 수 있습니다.
“MCP is to AI tools what USB-C is to device charging.” — 다양한 기기를 하나의 표준 포트로 연결하듯, MCP는 다양한 AI 클라이언트를 하나의 서버 인터페이스로 연결합니다.
기존 방식과의 비교
섹션 제목: “기존 방식과의 비교”기존 function calling 방식에서는 OpenAI와 Anthropic이 서로 다른 스키마를 요구했습니다.
// OpenAI function calling 스키마{ "type": "function", "function": { "name": "read_file", "parameters": { "type": "object", "properties": { "path": { "type": "string" } } } }}
// Anthropic tool_use 스키마{ "name": "read_file", "input_schema": { "type": "object", "properties": { "path": { "type": "string" } } }}MCP를 사용하면 서버에 도구를 한 번 정의하면, 호환 클라이언트는 모델에 관계없이 동일한 서버를 사용할 수 있습니다. 통합 코드를 모델마다 작성하는 N×M 문제가 N+M 문제로 줄어듭니다.
아키텍처 개요
섹션 제목: “아키텍처 개요”┌─────────────────────────────────────────────────────┐│ Host Application ││ (Claude Desktop, Cursor, 커스텀 에이전트 등) ││ ││ ┌──────────────┐ ┌──────────────────────────┐ ││ │ MCP Client 1 │ │ MCP Client 2 │ ││ └──────┬───────┘ └────────────┬─────────────┘ │└─────────│────────────────────────│─────────────────┘ │ JSON-RPC 2.0 │ JSON-RPC 2.0 ▼ ▼┌─────────────────┐ ┌──────────────────────────┐│ MCP Server A │ │ MCP Server B ││ (파일 시스템) │ │ (GitHub, Slack, DB 등) │└─────────────────┘ └──────────────────────────┘각 MCP 클라이언트는 단일 MCP 서버와 1:1로 연결됩니다. 하나의 호스트 애플리케이션은 여러 클라이언트를 통해 여러 서버에 동시에 연결할 수 있습니다.
전송 계층과 메시지 형식
섹션 제목: “전송 계층과 메시지 형식”통신은 JSON-RPC 2.0 프로토콜을 사용합니다. 전송 계층은 연결 방식에 따라 다릅니다.
| 전송 방식 | 사용 시나리오 | 특징 |
|---|---|---|
| Stdio | 로컬 프로세스 | 클라이언트가 서버를 자식 프로세스로 실행 |
| Streamable HTTP | 원격·로컬 HTTP 서버 | 단일 MCP 엔드포인트로 POST하고 JSON 또는 요청별 SSE 응답을 수신 |
| Custom transport | 특수 런타임 | JSON-RPC 메시지와 라이프사이클 요구사항을 보존하는 범위에서 구현 |
JSON-RPC 2.0 메시지 구조
섹션 제목: “JSON-RPC 2.0 메시지 구조”MCP의 모든 통신은 JSON-RPC 2.0 형식을 따릅니다. 요청, 응답, 알림 세 종류의 메시지가 있습니다.
요청 (Request): 클라이언트가 서버에 작업을 요청할 때
다음 요청·응답은 2026-07-28 명세 기준입니다. SDK는 버전과 capability 메타데이터를 구성합니다. 직접 JSON-RPC를 구현할 때는 이 필드를 생략하지 않습니다.
{ "jsonrpc": "2.0", "id": "req-001", "method": "tools/call", "params": { "_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} }, "name": "read_file", "arguments": { "path": "/workspace/src/main.ts" } }}응답 (Response): 서버가 요청에 대한 결과를 반환할 때
{ "jsonrpc": "2.0", "id": "req-001", "result": { "resultType": "complete", "content": [ { "type": "text", "text": "import { createServer } from 'http';\n..." } ] }}알림 (Notification): 응답을 기다리지 않는 단방향 메시지 (예: 진행 상황 업데이트)
{ "jsonrpc": "2.0", "method": "notifications/progress", "params": { "progressToken": "task-001", "progress": 45, "total": 100 }}요청별 버전과 기능
섹션 제목: “요청별 버전과 기능”2026-07-28부터 initialize와 notifications/initialized 핸드셰이크가 제거됐습니다. 각 요청이 버전과 클라이언트 capability를 전달하며 서버는 요청별로 지원 여부를 판단합니다.
클라이언트 → 서버: server/discover (선택적 사전 탐색)서버 → 클라이언트: 지원 버전, capability, 서버 식별 정보클라이언트 → 서버: tools/call + 요청별 버전·capability서버 → 클라이언트: resultType: complete 또는 input_requiredMCP 기능 구분
섹션 제목: “MCP 기능 구분”MCP 기능은 누가 기능을 제공하느냐에 따라 나누어 이해하면 쉽습니다. 서버 기능은 MCP 서버가 클라이언트에 제공하는 기능이고, 클라이언트 기능은 서버가 작업 중 호스트 애플리케이션 쪽 능력을 요청하는 기능입니다.
| 구분 | 기능 | 핵심 역할 |
|---|---|---|
| 서버 기능 | Tools | 모델이 실행할 수 있는 함수 |
| 서버 기능 | Resources | 모델이나 사용자가 읽을 수 있는 데이터 |
| 서버 기능 | Prompts | 재사용 가능한 워크플로우 템플릿 |
| 클라이언트 기능 | Elicitation | MRTR을 통해 사용자에게 추가 정보 요청 |
| 이전 명세 기능 | Sampling, Roots | 2026-07-28에서 폐기 예정으로 지정, 신규 구현에는 추가하지 않음 |
1. Tools (도구)
섹션 제목: “1. Tools (도구)”LLM이 호출할 수 있는 함수입니다. 타입이 명시된 입력/출력 스키마를 가집니다. 기존의 function calling과 가장 유사한 개념입니다.
{ "name": "read_file", "description": "파일 내용을 읽습니다", "inputSchema": { "type": "object", "properties": { "path": { "type": "string", "description": "읽을 파일 경로" } }, "required": ["path"] }}실제 GitHub MCP 서버의 Tool 예시입니다.
{ "name": "create_pull_request", "description": "GitHub 저장소에 PR을 생성합니다", "inputSchema": { "type": "object", "properties": { "owner": { "type": "string" }, "repo": { "type": "string" }, "title": { "type": "string" }, "head": { "type": "string", "description": "소스 브랜치" }, "base": { "type": "string", "description": "대상 브랜치" }, "body": { "type": "string" } }, "required": ["owner", "repo", "title", "head", "base"] }}2. Resources (리소스)
섹션 제목: “2. Resources (리소스)”LLM이 읽을 수 있는 데이터입니다. 파일, 데이터베이스 레코드, API 응답 등을 URI로 노출합니다. 도구와 달리 부작용(side effect) 없이 데이터를 제공합니다.
{ "uri": "file:///project/src/main.ts", "name": "main.ts", "mimeType": "text/typescript"}Resources는 정적 리소스와 동적 리소스 두 종류로 나뉩니다.
정적: file:///docs/api-spec.md (고정된 파일)동적: db://customers/{id}/orders (파라미터 기반 조회) github://repos/{owner}/{repo}/issues (실시간 데이터)동적 리소스는 URI 템플릿을 통해 파라미터를 받아 실시간으로 데이터를 생성합니다.
3. Prompts (프롬프트)
섹션 제목: “3. Prompts (프롬프트)”재사용 가능한 프롬프트 템플릿입니다. 서버가 클라이언트에게 제안하는 프롬프트 구조로, 일관된 방식으로 특정 작업을 요청할 때 사용합니다.
{ "name": "code_review", "description": "코드 리뷰 요청 템플릿", "arguments": [ { "name": "language", "required": true }, { "name": "focus", "required": false } ]}클라이언트가 이 프롬프트를 호출하면 서버는 채워진 메시지 배열을 반환합니다.
{ "resultType": "complete", "messages": [ { "role": "user", "content": { "type": "text", "text": "다음 TypeScript 코드를 리뷰해 주세요. 보안 측면에 집중하세요:\n\n{{code}}" } } ]}4. 이전 명세의 Sampling과 Roots
섹션 제목: “4. 이전 명세의 Sampling과 Roots”이전 명세의 Sampling은 서버가 클라이언트에 LLM 생성을 요청하는 기능입니다. Roots는 클라이언트가 공유하는 파일·URI 목록입니다. Roots 자체는 접근을 강제하는 보안 경계가 아니므로 서버가 실제 파일 권한을 검사해야 합니다.
2026-07-28 명세는 두 기능을 폐기 예정으로 지정했습니다. 신규 구현은 LLM 제공자 API와 직접 연결하거나, 파일·디렉터리를 도구 인수와 서버 설정으로 명시합니다. 기존 기능은 폐기 유예 기간에 동작할 수 있으므로 구형 연결을 분석할 때 구분합니다.
5. Elicitation과 MRTR
섹션 제목: “5. Elicitation과 MRTR”Elicitation은 서버 작업에 필요한 사용자 정보를 클라이언트가 수집하는 기능입니다. 최신 명세의 MRTR(Multi Round-Trip Requests)은 서버의 역방향 JSON-RPC 요청을 대체합니다.
클라이언트 → 서버: 원래 도구 요청서버 → 클라이언트: resultType: input_required + inputRequests클라이언트: 사용자 입력 또는 승인된 정보를 수집클라이언트 → 서버: 원래 요청을 inputResponses와 함께 재시도서버 → 클라이언트: resultType: complete사용자 정보 요청이 실제 작업의 실행 승인과 같은 뜻은 아닙니다. 호스트는 민감 정보, 외부 전송, 상태 변경에 대한 권한을 별도로 검사합니다.
기능 선택 가이드
섹션 제목: “기능 선택 가이드”| 상황 | 사용할 기능 |
|---|---|
| 호스트가 URI로 자료를 선택해 읽기 | Resources |
| 모델이 검색·조회·변경을 선택해 실행 | Tools |
| 사용자가 재사용 워크플로우를 선택 | Prompts |
| 작업 중 사용자 정보가 추가로 필요 | Elicitation + MRTR |
| 장기 작업의 상태·결과 조회 | Tasks 확장, 양쪽 지원 확인 |
읽기 전용 검색도 Tool로 제공할 수 있습니다. Tools와 Resources의 차이는 쓰기 여부만이 아니라 모델이 호출하는 작업인지, 호스트가 선택하는 자료인지에 있습니다.
MCP 서버 구체 예시
섹션 제목: “MCP 서버 구체 예시”파일 시스템 서버
섹션 제목: “파일 시스템 서버”로컬 파일 시스템을 MCP로 노출하는 가장 기본적인 서버입니다. Claude Desktop에 다음과 같이 등록합니다.
{ "mcpServers": { "filesystem": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-filesystem", "/Users/user/Documents" ] } }}등록 후 Claude는 /Users/user/Documents 하위 파일을 읽고 쓸 수 있습니다.
데이터베이스 서버
섹션 제목: “데이터베이스 서버”데이터베이스 MCP 서버는 스키마를 Resource로, 제한된 조회를 Tool로 노출할 수 있습니다. 과거 예제 패키지인 @modelcontextprotocol/server-postgres를 신규 기본값으로 설치하기보다, 관리 주체·업데이트·접근 범위를 확인한 서버를 선택합니다. 공식 예제 저장소의 보관된 구현은 현재 운영 지원을 뜻하지 않습니다.
DB 계정의 실제 권한도 읽기 전용으로 제한하고, 허용 스키마·조회 시간·결과 행 수를 서버에서 검사합니다. 도구 설명에 “SELECT만 허용”이라고 쓰는 것으로 DB 권한이 제한되지는 않습니다.
MCP 보안 고려 사항
섹션 제목: “MCP 보안 고려 사항”MCP 서버는 강력한 기능을 제공하는 만큼, 보안 설계에 주의가 필요합니다.
도구 권한 최소화
섹션 제목: “도구 권한 최소화”MCP 서버가 제공하는 도구는 필요한 최소 권한만 가져야 합니다. 읽기 전용 작업에 쓰기 도구를 함께 노출하지 않습니다.
# 잘못된 설계: 모든 권한을 하나의 서버에 노출tools = [read_file, write_file, delete_file, exec_shell]
# 올바른 설계: 역할별로 서버를 분리read_only_server_tools = [read_file, list_directory, search_files]write_server_tools = [write_file, create_directory]exec_server_tools = [run_test, run_lint] # 별도 승인 필요입력 검증
섹션 제목: “입력 검증”Tool의 inputSchema만으로는 악의적인 입력을 막기 어렵습니다. 서버 내부에서 추가 검증을 수행합니다.
from pathlib import Path
ALLOWED_BASE = Path("/workspace").resolve(strict=True)
def read_file(path: str) -> str: resolved = (ALLOWED_BASE / path).resolve(strict=True) if not resolved.is_relative_to(ALLOWED_BASE): raise PermissionError(f"허용되지 않는 경로: {path}") return resolved.read_text()원격 서버의 신뢰 문제
섹션 제목: “원격 서버의 신뢰 문제”Stdio 서버도 호스트 권한으로 실행되는 프로그램이므로 설치 출처와 파일·네트워크 권한을 검토합니다. Streamable HTTP 서버에는 TLS와 인증·인가, Host·Origin 검증도 적용합니다.
| 위협 | 완화 전략 |
|---|---|
| 중간자 공격 | TLS 적용, 서버 인증서 검증 |
| 무단 접근 | API 키 또는 OAuth 토큰 인증, Resource Indicator 사용 |
| 서버 사칭 | 서버 신원 검증 (핀닝 또는 CA 검증) |
| 과도한 권한 요청 | Tool 목록 검토 후 선택적 허용 |
최신 MCP 변화 관찰 포인트
섹션 제목: “최신 MCP 변화 관찰 포인트”2026-07-28의 요청은 연결 세션에 의존하지 않습니다. 여러 호출에 걸친 상태는 서버가 발급한 작업 핸들을 도구 인수로 전달해 관리합니다. 서버 알림 구독은 subscriptions/listen을 사용합니다.
목록과 리소스 응답의 ttlMs·cacheScope는 클라이언트 캐시의 유효 기간과 공유 범위를 지정합니다. 모든 성공 결과에는 resultType이 있으며, Tasks는 코어의 실험 기능에서 io.modelcontextprotocol/tasks 확장으로 이동했습니다.
원격 인가는 OAuth Resource Server, Resource Indicator, Protected Resource Metadata를 함께 구현합니다. 재연결로 끊긴 변경 요청을 다시 실행할 때는 작업 ID로 중복 효과를 방지합니다.
MCP는 LLM과 외부 도구 통합의 공통 표준입니다. JSON-RPC 2.0 기반으로 동작하며 표준 전송 계층은 Stdio와 Streamable HTTP입니다. 서버는 Tools, Resources, Prompts를 제공하고, 추가 정보는 MRTR로 교환합니다. Sampling과 Roots는 폐기 예정이며 장기 작업은 Tasks 확장으로 분리됩니다. 보안 측면에서는 최소 권한 원칙, 입력 검증, 원격 서버 신뢰 검토가 필수입니다. 한 번 작성한 MCP 서버는 모든 호환 AI 클라이언트에서 재사용할 수 있습니다.