use serde::{Deserialize, Serialize};
use serde_json::Value;
pub const LATEST_PROTOCOL_VERSION: &str = "2024-11-05";
pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2024-11-05"];
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Id {
Number(i64),
String(String),
Null,
}
impl Id {
pub fn to_string_key(&self) -> String {
match self {
Id::Number(n) => n.to_string(),
Id::String(s) => s.clone(),
Id::Null => "null".to_string(),
}
}
pub fn to_value(&self) -> Value {
match self {
Id::Number(n) => Value::Number((*n).into()),
Id::String(s) => Value::String(s.clone()),
Id::Null => Value::Null,
}
}
}
impl std::fmt::Display for Id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Id::Number(n) => write!(f, "{}", n),
Id::String(s) => write!(f, "{}", s),
Id::Null => write!(f, "null"),
}
}
}
impl From<Id> for Value {
fn from(id: Id) -> Self {
id.to_value()
}
}
impl From<&Id> for Value {
fn from(id: &Id) -> Self {
id.to_value()
}
}
impl From<i64> for Id {
fn from(n: i64) -> Self {
Id::Number(n)
}
}
impl From<i32> for Id {
fn from(n: i32) -> Self {
Id::Number(n as i64)
}
}
impl From<u64> for Id {
fn from(n: u64) -> Self {
Id::Number(n as i64)
}
}
impl From<String> for Id {
fn from(s: String) -> Self {
Id::String(s)
}
}
impl From<&str> for Id {
fn from(s: &str) -> Self {
Id::String(s.to_string())
}
}
impl From<Value> for Id {
fn from(v: Value) -> Self {
match v {
Value::Number(n) => {
if let Some(i) = n.as_i64() {
Id::Number(i)
} else if let Some(u) = n.as_u64() {
Id::Number(u as i64)
} else {
Id::String(n.to_string())
}
}
Value::String(s) => Id::String(s),
_ => Id::Null,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcRequest {
pub jsonrpc: String,
#[serde(default)]
pub id: Option<Id>,
pub method: String,
#[serde(default)]
pub params: Option<Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcResponse {
pub jsonrpc: String,
pub id: Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<JsonRpcError>,
}
impl JsonRpcResponse {
pub fn success(id: impl Into<Value>, result: Value) -> Self {
Self {
jsonrpc: "2.0".to_string(),
id: id.into(),
result: Some(result),
error: None,
}
}
pub fn error(id: impl Into<Value>, code: i32, message: String, data: Option<Value>) -> Self {
Self {
jsonrpc: "2.0".to_string(),
id: id.into(),
result: None,
error: Some(JsonRpcError {
code,
message,
data,
}),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcError {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Implementation {
pub name: String,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CapabilityInfo {
#[serde(skip_serializing_if = "Option::is_none")]
pub list_changed: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct ServerCapabilities {
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<CapabilityInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resources: Option<CapabilityInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompts: Option<CapabilityInfo>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct InitializeResult {
pub protocol_version: String,
pub capabilities: ServerCapabilities,
pub server_info: Implementation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolDefinition {
pub name: String,
pub description: String,
pub input_schema: Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListToolsResult {
pub tools: Vec<ToolDefinition>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum ContentItem {
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "image")]
Image { data: String, mime_type: String },
#[serde(rename = "resource")]
Resource { resource: ResourceContent },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CallToolResult {
pub content: Vec<ContentItem>,
pub is_error: bool,
}
impl CallToolResult {
pub fn text(text: impl Into<String>) -> Self {
Self {
content: vec![ContentItem::Text { text: text.into() }],
is_error: false,
}
}
pub fn error(message: impl Into<String>) -> Self {
Self {
content: vec![ContentItem::Text {
text: message.into(),
}],
is_error: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResourceDefinition {
pub uri: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListResourcesResult {
pub resources: Vec<ResourceDefinition>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResourceContent {
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
pub text: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReadResourceResult {
pub contents: Vec<ResourceContent>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PromptArgument {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub required: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PromptDefinition {
pub name: String,
pub description: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub arguments: Option<Vec<PromptArgument>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListPromptsResult {
pub prompts: Vec<PromptDefinition>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PromptMessage {
pub role: String,
pub content: ContentItem,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetPromptResult {
pub description: Option<String>,
pub messages: Vec<PromptMessage>,
}