JSON-RPC
JSON-RPC is a stateless, lightweight remote procedure call (RPC) protocol that uses JSON (as defined in RFC 4627) as its data interchange format.[1] It enables clients to invoke procedures on remote servers by sending structured requests and receiving corresponding responses, emphasizing simplicity and independence from specific transport mechanisms such as HTTP, WebSockets, or TCP sockets.[1]
The protocol's core data structures include request objects, which specify a version ("2.0"), a method name, optional parameters (as an array for positional arguments or an object for named arguments), and an identifier for matching responses; response objects mirror the identifier and contain either a result or an error with standardized codes.[1] Notifications are requests without an identifier, eliciting no response, while batch calls allow multiple requests in an array for efficient processing.[1] All member names are case-sensitive, and predefined error codes range from -32768 to -32000, with methods prefixed by "rpc." reserved for extensions.[1]
JSON-RPC 2.0, the current specification, originated on March 26, 2010 (based on a May 24, 2009 draft) and was last updated on January 4, 2013, by the JSON-RPC Working Group via a Google Group discussion.[1] It is not backward-compatible with earlier versions, such as JSON-RPC 1.0 released in 2005, which lacked features like named parameters and batch support; compatibility is enforced by the mandatory "jsonrpc": "2.0" field.[1][2]
In practice, JSON-RPC facilitates interoperability in networked applications, most notably serving as the primary API for Ethereum execution clients to query and interact with the blockchain, supporting methods for account balances, transaction submission, and block data retrieval over HTTP or WebSockets. Its transport-agnostic design has also made it popular in other domains, including software development tools and distributed systems requiring minimal overhead for client-server communication.[1]
Overview
Definition and Purpose
JSON-RPC is a stateless, lightweight remote procedure call (RPC) protocol that enables clients to invoke methods on remote servers by encoding requests and responses in JSON format.[1] It operates independently for each request, without maintaining session state, which simplifies implementation and reduces overhead in distributed systems.[1] The protocol relies on JSON as defined in RFC 4627, leveraging its simple data types—such as objects, arrays, strings, numbers, booleans, and null—for serialization, ensuring compatibility across diverse programming languages and platforms.
The primary purpose of JSON-RPC is to facilitate straightforward inter-network communication between clients and servers, allowing the invocation of server-side methods with parameters and the return of corresponding values or errors.[1] This design supports efficient remote execution of procedures over various transports, including HTTP, WebSockets, or even intra-process calls, without tying the protocol to a specific underlying mechanism.[1] By focusing on essential RPC semantics—method name, parameters, and result—JSON-RPC streamlines development for applications requiring distributed function calls, such as in web services, blockchain nodes, and API integrations.[1]
JSON-RPC is explicitly designed to require minimal development effort for achieving interoperability between heterogeneous systems, promoting ease of adoption in multi-language ecosystems.[1]
Key Features
JSON-RPC operates in a stateless manner, where each request is independent and does not rely on maintaining session state between calls, enabling scalable and simple implementations across distributed systems.[1] This design contrasts with stateful protocols by treating every invocation as a self-contained unit, reducing complexity in client-server interactions.
The protocol's lightweight nature is evident in its minimal data structures, which consist primarily of a method name, optional parameters, a unique identifier for requests, and either a result or error in responses, all encapsulated within a JSON envelope.[1] This parsimony minimizes overhead, making JSON-RPC suitable for resource-constrained environments while supporting efficient one-way notifications—requests without an identifier that elicit no response—and batch requests that allow multiple method calls in a single transmission to optimize network usage.[1]
JSON-RPC is transport-agnostic, functioning over diverse channels such as HTTP, WebSockets, or TCP without protocol-specific modifications, which provides deployment flexibility in various architectures from web applications to real-time systems.[1] Its reliance on JSON as the data interchange format ensures human-readability, facilitating easier debugging, logging, and integration with tools that parse structured text.[1] For error handling, the specification defines predefined error codes such as -32700 for parse errors (invalid JSON) and -32601 for method not found, with the range -32000 to -32099 reserved for implementation-defined server errors.[1]
Protocol Specification
Version 2.0
JSON-RPC 2.0, published initially on May 24, 2009, and revised on March 26, 2010, and January 4, 2013, by the JSON-RPC Working Group, serves as the current de facto standard for the protocol.[1] This version establishes a stateless, lightweight remote procedure call (RPC) framework using JSON for encoding, emphasizing simplicity and transport-agnostic design while introducing formalized rules for interoperability.[1]
A valid JSON-RPC 2.0 request object must include the mandatory members jsonrpc set to the string "2.0", method as a non-empty string specifying the invoked procedure (with names being case-sensitive and reserving the "rpc." prefix for protocol extensions), and id as a JSON number, string, or null value to identify the request.[1] The params member is optional and, if present, must be a structured JSON value—either an array for positional parameters or an object for named parameters—allowing flexibility in argument passing without enforcing a single style.[1] For notifications, which do not expect a response, the id member is omitted, ensuring no reply is generated.[1]
Responses in JSON-RPC 2.0 require the jsonrpc member as "2.0" and must echo the id from the corresponding request (or null if the request lacked one or was invalid).[1] Exactly one of result (a structured value on success) or error (an object on failure, containing a numeric code, string message, and optional data) must be present, but never both, to clearly delineate outcomes.[1] Batch calls, sent as an array of request objects, are processed by the server potentially concurrently and in any order, with the response array containing corresponding objects matched by id, excluding any for notifications to avoid unnecessary output.[1] Error handling follows standard codes such as -32700 for parse errors, with custom extensions possible via the data field.[1]
Earlier Versions
JSON-RPC 1.0, released in 2005, established the foundational structure for the protocol as a lightweight remote procedure call mechanism using JSON objects for serialization.[2] It required requests to include a method name as a string and parameters strictly as a JSON array for positional arguments only, with no support for named parameters.[2] Notifications were handled by setting the request ID to null, indicating no response was expected, while responses included a result or a structured error object or null, with less standardized error handling than later versions.[2] Batching of multiple calls in a single message was not supported, and the protocol assumed a peer-to-peer model without transport-specific bindings.[2]
The JSON-RPC 1.1 Working Draft, published on August 7, 2006, introduced enhancements to address limitations in 1.0 while remaining an informal draft that sought community feedback but was never finalized.[3] Key additions included support for named parameters by allowing the params field to be a JSON object, enabling more flexible argument passing alongside positional arrays.[3] It specified HTTP bindings, permitting POST for general requests and GET for safe, idempotent procedures, and defined preliminary error codes in the range 100-999 for issues like procedure not found, though these were tentative.[3] Introspection was mandated via a system.describe method to return service descriptions, but notifications still relied on a null ID, differing from some later proposals.[3]
In 2007, the JSON-RPC 1.2 Proposal, dated December 27, aimed to refine the protocol further but remained an unformalized suggestion without widespread adoption.[4] It shifted to a strict client-server architecture from the peer-to-peer model of 1.0, emphasized transport independence, and added optional named parameters with support for default values.[4] Error handling was improved with defined codes from -32768 to -32000, and system extensions like method listing were proposed, though the version field remained optional for backward compatibility.[4]
Variants such as the 1.1 Alt specification (May 6, 2007) and the 1.1 Object Specification sought to bridge gaps between drafts by incorporating named parameters via "kwparams" or object-based params, while introducing multicall support and bi-directional communication through dual client-server setups to enable peer-to-peer-like interactions.[5][6] These variants, however, saw limited adoption due to their non-standard status and the emerging focus on version 2.0.[5][6]
Early versions like 1.0 lacked the batching and predefined error codes of the modern 2.0 standard.[2] Many contemporary implementations maintain backward compatibility with 1.0 to support legacy systems in early web services and embedded applications.[6]
Requests and Notifications
In JSON-RPC 2.0, a request is a JSON object transmitted from a client to a server to invoke a remote method. It consists of four mandatory or optional members: "jsonrpc", which must be the string "2.0"; "method", a string specifying the name of the method to be invoked and which must not begin with "rpc."; "params", an optional structured value representing the parameters passed to the method; and "id", an identifier (either a string, a number without fractional parts, or null, though null is discouraged) used to correlate the request with its corresponding response.[1]
The "params" member supports two styles of parameter passing. In positional notation, parameters are provided as an ordered array of JSON values, corresponding to the method's expected argument sequence; for example, a request to subtract 23 from 42 might use {"jsonrpc": "2.0", "id": 1, "method": "subtract", "params": [42, 23]}.[1] In named notation, parameters are supplied as a JSON object with case-sensitive keys matching the method's named arguments, allowing unordered and optional values; an example could be {"jsonrpc": "2.0", "id": 2, "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}}.[1] All values in "params" must conform to valid JSON types as defined in RFC 4627.[1]
A notification is a variant of the request object that omits the "id" member, signaling to the server that no response is expected or required.[1] Its structure is otherwise identical to a standard request, including the "jsonrpc", "method", and optional "params" members; for instance, {"jsonrpc": "2.0", "method": "[update](/page/Update)", "params": [1, 2, 3, 4, 5]} notifies the server to process an update without acknowledgment.[1] Upon receiving a notification, the server must not generate a reply, and any errors during processing provide no feedback to the client.[1]
The "id" member in requests enables precise matching of responses to their originating calls, particularly in scenarios involving multiple concurrent or batched requests; it is recommended to use sequential integers or other unique values to facilitate this correlation and avoid ambiguity.[1] If the "id" is absent (as in notifications) or invalid, the server's response—if any—must set its own "id" to null.[1]
Responses and Batch Calls
In JSON-RPC 2.0, the server responds to a request by sending a response object, which is a JSON object that includes the version identifier, the result or error, and an identifier matching the original request.[1] This structure ensures that the client can correlate the response with the corresponding request, using the id field, which must be present and identical to the request's id unless the server cannot detect it, in which case it is set to null.[1] The response object contains exactly three members: jsonrpc set to the string "2.0", either a result or an error member (but not both), and the id member.[1]
For successful responses, the result member holds the return value from the invoked method, which can be any JSON value, while the error member is absent.[1] This design allows the server to convey the outcome of the procedure execution directly within the response structure. For instance, in response to a request to subtract 23 from 42, the server might return the following success response:
json
{"jsonrpc": "[2.0](/page/2point0)", "id": 1, "result": 19}
{"jsonrpc": "[2.0](/page/2point0)", "id": 1, "result": 19}
[1] Each individual response, whether single or part of a batch, must include either a result or an error, but never both, enforcing a clear distinction between successful and failed invocations.[1]
Batch calls enable a client to send multiple requests in a single array, and the server processes them accordingly, returning an array of individual response objects, which may be in any order.[1] Notifications within a batch are excluded from the response array, as they do not elicit replies, resulting in no output for those elements.[1] Errors are handled per individual call, with the corresponding response object containing the error details instead of a result. The server may process batch requests concurrently or in any order, and the client matches the responses to the requests using the id values.[1] Importantly, if a batch consists entirely of notifications, the server sends no response array at all; similarly, the response array must never be empty unless there are no responses to send, in which case nothing is returned.[1] For an invalid batch, such as one that is not an array, the server returns a single error response object rather than an array.[1]
Error Handling
Standard Error Codes
In JSON-RPC 2.0, errors are reported using a standardized error object within responses, consisting of a required integer code that identifies the error type, a required string message providing a short description of the error, and an optional data field containing additional structured information to aid in debugging, such as stack traces or further context.[1]
The protocol defines several predefined error codes, all negative integers to distinguish them from successful results, which do not use positive codes. Codes in the range -32768 to -32000 are reserved for protocol-defined errors, ensuring consistency across implementations.[1]
The standard error codes include:
| Code | Message | Meaning |
|---|
| -32700 | Parse error | Invalid JSON was received by the server, preventing proper parsing. |
| -32600 | Invalid Request | The JSON received is not a valid request object, such as malformed syntax or missing required fields. |
| -32601 | Method not found | The requested method does not exist or is not available on the server. |
| -32602 | Invalid params | The method parameters provided are invalid, for example, due to type mismatches or incorrect values. |
| -32603 | Internal error | An internal error occurred on the server while processing the request. |
Additionally, the range -32000 to -32099 is reserved for implementation-specific server errors, allowing developers to define custom errors within this bounded space without conflicting with protocol standards.[1]
When constructing error objects, the code and message fields must always be present to ensure interoperability, while the data field should be used judiciously to provide supplementary details without altering the core protocol semantics.[1]
Custom Error Extensions
JSON-RPC implementations extend the protocol's standard error handling by defining custom error codes outside the reserved range and leveraging the optional "data" member in the error object to include application-specific details, such as validation failures or business logic exceptions.[1] The "data" member, which can hold a primitive or structured value, allows servers to provide machine-readable extensions like error context or nested details without altering the core error structure.[1]
The specification reserves error codes from -32768 to -32000 for pre-defined errors, with the subrange -32000 to -32099 allocated for implementation-defined server errors, enabling custom codes in this interval for transient issues like temporary resource unavailability while avoiding overlap with standard codes.[1]
Best practices for custom extensions emphasize concise, single-sentence error messages that remain user-friendly for human readers, while reserving the "data" field for programmatic details to support automated handling.[1] Implementations should prioritize backward compatibility by adhering to the standard error object format and avoiding modifications that could break clients expecting core protocol behavior.[1] There is no official registry for custom error codes, which can result in interoperability challenges within federated systems combining multiple vendor-specific implementations.[1]
In batch calls, custom errors are handled individually per request, ensuring that a domain-specific failure in one does not propagate to others in the array.[1]
History and Development
Origins and Initial Proposals
JSON-RPC emerged in 2005 as a lightweight alternative to XML-RPC, leveraging JSON for data serialization to address the need for simpler, more efficient protocols in developing web APIs.[7] This development was motivated by the desire to reduce the verbosity and complexity associated with XML-based formats, enabling easier integration in dynamic web applications.[2]
The initial version 1.0 specification was released in 2005 by the JSON-RPC.ORG community, with early contributions including the JSON-RPC-Java implementation proposed by Michael Clark to facilitate server-side support in Java environments.[2][7] The protocol emphasized simplicity and stateless operation, positioning it as a direct counter to the heavier SOAP standard, which was seen as overly complex for many use cases.[2]
JSON-RPC drew influence from the growing popularity of JSON, a data-interchange format discovered by Douglas Crockford in spring 2001 while working on cross-language data exchange at State Software.[8] It also built on longstanding RPC traditions, such as the Open Network Computing RPC (ONC RPC) developed by Sun Microsystems in the 1980s for distributed computing.
The 2005 release of the version 1.0 specification coincided with the burgeoning trend of AJAX-enabled web services, which popularized asynchronous browser-server communication using JavaScript and XMLHttpRequest.[7] JSON-RPC saw early adoption in JavaScript environments, particularly for facilitating direct procedure calls between browsers and servers in interactive web applications like those demonstrated in early demos supporting multiple browsers.[7]
Unlike protocols governed by formal standards bodies, JSON-RPC has remained community-driven, with ongoing development and specifications hosted at jsonrpc.org without affiliation to organizations like the IETF or W3C.[9]
Version Timeline
JSON-RPC version 1.0 was released in 2005, establishing the foundational specification for a lightweight remote procedure call protocol using JSON for serialization.[2]
In 2006, a working draft for version 1.1 was published on August 7, introducing enhancements such as named parameters, specific error codes, and introspection functions to improve interoperability and error handling.[3]
By 2007, alternative proposals for version 1.1 emerged alongside a 1.2 draft, emphasizing simplicity and minimal changes from 1.0 to address community feedback, though these efforts failed to achieve consensus and were eventually superseded.[5][4]
The initial specification for version 2.0 was released on March 26, 2010, building on a May 24, 2009 draft, with key standardizations for notifications, batch requests, and improved error reporting to resolve ambiguities in prior versions.[1]
A minor revision to the 2.0 specification occurred on January 4, 2013, providing clarifications on batch processing and response formatting without altering core mechanics.[1]
No major updates have followed since 2013, reflecting the protocol's stability amid widespread adoption, particularly in blockchain ecosystems like Ethereum, which integrated JSON-RPC as its primary API interface upon mainnet launch in July 2015.
As of 2025, JSON-RPC continues to see active use in emerging domains such as AI agent integrations via protocols like the Model Context Protocol (MCP), proposed by Anthropic in November 2024, and microservices architectures, leveraging its unchanged 2.0 standard for reliable, lightweight communication.[10][11]
Applications and Implementations
Common Use Cases
JSON-RPC is widely employed in blockchain ecosystems for interacting with distributed ledger nodes, particularly in Ethereum where it facilitates queries for account balances and transaction simulations without on-chain execution. For instance, the eth_call method allows developers to invoke smart contract functions to retrieve data such as token balances or execute read-only operations, enabling efficient off-chain analysis of blockchain states.[12] This approach is essential for decentralized applications (dApps) that need to verify transaction outcomes or fetch real-time network data, reducing the computational overhead of full node synchronization. In Polkadot's ecosystem, 2025 updates to the JSON-RPC API introduced a legacy-provider interface, which enhances interoperability by allowing seamless integration with existing tools and libraries while supporting the transition to a more structured API design.[13]
In web services and microservices architectures, JSON-RPC serves as a lightweight protocol for inter-service communication over HTTP, offering a structured alternative to REST for procedure-based calls in cloud environments. It enables microservices to invoke remote functions directly, such as processing payments or querying databases across distributed systems, with payloads serialized in JSON for simplicity and readability. This is particularly useful in scalable cloud APIs where low-latency, payload-efficient exchanges are prioritized over resource-oriented designs.[14][15]
Recent advancements in AI and agentic systems have leveraged JSON-RPC through the Model Context Protocol (MCP), introduced by Anthropic in late 2024, to standardize integrations for AI memory management and tool access. MCP servers expose external services—like databases or APIs—to AI agents via JSON-RPC, allowing models to maintain persistent context or retrieve dynamic information during inference, which has accelerated the development of autonomous agents in 2025. This protocol acts as a universal interface, enabling plug-and-play connections that enhance AI's ability to handle complex, multi-step tasks without custom integrations.[16][17][18]
For desktop applications, JSON-RPC facilitates cross-platform bindings to core libraries, as seen in Delta Chat's 2025 updates to its RPC server, which provides a stdio-based interface for instant messaging functionality. This allows developers to embed secure, end-to-end encrypted chat features into applications written in languages like Python or Node.js, bypassing the need for native recompilation and enabling rapid prototyping of desktop clients.[19][20]
Security remains a critical aspect of JSON-RPC deployments, especially for public endpoints where detailed error messages can inadvertently expose internal system details, potentially aiding attackers in reconnaissance or exploitation. To mitigate this, implementations often sanitize error responses to generic codes and incorporate rate limiting—typically enforcing thresholds like 100 requests per second on public nodes—to prevent denial-of-service attacks and abuse.[21][22]
JSON-RPC supports flexible transports to suit different scenarios: HTTP POST emulates REST-like request-response patterns for stateless, one-off calls, while WebSockets enable persistent, real-time bidirectional communication ideal for streaming updates or interactive sessions. For example, in blockchain nodes, WebSockets allow clients to subscribe to event filters for live transaction notifications, improving responsiveness in dynamic environments.[23][24][25]
Libraries and Frameworks
JSON-RPC implementations are available across numerous programming languages through dedicated libraries that facilitate both client and server functionalities. In JavaScript and Node.js ecosystems, the json-rpc-2.0 package provides a lightweight implementation supporting version 2.0 specifications, including request handling, batch calls, and error management, and is widely used in blockchain applications for interacting with Ethereum nodes via HTTP, WebSocket, or IPC transports.
For Python developers, the jsonrpcserver library offers a robust server-side framework for building JSON-RPC endpoints, featuring automatic request dispatching, validation, and support for asynchronous operations, while the json-rpc package complements it by providing client-side capabilities for sending requests and handling responses in both synchronous and asynchronous modes.
In Java, the json-rpc-client library enables straightforward client implementations with support for HTTP and TCP transports, and it integrates seamlessly with Spring Boot frameworks for creating microservices that expose or consume JSON-RPC APIs, often used in enterprise environments for remote procedure calls in distributed systems.
The Go programming language features prominent JSON-RPC support through the go-ethereum project's RPC module, which implements a full server and client stack optimized for high-performance blockchain interactions, including WebSocket subscriptions and batch processing, making it a staple in decentralized application development.
Rust's jsonrpsee crate, which received significant updates in 2025 enhancing asynchronous support via the Tokio runtime, positioning it as a preferred choice for high-throughput applications in AI services and blockchain protocols due to its memory safety and concurrency features.
Framework-level integrations further extend JSON-RPC's reach; for instance, Cisco's Network Services Orchestrator (NSO) incorporates JSON-RPC in its 2025 documentation for northbound API interactions in network automation, while the OpenDaylight platform uses it for controller-to-device communications in software-defined networking environments.
A recommended best practice for robust implementations involves auto-generating client and server stubs from JSON-RPC method schemas using tools like OpenAPI or Protocol Buffers extensions, which ensures type safety, reduces boilerplate code, and minimizes runtime errors in polyglot environments.