#![allow(missing_docs)]
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::*;
use crate::{Arguments, macros::with_meta, request_handler::RequestMethod};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "method")]
pub enum ClientRequest {
#[serde(rename = "ping")]
Ping {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "initialize")]
Initialize {
#[serde(rename = "protocolVersion")]
protocol_version: String,
capabilities: Box<ClientCapabilities>,
#[serde(rename = "clientInfo")]
client_info: Implementation,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "completion/complete")]
Complete {
#[serde(rename = "ref")]
reference: Reference,
argument: ArgumentInfo,
#[serde(skip_serializing_if = "Option::is_none")]
context: Option<CompleteContext>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "logging/setLevel")]
SetLevel {
level: LoggingLevel,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "prompts/get")]
GetPrompt {
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
arguments: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "prompts/list")]
ListPrompts {
#[serde(skip_serializing_if = "Option::is_none")]
cursor: Option<Cursor>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "resources/list")]
ListResources {
#[serde(skip_serializing_if = "Option::is_none")]
cursor: Option<Cursor>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "resources/templates/list")]
ListResourceTemplates {
#[serde(skip_serializing_if = "Option::is_none")]
cursor: Option<Cursor>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "resources/read")]
ReadResource {
uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "resources/subscribe")]
Subscribe {
uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "resources/unsubscribe")]
Unsubscribe {
uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tools/call")]
CallTool {
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
arguments: Option<Arguments>,
#[serde(skip_serializing_if = "Option::is_none")]
task: Option<TaskMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tools/list")]
ListTools {
#[serde(skip_serializing_if = "Option::is_none")]
cursor: Option<Cursor>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tasks/get")]
GetTask {
#[serde(rename = "taskId")]
task_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tasks/result")]
GetTaskPayload {
#[serde(rename = "taskId")]
task_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tasks/list")]
ListTasks {
#[serde(skip_serializing_if = "Option::is_none")]
cursor: Option<Cursor>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tasks/cancel")]
CancelTask {
#[serde(rename = "taskId")]
task_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
}
impl ClientRequest {
pub fn ping() -> Self {
Self::Ping { _meta: None }
}
pub fn initialize(
protocol_version: impl Into<String>,
capabilities: ClientCapabilities,
client_info: Implementation,
) -> Self {
Self::Initialize {
protocol_version: protocol_version.into(),
capabilities: Box::new(capabilities),
client_info,
_meta: None,
}
}
pub fn complete(
reference: Reference,
argument: ArgumentInfo,
context: Option<CompleteContext>,
) -> Self {
Self::Complete {
reference,
argument,
context,
_meta: None,
}
}
pub fn set_level(level: LoggingLevel) -> Self {
Self::SetLevel { level, _meta: None }
}
pub fn get_prompt(name: impl Into<String>, arguments: Option<HashMap<String, String>>) -> Self {
Self::GetPrompt {
name: name.into(),
arguments,
_meta: None,
}
}
pub fn list_prompts(cursor: Option<Cursor>) -> Self {
Self::ListPrompts {
cursor,
_meta: None,
}
}
pub fn list_resources(cursor: Option<Cursor>) -> Self {
Self::ListResources {
cursor,
_meta: None,
}
}
pub fn list_resource_templates(cursor: Option<Cursor>) -> Self {
Self::ListResourceTemplates {
cursor,
_meta: None,
}
}
pub fn read_resource(uri: impl Into<String>) -> Self {
Self::ReadResource {
uri: uri.into(),
_meta: None,
}
}
pub fn subscribe(uri: impl Into<String>) -> Self {
Self::Subscribe {
uri: uri.into(),
_meta: None,
}
}
pub fn unsubscribe(uri: impl Into<String>) -> Self {
Self::Unsubscribe {
uri: uri.into(),
_meta: None,
}
}
pub fn call_tool(
name: impl Into<String>,
arguments: Option<Arguments>,
task: Option<TaskMetadata>,
) -> Self {
Self::CallTool {
name: name.into(),
arguments,
task,
_meta: None,
}
}
pub fn list_tools(cursor: Option<Cursor>) -> Self {
Self::ListTools {
cursor,
_meta: None,
}
}
pub fn get_task(task_id: impl Into<String>) -> Self {
Self::GetTask {
task_id: task_id.into(),
_meta: None,
}
}
pub fn get_task_payload(task_id: impl Into<String>) -> Self {
Self::GetTaskPayload {
task_id: task_id.into(),
_meta: None,
}
}
pub fn list_tasks(cursor: Option<Cursor>) -> Self {
Self::ListTasks {
cursor,
_meta: None,
}
}
pub fn cancel_task(task_id: impl Into<String>) -> Self {
Self::CancelTask {
task_id: task_id.into(),
_meta: None,
}
}
pub fn method(&self) -> &'static str {
match self {
Self::Ping { .. } => "ping",
Self::Initialize { .. } => "initialize",
Self::Complete { .. } => "completion/complete",
Self::SetLevel { .. } => "logging/setLevel",
Self::GetPrompt { .. } => "prompts/get",
Self::ListPrompts { .. } => "prompts/list",
Self::ListResources { .. } => "resources/list",
Self::ListResourceTemplates { .. } => "resources/templates/list",
Self::ReadResource { .. } => "resources/read",
Self::Subscribe { .. } => "resources/subscribe",
Self::Unsubscribe { .. } => "resources/unsubscribe",
Self::CallTool { .. } => "tools/call",
Self::ListTools { .. } => "tools/list",
Self::GetTask { .. } => "tasks/get",
Self::GetTaskPayload { .. } => "tasks/result",
Self::ListTasks { .. } => "tasks/list",
Self::CancelTask { .. } => "tasks/cancel",
}
}
}
impl RequestMethod for ClientRequest {
fn method(&self) -> &'static str {
self.method()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "method")]
pub enum ClientNotification {
#[serde(rename = "notifications/cancelled")]
Cancelled {
#[serde(rename = "requestId", skip_serializing_if = "Option::is_none")]
request_id: Option<RequestId>,
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/progress")]
Progress {
#[serde(rename = "progressToken")]
progress_token: ProgressToken,
progress: f64,
#[serde(skip_serializing_if = "Option::is_none")]
total: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/initialized")]
Initialized {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/roots/list_changed")]
RootsListChanged {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/tasks/status")]
TaskStatus {
#[serde(flatten)]
params: TaskStatusNotificationParams,
},
}
impl ClientNotification {
pub fn cancelled(request_id: Option<RequestId>, reason: Option<String>) -> Self {
Self::Cancelled {
request_id,
reason,
_meta: None,
}
}
pub fn progress(
progress_token: ProgressToken,
progress: f64,
total: Option<f64>,
message: Option<String>,
) -> Self {
Self::Progress {
progress_token,
progress,
total,
message,
_meta: None,
}
}
pub fn initialized() -> Self {
Self::Initialized { _meta: None }
}
pub fn roots_list_changed() -> Self {
Self::RootsListChanged { _meta: None }
}
pub fn task_status(params: TaskStatusNotificationParams) -> Self {
Self::TaskStatus { params }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "method")]
pub enum ServerRequest {
#[serde(rename = "ping")]
Ping {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "sampling/createMessage")]
CreateMessage(Box<CreateMessageParams>),
#[serde(rename = "roots/list")]
ListRoots {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "elicitation/create")]
Elicit(Box<ElicitRequestParams>),
#[serde(rename = "tasks/get")]
GetTask {
#[serde(rename = "taskId")]
task_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tasks/result")]
GetTaskPayload {
#[serde(rename = "taskId")]
task_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tasks/list")]
ListTasks {
#[serde(skip_serializing_if = "Option::is_none")]
cursor: Option<Cursor>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
#[serde(rename = "tasks/cancel")]
CancelTask {
#[serde(rename = "taskId")]
task_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<RequestMeta>,
},
}
impl ServerRequest {
pub fn ping() -> Self {
Self::Ping { _meta: None }
}
pub fn create_message(params: CreateMessageParams) -> Self {
Self::CreateMessage(Box::new(params))
}
pub fn list_roots() -> Self {
Self::ListRoots { _meta: None }
}
pub fn elicit(params: ElicitRequestParams) -> Self {
Self::Elicit(Box::new(params))
}
pub fn get_task(task_id: impl Into<String>) -> Self {
Self::GetTask {
task_id: task_id.into(),
_meta: None,
}
}
pub fn get_task_payload(task_id: impl Into<String>) -> Self {
Self::GetTaskPayload {
task_id: task_id.into(),
_meta: None,
}
}
pub fn list_tasks(cursor: Option<Cursor>) -> Self {
Self::ListTasks {
cursor,
_meta: None,
}
}
pub fn cancel_task(task_id: impl Into<String>) -> Self {
Self::CancelTask {
task_id: task_id.into(),
_meta: None,
}
}
pub fn method(&self) -> &'static str {
match self {
Self::Ping { .. } => "ping",
Self::CreateMessage(_) => "sampling/createMessage",
Self::ListRoots { .. } => "roots/list",
Self::Elicit(_) => "elicitation/create",
Self::GetTask { .. } => "tasks/get",
Self::GetTaskPayload { .. } => "tasks/result",
Self::ListTasks { .. } => "tasks/list",
Self::CancelTask { .. } => "tasks/cancel",
}
}
}
impl RequestMethod for ServerRequest {
fn method(&self) -> &'static str {
self.method()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "method")]
pub enum ServerNotification {
#[serde(rename = "notifications/cancelled")]
Cancelled {
#[serde(rename = "requestId", skip_serializing_if = "Option::is_none")]
request_id: Option<RequestId>,
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/progress")]
Progress {
#[serde(rename = "progressToken")]
progress_token: ProgressToken,
progress: f64,
#[serde(skip_serializing_if = "Option::is_none")]
total: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/message")]
LoggingMessage {
level: LoggingLevel,
#[serde(skip_serializing_if = "Option::is_none")]
logger: Option<String>,
data: Value,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/resources/updated")]
ResourceUpdated {
uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/resources/list_changed")]
ResourceListChanged {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/tools/list_changed")]
ToolListChanged {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/prompts/list_changed")]
PromptListChanged {
#[serde(skip_serializing_if = "Option::is_none")]
_meta: Option<HashMap<String, Value>>,
},
#[serde(rename = "notifications/elicitation/complete")]
ElicitationComplete {
#[serde(rename = "elicitationId")]
elicitation_id: String,
},
#[serde(rename = "notifications/tasks/status")]
TaskStatus {
#[serde(flatten)]
params: TaskStatusNotificationParams,
},
}
impl ServerNotification {
pub fn cancelled(request_id: Option<RequestId>, reason: Option<String>) -> Self {
Self::Cancelled {
request_id,
reason,
_meta: None,
}
}
pub fn progress(
progress_token: ProgressToken,
progress: f64,
total: Option<f64>,
message: Option<String>,
) -> Self {
Self::Progress {
progress_token,
progress,
total,
message,
_meta: None,
}
}
pub fn logging_message(level: LoggingLevel, logger: Option<String>, data: Value) -> Self {
Self::LoggingMessage {
level,
logger,
data,
_meta: None,
}
}
pub fn resource_updated(uri: impl Into<String>) -> Self {
Self::ResourceUpdated {
uri: uri.into(),
_meta: None,
}
}
pub fn resource_list_changed() -> Self {
Self::ResourceListChanged { _meta: None }
}
pub fn tool_list_changed() -> Self {
Self::ToolListChanged { _meta: None }
}
pub fn prompt_list_changed() -> Self {
Self::PromptListChanged { _meta: None }
}
pub fn elicitation_complete(elicitation_id: impl Into<String>) -> Self {
Self::ElicitationComplete {
elicitation_id: elicitation_id.into(),
}
}
pub fn task_status(params: TaskStatusNotificationParams) -> Self {
Self::TaskStatus { params }
}
}
#[cfg(test)]
mod tests {
use schemars::JsonSchema;
use super::*;
#[derive(JsonSchema, Serialize)]
struct TestInput {
name: String,
age: u32,
#[serde(skip_serializing_if = "Option::is_none")]
email: Option<String>,
}
#[test]
fn test_tool_input_schema_from_json_schema() {
let schema = ToolSchema::from_json_schema::<TestInput>();
assert_eq!(schema.schema_type(), Some("object"));
let properties = schema.properties().expect("Should have properties");
assert!(properties.contains_key("name"));
assert!(properties.contains_key("age"));
assert!(properties.contains_key("email"));
let required = schema.required().expect("Should have required fields");
assert!(required.contains(&"name"));
assert!(required.contains(&"age"));
assert!(!required.contains(&"email"));
}
#[derive(JsonSchema, Serialize)]
struct ComplexInput {
id: i64,
tags: Vec<String>,
metadata: HashMap<String, String>,
}
#[test]
fn test_complex_schema_conversion() {
let schema = ToolSchema::from_json_schema::<ComplexInput>();
assert_eq!(schema.schema_type(), Some("object"));
let properties = schema.properties().expect("Should have properties");
assert!(properties.contains_key("id"));
assert!(properties.contains_key("tags"));
assert!(properties.contains_key("metadata"));
let tags_schema = &properties["tags"];
assert_eq!(
tags_schema.get("type").and_then(|v| v.as_str()),
Some("array")
);
let metadata_schema = &properties["metadata"];
assert_eq!(
metadata_schema.get("type").and_then(|v| v.as_str()),
Some("object")
);
}
#[test]
fn test_paginated_request_serialization() {
let request = ClientRequest::ListTools {
cursor: Some("test-cursor".into()),
_meta: None,
};
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["method"], "tools/list");
assert_eq!(json["cursor"], "test-cursor");
let request = ClientRequest::ListTools {
cursor: None,
_meta: None,
};
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["method"], "tools/list");
assert!(!json.as_object().unwrap().contains_key("cursor"));
let request = ClientRequest::ListResources {
cursor: Some("res-cursor".into()),
_meta: None,
};
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["method"], "resources/list");
assert_eq!(json["cursor"], "res-cursor");
let request = ClientRequest::ListPrompts {
cursor: Some("prompt-cursor".into()),
_meta: None,
};
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["method"], "prompts/list");
assert_eq!(json["cursor"], "prompt-cursor");
let request = ClientRequest::ListResourceTemplates {
cursor: Some("template-cursor".into()),
_meta: None,
};
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["method"], "resources/templates/list");
assert_eq!(json["cursor"], "template-cursor");
}
#[test]
fn test_client_capabilities_elicitation() {
let caps = ClientCapabilities::default().with_elicitation();
let json = serde_json::to_value(&caps).unwrap();
assert!(json["elicitation"].is_object());
}
#[test]
fn test_tool_output_schema() {
let tool =
Tool::new("test_tool", ToolSchema::default()).with_output_schema(ToolSchema::default());
let json = serde_json::to_value(&tool).unwrap();
assert!(json["outputSchema"].is_object());
}
#[test]
fn test_call_tool_result_structured_content() {
let structured = serde_json::json!({"type": "table"});
let result = CallToolResult::new().with_structured_content(structured.clone());
let json = serde_json::to_value(&result).unwrap();
assert_eq!(json["structuredContent"], structured);
}
#[test]
fn test_annotations_last_modified() {
let annotations = Annotations {
audience: None,
priority: None,
last_modified: Some("2024-01-15T10:30:00Z".to_string()),
};
let json = serde_json::to_value(&annotations).unwrap();
assert_eq!(json["lastModified"], "2024-01-15T10:30:00Z");
}
#[test]
fn test_complete_request_context() {
let request = ClientRequest::Complete {
reference: Reference::Resource(ResourceTemplateReference {
uri: "test://resource".to_string(),
}),
argument: ArgumentInfo {
name: "arg".to_string(),
value: "value".to_string(),
},
context: Some(CompleteContext::new().add_argument("sessionId", "123")),
_meta: None,
};
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["context"]["arguments"]["sessionId"], "123");
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitializeRequest {
pub method: String, pub params: InitializeParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitializeParams {
#[serde(rename = "protocolVersion")]
pub protocol_version: String,
pub capabilities: ClientCapabilities,
#[serde(rename = "clientInfo")]
pub client_info: Implementation,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitializedNotification {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PingRequest {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CancelledNotification {
pub method: String, pub params: CancelledParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CancelledParams {
#[serde(rename = "requestId", skip_serializing_if = "Option::is_none")]
pub request_id: Option<RequestId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProgressNotification {
pub method: String, pub params: ProgressParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProgressParams {
#[serde(rename = "progressToken")]
pub progress_token: ProgressToken,
pub progress: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub total: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaginatedRequest {
pub method: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<PaginatedParams>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaginatedParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<Cursor>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[with_meta]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaginatedResult {
#[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<Cursor>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListResourcesRequest {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<PaginatedParams>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListResourceTemplatesRequest {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<PaginatedParams>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReadResourceRequest {
pub method: String, pub params: ReadResourceParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReadResourceParams {
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubscribeRequest {
pub method: String, pub params: SubscribeParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubscribeParams {
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnsubscribeRequest {
pub method: String, pub params: UnsubscribeParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnsubscribeParams {
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceListChangedNotification {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceUpdatedNotification {
pub method: String, pub params: ResourceUpdatedParams,
}
#[with_meta]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceUpdatedParams {
pub uri: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListPromptsRequest {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<PaginatedParams>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetPromptRequest {
pub method: String, pub params: GetPromptParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetPromptParams {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub arguments: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PromptListChangedNotification {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListToolsRequest {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<PaginatedParams>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CallToolRequest {
pub method: String, pub params: CallToolParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CallToolParams {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub arguments: Option<Arguments>,
#[serde(skip_serializing_if = "Option::is_none")]
pub task: Option<TaskMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolListChangedNotification {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SetLevelRequest {
pub method: String, pub params: SetLevelParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SetLevelParams {
pub level: LoggingLevel,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingMessageNotification {
pub method: String, pub params: LoggingMessageParams,
}
#[with_meta]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingMessageParams {
pub level: LoggingLevel,
#[serde(skip_serializing_if = "Option::is_none")]
pub logger: Option<String>,
pub data: Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateMessageRequest {
pub method: String, pub params: CreateMessageParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompleteRequest {
pub method: String, pub params: CompleteParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompleteParams {
#[serde(rename = "ref")]
pub reference: Reference,
pub argument: ArgumentInfo,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<CompleteContext>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompleteContext {
#[serde(skip_serializing_if = "Option::is_none")]
pub arguments: Option<HashMap<String, String>>,
}
impl CompleteContext {
pub fn new() -> Self {
Self { arguments: None }
}
pub fn with_arguments(arguments: HashMap<String, String>) -> Self {
Self {
arguments: Some(arguments),
}
}
pub fn add_argument(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
let arguments = self.arguments.get_or_insert_with(HashMap::new);
arguments.insert(key.into(), value.into());
self
}
pub fn set_arguments(mut self, arguments: HashMap<String, String>) -> Self {
self.arguments = Some(arguments);
self
}
}
impl Default for CompleteContext {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListRootsRequest {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RootsListChangedNotification {
pub method: String, #[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ElicitRequest {
pub method: String, pub params: ElicitRequestParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ElicitRequestParams {
Form(ElicitRequestFormParams),
Url(ElicitRequestURLParams),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ElicitRequestFormParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<ElicitMode>,
pub message: String,
#[serde(rename = "requestedSchema")]
pub requested_schema: ElicitSchema,
#[serde(skip_serializing_if = "Option::is_none")]
pub task: Option<TaskMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ElicitRequestURLParams {
pub mode: ElicitMode,
pub message: String,
#[serde(rename = "elicitationId")]
pub elicitation_id: String,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub task: Option<TaskMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ElicitMode {
Form,
Url,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ElicitSchema {
#[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
pub schema: Option<String>,
#[serde(rename = "type")]
pub schema_type: String, pub properties: HashMap<String, PrimitiveSchemaDefinition>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<Vec<String>>,
}
#[with_meta]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ElicitResult {
pub action: ElicitAction,
#[serde(skip_serializing_if = "Option::is_none")]
pub content: Option<HashMap<String, ElicitValue>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ElicitAction {
Accept,
Decline,
Cancel,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ElicitValue {
String(String),
Number(f64),
Boolean(bool),
StringArray(Vec<String>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum PrimitiveSchemaDefinition {
Enum(EnumSchema),
String(StringSchema),
Number(NumberSchema),
Boolean(BooleanSchema),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum StringSchemaType {
String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum NumberSchemaType {
Number,
Integer,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum BooleanSchemaType {
Boolean,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ArraySchemaType {
Array,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StringSchema {
#[serde(rename = "type")]
pub schema_type: StringSchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
pub min_length: Option<u32>,
#[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
pub max_length: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<StringFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum StringFormat {
Email,
Uri,
Date,
DateTime,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct NumberSchema {
#[serde(rename = "type")]
pub schema_type: NumberSchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub minimum: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub maximum: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct BooleanSchema {
#[serde(rename = "type")]
pub schema_type: BooleanSchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnumOption {
#[serde(rename = "const")]
pub value: String,
pub title: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UntitledSingleSelectEnumSchema {
#[serde(rename = "type")]
pub schema_type: StringSchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "enum")]
pub values: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TitledSingleSelectEnumSchema {
#[serde(rename = "type")]
pub schema_type: StringSchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "oneOf")]
pub options: Vec<EnumOption>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SingleSelectEnumSchema {
Untitled(UntitledSingleSelectEnumSchema),
Titled(TitledSingleSelectEnumSchema),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UntitledMultiSelectItems {
#[serde(rename = "type")]
pub schema_type: StringSchemaType,
#[serde(rename = "enum")]
pub values: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TitledMultiSelectItems {
#[serde(rename = "anyOf")]
pub options: Vec<EnumOption>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UntitledMultiSelectEnumSchema {
#[serde(rename = "type")]
pub schema_type: ArraySchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "minItems", skip_serializing_if = "Option::is_none")]
pub min_items: Option<u32>,
#[serde(rename = "maxItems", skip_serializing_if = "Option::is_none")]
pub max_items: Option<u32>,
pub items: UntitledMultiSelectItems,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TitledMultiSelectEnumSchema {
#[serde(rename = "type")]
pub schema_type: ArraySchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "minItems", skip_serializing_if = "Option::is_none")]
pub min_items: Option<u32>,
#[serde(rename = "maxItems", skip_serializing_if = "Option::is_none")]
pub max_items: Option<u32>,
pub items: TitledMultiSelectItems,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum MultiSelectEnumSchema {
Untitled(UntitledMultiSelectEnumSchema),
Titled(TitledMultiSelectEnumSchema),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LegacyTitledEnumSchema {
#[serde(rename = "type")]
pub schema_type: StringSchemaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "enum")]
pub values: Vec<String>,
#[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")]
pub enum_names: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum EnumSchema {
Single(SingleSelectEnumSchema),
Multi(MultiSelectEnumSchema),
Legacy(LegacyTitledEnumSchema),
}