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}
89#[derive(Debug, Clone, Serialize, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub struct CallToolRequest {
92    pub name: String,
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub arguments: Option<HashMap<String, serde_json::Value>>,
95    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
96    pub meta: Option<serde_json::Value>,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
100#[serde(rename_all = "camelCase")]
101pub struct CallToolResponse {
102    pub content: Vec<ToolResponseContent>,
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub is_error: Option<bool>,
105    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
106    pub meta: Option<serde_json::Value>,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110#[serde(tag = "type")]
111pub enum ToolResponseContent {
112    #[serde(rename = "text")]
113    Text { text: String },
114    #[serde(rename = "image")]
115    Image { data: String, mime_type: String },
116    #[serde(rename = "resource")]
117    Resource { resource: ResourceContents },
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct ResourceContents {
123    pub uri: Url,
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub mime_type: Option<String>,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
129#[serde(rename_all = "camelCase")]
130pub struct ReadResourceRequest {
131    pub uri: Url,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135#[serde(rename_all = "camelCase")]
136pub struct ListRequest {
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub cursor: Option<String>,
139    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
140    pub meta: Option<serde_json::Value>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144#[serde(rename_all = "camelCase")]
145pub struct ToolsListResponse {
146    pub tools: Vec<Tool>,
147    #[serde(skip_serializing_if = "Option::is_none")]
148    pub next_cursor: Option<String>,
149    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
150    pub meta: Option<serde_json::Value>,
151}
152#[derive(Debug, Clone, Deserialize, Serialize)]
153#[serde(rename_all = "camelCase")]
154pub struct PromptsListResponse {
155    pub prompts: Vec<Prompt>,
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub next_cursor: Option<String>,
158    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
159    pub meta: Option<HashMap<String, serde_json::Value>>,
160}
161
162#[derive(Debug, Clone, Deserialize, Serialize)]
163#[serde(rename_all = "camelCase")]
164pub struct Prompt {
165    pub name: String,
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub description: Option<String>,
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub arguments: Option<Vec<PromptArgument>>,
170}
171
172#[derive(Debug, Clone, Deserialize, Serialize)]
173#[serde(rename_all = "camelCase")]
174pub struct PromptArgument {
175    pub name: String,
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub description: Option<String>,
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub required: Option<bool>,
180}
181
182#[derive(Debug, Clone, Deserialize, Serialize)]
183#[serde(rename_all = "camelCase")]
184pub struct ResourcesListResponse {
185    pub resources: Vec<Resource>,
186    #[serde(skip_serializing_if = "Option::is_none")]
187    pub next_cursor: Option<String>,
188    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
189    pub meta: Option<HashMap<String, serde_json::Value>>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct Resource {
195    pub uri: Url,
196    pub name: String,
197    #[serde(skip_serializing_if = "Option::is_none")]
198    pub description: Option<String>,
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub mime_type: Option<String>,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204pub enum ErrorCode {
205    // SDK error codes
206    ConnectionClosed = -1,
207    RequestTimeout = -2,
208
209    // Standard JSON-RPC error codes
210    ParseError = -32700,
211    InvalidRequest = -32600,
212    MethodNotFound = -32601,
213    InvalidParams = -32602,
214    InternalError = -32603,
215}
216
217#[cfg(test)]
218mod tests {
219    use super::*;
220
221    #[test]
222    fn test_server_capabilities() {
223        let capabilities = ServerCapabilities::default();
224        let json = serde_json::to_string(&capabilities).unwrap();
225        assert_eq!(json, "{}");
226    }
227}