Skip to main content

tap_mcp/mcp/
protocol.rs

1//! MCP Protocol message definitions
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6/// MCP protocol version
7pub const MCP_VERSION: &str = "2024-11-05";
8
9/// JSON-RPC 2.0 request
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct JsonRpcRequest {
12    pub jsonrpc: String,
13    pub id: Option<Value>,
14    pub method: String,
15    pub params: Option<Value>,
16}
17
18/// JSON-RPC 2.0 response
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct JsonRpcResponse {
21    pub jsonrpc: String,
22    pub id: Option<Value>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub result: Option<Value>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub error: Option<JsonRpcError>,
27}
28
29/// JSON-RPC 2.0 error
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct JsonRpcError {
32    pub code: i32,
33    pub message: String,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub data: Option<Value>,
36}
37
38/// MCP Initialize request parameters
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct InitializeParams {
41    #[serde(rename = "protocolVersion")]
42    pub protocol_version: String,
43    pub capabilities: ClientCapabilities,
44    #[serde(rename = "clientInfo")]
45    pub client_info: ClientInfo,
46}
47
48/// Client capabilities
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct ClientCapabilities {
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub experimental: Option<Value>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub sampling: Option<Value>,
55}
56
57/// Client information
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct ClientInfo {
60    pub name: String,
61    pub version: String,
62}
63
64/// MCP Initialize response
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct InitializeResult {
67    #[serde(rename = "protocolVersion")]
68    pub protocol_version: String,
69    pub capabilities: ServerCapabilities,
70    #[serde(rename = "serverInfo")]
71    pub server_info: ServerInfo,
72}
73
74/// Server capabilities
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct ServerCapabilities {
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub logging: Option<Value>,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub prompts: Option<Value>,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub resources: Option<ResourcesCapability>,
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub tools: Option<ToolsCapability>,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub experimental: Option<Value>,
87}
88
89/// Resources capability
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct ResourcesCapability {
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub subscribe: Option<bool>,
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub list_changed: Option<bool>,
96}
97
98/// Tools capability
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct ToolsCapability {
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub list_changed: Option<bool>,
103}
104
105/// Server information
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct ServerInfo {
108    pub name: String,
109    pub version: String,
110}
111
112/// Tool definition
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct Tool {
115    pub name: String,
116    pub description: String,
117    #[serde(rename = "inputSchema")]
118    pub input_schema: Value,
119}
120
121/// Tool call parameters
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct CallToolParams {
124    pub name: String,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub arguments: Option<Value>,
127}
128
129/// Tool call result
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct CallToolResult {
132    pub content: Vec<ToolContent>,
133    #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
134    pub is_error: Option<bool>,
135}
136
137/// Tool content
138#[derive(Debug, Clone, Serialize, Deserialize)]
139#[serde(tag = "type")]
140pub enum ToolContent {
141    #[serde(rename = "text")]
142    Text { text: String },
143    #[serde(rename = "image")]
144    Image { data: String, mime_type: String },
145    #[serde(rename = "resource")]
146    Resource { resource: ResourceContent },
147}
148
149/// Resource content
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct ResourceContent {
152    pub uri: String,
153    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
154    pub mime_type: Option<String>,
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub text: Option<String>,
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub blob: Option<String>,
159}
160
161/// Resource definition
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct Resource {
164    pub uri: String,
165    pub name: String,
166    pub description: String,
167    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
168    pub mime_type: Option<String>,
169}
170
171/// List resources parameters
172#[allow(dead_code)]
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct ListResourcesParams {
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub cursor: Option<String>,
177}
178
179/// List resources result
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct ListResourcesResult {
182    pub resources: Vec<Resource>,
183    #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
184    pub next_cursor: Option<String>,
185}
186
187/// Read resource parameters
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct ReadResourceParams {
190    pub uri: String,
191}
192
193/// Read resource result
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct ReadResourceResult {
196    pub contents: Vec<ResourceContent>,
197}
198
199/// List tools result
200#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct ListToolsResult {
202    pub tools: Vec<Tool>,
203    #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
204    pub next_cursor: Option<String>,
205}
206
207/// JSON-RPC error codes
208pub mod error_codes {
209    pub const INVALID_REQUEST: i32 = -32600;
210    pub const METHOD_NOT_FOUND: i32 = -32601;
211    pub const INVALID_PARAMS: i32 = -32602;
212    pub const INTERNAL_ERROR: i32 = -32603;
213}
214
215impl JsonRpcResponse {
216    pub fn success(id: Option<Value>, result: Value) -> Self {
217        Self {
218            jsonrpc: "2.0".to_string(),
219            id,
220            result: Some(result),
221            error: None,
222        }
223    }
224
225    pub fn error(id: Option<Value>, error: JsonRpcError) -> Self {
226        Self {
227            jsonrpc: "2.0".to_string(),
228            id,
229            result: None,
230            error: Some(error),
231        }
232    }
233}
234
235impl JsonRpcError {
236    pub fn invalid_request(message: impl Into<String>) -> Self {
237        Self {
238            code: error_codes::INVALID_REQUEST,
239            message: message.into(),
240            data: None,
241        }
242    }
243
244    pub fn method_not_found(method: impl Into<String>) -> Self {
245        Self {
246            code: error_codes::METHOD_NOT_FOUND,
247            message: format!("Method not found: {}", method.into()),
248            data: None,
249        }
250    }
251
252    pub fn invalid_params(message: impl Into<String>) -> Self {
253        Self {
254            code: error_codes::INVALID_PARAMS,
255            message: message.into(),
256            data: None,
257        }
258    }
259
260    pub fn internal_error(message: impl Into<String>) -> Self {
261        Self {
262            code: error_codes::INTERNAL_ERROR,
263            message: message.into(),
264            data: None,
265        }
266    }
267}