Blog
mcpmodel-context-protocolai-agenttool-useclaudeai

MCP(Model Context Protocol) 가이드 - AI 도구 연동의 새로운 표준

Anthropic의 MCP(Model Context Protocol) 개념, 아키텍처, 서버/클라이언트 구현, 주요 MCP 서버 생태계, 보안, 엔터프라이즈 활용을 체계적으로 정리합니다.

Data Dynamics2026年4月16日11 min read
This post is not yet translated. The original Korean version is shown below.

MCP(Model Context Protocol)는 Anthropic이 제안한 AI 모델과 외부 도구/데이터 소스를 연결하는 개방형 프로토콜입니다. 이 글에서는 MCP의 개념, 아키텍처, 구현 방법, 생태계를 체계적으로 다룹니다.


1. MCP란 무엇인가

정의와 등장 배경

MCP(Model Context Protocol)는 AI 모델이 외부 도구, 데이터 소스, 서비스에 접근하는 표준화된 프로토콜입니다. USB-C가 다양한 장치를 하나의 규격으로 연결하듯, MCP는 다양한 AI 도구를 하나의 프로토콜로 연결합니다.

[MCP 이전 — 도구마다 커스텀 통합]
Claude ─── 커스텀 코드 ──→ GitHub
Claude ─── 커스텀 코드 ──→ Slack
Claude ─── 커스텀 코드 ──→ Database
Claude ─── 커스텀 코드 ──→ File System

[MCP 이후 — 표준 프로토콜로 통합]
Claude ─── MCP ──→ GitHub MCP Server
                ──→ Slack MCP Server
                ──→ Database MCP Server
                ──→ File System MCP Server

MCP vs 기존 방식 비교

구분Function CallingMCP
표준화모델/플랫폼별 다름통일된 프로토콜
도구 발견수동 등록자동 발견 (서버가 도구 목록 제공)
양방향 통신단방향 (모델→도구)양방향 (도구→모델 알림 가능)
상태 관리없음 (Stateless)세션 기반 (Stateful)
생태계플랫폼 종속오픈 생태계 (서버 공유/재사용)
보안앱별 구현프로토콜 수준 권한 관리

2. MCP 아키텍처

핵심 구성 요소

[MCP 아키텍처]

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  MCP Host    │     │  MCP Client  │     │  MCP Server  │
│  (AI 앱)     │────→│  (프로토콜    │────→│  (도구 제공)  │
│              │     │   클라이언트) │     │              │
│  Claude Code │     │              │     │  GitHub      │
│  Claude.ai   │     │              │     │  Slack       │
│  IDE 확장    │     │              │     │  Database    │
└──────────────┘     └──────────────┘     └──────────────┘
구성 요소역할예시
HostMCP를 사용하는 AI 애플리케이션Claude Desktop, Claude Code, IDE
ClientMCP 프로토콜로 서버와 통신하는 클라이언트Host 내부에 내장
Server도구, 리소스, 프롬프트를 제공하는 서버GitHub, Slack, DB 서버

프로토콜 기능

MCP 서버는 세 가지 핵심 기능을 제공합니다.

기능설명예시
Tools모델이 호출할 수 있는 함수create_issue, query_db, send_message
Resources모델이 읽을 수 있는 데이터파일 내용, DB 스키마, API 문서
Prompts미리 정의된 프롬프트 템플릿코드 리뷰 프롬프트, 분석 프롬프트

통신 프로토콜

[MCP 메시지 흐름]

Client                           Server
  │                                │
  ├─── initialize ────────────→   │  (연결 및 기능 협상)
  │   ←── capabilities ───────   │
  │                                │
  ├─── tools/list ────────────→   │  (사용 가능한 도구 목록)
  │   ←── tool definitions ───   │
  │                                │
  ├─── tools/call ────────────→   │  (도구 호출)
  │   ←── result ─────────────   │
  │                                │
  ├─── resources/read ────────→   │  (리소스 읽기)
  │   ←── content ────────────   │
  │                                │
  │   ←── notification ───────   │  (서버→클라이언트 알림)
  │                                │

3. MCP 서버 구현

Python으로 MCP 서버 만들기

from mcp.server import Server
from mcp.types import Tool, TextContent
import mcp.server.stdio
 
# MCP 서버 생성
server = Server("data-dynamics-tools")
 
# 도구 정의
@server.list_tools()
async def list_tools():
    return [
        Tool(
            name="query_database",
            description="사내 데이터베이스에 SQL 쿼리를 실행합니다. SELECT만 허용.",
            inputSchema={
                "type": "object",
                "properties": {
                    "sql": {"type": "string", "description": "SQL SELECT 쿼리"},
                    "database": {
                        "type": "string",
                        "enum": ["analytics", "production"],
                        "description": "대상 데이터베이스"
                    }
                },
                "required": ["sql", "database"]
            }
        ),
        Tool(
            name="search_docs",
            description="사내 기술 문서를 검색합니다.",
            inputSchema={
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "검색 질의"}
                },
                "required": ["query"]
            }
        )
    ]
 
# 도구 실행
@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "query_database":
        result = execute_sql(arguments["sql"], arguments["database"])
        return [TextContent(type="text", text=str(result))]
    
    elif name == "search_docs":
        results = search_vector_db(arguments["query"])
        return [TextContent(type="text", text=format_results(results))]
    
    raise ValueError(f"Unknown tool: {name}")
 
# 서버 실행
async def main():
    async with mcp.server.stdio.stdio_server() as (read, write):
        await server.run(read, write, server.create_initialization_options())
 
import asyncio
asyncio.run(main())

TypeScript로 MCP 서버 만들기

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
 
const server = new McpServer({
  name: "data-dynamics-tools",
  version: "1.0.0"
});
 
// 도구 등록
server.tool(
  "query_database",
  "사내 데이터베이스에 SQL 쿼리를 실행합니다.",
  {
    sql: z.string().describe("SQL SELECT 쿼리"),
    database: z.enum(["analytics", "production"])
  },
  async ({ sql, database }) => {
    const result = await executeSQL(sql, database);
    return { content: [{ type: "text", text: JSON.stringify(result) }] };
  }
);
 
// 리소스 등록
server.resource(
  "schema://analytics",
  "analytics 데이터베이스의 스키마 정보",
  async () => ({
    contents: [{
      uri: "schema://analytics",
      text: await getSchemaInfo("analytics"),
      mimeType: "text/plain"
    }]
  })
);
 
// 서버 시작
const transport = new StdioServerTransport();
await server.connect(transport);

4. MCP 클라이언트 설정

Claude Desktop 설정

// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
  "mcpServers": {
    "data-dynamics-db": {
      "command": "python",
      "args": ["./mcp_servers/db_server.py"],
      "env": {
        "DB_HOST": "localhost",
        "DB_PORT": "5432"
      }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "ghp_xxxx"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
    }
  }
}

Claude Code 설정

// .claude/settings.json 또는 프로젝트 루트
{
  "mcpServers": {
    "database": {
      "command": "python",
      "args": ["./tools/db_mcp_server.py"]
    }
  }
}

5. 주요 MCP 서버 생태계

공식 MCP 서버

서버제공 도구용도
filesystem파일 읽기/쓰기/검색로컬 파일 시스템 접근
github이슈, PR, 리포 관리GitHub 연동
slack메시지 전송/검색Slack 연동
postgresSQL 쿼리 실행PostgreSQL 연동
sqliteSQL 쿼리 실행SQLite 연동
puppeteer웹 스크래핑/자동화브라우저 제어
memory지식 그래프 관리장기 기억
brave-search웹 검색Brave 검색 엔진
google-maps지도/장소 검색Google Maps API

커뮤니티 MCP 서버

서버제공 도구용도
jira이슈 관리Jira 연동
confluence문서 검색/편집Confluence 연동
docker컨테이너 관리Docker 연동
kubernetes클러스터 관리K8s 연동
grafana대시보드/메트릭모니터링
elasticsearch로그/데이터 검색ELK 스택 연동

6. 실전 활용 사례

데이터 엔지니어링 MCP 서버

# Spark 작업 관리 MCP 서버
@server.list_tools()
async def list_tools():
    return [
        Tool(name="spark_submit", description="Spark 작업을 제출합니다.", ...),
        Tool(name="spark_status", description="실행 중인 Spark 작업 상태를 조회합니다.", ...),
        Tool(name="spark_logs", description="Spark 작업 로그를 가져옵니다.", ...),
        Tool(name="hdfs_ls", description="HDFS 디렉토리를 조회합니다.", ...),
        Tool(name="hive_query", description="Hive 쿼리를 실행합니다.", ...),
    ]

활용 시나리오:

사용자: "어제 실행한 야간 배치 작업이 실패했어. 로그를 확인하고 원인을 분석해줘."

Claude (MCP 사용):
1. spark_status() → 실패한 작업 ID 확인
2. spark_logs(job_id) → 에러 로그 수집
3. 로그 분석 → OOM 에러 진단
4. 해결 방안 제시 (설정 변경 추천)

DevOps MCP 서버

사용자: "프로덕션 서버의 CPU가 90% 이상이야. 원인을 찾아줘."

Claude (MCP 사용):
1. grafana.query_metrics("cpu_usage", "prod-*") → 메트릭 수집
2. kubernetes.get_pods("production") → 파드 상태 확인
3. elasticsearch.search_logs("error", "last_1h") → 최근 에러 로그
4. 종합 분석 → 특정 파드의 메모리 누수 진단
5. slack.send_message("#ops", "장애 분석 보고서") → 팀에 공유

7. 보안 고려사항

MCP 보안 원칙

원칙설명구현
최소 권한필요한 권한만 부여도구별 세밀한 권한 설정
입력 검증도구 입력값 검증스키마 검증 + 비즈니스 규칙
감사 로깅모든 도구 호출 기록호출자, 입력, 결과 로깅
네트워크 격리서버 접근 범위 제한로컬/VPN만 허용
비밀 관리인증 정보 안전 관리환경 변수, 비밀 관리자

안전한 MCP 서버 구현

# 보안이 강화된 MCP 서버
@server.call_tool()
async def call_tool(name: str, arguments: dict):
    # 1. 입력 검증
    if name == "query_database":
        sql = arguments["sql"].strip().upper()
        if not sql.startswith("SELECT"):
            raise ValueError("SELECT 쿼리만 허용됩니다.")
        
        dangerous_keywords = ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "TRUNCATE"]
        for keyword in dangerous_keywords:
            if keyword in sql:
                raise ValueError(f"위험한 키워드 감지: {keyword}")
    
    # 2. 실행
    result = await execute_tool(name, arguments)
    
    # 3. 감사 로그
    audit_log.info(f"Tool: {name}, Args: {arguments}, Result: {len(str(result))} chars")
    
    return result

참고: MCP 서버는 AI 모델에 실제 시스템 접근 권한을 부여하므로, 보안 설계가 매우 중요합니다. 프로덕션 배포 전에 반드시 보안 검토를 수행하세요.


8. MCP의 미래

발전 방향

방향설명현재 상태
원격 MCP 서버HTTP/SSE 기반 원격 서버 지원지원 (Streamable HTTP)
인증 표준화OAuth 2.0 기반 인증 흐름진행 중
서버 마켓플레이스MCP 서버 검색/설치 허브초기 단계
멀티 모델 지원Claude 외 다른 모델도 MCP 지원확대 중
엔터프라이즈 관리중앙 집중식 서버 관리/모니터링개발 중

References


— Data Dynamics 엔지니어링 팀