async_mcp/
types.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use url::Url;
5
6pub const LATEST_PROTOCOL_VERSION: &str = "2024-11-05";
7
8#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9#[serde(rename_all = "camelCase")]
10#[serde(default)]
11pub struct Implementation {
12    pub name: String,
13    pub version: String,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, Default)]
17#[serde(rename_all = "camelCase")]
18#[serde(default)]
19pub struct InitializeRequest {
20    pub protocol_version: String,
21    pub capabilities: ClientCapabilities,
22    pub client_info: Implementation,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, Default)]
26#[serde(rename_all = "camelCase")]
27#[serde(default)]
28pub struct InitializeResponse {
29    pub protocol_version: String,
30    pub capabilities: ServerCapabilities,
31    pub server_info: Implementation,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, Default)]
35#[serde(rename_all = "camelCase")]
36#[serde(default)]
37pub struct ServerCapabilities {
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub tools: Option<serde_json::Value>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub experimental: Option<serde_json::Value>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub logging: Option<serde_json::Value>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub prompts: Option<PromptCapabilities>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub resources: Option<ResourceCapabilities>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, Default)]
51#[serde(rename_all = "camelCase")]
52#[serde(default)]
53pub struct PromptCapabilities {
54    pub list_changed: Option<bool>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, Default)]
58#[serde(rename_all = "camelCase")]
59#[serde(default)]
60pub struct ResourceCapabilities {
61    pub subscribe: Option<bool>,
62    pub list_changed: Option<bool>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, Default)]
66#[serde(rename_all = "camelCase")]
67#[serde(default)]
68pub struct ClientCapabilities {
69    pub experimental: Option<serde_json::Value>,
70    pub sampling: Option<serde_json::Value>,
71    pub roots: Option<RootCapabilities>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, Default)]
75#[serde(rename_all = "camelCase")]
76#[serde(default)]
77pub struct RootCapabilities {
78    pub list_changed: Option<bool>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct Tool {
84    pub name: String,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub description: Option<String>,
87    pub input_schema: serde_json::Value,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub output_schema: Option<serde_json::Value>,
90}
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct CallToolRequest {
94    pub name: String,
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub arguments: Option<HashMap<String, serde_json::Value>>,
97    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
98    pub meta: Option<serde_json::Value>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[serde(rename_all = "camelCase")]
103pub struct CallToolResponse {
104    pub content: Vec<ToolResponseContent>,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub is_error: Option<bool>,
107    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
108    pub meta: Option<serde_json::Value>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
112#[serde(tag = "type")]
113pub enum ToolResponseContent {
114    #[serde(rename = "text")]
115    Text { text: String },
116    #[serde(rename = "image")]
117    Image { data: String, mime_type: String },
118    #[serde(rename = "resource")]
119    Resource { resource: ResourceContents },
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
123#[serde(rename_all = "camelCase")]
124pub struct ResourceContents {
125    pub uri: Url,
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub mime_type: Option<String>,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131#[serde(rename_all = "camelCase")]
132pub struct ReadResourceRequest {
133    pub uri: Url,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct ListRequest {
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub cursor: Option<String>,
141    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
142    pub meta: Option<serde_json::Value>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
146#[serde(rename_all = "camelCase")]
147pub struct ToolsListResponse {
148    pub tools: Vec<Tool>,
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub next_cursor: Option<String>,
151    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
152    pub meta: Option<serde_json::Value>,
153}
154#[derive(Debug, Clone, Deserialize, Serialize)]
155#[serde(rename_all = "camelCase")]
156pub struct PromptsListResponse {
157    pub prompts: Vec<Prompt>,
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub next_cursor: Option<String>,
160    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
161    pub meta: Option<HashMap<String, serde_json::Value>>,
162}
163
164#[derive(Debug, Clone, Deserialize, Serialize)]
165#[serde(rename_all = "camelCase")]
166pub struct Prompt {
167    pub name: String,
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub description: Option<String>,
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub arguments: Option<Vec<PromptArgument>>,
172}
173
174#[derive(Debug, Clone, Deserialize, Serialize)]
175#[serde(rename_all = "camelCase")]
176pub struct PromptArgument {
177    pub name: String,
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub description: Option<String>,
180    #[serde(skip_serializing_if = "Option::is_none")]
181    pub required: Option<bool>,
182}
183
184#[derive(Debug, Clone, Deserialize, Serialize)]
185#[serde(rename_all = "camelCase")]
186pub struct ResourcesListResponse {
187    pub resources: Vec<Resource>,
188    #[serde(skip_serializing_if = "Option::is_none")]
189    pub next_cursor: Option<String>,
190    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
191    pub meta: Option<HashMap<String, serde_json::Value>>,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195#[serde(rename_all = "camelCase")]
196pub struct Resource {
197    pub uri: Url,
198    pub name: String,
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub description: Option<String>,
201    #[serde(skip_serializing_if = "Option::is_none")]
202    pub mime_type: Option<String>,
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
206pub enum ErrorCode {
207    // SDK error codes
208    ConnectionClosed = -1,
209    RequestTimeout = -2,
210
211    // Standard JSON-RPC error codes
212    ParseError = -32700,
213    InvalidRequest = -32600,
214    MethodNotFound = -32601,
215    InvalidParams = -32602,
216    InternalError = -32603,
217}
218
219#[cfg(test)]
220mod tests {
221    use super::*;
222
223    #[test]
224    fn test_server_capabilities() {
225        let capabilities = ServerCapabilities::default();
226        let json = serde_json::to_string(&capabilities).unwrap();
227        assert_eq!(json, "{}");
228    }
229}