//! MCP JSON-RPC message types
use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::{ClientCapabilities, Content, Info, Prompt, Resource, ServerCapabilities, Tool};
/// JSON-RPC request
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcRequest {
/// JSON-RPC version (always "2.0")
pub jsonrpc: String,
/// Request ID
pub id: RequestId,
/// Method name
pub method: String,
/// Parameters
#[serde(default, skip_serializing_if = "Option::is_none")]
pub params: Option<Value>,
}
/// JSON-RPC notification (no id)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcNotification {
/// JSON-RPC version (always "2.0")
pub jsonrpc: String,
/// Method name
pub method: String,
/// Parameters
#[serde(default, skip_serializing_if = "Option::is_none")]
pub params: Option<Value>,
}
/// JSON-RPC response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcResponse {
/// JSON-RPC version (always "2.0")
pub jsonrpc: String,
/// Request ID
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<RequestId>,
/// Result (on success)
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<Value>,
/// Error (on failure)
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<JsonRpcError>,
}
impl JsonRpcResponse {
/// Create a success response
#[must_use]
pub fn success(id: RequestId, result: Value) -> Self {
Self {
jsonrpc: "2.0".to_string(),
id: Some(id),
result: Some(result),
error: None,
}
}
/// Create an error response
pub fn error(id: Option<RequestId>, code: i32, message: impl Into<String>) -> Self {
Self {
jsonrpc: "2.0".to_string(),
id,
result: None,
error: Some(JsonRpcError {
code,
message: message.into(),
data: None,
}),
}
}
/// Create an error response with data
pub fn error_with_data(
id: Option<RequestId>,
code: i32,
message: impl Into<String>,
data: Value,
) -> Self {
Self {
jsonrpc: "2.0".to_string(),
id,
result: None,
error: Some(JsonRpcError {
code,
message: message.into(),
data: Some(data),
}),
}
}
}
/// JSON-RPC error
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcError {
/// Error code
pub code: i32,
/// Error message
pub message: String,
/// Optional error data
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<Value>,
}
/// Request ID (string or number)
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RequestId {
/// String ID
String(String),
/// Numeric ID
Number(i64),
}
impl std::fmt::Display for RequestId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::String(s) => write!(f, "{s}"),
Self::Number(n) => write!(f, "{n}"),
}
}
}
/// Generic JSON-RPC message (request, notification, or response)
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum JsonRpcMessage {
/// Request
Request(JsonRpcRequest),
/// Notification
Notification(JsonRpcNotification),
/// Response
Response(JsonRpcResponse),
}
impl JsonRpcMessage {
/// Check if this is a request
#[must_use]
pub fn is_request(&self) -> bool {
matches!(self, Self::Request(_))
}
/// Check if this is a notification
#[must_use]
pub fn is_notification(&self) -> bool {
matches!(self, Self::Notification(_))
}
/// Check if this is a response
#[must_use]
pub fn is_response(&self) -> bool {
matches!(self, Self::Response(_))
}
/// Get the method name (for requests and notifications)
#[must_use]
pub fn method(&self) -> Option<&str> {
match self {
Self::Request(r) => Some(&r.method),
Self::Notification(n) => Some(&n.method),
Self::Response(_) => None,
}
}
}
// ============================================================================
// Initialize
// ============================================================================
/// Initialize request params
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitializeParams {
/// Protocol version
#[serde(rename = "protocolVersion")]
pub protocol_version: String,
/// Client capabilities
pub capabilities: ClientCapabilities,
/// Client info
#[serde(rename = "clientInfo")]
pub client_info: Info,
}
/// Initialize result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitializeResult {
/// Protocol version
#[serde(rename = "protocolVersion")]
pub protocol_version: String,
/// Server capabilities
pub capabilities: ServerCapabilities,
/// Server info
#[serde(rename = "serverInfo")]
pub server_info: Info,
/// Optional instructions
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
}
// ============================================================================
// Tools
// ============================================================================
/// Tools list request params
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ToolsListParams {
/// Pagination cursor
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
/// Tools list result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolsListResult {
/// List of tools
pub tools: Vec<Tool>,
/// Next cursor for pagination
#[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<String>,
}
/// Tools call request params
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolsCallParams {
/// Tool name
pub name: String,
/// Tool arguments
#[serde(default)]
pub arguments: Value,
}
/// Tools call result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolsCallResult {
/// Content items
pub content: Vec<Content>,
/// Whether result is an error
#[serde(rename = "isError", default)]
pub is_error: bool,
}
// ============================================================================
// Resources
// ============================================================================
/// Resources list request params
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ResourcesListParams {
/// Pagination cursor
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
/// Resources list result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourcesListResult {
/// List of resources
pub resources: Vec<Resource>,
/// Next cursor for pagination
#[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<String>,
}
// ============================================================================
// Prompts
// ============================================================================
/// Prompts list request params
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PromptsListParams {
/// Pagination cursor
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
/// Prompts list result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PromptsListResult {
/// List of prompts
pub prompts: Vec<Prompt>,
/// Next cursor for pagination
#[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<String>,
}