Skip to main content

bn/mcp/
protocol.rs

1//! JSON-RPC 2.0 and MCP protocol types.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6// ---------------------------------------------------------------------------
7// JSON-RPC 2.0
8// ---------------------------------------------------------------------------
9
10/// A JSON-RPC 2.0 request or notification.
11#[derive(Debug, Deserialize)]
12pub struct JsonRpcRequest {
13    /// Must be "2.0"
14    pub jsonrpc: String,
15    /// Method name
16    pub method: String,
17    /// Parameters (optional)
18    #[serde(default)]
19    pub params: Option<Value>,
20    /// Request ID (absent for notifications)
21    pub id: Option<Value>,
22}
23
24/// A JSON-RPC 2.0 response.
25#[derive(Debug, Serialize)]
26pub struct JsonRpcResponse {
27    /// Always "2.0"
28    pub jsonrpc: String,
29    /// Result (mutually exclusive with error)
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub result: Option<Value>,
32    /// Error (mutually exclusive with result)
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub error: Option<JsonRpcError>,
35    /// Request ID (echoed from request)
36    pub id: Value,
37}
38
39/// A JSON-RPC 2.0 error object.
40#[derive(Debug, Serialize)]
41pub struct JsonRpcError {
42    /// Error code
43    pub code: i64,
44    /// Human-readable message
45    pub message: String,
46    /// Additional data
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub data: Option<Value>,
49}
50
51// Standard JSON-RPC error codes
52pub const PARSE_ERROR: i64 = -32700;
53pub const INVALID_REQUEST: i64 = -32600;
54pub const METHOD_NOT_FOUND: i64 = -32601;
55pub const INVALID_PARAMS: i64 = -32602;
56pub const INTERNAL_ERROR: i64 = -32603;
57
58impl JsonRpcResponse {
59    /// Create a success response.
60    pub fn success(id: Value, result: Value) -> Self {
61        Self {
62            jsonrpc: "2.0".to_string(),
63            result: Some(result),
64            error: None,
65            id,
66        }
67    }
68
69    /// Create an error response.
70    pub fn error(id: Value, code: i64, message: impl Into<String>) -> Self {
71        Self {
72            jsonrpc: "2.0".to_string(),
73            result: None,
74            error: Some(JsonRpcError {
75                code,
76                message: message.into(),
77                data: None,
78            }),
79            id,
80        }
81    }
82}
83
84// ---------------------------------------------------------------------------
85// MCP Protocol Types
86// ---------------------------------------------------------------------------
87
88/// MCP initialize request params.
89#[derive(Debug, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub struct InitializeParams {
92    /// Protocol version requested by client
93    pub protocol_version: String,
94    /// Client capabilities
95    #[serde(default)]
96    pub capabilities: Value,
97    /// Client info
98    #[serde(default)]
99    pub client_info: Option<ClientInfo>,
100}
101
102/// Client identification.
103#[derive(Debug, Deserialize)]
104pub struct ClientInfo {
105    pub name: String,
106    #[serde(default)]
107    pub version: Option<String>,
108}
109
110/// MCP server info returned in initialize response.
111#[derive(Debug, Serialize)]
112pub struct ServerInfo {
113    pub name: String,
114    pub version: String,
115}
116
117/// MCP tool definition.
118#[derive(Debug, Serialize)]
119#[serde(rename_all = "camelCase")]
120pub struct ToolDefinition {
121    pub name: String,
122    pub description: String,
123    pub input_schema: Value,
124}
125
126/// MCP tool call result content.
127#[derive(Debug, Serialize)]
128pub struct ToolContent {
129    #[serde(rename = "type")]
130    pub content_type: String,
131    pub text: String,
132}
133
134/// MCP resource definition.
135#[derive(Debug, Serialize)]
136#[serde(rename_all = "camelCase")]
137pub struct ResourceDefinition {
138    pub uri: String,
139    pub name: String,
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub description: Option<String>,
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub mime_type: Option<String>,
144}
145
146/// MCP resource content.
147#[derive(Debug, Serialize)]
148#[serde(rename_all = "camelCase")]
149pub struct ResourceContent {
150    pub uri: String,
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub mime_type: Option<String>,
153    pub text: String,
154}