Skip to main content

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}