본문 바로가기

AI/MCP

[MCP] MCP에서 JSON-RPC를 채택한 이유

제가 공부한 내용을 정리하는 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁

 

서론

앞서 JSON과 JSON-RPC, MCP에서 JSON-RPC를 어떻게 사용하는지를 살펴보았다.

https://dev-hiro.tistory.com/200

 

[MCP] MCP를 이해하기 위한 JSON과 JSON-RPC 2.0 차이

제가 공부한 내용을 정리하는 블로그입니다. 아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁 서론다른 프로젝트에서나 회

dev-hiro.tistory.com

그런데 왜 MCP는 JSON-RPC 2.0을 선택하고, 설계되었는지에 대한 더 자세한 답변을 확인해보려고 한다.

 

왜 MCP는 JSON-RPC를 선택했을까?

MCP가 해결하려는 문제는 무엇일까?를 먼저 고민해보자.

 

MCP Client와 Server 사이에서는 단순히 데이터를 전달하는 것뿐만 아니라 특정 동작을 요청하고, 그 결과를 돌려받고, 때로는 응답이 필요 없는 이벤트를 전달해야 한다.

예를 들어 MCP에서는 다음과 같은 상호작용이 발생한다.

Client
   │
   ├── 사용 가능한 Tool 목록을 알려줘
   │
   ├── 이 Tool을 실행해줘
   │
   ├── 이 Resource를 읽어줘
   │
   └── 이 Prompt를 가져와줘
   │
   ▼
Server

MCP는 단순히 특정 비즈니스 로직을 처리하기 보다, 어떠한 동작을 호출하는 것에 더욱 초점이 맞춰져있는 동작방식이다.
이는 단순한 데이터 전송(Data Transfer)을 통한 비즈니스 로직보다는 원격 동작 호출(Remote Procedure Call)에 더욱 가깝다.

 

JSON은 필드가 규정되어있지 않아, 각 서버마다 통일이 되어있지 않을 수 있고, 별도의 동작을 지정해야 하지만, 
JSON-RPC 2.0은 이러한 통신 규약이 이미 지정이 되어있어, 각 서버마다 모두 동일하다.

예를 들어

method  → 무엇을 호출할 것인가
params  → 어떤 값을 전달할 것인가
id      → 어떤 요청과 응답이 연결되는가
result  → 성공 결과
error   → 실패 결과

따라서 MCP는 이 기본적인 RPC 메시지 구조 위에서 MCP가 실제로 필요로 하는 메서드와 데이터 구조를 정의하는 데 집중할 수 있다.

 

비동기적인 통신

MCP에서는 동시에 여러 요청이 처리될 수 있다.

예를 들어 Client가 다음 요청들을 보냈다고 생각해보자.

id = 1 → tools/list
id = 2 → resources/list
id = 3 → prompts/list

응답이 반드시 요청 순서대로 처리된다고 가정해서는 안 된다.

예를 들어 처리 시간에 따라

id = 2 응답
id = 1 응답
id = 3 응답

순으로 결과가 도착할 수도 있다.

JSON-RPC에서는 id가 이 문제를 해결한다.

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {}
}

Client는 이 응답이

id = 3

이므로 자신이 보냈던 id = 3 요청에 대한 결과라는 것을 알 수 있다.

즉 id는 비동기적으로 여러 요청이 오가는 환경에서 Request와 Response를 correlation하는 역할을 한다.

 

Notification의 존재.

JSON 통신은 항상 응답 메시지가 필요하다. 기존 HTTP 통신은 Request가 있으면 Response를 줘야하기 때문이다.

 

하지만 모든 메시지에는 응답이 필요한 것은 아니다.

MCP에서는 상대방에게 어떤 상태 변화나 이벤트를 알려주기만 하면 되는 경우가 있다.

 

이러한 상황에서 매번 Request <-> Response를 수행하면 불필요한 통신이 발생한다.

 

JSON-RPC 2.0에는 이를 위한 Notification이 이미 정의되어 있다.

Notification은 Request와 비슷하지만 id가 없다.

{
  "jsonrpc": "2.0",
  "method": "notifications/...",
  "params": {}
}

id가 없기 때문에 수신자는 Response를 반환하지 않는다.

즉 JSON-RPC 하나만으로

응답이 필요한 통신
Request → Response

응답이 필요 없는 통신
Notification →

두 패턴을 모두 표현할 수 있다.

MCP의 이벤트성 메시지와도 잘 맞는 구조다.

 

Transport Agnostic

JSON-RPC 2.0의 중요한 특징 중 하나는 Transport Agnostic하다는 것이다.

즉 JSON-RPC는

이 메시지를 반드시 HTTP로 보내야 한다.

와 같이 특정 전송 방법을 강제하지 않는다.

JSON-RPC는 메시지 구조를 정의할 뿐이다.

{
    jsonrpc,
    id,
    method,
    params
}

이 메시지를 실제로 어떻게 전달할지는 별도의 문제다.

이 특성은 MCP와 특히 잘 맞는다.

MCP에서도 Protocol과 Transport가 분리되어 있기 때문이다.

              MCP
               │
       Protocol Message
               │
         JSON-RPC 2.0
               │
        ┌──────┴──────┐
        │             │
      stdio     Streamable HTTP

예를 들어 로컬 MCP Server는 stdio를 통해 메시지를 전달할 수 있고, Remote MCP Server는 Streamable HTTP를 사용할 수 있다.

하지만 Transport가 달라져도 MCP의 핵심 메시지 모델을 완전히 새로 만들 필요는 없다.

stdio
   │
   └── JSON-RPC Message

Streamable HTTP
   │
   └── JSON-RPC Message

즉

무엇을 말할 것인가와 어떻게 전달할 것인가를 분리할 수 있다.

이는 MCP처럼 로컬 프로세스와 원격 서버를 모두 고려해야 하는 프로토콜에서 중요한 특성이다.

 

REST API와 차이점은?

물론 기술적으로 MCP와 비슷한 시스템을 REST API로 구현하는 것도 가능하다.

하지만 추상화 방식이 다르다.

REST에서는 일반적으로 Resource와 HTTP Method를 중심으로 API를 표현한다.

GET    /tools
POST   /tools/get_weather
GET    /resources/123

반면 JSON-RPC는 Method 호출을 중심으로 표현한다.

tools/list
tools/call
resources/read
prompts/get

예를 들어 JSON-RPC에서는 여러 종류의 동작이 동일한 메시지 구조를 사용한다.

{
  "jsonrpc": "2.0",
  "id": 10,
  "method": "...",
  "params": {}
}

MCP 입장에서는 각 기능마다 새로운 URL이나 HTTP Method 의미를 설계하기보다 하나의 일관된 메시지 모델 안에서 메서드를 확장할 수 있다.

더 중요한 차이는 MCP가 HTTP 자체에 종속되지 않는다는 점이다.

REST 스타일을 중심으로 설계했다면 HTTP의 URL, Method, Status Code 등의 개념과 강하게 결합될 가능성이 높다.

반면 JSON-RPC를 사용하면

MCP Protocol

       ↓

JSON-RPC Message

       ↓

Transport

라는 계층 분리가 가능하다.

따라서 MCP는 동일한 프로토콜 모델을 로컬 stdio 환경과 네트워크 기반 환경 모두에서 사용할 수 있다.

 

요약

따라서 요약하자면

MCP가 JSON-RPC 2.0을 채택한 이유는 MCP의 통신 구조가 단순한 데이터 전달이 아니라 Client와 Server가 서로 기능을 요청하고 결과를 반환하는 RPC 구조이기 때문이다.

  • RPC 모델과 잘 맞음 — tools/list, tools/call, resources/read처럼 MCP의 주요 동작은 사실상 원격 메서드 호출이다.
  • 표준화된 메시지 구조 — method, params, id, result, error가 이미 정의되어 있어 MCP가 요청·응답 규칙을 새로 설계할 필요가 없다.
  • 비동기 요청 처리에 적합 — id를 통해 여러 요청이 동시에 처리되더라도 각각의 Request와 Response를 정확히 연결할 수 있다.
  • Notification 지원 — 응답이 필요 없는 이벤트나 상태 변경은 id 없는 Notification으로 처리할 수 있다.
  • 표준 Error 모델 제공 — 잘못된 요청, 존재하지 않는 Method, 잘못된 Parameter 등의 오류 표현 방식이 이미 정의되어 있다.
  • Transport와 독립적 — JSON-RPC는 메시지 규칙만 정의하므로 MCP가 stdio, Streamable HTTP 등 서로 다른 Transport 위에서 동일한 프로토콜 구조를 사용할 수 있다.
  • 가볍고 구현하기 쉬움 — JSON 기반이라 대부분의 언어에서 별도 복잡한 직렬화 과정 없이 쉽게 처리할 수 있다.
  • 디버깅이 쉬움 — 바이너리가 아니라 사람이 읽을 수 있는 JSON이므로 실제 MCP 통신 메시지를 직접 확인하기 쉽다.

MCP는 Client와 Server 사이의 상호작용이 원격 메서드 호출 구조와 잘 맞고, JSON-RPC 2.0이 Request/Response, Notification, Error, 요청 식별 등의 RPC 기본 기능을 가볍고 Transport 독립적인 형태로 이미 제공하기 때문에 이를 기반 메시지 프로토콜로 사용한다.

“MCP는 AI 연결 규칙에 집중하고, RPC 통신의 기본 규칙은 JSON-RPC 2.0에 맡긴다.” 정도로 요약할 수 있을 것이다.