우와한 개발자

[Spring AI] MCP(Model Context Protocol)란? 구조와JSON-RPC 2.0 통신

by 우와한개발자

1. MCP(Model Context Protocol)

  • LLM을 활용하는 AI 애플리케이션이 외부 도구·데이터·서비스와 표준화된 방식으로 통신하기 위한 오픈 프로토콜
  • Anthropic이 2024년 공개했으며, 한마디로 "AI를 위한 USB-C 포트" — 어떤 AI든 MCP 하나로 어떤 도구와도 연결

 

1) 등장 배경

구분 내용
이전 문제 LLM마다 외부 도구 연결 방식이 제각각 (OpenAI Function Calling, LangChain Tool 등)
N×M 문제 N개의 AI 플랫폼 × M개의 외부 도구(파일, DB, API 등) = N×M개의 커스텀 연동 코드 필요. 도구 스펙이 바뀌면 연동된 모든 AI 플랫폼 코드를 수정해야 함
MCP 해결 외부 도구를 MCP 서버로 한 번만 구현하면 MCP를 지원하는 모든 AI에서 재사용 가능
결과 N×M → N+M으로 연동 비용 절감. AI가 늘어나도, 도구가 늘어나도 각각 MCP만 구현하면 끝

 

2) MCP의 관심사 분리

  • MCP가 기존과 다른 핵심은 AI 시스템에서 뒤섞여 있던 역할을 세 가지로 명확하게 분리한 것이다.
개념 역할 예시
Model 생성만 담당. 주어진 컨텍스트를 바탕으로 텍스트 생성 GPT, Claude, Llama
Context 모델이 답변 생성 시 참고하는 모든 정보 질문, 대화 히스토리, 파일 내용, DB 조회 결과
Context Provider 컨텍스트를 생성·조회·관리하는 시스템 요소. MCP Server가 바로 이 역할 파일 읽기, DB 조회, 외부 API 호출

 

2. MCP 전체 구조

  • MCP는 Host, MCP Client, MCP Server 세 요소로 구성
  • Host와 Server가 직접 통신하는 게 아니라 Host 안의 MCP Client가 Server와 통신하는 구조
[Host (Cursor, Claude Desktop)]
        │
   [MCP Client]         ← Host 안에 내장된 통신 모듈
        │
        │  JSON-RPC 2.0 (STDIO or SSE)
        │
   [MCP Server]         ← 직접 만들거나 공식 서버 사용
        │
[외부 시스템 (파일, DB, API 등)]

 

1) Host / Client / Server

요소 역할 예시
Host 사용자가 직접 사용하는 AI 클라이언트 애플리케이션 전체 Cursor, Claude Desktop, Claude Code
MCP Client Host 내부에 내장된 MCP 통신 전담 모듈. Server와 1:1 연결 관리 Host 내부 컴포넌트
MCP Server 외부 도구·데이터를 MCP 표준으로 포장해서 노출하는 서버 파일시스템 서버, DB 서버

 

2) 세 요소의 관계

  • Host → 사용자 질문을 LLM에 전달하고, MCP Client를 통해 서버와 통신
  • MCP Client → JSON-RPC 2.0 형식으로 메시지를 만들어 서버에 전달하고 응답을 LLM에 전달
  • MCP Server → Tool 실행, 데이터 조회 등 실제 작업을 처리하고 결과 반환

 

3. JSON-RPC 2.0

1) 개념

  • HTTP, WebSocket 등 전송 계층 위에서 동작하는 경량 원격 호출(RPC) 프로토콜
  • 요청과 응답을 JSON 형식으로 표현한다.(사람이 읽기 쉽고 디버깅 용이)
  • MCP의 모든 통신은 JSON-RPC 2.0 규격을 기반으로 동작한다.
[MCP Client] ──── JSON-RPC 2.0 메시지 ────→ [MCP Server]
                  {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "tools/call",  ← MCP 명령어
                    "params": { ... }
                  }

 

2) 메시지 종류

(1) Request (요청)

  • Client → Server, 반드시 응답을 기대하는 메시지
  • id 필드가 있어야 Request로 인식
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "readFile",
    "arguments": { "filePath": "src/main/Application.java" }
  }
}

 

(2) Response (응답)

  • Server → Client, Request에 대한 결과 반환
  • id는 대응되는 Request의 id와 반드시 동일
  • 성공이면 result, 실패면 error (둘 중 하나만 존재)
// 성공
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{ "type": "text", "text": "파일 내용..." }]
  }
}

// 실패
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "filePath 파라미터가 누락되었습니다."
  }
}
  • 주요 에러 코드
에러 코드 의미
-32700 Parse error — JSON 파싱 실패
-32600 Invalid Request — 잘못된 요청 구조
-32601 Method not found — 존재하지 않는 메서드
-32602 Invalid params — 잘못된 파라미터
-32603 Internal error — 서버 내부 오류

 

(3) Notification (알림)

  • 응답을 기대하지 않는 단방향 메시지
  • id 필드가 없는 것이 Request와의 차이가 있다.
{
  "jsonrpc": "2.0",
  "method": "notifications/progress",
  "params": { "progressToken": "abc123", "progress": 50, "total": 100 }
}

 

3) 메서드 종류 — domain/operation 규칙

  • MCP 메서드는 <domain>/<operation> 형식의 네이밍 규칙을 따른다.
  • 알림(Notification)은 notifications/<domain>/<operation> 형태
  • domain은 작업의 범위, operation은 구체적인 작업을 나타낸다.
도메인 메서드 설명
Roots roots/list 클라이언트가 서버로부터 접근 가능한 루트(파일 시스템 경로) 목록 요청
- notifications/roots/list_changed 루트 목록이 변경되었음을 알리는 알림
Sampling sampling/requestCompletion MCP 서버가 클라이언트(LLM)에게 텍스트 완성(completion)을 요청
Elicitation elicitation/create 서버가 사용자 입력이나 확인을 요청하는 상호작용 생성
- notifications/elicitation/responded 사용자가 elicitation 요청에 응답했을 때 서버에 알림
Resources resources/list 서버가 제공하는 리소스 목록(문서, 파일 등) 조회
- resources/read 특정 리소스 내용 읽기
- resources/subscribe 특정 리소스의 변경 사항 구독
- notifications/resources/list_changed 리소스 목록이 변경되었을 때 알림
- notifications/resources/updated 구독 중인 리소스가 변경되었을 때 알림
Prompts prompts/list 사용 가능한 프롬프트 템플릿 목록 조회
- prompts/get 특정 프롬프트 템플릿 조회
- notifications/prompts/list_changed 프롬프트 목록 변경 알림
Tools tools/list MCP 서버가 제공하는 툴 목록 요청
- tools/call 특정 툴 실행 요청
- notifications/tools/list_changed 툴 목록이 변경되었음을 알림
Completion completion/complete 사용자가 입력 중인 인자나 참조값에 대한 자동완성 제안 반환
Notifications notifications/<domain>/list_changed 특정 도메인(resources, tools, prompts)의 목록이 변경됨을 알림
(공통) notifications/<domain>/updated 특정 도메인의 항목이 업데이트됨을 알림

 

4) 통신 흐름

(1) 연결 시점 — initialize

  • MCP 클라이언트(Cursor, Claude Desktop 등)가 MCP 서버에 연결하면 아래 메서드들이 순서대로 자동 호출된다
Client                              Server
  │──── initialize ────────────────→ │  프로토콜 버전, 클라이언트 정보 전달
  │←─── initialize result ────────── │  서버 정보, 보유 기능 목록 반환
  │──── notifications/initialized ─→ │  초기화 완료 알림 (Notification)
  │──── tools/list ────────────────→ │  Tool 목록 요청
  │←─── tools/list result ────────── │  Tool 목록 + description 전체 반환

 

(2) 질문 시점 — tools/call까지

  • 사용자가 질문하면 LLM이 판단해서 자동으로 Tool을 호출하는 흐름이다.
사용자: "src 폴더에 Java 파일 몇 개야?"
  ↓
LLM이 연결 시점에 받아둔 Tool 목록(description)과 대조
  ├── readFile    → ❌
  ├── searchFiles → ✅
  └── writeFile   → ❌
  ↓
Client ──── tools/call ──────────────→ Server
            {
              "method": "tools/call",
              "params": {
                "name": "searchFiles",
                "arguments": { "dirPath": "src", "pattern": "*.java" }
              }
            }
  ↓
Server ──── result ──────────────────→ Client
            { "content": [{ "text": "23개" }] }
  ↓
LLM: "src 폴더에 Java 파일은 총 23개 있습니다."
  • LLM이 Tool을 자동으로 선택하고 호출 — 개발자가 직접 호출 코드 작성 불필요
  • 선택 기준은 Tool의 description — description이 명확할수록 정확한 Tool 선택한다.
  • Cursor 설정에 따라 실행 전 사용자 승인을 묻는 경우도 있다.

블로그의 정보

우와한개발자 님의 블로그

우와한개발자

활동하기