tapes_client/core/models/protocol.rs
1//! Shapes that belong to a protocol rather than to the read model: the error
2//! body every non-success answer carries, and the JSON-RPC frames of the MCP
3//! endpoint.
4//!
5//! The MCP frames are modelled because they are response schemas of a sealed
6//! operation and the gate accounts for every one of those. Typing a frame is
7//! not the same as offering an MCP session, and this crate does not offer one.
8
9use std::collections::BTreeMap;
10
11use serde::{Deserialize, Serialize};
12use serde_json::Value;
13
14use super::ContractModel;
15
16/// An error body, as every non-success tapes response spells one.
17///
18/// Models the contract's `ErrorResponse` schema.
19#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
20#[serde(default)]
21#[non_exhaustive]
22pub struct ErrorResponse {
23 /// The contract's `error`.
24 pub error: String,
25}
26
27impl ContractModel for ErrorResponse {
28 const SCHEMA: &'static str = "ErrorResponse";
29}
30
31/// A JSON-RPC 2.0 request to the streamable MCP endpoint.
32///
33/// Models the contract's `MCPRequest` schema.
34#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
35#[serde(default)]
36pub struct McpRequest {
37 /// ID correlates a response with this request. `None` is a notification,
38 /// and is omitted from the wire rather than sent as an empty string —
39 /// JSON-RPC reads a present id as "answer me", so a notification that
40 /// carried one would not be a notification.
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub id: Option<String>,
43
44 /// The protocol version, always "2.0".
45 pub jsonrpc: String,
46
47 /// The MCP method being invoked, such as tools/call.
48 pub method: String,
49
50 /// The method's arguments.
51 #[serde(deserialize_with = "super::null_default")]
52 pub params: BTreeMap<String, Value>,
53}
54
55impl ContractModel for McpRequest {
56 const SCHEMA: &'static str = "MCPRequest";
57}
58
59/// A JSON-RPC 2.0 response from the streamable MCP endpoint.
60///
61/// Models the contract's `MCPResponse` schema.
62#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
63#[serde(default)]
64#[non_exhaustive]
65pub struct McpResponse {
66 /// The contract's `error`.
67 #[serde(deserialize_with = "super::null_default")]
68 pub error: McpError,
69
70 /// The id of the request this answers.
71 pub id: String,
72
73 /// The protocol version, always "2.0".
74 pub jsonrpc: String,
75
76 /// The method's return value on success.
77 #[serde(deserialize_with = "super::null_default")]
78 pub result: BTreeMap<String, Value>,
79}
80
81impl ContractModel for McpResponse {
82 const SCHEMA: &'static str = "MCPResponse";
83}
84
85/// A JSON-RPC 2.0 error object.
86///
87/// Models the contract's `MCPError` schema.
88#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
89#[serde(default)]
90#[non_exhaustive]
91pub struct McpError {
92 /// The JSON-RPC error code.
93 pub code: i32,
94
95 /// A short description of the failure.
96 pub message: String,
97}
98
99impl ContractModel for McpError {
100 const SCHEMA: &'static str = "MCPError";
101}