turul-rpc
Typed JSON-RPC 2.0 framework for Rust. Handlers return domain errors; the dispatcher owns the wire.
This is the facade crate of the turul-rpc family. It re-exports
turul-rpc-core, turul-rpc-jsonrpc, and turul-rpc-server
under a single import path. Most consumers should depend on this
crate; the split crates exist so you can pull in only the wire types
(no async runtime) when needed.
Why
Most JSON-RPC crates either hand you raw envelopes or hide the wire
entirely. turul-rpc keeps a hard line between the two:
- Handlers return
Result<Value, YourError>— neverJsonRpcError. - Dispatcher converts
YourError → JsonRpcErrorvia yourToJsonRpcErrorimpl. One boundary, one direction. - Transport-agnostic. Bring your own HTTP / SSE / stdio / Lambda. The crate is pure dispatch and types.
- JSON-RPC 2.0 batch is implemented and tested per spec (§6).
Quick start
use ;
use JsonRpcErrorObject;
use r#ToJsonRpcError;
use async_trait;
use ;
;
# async
Runnable examples
Three examples ship with the crate:
in_process_round_trip shows the calling pattern — id generation,
request construction, serialization, dispatch, response parsing, and
id correlation. For peers that read messages off the wire,
JsonRpcWireMessage (the schema's JSONRPCMessage union) parses any
inbound request, notification, or response via
parse_json_rpc_wire_message. There is no dedicated client crate; these
pieces cover the in-process and bring-your-own-transport cases (see
ADR-004).
Compliance posture
JSON-RPC 2.0, fully spec-conformant on id handling. Incoming requests
with "id": null are accepted per §4.2 (permitted, though the spec
discourages them); RequestId is String | Number | Null. The only
narrowing is that fractional numeric ids are rejected — only i64 is
representable. Server-emitted error responses use id: null for
unparseable or unidentifiable requests, as the spec requires. Batch
(§6) is implemented and tested. See ADR-002 for the full posture.
Relationship to turul-mcp
turul-mcp-server is built
on top of turul-rpc. If you want MCP semantics (tools, resources,
prompts, sessions, the Inspector flow), reach for turul-mcp-server
directly — it pulls turul-rpc in transitively.
turul-mcp-json-rpc-server (0.3.x) is a thin re-export shim over this
crate, so existing consumers resolve the same paths through it. New code
should depend on turul-rpc directly. See ADR-003.
Architecture decisions
- ADR-001 — Crate boundaries
- ADR-002 — JSON-RPC 2.0 compliance
- ADR-003 — Compatibility with turul-mcp-json-rpc-server
- ADR-004 — Non-goals for v0.1
License
Dual-licensed under MIT or Apache-2.0 at your option. See the workspace README for details.