JSON-RPC 2.0 이해하기 - 요청, 알림, 응답을 id로 연결하는 법
JSON-RPC 2.0은 원격 함수를 호출하는 메시지를 JSON 객체로 표현하는 규약이다. 요청과 응답의 모양은 정하지만, 그 JSON을 HTTP로 보낼지 표준입출력으로 보낼지는 정하지 않는다.

MCP처럼 JSON-RPC를 사용하는 프로토콜을 읽을 때도 메시지 규약과 전송 방식을 분리해야 한다. 먼저 JSON-RPC 자체의 네 가지 메시지부터 살펴본다.
네 가지 메시지 형태
모든 메시지는 "jsonrpc": "2.0"을 포함한다. 나머지 필드 조합으로 역할이 갈린다.
| 형태 | method |
id |
result |
error |
응답 |
|---|---|---|---|---|---|
| 요청 | 있음 | 있음 | 없음 | 없음 | 필요 |
| 알림 | 있음 | 없음 | 없음 | 없음 | 금지 |
| 성공 응답 | 없음 | 있음 | 있음 | 없음 | 요청에 대한 결과 |
| 에러 응답 | 없음 | 있음 | 없음 | 있음 | 요청에 대한 실패 |
요청과 성공 응답
{"jsonrpc":"2.0","method":"subtract","params":{"minuend":42,"subtrahend":23},"id":1}
수신자가 메서드를 실행하면 요청의 id를 그대로 담아 결과를 보낸다.
{"jsonrpc":"2.0","result":19,"id":1}
알림
알림은 요청에서 id만 빠진 형태다.
{"jsonrpc":"2.0","method":"update","params":{"status":"ready"}}
수신자는 처리에 성공해도, 실패해도 응답하지 않는다. 결과 확인이 필요 없는 상태 통지에만 사용해야 한다.
에러 응답
실패 응답은 result 대신 error를 쓴다. 두 필드는 한 응답에 함께 올 수 없다.
{
"jsonrpc": "2.0",
"error": {
"code": -32601,
"message": "Method not found"
},
"id": 1
}
params는 배열과 객체를 모두 허용한다
일반 JSON-RPC 2.0은 위치 인자 배열과 이름 인자 객체를 모두 허용한다.
{"jsonrpc":"2.0","method":"subtract","params":[42,23],"id":1}
{"jsonrpc":"2.0","method":"subtract","params":{"minuend":42,"subtrahend":23},"id":2}
배열은 순서가 계약이고 객체는 키 이름이 계약이다. JSON-RPC를 채택한 상위 프로토콜은 둘 중 하나만 허용할 수 있다. MCP는 객체 형태만 사용한다.
동시에 보낸 요청은 id로 구분한다
응답은 요청한 순서대로 돌아온다는 보장이 없다.
보냄 id=1 ────────────────┐
보냄 id=2 ───────┐ │
받음 id=2 ◀──────┘ │
받음 id=1 ◀───────────────┘
id는 요청자가 정하고 응답자는 값을 바꾸지 않고 돌려준다. 일반 명세는 문자열, 숫자, null을 허용하지만 null과 소수 숫자는 피하는 편이 안전하다.
응답은 값뿐 아니라 JSON 타입도 같아야 한다. 숫자 2를 문자열 "2"로 바꾸어 돌려주면 서로 다른 식별자다.
표준 에러 코드
error 객체에는 정수 code, 짧은 message, 선택적인 data가 들어간다.
| 코드 | 이름 | 의미 |
|---|---|---|
-32700 |
Parse error | JSON 파싱 실패 |
-32600 |
Invalid Request | 요청 객체 형식 오류 |
-32601 |
Method not found | 메서드가 없음 |
-32602 |
Invalid params | 인자 오류 |
-32603 |
Internal error | 수신자 내부 오류 |
-32000~-32099 |
Server error | 구현이 세분화할 수 있는 예약 범위 |
요청의 id를 알아낼 수 없는 파싱 실패는 id: null로 응답한다.
{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}
배치 요청
일반 JSON-RPC 2.0은 여러 요청과 알림을 배열에 묶을 수 있다.
[
{"jsonrpc":"2.0","method":"sum","params":[1,2],"id":1},
{"jsonrpc":"2.0","method":"notify","params":[7]},
{"jsonrpc":"2.0","method":"get","id":2}
]
응답도 배열이지만 알림에 해당하는 항목은 생기지 않는다. 처리와 응답 순서가 달라질 수 있으므로 배치 안에서도 id로 짝을 맞춘다.
배치는 왕복 횟수를 줄이는 대신 부분 실패와 병렬 처리 규칙이 복잡해진다. JSON-RPC를 쓰는 상위 프로토콜이 배치를 지원하지 않는 경우도 있다.
JSON-RPC와 MCP를 구분해서 읽기
MCP는 JSON-RPC 2.0의 메시지 형태를 사용하지만 허용 범위를 좁힌다.
| 항목 | JSON-RPC 2.0 | MCP 2026-07-28 |
|---|---|---|
params |
배열 또는 객체 | 객체만 |
요청 id |
문자열, 숫자, null |
문자열 또는 숫자 |
| 배치 | 허용 | 미지원 |
| 메타데이터 | 별도 규정 없음 | params._meta 사용 |
| 완료 상태 | 메서드별 결과 구조 | resultType으로 상태 구분 |
따라서 JSON-RPC 명세에 존재하는 기능이 MCP에서도 그대로 지원된다고 가정하면 안 된다. 다음 글에서는 이 메시지가 실제 MCP의 stdio와 Streamable HTTP에서 어떻게 오가는지 이어서 살펴본다.
댓글남기기