use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
#[derive(Debug, Serialize, Deserialize)]
pub struct JsonRpcRequest {
pub jsonrpc: String,
pub id: Option<Value>,
pub method: String,
pub params: Option<Value>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct JsonRpcResponse {
pub jsonrpc: String,
pub id: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<JsonRpcError>,
}
#[derive(Debug, 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)]
pub struct McpError {
pub code: i32,
pub message: String,
pub operation: String,
pub details: Option<String>,
}
impl McpError {
pub fn new(code: i32, message: impl Into<String>, operation: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
operation: operation.into(),
details: None,
}
}
pub fn with_details(mut self, details: impl Into<String>) -> Self {
self.details = Some(details.into());
self
}
pub fn into_anyhow(self) -> anyhow::Error {
anyhow::anyhow!(
"MCP_ERROR:{}:{}:{}:{}",
self.code,
self.message,
self.operation,
self.details.unwrap_or_default()
)
}
pub fn into_jsonrpc(self) -> JsonRpcError {
JsonRpcError {
code: self.code,
message: self.message.clone(),
data: Some(json!({
"operation": self.operation,
"details": self.details.unwrap_or_default(),
"error_type": match self.code {
-32602 => "invalid_params",
-32601 => "method_not_found",
-32603 => "internal_error",
-32600 => "invalid_request",
_ => "application_error"
}
})),
}
}
pub fn invalid_params(message: impl Into<String>, operation: impl Into<String>) -> Self {
Self::new(-32602, message, operation)
}
pub fn internal_error(message: impl Into<String>, operation: impl Into<String>) -> Self {
Self::new(-32603, message, operation)
}
pub fn method_not_found(message: impl Into<String>, operation: impl Into<String>) -> Self {
Self::new(-32601, message, operation)
}
}
impl From<anyhow::Error> for McpError {
fn from(error: anyhow::Error) -> Self {
McpError::internal_error(error.to_string(), "unknown_operation")
}
}
impl std::fmt::Display for McpError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({})", self.message, self.operation)
}
}
impl std::error::Error for McpError {}
pub fn parse_mcp_error(error_str: &str) -> Option<JsonRpcError> {
if let Some(mcp_part) = error_str.strip_prefix("MCP_ERROR:") {
let parts: Vec<&str> = mcp_part.splitn(4, ':').collect();
if parts.len() >= 3 {
if let Ok(code) = parts[0].parse::<i32>() {
let operation = parts[2];
let details = parts.get(3).unwrap_or(&"");
return Some(JsonRpcError {
code,
message: parts[1].to_string(),
data: Some(json!({
"operation": operation,
"details": details,
"error_type": match code {
-32602 => "invalid_params",
-32601 => "method_not_found",
-32603 => "internal_error",
-32600 => "invalid_request",
_ => "application_error"
}
})),
});
}
}
}
None
}
#[derive(Debug, Serialize, Deserialize)]
pub struct McpTool {
pub name: String,
pub description: String,
#[serde(rename = "inputSchema")]
pub input_schema: Value,
}