// Internal references to the SEP-2577-deprecated Roots/Sampling/Logging types
// defined in this module are expected; the deprecation is advisory for downstream users.
#![expect(deprecated)]
use std::{
    borrow::Cow,
    ops::{Deref, DerefMut},
    sync::Arc,
};
mod annotated;
mod capabilities;
mod content;
mod elicitation_schema;
mod extension;
mod meta;
mod prompt;
mod resource;
mod serde_impl;
mod task;
mod tool;
pub use annotated::*;
pub use capabilities::*;
pub use content::*;
pub use elicitation_schema::*;
pub use extension::*;
pub use meta::*;
pub use prompt::*;
pub use resource::*;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde_json::Value;
pub use task::*;
pub use tool::*;

/// A JSON object type alias for convenient handling of JSON data.
///
/// You can use [`crate::object!`] or [`crate::model::object`] to create a json object quickly.
/// This is commonly used for storing arbitrary JSON data in MCP messages.
pub type JsonObject<F = Value> = serde_json::Map<String, F>;

/// unwrap the JsonObject under [`serde_json::Value`]
///
/// # Panic
/// This will panic when the value is not a object in debug mode.
pub fn object(value: serde_json::Value) -> JsonObject {
    debug_assert!(value.is_object());
    match value {
        serde_json::Value::Object(map) => map,
        _ => JsonObject::default(),
    }
}

/// Use this macro just like [`serde_json::json!`]
#[cfg(feature = "macros")]
#[macro_export]
macro_rules! object {
    ({$($tt:tt)*}) => {
        $crate::model::object(serde_json::json! {
            {$($tt)*}
        })
    };
}

/// This is commonly used for representing empty objects in MCP messages.
///
/// without returning any specific data.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Eq)]
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "server", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct EmptyObject {}

pub trait ConstString: Default {
    const VALUE: &str;
    fn as_str(&self) -> &'static str {
        Self::VALUE
    }
}
#[macro_export]
macro_rules! const_string {
    ($name:ident = $value:literal) => {
        #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
        #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
        pub struct $name;

        impl ConstString for $name {
            const VALUE: &str = $value;
        }

        impl serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: serde::Serializer,
            {
                $value.serialize(serializer)
            }
        }

        impl<'de> serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
            where
                D: serde::Deserializer<'de>,
            {
                let s: String = serde::Deserialize::deserialize(deserializer)?;
                if s == $value {
                    Ok($name)
                } else {
                    Err(serde::de::Error::custom(format!(concat!(
                        "expect const string value \"",
                        $value,
                        "\""
                    ))))
                }
            }
        }

        #[cfg(feature = "schemars")]
        impl schemars::JsonSchema for $name {
            fn schema_name() -> Cow<'static, str> {
                Cow::Borrowed(stringify!($name))
            }

            fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
                use serde_json::{Map, json};

                let mut schema_map = Map::new();
                schema_map.insert("type".to_string(), json!("string"));
                schema_map.insert("format".to_string(), json!("const"));
                schema_map.insert("const".to_string(), json!($value));

                schemars::Schema::from(schema_map)
            }
        }
    };
}

const_string!(JsonRpcVersion2_0 = "2.0");

// =============================================================================
// CORE PROTOCOL TYPES
// =============================================================================

/// Represents the MCP protocol version used for communication.
///
/// This ensures compatibility between clients and servers by specifying
/// which version of the Model Context Protocol is being used.
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ProtocolVersion(Cow<'static, str>);

impl Default for ProtocolVersion {
    fn default() -> Self {
        Self::LATEST
    }
}

impl std::fmt::Display for ProtocolVersion {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl ProtocolVersion {
    pub const V_2026_07_28: Self = Self(Cow::Borrowed("2026-07-28"));
    pub const V_2025_11_25: Self = Self(Cow::Borrowed("2025-11-25"));
    pub const V_2025_06_18: Self = Self(Cow::Borrowed("2025-06-18"));
    pub const V_2025_03_26: Self = Self(Cow::Borrowed("2025-03-26"));
    pub const V_2024_11_05: Self = Self(Cow::Borrowed("2024-11-05"));
    pub const LATEST: Self = Self::V_2025_11_25;

    /// All protocol versions known to this SDK.
    pub const KNOWN_VERSIONS: &[Self] = &[
        Self::V_2024_11_05,
        Self::V_2025_03_26,
        Self::V_2025_06_18,
        Self::V_2025_11_25,
        Self::V_2026_07_28,
    ];

    /// Returns the string representation of this protocol version.
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl Serialize for ProtocolVersion {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.0.serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for ProtocolVersion {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s: String = Deserialize::deserialize(deserializer)?;
        #[allow(clippy::single_match)]
        match s.as_str() {
            "2024-11-05" => return Ok(ProtocolVersion::V_2024_11_05),
            "2025-03-26" => return Ok(ProtocolVersion::V_2025_03_26),
            "2025-06-18" => return Ok(ProtocolVersion::V_2025_06_18),
            "2025-11-25" => return Ok(ProtocolVersion::V_2025_11_25),
            "2026-07-28" => return Ok(ProtocolVersion::V_2026_07_28),
            _ => {}
        }
        Ok(ProtocolVersion(Cow::Owned(s)))
    }
}

/// A flexible identifier type that can be either a number or a string.
///
/// This is commonly used for request IDs and other identifiers in JSON-RPC
/// where the specification allows both numeric and string values.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum NumberOrString {
    /// A numeric identifier
    Number(i64),
    /// A string identifier
    String(Arc<str>),
}

impl NumberOrString {
    pub fn into_json_value(self) -> Value {
        match self {
            NumberOrString::Number(n) => Value::Number(serde_json::Number::from(n)),
            NumberOrString::String(s) => Value::String(s.to_string()),
        }
    }
}

impl std::fmt::Display for NumberOrString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            NumberOrString::Number(n) => n.fmt(f),
            NumberOrString::String(s) => s.fmt(f),
        }
    }
}

impl Serialize for NumberOrString {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            NumberOrString::Number(n) => n.serialize(serializer),
            NumberOrString::String(s) => s.serialize(serializer),
        }
    }
}

impl<'de> Deserialize<'de> for NumberOrString {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value: Value = Deserialize::deserialize(deserializer)?;
        match value {
            Value::Number(n) => {
                if let Some(i) = n.as_i64() {
                    Ok(NumberOrString::Number(i))
                } else if let Some(u) = n.as_u64() {
                    // Handle large unsigned numbers that fit in i64
                    if u <= i64::MAX as u64 {
                        Ok(NumberOrString::Number(u as i64))
                    } else {
                        Err(serde::de::Error::custom("Number too large for i64"))
                    }
                } else {
                    Err(serde::de::Error::custom("Expected an integer"))
                }
            }
            Value::String(s) => Ok(NumberOrString::String(s.into())),
            _ => Err(serde::de::Error::custom("Expect number or string")),
        }
    }
}

#[cfg(feature = "schemars")]
impl schemars::JsonSchema for NumberOrString {
    fn schema_name() -> Cow<'static, str> {
        Cow::Borrowed("NumberOrString")
    }

    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
        use serde_json::{Map, json};

        let mut number_schema = Map::new();
        number_schema.insert("type".to_string(), json!("number"));

        let mut string_schema = Map::new();
        string_schema.insert("type".to_string(), json!("string"));

        let mut schema_map = Map::new();
        schema_map.insert("oneOf".to_string(), json!([number_schema, string_schema]));

        schemars::Schema::from(schema_map)
    }
}

/// Type alias for request identifiers used in JSON-RPC communication.
pub type RequestId = NumberOrString;

/// A token used to track the progress of long-running operations.
///
/// Progress tokens allow clients and servers to associate progress notifications
/// with specific requests, enabling real-time updates on operation status.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
#[serde(transparent)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ProgressToken(pub NumberOrString);

// =============================================================================
// JSON-RPC MESSAGE STRUCTURES
// =============================================================================

/// Represents a JSON-RPC request with method, parameters, and extensions.
///
/// This is the core structure for all MCP requests, containing:
/// - `method`: The name of the method being called
/// - `params`: The parameters for the method
/// - `extensions`: Additional context data (similar to HTTP headers)
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct Request<M = String, P = JsonObject> {
    pub method: M,
    pub params: P,
    /// extensions will carry anything possible in the context, including [`Meta`]
    ///
    /// this is similar with the Extensions in `http` crate
    #[cfg_attr(feature = "schemars", schemars(skip))]
    pub extensions: Extensions,
}

impl<M: Default, P> Request<M, P> {
    pub fn new(params: P) -> Self {
        Self {
            method: Default::default(),
            params,
            extensions: Extensions::default(),
        }
    }
}

impl<M, P> GetExtensions for Request<M, P> {
    fn extensions(&self) -> &Extensions {
        &self.extensions
    }
    fn extensions_mut(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}

#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RequestOptionalParam<M = String, P = JsonObject> {
    pub method: M,
    // #[serde(skip_serializing_if = "Option::is_none")]
    pub params: Option<P>,
    /// extensions will carry anything possible in the context, including [`Meta`]
    ///
    /// this is similar with the Extensions in `http` crate
    #[cfg_attr(feature = "schemars", schemars(skip))]
    pub extensions: Extensions,
}

impl<M: Default, P> RequestOptionalParam<M, P> {
    pub fn with_param(params: P) -> Self {
        Self {
            method: Default::default(),
            params: Some(params),
            extensions: Extensions::default(),
        }
    }
}

#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct RequestNoParam<M = String> {
    pub method: M,
    /// extensions will carry anything possible in the context, including [`Meta`]
    ///
    /// this is similar with the Extensions in `http` crate
    #[cfg_attr(feature = "schemars", schemars(skip))]
    pub extensions: Extensions,
}

impl<M> GetExtensions for RequestNoParam<M> {
    fn extensions(&self) -> &Extensions {
        &self.extensions
    }
    fn extensions_mut(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct Notification<M = String, P = JsonObject> {
    pub method: M,
    pub params: P,
    /// extensions will carry anything possible in the context, including [`Meta`]
    ///
    /// this is similar with the Extensions in `http` crate
    #[cfg_attr(feature = "schemars", schemars(skip))]
    pub extensions: Extensions,
}

impl<M: Default, P> Notification<M, P> {
    pub fn new(params: P) -> Self {
        Self {
            method: Default::default(),
            params,
            extensions: Extensions::default(),
        }
    }
}

#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct NotificationNoParam<M = String> {
    pub method: M,
    /// extensions will carry anything possible in the context, including [`Meta`]
    ///
    /// this is similar with the Extensions in `http` crate
    #[cfg_attr(feature = "schemars", schemars(skip))]
    pub extensions: Extensions,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcRequest<R = Request> {
    pub jsonrpc: JsonRpcVersion2_0,
    pub id: RequestId,
    #[serde(flatten)]
    pub request: R,
}

impl<R> JsonRpcRequest<R> {
    /// Create a new JsonRpcRequest.
    pub fn new(id: RequestId, request: R) -> Self {
        Self {
            jsonrpc: JsonRpcVersion2_0,
            id,
            request,
        }
    }
}

type DefaultResponse = JsonObject;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcResponse<R = JsonObject> {
    pub jsonrpc: JsonRpcVersion2_0,
    pub id: RequestId,
    pub result: R,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcError {
    pub jsonrpc: JsonRpcVersion2_0,
    // MCP 2025-11-25 §Error Responses: `id` is optional and omitted when the
    // server cannot read the request id (e.g. parse error / invalid request).
    // https://modelcontextprotocol.io/specification/2025-11-25/basic#error-responses
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub id: Option<RequestId>,
    pub error: ErrorData,
}

impl JsonRpcError {
    /// Create a new JsonRpcError.
    pub fn new(id: Option<RequestId>, error: ErrorData) -> Self {
        Self {
            jsonrpc: JsonRpcVersion2_0,
            id,
            error,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcNotification<N = Notification> {
    pub jsonrpc: JsonRpcVersion2_0,
    #[serde(flatten)]
    pub notification: N,
}

/// Standard JSON-RPC error codes used throughout the MCP protocol.
///
/// These codes follow the JSON-RPC 2.0 specification and provide
/// standardized error reporting across all MCP implementations.
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(transparent)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ErrorCode(pub i32);

impl ErrorCode {
    pub const RESOURCE_NOT_FOUND: Self = Self(-32002);
    pub const INVALID_REQUEST: Self = Self(-32600);
    pub const METHOD_NOT_FOUND: Self = Self(-32601);
    pub const INVALID_PARAMS: Self = Self(-32602);
    pub const INTERNAL_ERROR: Self = Self(-32603);
    pub const PARSE_ERROR: Self = Self(-32700);
    pub const URL_ELICITATION_REQUIRED: Self = Self(-32042);
}

/// Error information for JSON-RPC error responses.
///
/// This structure follows the JSON-RPC 2.0 specification for error reporting,
/// providing a standardized way to communicate errors between clients and servers.
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct ErrorData {
    /// The error type that occurred (using standard JSON-RPC error codes)
    pub code: ErrorCode,

    /// A short description of the error. The message SHOULD be limited to a concise single sentence.
    pub message: Cow<'static, str>,

    /// Additional information about the error. The value of this member is defined by the
    /// sender (e.g. detailed error information, nested errors etc.).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<Value>,
}

impl ErrorData {
    pub fn new(
        code: ErrorCode,
        message: impl Into<Cow<'static, str>>,
        data: Option<Value>,
    ) -> Self {
        Self {
            code,
            message: message.into(),
            data,
        }
    }
    /// Resource-not-found error (`-32002`). The server upgrades this to `INVALID_PARAMS`
    /// (`-32602`) for peers negotiating protocol `2026-07-28` or newer (SEP-2164).
    pub fn resource_not_found(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
        Self::new(ErrorCode::RESOURCE_NOT_FOUND, message, data)
    }

    pub fn parse_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
        Self::new(ErrorCode::PARSE_ERROR, message, data)
    }
    pub fn invalid_request(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
        Self::new(ErrorCode::INVALID_REQUEST, message, data)
    }
    pub fn method_not_found<M: ConstString>() -> Self {
        Self::new(ErrorCode::METHOD_NOT_FOUND, M::VALUE, None)
    }
    pub fn invalid_params(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
        Self::new(ErrorCode::INVALID_PARAMS, message, data)
    }
    pub fn internal_error(message: impl Into<Cow<'static, str>>, data: Option<Value>) -> Self {
        Self::new(ErrorCode::INTERNAL_ERROR, message, data)
    }
    pub fn url_elicitation_required(
        message: impl Into<Cow<'static, str>>,
        data: Option<Value>,
    ) -> Self {
        Self::new(ErrorCode::URL_ELICITATION_REQUIRED, message, data)
    }
}

/// Represents any JSON-RPC message that can be sent or received.
///
/// This enum covers all possible message types in the JSON-RPC protocol:
/// individual requests/responses, notifications, and errors.
/// It serves as the top-level message container for MCP communication.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(untagged)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum JsonRpcMessage<Req = Request, Resp = DefaultResponse, Noti = Notification> {
    /// A single request expecting a response
    Request(JsonRpcRequest<Req>),
    /// A response to a previous request
    Response(JsonRpcResponse<Resp>),
    /// A one-way notification (no response expected)
    Notification(JsonRpcNotification<Noti>),
    /// An error response
    Error(JsonRpcError),
}

impl<Req, Resp, Not> JsonRpcMessage<Req, Resp, Not> {
    #[inline]
    pub const fn request(request: Req, id: RequestId) -> Self {
        JsonRpcMessage::Request(JsonRpcRequest {
            jsonrpc: JsonRpcVersion2_0,
            id,
            request,
        })
    }
    #[inline]
    pub const fn response(response: Resp, id: RequestId) -> Self {
        JsonRpcMessage::Response(JsonRpcResponse {
            jsonrpc: JsonRpcVersion2_0,
            id,
            result: response,
        })
    }
    #[inline]
    pub const fn error(error: ErrorData, id: Option<RequestId>) -> Self {
        JsonRpcMessage::Error(JsonRpcError {
            jsonrpc: JsonRpcVersion2_0,
            id,
            error,
        })
    }
    #[inline]
    pub const fn notification(notification: Not) -> Self {
        JsonRpcMessage::Notification(JsonRpcNotification {
            jsonrpc: JsonRpcVersion2_0,
            notification,
        })
    }
    pub fn into_request(self) -> Option<(Req, RequestId)> {
        match self {
            JsonRpcMessage::Request(r) => Some((r.request, r.id)),
            _ => None,
        }
    }
    pub fn into_response(self) -> Option<(Resp, RequestId)> {
        match self {
            JsonRpcMessage::Response(r) => Some((r.result, r.id)),
            _ => None,
        }
    }
    pub fn into_notification(self) -> Option<Not> {
        match self {
            JsonRpcMessage::Notification(n) => Some(n.notification),
            _ => None,
        }
    }
    pub fn into_error(self) -> Option<(ErrorData, Option<RequestId>)> {
        match self {
            JsonRpcMessage::Error(e) => Some((e.error, e.id)),
            _ => None,
        }
    }
    pub fn into_result(self) -> Option<(Result<Resp, ErrorData>, Option<RequestId>)> {
        match self {
            JsonRpcMessage::Response(r) => Some((Ok(r.result), Some(r.id))),
            JsonRpcMessage::Error(e) => Some((Err(e.error), e.id)),

            _ => None,
        }
    }
}

// =============================================================================
// INITIALIZATION AND CONNECTION SETUP
// =============================================================================

/// # Empty result
/// A response that indicates success but carries no data.
pub type EmptyResult = EmptyObject;

impl From<()> for EmptyResult {
    fn from(_value: ()) -> Self {
        EmptyResult {}
    }
}

impl From<EmptyResult> for () {
    fn from(_value: EmptyResult) {}
}

/// A catch-all response either side can use for custom requests.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(transparent)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CustomResult(pub Value);

impl CustomResult {
    pub fn new(result: Value) -> Self {
        Self(result)
    }

    /// Deserialize the result into a strongly-typed structure.
    pub fn result_as<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
        serde_json::from_value(self.0.clone())
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CancelledNotificationParam {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub request_id: Option<RequestId>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl CancelledNotificationParam {
    pub fn new(request_id: Option<RequestId>, reason: Option<String>) -> Self {
        Self {
            request_id,
            reason,
            meta: None,
        }
    }
}

const_string!(CancelledNotificationMethod = "notifications/cancelled");

/// # Cancellation
/// This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
///
/// The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
///
/// This notification indicates that the result will be unused, so any associated processing SHOULD cease.
///
/// A client MUST NOT attempt to cancel its `initialize` request.
pub type CancelledNotification =
    Notification<CancelledNotificationMethod, CancelledNotificationParam>;

/// A catch-all notification either side can use to send custom messages to its peer.
///
/// This preserves the raw `method` name and `params` payload so handlers can
/// deserialize them into domain-specific types.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CustomNotification {
    pub method: String,
    pub params: Option<Value>,
    /// extensions will carry anything possible in the context, including [`Meta`]
    ///
    /// this is similar with the Extensions in `http` crate
    #[cfg_attr(feature = "schemars", schemars(skip))]
    pub extensions: Extensions,
}

impl CustomNotification {
    pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
        Self {
            method: method.into(),
            params,
            extensions: Extensions::default(),
        }
    }

    /// Deserialize `params` into a strongly-typed structure.
    pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
        self.params
            .as_ref()
            .map(|params| serde_json::from_value(params.clone()))
            .transpose()
    }
}

/// A catch-all request either side can use to send custom messages to its peer.
///
/// This preserves the raw `method` name and `params` payload so handlers can
/// deserialize them into domain-specific types.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct CustomRequest {
    pub method: String,
    pub params: Option<Value>,
    /// extensions will carry anything possible in the context, including [`Meta`]
    ///
    /// this is similar with the Extensions in `http` crate
    #[cfg_attr(feature = "schemars", schemars(skip))]
    pub extensions: Extensions,
}

impl CustomRequest {
    pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
        Self {
            method: method.into(),
            params,
            extensions: Extensions::default(),
        }
    }

    /// Deserialize `params` into a strongly-typed structure.
    pub fn params_as<T: DeserializeOwned>(&self) -> Result<Option<T>, serde_json::Error> {
        self.params
            .as_ref()
            .map(|params| serde_json::from_value(params.clone()))
            .transpose()
    }
}

const_string!(InitializeResultMethod = "initialize");
/// # Initialization
/// This request is sent from the client to the server when it first connects, asking it to begin initialization.
pub type InitializeRequest = Request<InitializeResultMethod, InitializeRequestParams>;

const_string!(InitializedNotificationMethod = "notifications/initialized");
/// This notification is sent from the client to the server after initialization has finished.
pub type InitializedNotification = NotificationNoParam<InitializedNotificationMethod>;

/// Parameters sent by a client when initializing a connection to an MCP server.
///
/// This contains the client's protocol version, capabilities, and implementation
/// information, allowing the server to understand what the client supports.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct InitializeRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    /// The MCP protocol version this client supports
    pub protocol_version: ProtocolVersion,
    /// The capabilities this client supports (sampling, roots, etc.)
    pub capabilities: ClientCapabilities,
    /// Information about the client implementation
    pub client_info: Implementation,
}

impl InitializeRequestParams {
    /// Create a new InitializeRequestParams.
    pub fn new(capabilities: ClientCapabilities, client_info: Implementation) -> Self {
        Self {
            meta: None,
            protocol_version: ProtocolVersion::default(),
            capabilities,
            client_info,
        }
    }

    pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
        self.protocol_version = protocol_version;
        self
    }
}

impl RequestParamsMeta for InitializeRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`InitializeRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use InitializeRequestParams instead")]
pub type InitializeRequestParam = InitializeRequestParams;

/// The server's response to an initialization request.
///
/// Contains the server's protocol version, capabilities, and implementation
/// information, along with optional instructions for the client.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct InitializeResult {
    /// The MCP protocol version this server supports
    pub protocol_version: ProtocolVersion,
    /// The capabilities this server provides (tools, resources, prompts, etc.)
    pub capabilities: ServerCapabilities,
    /// Information about the server implementation
    pub server_info: Implementation,
    /// Optional human-readable instructions about using this server
    #[serde(skip_serializing_if = "Option::is_none")]
    pub instructions: Option<String>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl InitializeResult {
    /// Create a new `InitializeResult` with default protocol version and the given capabilities.
    pub fn new(capabilities: ServerCapabilities) -> Self {
        Self {
            protocol_version: ProtocolVersion::default(),
            capabilities,
            server_info: Implementation::from_build_env(),
            instructions: None,
            meta: None,
        }
    }

    /// Set instructions on this result.
    pub fn with_instructions(mut self, instructions: impl Into<String>) -> Self {
        self.instructions = Some(instructions.into());
        self
    }

    /// Set the server info on this result.
    pub fn with_server_info(mut self, server_info: Implementation) -> Self {
        self.server_info = server_info;
        self
    }

    /// Set the protocol version on this result.
    pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
        self.protocol_version = protocol_version;
        self
    }
}

pub type ServerInfo = InitializeResult;
pub type ClientInfo = InitializeRequestParams;

#[allow(clippy::derivable_impls)]
impl Default for ServerInfo {
    fn default() -> Self {
        ServerInfo {
            protocol_version: ProtocolVersion::default(),
            capabilities: ServerCapabilities::default(),
            server_info: Implementation::from_build_env(),
            instructions: None,
            meta: None,
        }
    }
}

#[allow(clippy::derivable_impls)]
impl Default for ClientInfo {
    fn default() -> Self {
        ClientInfo {
            meta: None,
            protocol_version: ProtocolVersion::default(),
            capabilities: ClientCapabilities::default(),
            client_info: Implementation::from_build_env(),
        }
    }
}

/// Icon themes supported by the MCP specification
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Copy)]
#[serde(rename_all = "lowercase")] //match spec
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub enum IconTheme {
    /// Indicates the icon is designed to be used with a light background
    Light,
    /// Indicates the icon is designed to be used with a dark background
    Dark,
}

/// A URL pointing to an icon resource or a base64-encoded data URI.
///
/// Clients that support rendering icons MUST support at least the following MIME types:
/// - image/png - PNG images (safe, universal compatibility)
/// - image/jpeg (and image/jpg) - JPEG images (safe, universal compatibility)
///
/// Clients that support rendering icons SHOULD also support:
/// - image/svg+xml - SVG images (scalable but requires security precautions)
/// - image/webp - WebP images (modern, efficient format)
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct Icon {
    /// A standard URI pointing to an icon resource
    pub src: String,
    /// Optional override if the server's MIME type is missing or generic
    #[serde(skip_serializing_if = "Option::is_none")]
    pub mime_type: Option<String>,
    /// Size specification, each string should be in WxH format (e.g., `\"48x48\"`, `\"96x96\"`) or `\"any\"` for scalable formats like SVG
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sizes: Option<Vec<String>>,
    /// Optional specifier for the theme this icon is designed for
    /// If not provided, the client should assume the icon can be used with any theme.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub theme: Option<IconTheme>,
}

impl Icon {
    /// Create a new Icon with the given source URL.
    pub fn new(src: impl Into<String>) -> Self {
        Self {
            src: src.into(),
            mime_type: None,
            sizes: None,
            theme: None,
        }
    }

    /// Set the MIME type.
    pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
        self.mime_type = Some(mime_type.into());
        self
    }

    /// Set the sizes.
    pub fn with_sizes(mut self, sizes: Vec<String>) -> Self {
        self.sizes = Some(sizes);
        self
    }

    /// Set the theme.
    pub fn with_theme(mut self, theme: IconTheme) -> Self {
        self.theme = Some(theme);
        self
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct Implementation {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
    pub version: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub icons: Option<Vec<Icon>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub website_url: Option<String>,
}

impl Default for Implementation {
    fn default() -> Self {
        Self::from_build_env()
    }
}

impl Implementation {
    /// Create a new Implementation.
    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            title: None,
            version: version.into(),
            description: None,
            icons: None,
            website_url: None,
        }
    }

    pub fn from_build_env() -> Self {
        Implementation {
            name: env!("CARGO_CRATE_NAME").to_owned(),
            title: None,
            version: env!("CARGO_PKG_VERSION").to_owned(),
            description: None,
            icons: None,
            website_url: None,
        }
    }

    /// Set the human-readable title.
    pub fn with_title(mut self, title: impl Into<String>) -> Self {
        self.title = Some(title.into());
        self
    }

    /// Set the description.
    pub fn with_description(mut self, description: impl Into<String>) -> Self {
        self.description = Some(description.into());
        self
    }

    /// Set the icons.
    pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
        self.icons = Some(icons);
        self
    }

    /// Set the website URL.
    pub fn with_website_url(mut self, website_url: impl Into<String>) -> Self {
        self.website_url = Some(website_url.into());
        self
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct PaginatedRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cursor: Option<String>,
}

impl PaginatedRequestParams {
    pub fn with_cursor(mut self, cursor: Option<String>) -> Self {
        self.cursor = cursor;
        self
    }
}

impl RequestParamsMeta for PaginatedRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`PaginatedRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use PaginatedRequestParams instead")]
pub type PaginatedRequestParam = PaginatedRequestParams;
// =============================================================================
// PROGRESS AND PAGINATION
// =============================================================================

const_string!(PingRequestMethod = "ping");
pub type PingRequest = RequestNoParam<PingRequestMethod>;

const_string!(ProgressNotificationMethod = "notifications/progress");
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ProgressNotificationParam {
    pub progress_token: ProgressToken,
    /// The progress thus far. This should increase every time progress is made, even if the total is unknown.
    pub progress: f64,
    /// Total number of items to process (or total progress required), if known
    #[serde(skip_serializing_if = "Option::is_none")]
    pub total: Option<f64>,
    /// An optional message describing the current progress.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl ProgressNotificationParam {
    /// Create a new ProgressNotificationParam with required fields.
    pub fn new(progress_token: ProgressToken, progress: f64) -> Self {
        Self {
            progress_token,
            progress,
            total: None,
            message: None,
            meta: None,
        }
    }

    /// Set the total number of items to process.
    pub fn with_total(mut self, total: f64) -> Self {
        self.total = Some(total);
        self
    }

    /// Set a message describing the current progress.
    pub fn with_message(mut self, message: impl Into<String>) -> Self {
        self.message = Some(message.into());
        self
    }
}

pub type ProgressNotification = Notification<ProgressNotificationMethod, ProgressNotificationParam>;

pub type Cursor = String;

macro_rules! paginated_result {
    ($t:ident {
        $i_item: ident: $t_item: ty
    }) => {
        #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
        #[serde(rename_all = "camelCase")]
        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
        #[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
        pub struct $t {
            #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
            pub meta: Option<Meta>,
            #[serde(skip_serializing_if = "Option::is_none")]
            pub next_cursor: Option<Cursor>,
            pub $i_item: $t_item,
        }

        impl $t {
            pub fn with_all_items(
                items: $t_item,
            ) -> Self {
                Self {
                    meta: None,
                    next_cursor: None,
                    $i_item: items,
                }
            }
        }
    };
}

// =============================================================================
// RESOURCE MANAGEMENT
// =============================================================================

const_string!(ListResourcesRequestMethod = "resources/list");
/// Request to list all available resources from a server
pub type ListResourcesRequest =
    RequestOptionalParam<ListResourcesRequestMethod, PaginatedRequestParams>;

paginated_result!(ListResourcesResult {
    resources: Vec<Resource>
});

const_string!(ListResourceTemplatesRequestMethod = "resources/templates/list");
/// Request to list all available resource templates from a server
pub type ListResourceTemplatesRequest =
    RequestOptionalParam<ListResourceTemplatesRequestMethod, PaginatedRequestParams>;

paginated_result!(ListResourceTemplatesResult {
    resource_templates: Vec<ResourceTemplate>
});

const_string!(ReadResourceRequestMethod = "resources/read");
/// Parameters for reading a specific resource
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ReadResourceRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    /// The URI of the resource to read
    pub uri: String,
}

impl ReadResourceRequestParams {
    /// Create a new ReadResourceRequestParams with the given URI.
    pub fn new(uri: impl Into<String>) -> Self {
        Self {
            meta: None,
            uri: uri.into(),
        }
    }

    /// Set the metadata for this request.
    pub fn with_meta(mut self, meta: Meta) -> Self {
        self.meta = Some(meta);
        self
    }
}

impl RequestParamsMeta for ReadResourceRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`ReadResourceRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use ReadResourceRequestParams instead")]
pub type ReadResourceRequestParam = ReadResourceRequestParams;

/// Result containing the contents of a read resource
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ReadResourceResult {
    /// The actual content of the resource
    pub contents: Vec<ResourceContents>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl ReadResourceResult {
    /// Create a new ReadResourceResult with the given contents.
    pub fn new(contents: Vec<ResourceContents>) -> Self {
        Self {
            contents,
            meta: None,
        }
    }
}

/// Request to read a specific resource
pub type ReadResourceRequest = Request<ReadResourceRequestMethod, ReadResourceRequestParams>;

const_string!(ResourceListChangedNotificationMethod = "notifications/resources/list_changed");
/// Notification sent when the list of available resources changes
pub type ResourceListChangedNotification =
    NotificationNoParam<ResourceListChangedNotificationMethod>;

const_string!(SubscribeRequestMethod = "resources/subscribe");
/// Parameters for subscribing to resource updates
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct SubscribeRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    /// The URI of the resource to subscribe to
    pub uri: String,
}

impl SubscribeRequestParams {
    /// Create a new SubscribeRequestParams.
    pub fn new(uri: impl Into<String>) -> Self {
        Self {
            meta: None,
            uri: uri.into(),
        }
    }
}

impl RequestParamsMeta for SubscribeRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`SubscribeRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use SubscribeRequestParams instead")]
pub type SubscribeRequestParam = SubscribeRequestParams;

/// Request to subscribe to resource updates
pub type SubscribeRequest = Request<SubscribeRequestMethod, SubscribeRequestParams>;

const_string!(UnsubscribeRequestMethod = "resources/unsubscribe");
/// Parameters for unsubscribing from resource updates
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct UnsubscribeRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    /// The URI of the resource to unsubscribe from
    pub uri: String,
}

impl UnsubscribeRequestParams {
    /// Creates a new `UnsubscribeRequestParams` for the given URI.
    pub fn new(uri: impl Into<String>) -> Self {
        Self {
            meta: None,
            uri: uri.into(),
        }
    }
}

impl RequestParamsMeta for UnsubscribeRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`UnsubscribeRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use UnsubscribeRequestParams instead")]
pub type UnsubscribeRequestParam = UnsubscribeRequestParams;

/// Request to unsubscribe from resource updates
pub type UnsubscribeRequest = Request<UnsubscribeRequestMethod, UnsubscribeRequestParams>;

const_string!(ResourceUpdatedNotificationMethod = "notifications/resources/updated");
/// Parameters for a resource update notification
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ResourceUpdatedNotificationParam {
    /// The URI of the resource that was updated
    pub uri: String,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl ResourceUpdatedNotificationParam {
    /// Create a new ResourceUpdatedNotificationParam.
    pub fn new(uri: impl Into<String>) -> Self {
        Self {
            uri: uri.into(),
            meta: None,
        }
    }
}

/// Notification sent when a subscribed resource is updated
pub type ResourceUpdatedNotification =
    Notification<ResourceUpdatedNotificationMethod, ResourceUpdatedNotificationParam>;

// =============================================================================
// PROMPT MANAGEMENT
// =============================================================================

const_string!(ListPromptsRequestMethod = "prompts/list");
/// Request to list all available prompts from a server
pub type ListPromptsRequest =
    RequestOptionalParam<ListPromptsRequestMethod, PaginatedRequestParams>;

paginated_result!(ListPromptsResult {
    prompts: Vec<Prompt>
});

const_string!(GetPromptRequestMethod = "prompts/get");
/// Parameters for retrieving a specific prompt
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct GetPromptRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub arguments: Option<JsonObject>,
}

impl GetPromptRequestParams {
    /// Create a new `GetPromptRequestParams` with the given prompt name.
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            meta: None,
            name: name.into(),
            arguments: None,
        }
    }

    /// Set the arguments for this prompt request.
    pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
        self.arguments = Some(arguments);
        self
    }

    /// Set the metadata for this request.
    pub fn with_meta(mut self, meta: Meta) -> Self {
        self.meta = Some(meta);
        self
    }
}

impl RequestParamsMeta for GetPromptRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`GetPromptRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use GetPromptRequestParams instead")]
pub type GetPromptRequestParam = GetPromptRequestParams;

/// Request to get a specific prompt
pub type GetPromptRequest = Request<GetPromptRequestMethod, GetPromptRequestParams>;

const_string!(PromptListChangedNotificationMethod = "notifications/prompts/list_changed");
/// Notification sent when the list of available prompts changes
pub type PromptListChangedNotification = NotificationNoParam<PromptListChangedNotificationMethod>;

const_string!(ToolListChangedNotificationMethod = "notifications/tools/list_changed");
/// Notification sent when the list of available tools changes
pub type ToolListChangedNotification = NotificationNoParam<ToolListChangedNotificationMethod>;

// =============================================================================
// LOGGING
// =============================================================================

/// Logging levels supported by the MCP protocol
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
#[serde(rename_all = "lowercase")] //match spec
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
#[deprecated(
    since = "2.0.0",
    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub enum LoggingLevel {
    Debug,
    Info,
    Notice,
    Warning,
    Error,
    Critical,
    Alert,
    Emergency,
}

const_string!(SetLevelRequestMethod = "logging/setLevel");
/// Parameters for setting the logging level
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct SetLevelRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    /// The desired logging level
    pub level: LoggingLevel,
}

impl SetLevelRequestParams {
    /// Create a new SetLevelRequestParams with the given logging level.
    pub fn new(level: LoggingLevel) -> Self {
        Self { meta: None, level }
    }
}

impl RequestParamsMeta for SetLevelRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`SetLevelRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use SetLevelRequestParams instead")]
pub type SetLevelRequestParam = SetLevelRequestParams;

/// Request to set the logging level
#[deprecated(
    since = "2.0.0",
    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub type SetLevelRequest = Request<SetLevelRequestMethod, SetLevelRequestParams>;

const_string!(LoggingMessageNotificationMethod = "notifications/message");
/// Parameters for a logging message notification
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct LoggingMessageNotificationParam {
    /// The severity level of this log message
    pub level: LoggingLevel,
    /// Optional logger name that generated this message
    #[serde(skip_serializing_if = "Option::is_none")]
    pub logger: Option<String>,
    /// The actual log data
    pub data: Value,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl LoggingMessageNotificationParam {
    /// Create a new LoggingMessageNotificationParam.
    pub fn new(level: LoggingLevel, data: Value) -> Self {
        Self {
            level,
            logger: None,
            data,
            meta: None,
        }
    }

    /// Set the logger name.
    pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
        self.logger = Some(logger.into());
        self
    }
}

/// Notification containing a log message
#[deprecated(
    since = "2.0.0",
    note = "Logging is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub type LoggingMessageNotification =
    Notification<LoggingMessageNotificationMethod, LoggingMessageNotificationParam>;

// =============================================================================
// SAMPLING (LLM INTERACTION)
// =============================================================================

const_string!(CreateMessageRequestMethod = "sampling/createMessage");
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub type CreateMessageRequest = Request<CreateMessageRequestMethod, CreateMessageRequestParams>;

/// Represents the role of a participant in a conversation or message exchange.
///
/// Used in sampling and chat contexts to distinguish between different
/// types of message senders in the conversation flow.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum Role {
    /// A human user or client making a request
    User,
    /// An AI assistant or server providing a response
    Assistant,
}

/// Tool selection mode (SEP-1577).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub enum ToolChoiceMode {
    /// Model decides whether to use tools
    #[default]
    Auto,
    /// Model must use at least one tool
    Required,
    /// Model must not use tools
    None,
}

/// Tool choice configuration (SEP-1577).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct ToolChoice {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub mode: Option<ToolChoiceMode>,
}

impl ToolChoice {
    pub fn auto() -> Self {
        Self {
            mode: Some(ToolChoiceMode::Auto),
        }
    }

    pub fn required() -> Self {
        Self {
            mode: Some(ToolChoiceMode::Required),
        }
    }

    pub fn none() -> Self {
        Self {
            mode: Some(ToolChoiceMode::None),
        }
    }
}

/// Single or array content wrapper (SEP-1577).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
pub enum SamplingContent<T> {
    Single(T),
    Multiple(Vec<T>),
}

impl<T> SamplingContent<T> {
    /// Convert to a Vec regardless of whether it's single or multiple
    pub fn into_vec(self) -> Vec<T> {
        match self {
            SamplingContent::Single(item) => vec![item],
            SamplingContent::Multiple(items) => items,
        }
    }

    /// Check if the content is empty
    pub fn is_empty(&self) -> bool {
        match self {
            SamplingContent::Single(_) => false,
            SamplingContent::Multiple(items) => items.is_empty(),
        }
    }

    /// Get the number of content items
    pub fn len(&self) -> usize {
        match self {
            SamplingContent::Single(_) => 1,
            SamplingContent::Multiple(items) => items.len(),
        }
    }
}

impl<T> Default for SamplingContent<T> {
    fn default() -> Self {
        SamplingContent::Multiple(Vec::new())
    }
}

impl<T> SamplingContent<T> {
    /// Get the first item if present
    pub fn first(&self) -> Option<&T> {
        match self {
            SamplingContent::Single(item) => Some(item),
            SamplingContent::Multiple(items) => items.first(),
        }
    }

    /// Iterate over all content items
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        let items: Vec<&T> = match self {
            SamplingContent::Single(item) => vec![item],
            SamplingContent::Multiple(items) => items.iter().collect(),
        };
        items.into_iter()
    }
}

impl SamplingMessageContentBlock {
    /// Get the text content if this is a Text variant
    pub fn as_text(&self) -> Option<&TextContent> {
        match self {
            SamplingMessageContentBlock::Text(text) => Some(text),
            _ => None,
        }
    }

    /// Get the tool use content if this is a ToolUse variant
    pub fn as_tool_use(&self) -> Option<&ToolUseContent> {
        match self {
            SamplingMessageContentBlock::ToolUse(tool_use) => Some(tool_use),
            _ => None,
        }
    }

    /// Get the tool result content if this is a ToolResult variant
    pub fn as_tool_result(&self) -> Option<&ToolResultContent> {
        match self {
            SamplingMessageContentBlock::ToolResult(tool_result) => Some(tool_result),
            _ => None,
        }
    }
}

impl<T> From<T> for SamplingContent<T> {
    fn from(item: T) -> Self {
        SamplingContent::Single(item)
    }
}

impl<T> From<Vec<T>> for SamplingContent<T> {
    fn from(items: Vec<T>) -> Self {
        SamplingContent::Multiple(items)
    }
}

/// A message in a sampling conversation, containing a role and content.
///
/// This represents a single message in a conversation flow, used primarily
/// in LLM sampling requests where the conversation history is important
/// for generating appropriate responses.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct SamplingMessage {
    /// The role of the message sender (User or Assistant)
    pub role: Role,
    /// The actual content of the message (text, image, audio, tool use, or tool result)
    pub content: SamplingContent<SamplingMessageContentBlock>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

/// Content types for sampling messages (SEP-1577).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub enum SamplingMessageContentBlock {
    Text(TextContent),
    Image(ImageContent),
    Audio(AudioContent),
    /// Assistant only
    ToolUse(ToolUseContent),
    /// User only
    ToolResult(ToolResultContent),
}

#[deprecated(since = "2.0.0", note = "Renamed to SamplingMessageContentBlock")]
pub type SamplingMessageContent = SamplingMessageContentBlock;

impl SamplingMessageContentBlock {
    /// Create a text content
    pub fn text(text: impl Into<String>) -> Self {
        Self::Text(TextContent::new(text))
    }

    pub fn tool_use(id: impl Into<String>, name: impl Into<String>, input: JsonObject) -> Self {
        Self::ToolUse(ToolUseContent::new(id, name, input))
    }

    pub fn tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
        Self::ToolResult(ToolResultContent::new(tool_use_id, content))
    }
}

impl SamplingMessage {
    pub fn new(role: Role, content: impl Into<SamplingMessageContentBlock>) -> Self {
        Self {
            role,
            content: SamplingContent::Single(content.into()),
            meta: None,
        }
    }

    pub fn new_multiple(role: Role, contents: Vec<SamplingMessageContentBlock>) -> Self {
        Self {
            role,
            content: SamplingContent::Multiple(contents),
            meta: None,
        }
    }

    pub fn user_text(text: impl Into<String>) -> Self {
        Self::new(Role::User, SamplingMessageContentBlock::text(text))
    }

    pub fn assistant_text(text: impl Into<String>) -> Self {
        Self::new(Role::Assistant, SamplingMessageContentBlock::text(text))
    }

    pub fn user_tool_result(tool_use_id: impl Into<String>, content: Vec<ContentBlock>) -> Self {
        Self::new(
            Role::User,
            SamplingMessageContentBlock::tool_result(tool_use_id, content),
        )
    }

    pub fn assistant_tool_use(
        id: impl Into<String>,
        name: impl Into<String>,
        input: JsonObject,
    ) -> Self {
        Self::new(
            Role::Assistant,
            SamplingMessageContentBlock::tool_use(id, name, input),
        )
    }
}

impl From<TextContent> for SamplingMessageContentBlock {
    fn from(text: TextContent) -> Self {
        SamplingMessageContentBlock::Text(text)
    }
}

// Conversion from String to SamplingMessageContentBlock (as text)
impl From<String> for SamplingMessageContentBlock {
    fn from(text: String) -> Self {
        SamplingMessageContentBlock::text(text)
    }
}

impl From<&str> for SamplingMessageContentBlock {
    fn from(text: &str) -> Self {
        SamplingMessageContentBlock::text(text)
    }
}

impl TryFrom<ContentBlock> for SamplingMessageContentBlock {
    type Error = &'static str;

    fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
        match content {
            ContentBlock::Text(text) => Ok(SamplingMessageContentBlock::Text(text)),
            ContentBlock::Image(image) => Ok(SamplingMessageContentBlock::Image(image)),
            ContentBlock::Audio(audio) => Ok(SamplingMessageContentBlock::Audio(audio)),
            ContentBlock::Resource(_) => {
                Err("Resource content is not supported in sampling messages")
            }
            ContentBlock::ResourceLink(_) => {
                Err("ResourceLink content is not supported in sampling messages")
            }
        }
    }
}

impl TryFrom<ContentBlock> for SamplingContent<SamplingMessageContentBlock> {
    type Error = &'static str;

    fn try_from(content: ContentBlock) -> Result<Self, Self::Error> {
        Ok(SamplingContent::Single(content.try_into()?))
    }
}

/// Specifies how much context should be included in sampling requests.
///
/// This allows clients to control what additional context information
/// should be provided to the LLM when processing sampling requests.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub enum ContextInclusion {
    /// Include context from all connected MCP servers
    #[serde(rename = "allServers")]
    AllServers,
    /// Include no additional context
    #[serde(rename = "none")]
    None,
    /// Include context only from the requesting server
    #[serde(rename = "thisServer")]
    ThisServer,
}

/// Parameters for creating a message through LLM sampling.
///
/// This structure contains all the necessary information for a client to
/// generate an LLM response, including conversation history, model preferences,
/// and generation parameters.
///
/// This implements `TaskAugmentedRequestParamsMeta` as sampling requests can be
/// long-running and may benefit from task-based execution.
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct CreateMessageRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    /// Task metadata for async task management (SEP-1319)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub task: Option<TaskMetadata>,
    /// The conversation history and current messages
    pub messages: Vec<SamplingMessage>,
    /// Preferences for model selection and behavior
    #[serde(skip_serializing_if = "Option::is_none")]
    pub model_preferences: Option<ModelPreferences>,
    /// System prompt to guide the model's behavior
    #[serde(skip_serializing_if = "Option::is_none")]
    pub system_prompt: Option<String>,
    /// How much context to include from MCP servers
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include_context: Option<ContextInclusion>,
    /// Temperature for controlling randomness (0.0 to 1.0)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub temperature: Option<f32>,
    /// Maximum number of tokens to generate
    pub max_tokens: u32,
    /// Sequences that should stop generation
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stop_sequences: Option<Vec<String>>,
    /// Additional metadata for the request
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<Value>,
    /// Tools available for the model to call (SEP-1577)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tools: Option<Vec<Tool>>,
    /// Tool selection behavior (SEP-1577)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tool_choice: Option<ToolChoice>,
}

impl RequestParamsMeta for CreateMessageRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

impl TaskAugmentedRequestParamsMeta for CreateMessageRequestParams {
    fn task(&self) -> Option<&TaskMetadata> {
        self.task.as_ref()
    }
    fn task_mut(&mut self) -> &mut Option<TaskMetadata> {
        &mut self.task
    }
}

impl CreateMessageRequestParams {
    /// Create a new CreateMessageRequestParams with required fields.
    pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
        Self {
            meta: None,
            task: None,
            messages,
            model_preferences: None,
            system_prompt: None,
            include_context: None,
            temperature: None,
            max_tokens,
            stop_sequences: None,
            metadata: None,
            tools: None,
            tool_choice: None,
        }
    }

    /// Set model preferences.
    pub fn with_model_preferences(mut self, model_preferences: ModelPreferences) -> Self {
        self.model_preferences = Some(model_preferences);
        self
    }

    /// Set system prompt.
    pub fn with_system_prompt(mut self, system_prompt: impl Into<String>) -> Self {
        self.system_prompt = Some(system_prompt.into());
        self
    }

    /// Set include context.
    pub fn with_include_context(mut self, include_context: ContextInclusion) -> Self {
        self.include_context = Some(include_context);
        self
    }

    /// Set temperature.
    pub fn with_temperature(mut self, temperature: f32) -> Self {
        self.temperature = Some(temperature);
        self
    }

    /// Set stop sequences.
    pub fn with_stop_sequences(mut self, stop_sequences: Vec<String>) -> Self {
        self.stop_sequences = Some(stop_sequences);
        self
    }

    /// Set metadata.
    pub fn with_metadata(mut self, metadata: Value) -> Self {
        self.metadata = Some(metadata);
        self
    }

    /// Set tools.
    pub fn with_tools(mut self, tools: Vec<Tool>) -> Self {
        self.tools = Some(tools);
        self
    }

    /// Set tool choice.
    pub fn with_tool_choice(mut self, tool_choice: ToolChoice) -> Self {
        self.tool_choice = Some(tool_choice);
        self
    }

    /// Validate the sampling request parameters per SEP-1577 spec requirements.
    ///
    /// Checks:
    /// - ToolUse content is only allowed in assistant messages
    /// - ToolResult content is only allowed in user messages
    /// - Messages with tool result content MUST NOT contain other content types
    /// - Every assistant ToolUse must be balanced with a corresponding user ToolResult
    pub fn validate(&self) -> Result<(), String> {
        for msg in &self.messages {
            for content in msg.content.iter() {
                // ToolUse only in assistant messages, ToolResult only in user messages
                match content {
                    SamplingMessageContentBlock::ToolUse(_) if msg.role != Role::Assistant => {
                        return Err("ToolUse content is only allowed in assistant messages".into());
                    }
                    SamplingMessageContentBlock::ToolResult(_) if msg.role != Role::User => {
                        return Err("ToolResult content is only allowed in user messages".into());
                    }
                    _ => {}
                }
            }

            // Tool result messages MUST NOT contain other content types
            let contents: Vec<_> = msg.content.iter().collect();
            let has_tool_result = contents
                .iter()
                .any(|c| matches!(c, SamplingMessageContentBlock::ToolResult(_)));
            if has_tool_result
                && contents
                    .iter()
                    .any(|c| !matches!(c, SamplingMessageContentBlock::ToolResult(_)))
            {
                return Err(
                    "SamplingMessage with tool result content MUST NOT contain other content types"
                        .into(),
                );
            }
        }

        // Every assistant ToolUse must be balanced with a user ToolResult
        self.validate_tool_use_result_balance()?;

        Ok(())
    }

    fn validate_tool_use_result_balance(&self) -> Result<(), String> {
        let mut pending_tool_use_ids: Vec<String> = Vec::new();
        for msg in &self.messages {
            if msg.role == Role::Assistant {
                for content in msg.content.iter() {
                    if let SamplingMessageContentBlock::ToolUse(tu) = content {
                        pending_tool_use_ids.push(tu.id.clone());
                    }
                }
            } else if msg.role == Role::User {
                for content in msg.content.iter() {
                    if let SamplingMessageContentBlock::ToolResult(tr) = content {
                        if !pending_tool_use_ids.contains(&tr.tool_use_id) {
                            return Err(format!(
                                "ToolResult with toolUseId '{}' has no matching ToolUse",
                                tr.tool_use_id
                            ));
                        }
                        pending_tool_use_ids.retain(|id| id != &tr.tool_use_id);
                    }
                }
            }
        }
        if !pending_tool_use_ids.is_empty() {
            return Err(format!(
                "ToolUse with id(s) {:?} not balanced with ToolResult",
                pending_tool_use_ids
            ));
        }
        Ok(())
    }
}

/// Deprecated: Use [`CreateMessageRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use CreateMessageRequestParams instead")]
pub type CreateMessageRequestParam = CreateMessageRequestParams;

/// Preferences for model selection and behavior in sampling requests.
///
/// This allows servers to express their preferences for which model to use
/// and how to balance different priorities when the client has multiple
/// model options available.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct ModelPreferences {
    /// Specific model names or families to prefer (e.g., "claude", "gpt")
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hints: Option<Vec<ModelHint>>,
    /// Priority for cost optimization (0.0 to 1.0, higher = prefer cheaper models)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cost_priority: Option<f32>,
    /// Priority for speed/latency (0.0 to 1.0, higher = prefer faster models)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub speed_priority: Option<f32>,
    /// Priority for intelligence/capability (0.0 to 1.0, higher = prefer more capable models)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub intelligence_priority: Option<f32>,
}

impl ModelPreferences {
    /// Create a new default ModelPreferences.
    pub fn new() -> Self {
        Self {
            hints: None,
            cost_priority: None,
            speed_priority: None,
            intelligence_priority: None,
        }
    }

    /// Set hints for model selection.
    pub fn with_hints(mut self, hints: Vec<ModelHint>) -> Self {
        self.hints = Some(hints);
        self
    }

    /// Set cost priority (0.0 to 1.0).
    pub fn with_cost_priority(mut self, cost_priority: f32) -> Self {
        self.cost_priority = Some(cost_priority);
        self
    }

    /// Set speed priority (0.0 to 1.0).
    pub fn with_speed_priority(mut self, speed_priority: f32) -> Self {
        self.speed_priority = Some(speed_priority);
        self
    }

    /// Set intelligence priority (0.0 to 1.0).
    pub fn with_intelligence_priority(mut self, intelligence_priority: f32) -> Self {
        self.intelligence_priority = Some(intelligence_priority);
        self
    }
}

impl Default for ModelPreferences {
    fn default() -> Self {
        Self::new()
    }
}

/// A hint suggesting a preferred model name or family.
///
/// Model hints are advisory suggestions that help clients choose appropriate
/// models. They can be specific model names or general families like "claude" or "gpt".
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct ModelHint {
    /// The suggested model name or family identifier
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl ModelHint {
    /// Create a new ModelHint with a name.
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: Some(name.into()),
        }
    }
}

// =============================================================================
// COMPLETION AND AUTOCOMPLETE
// =============================================================================

/// Context for completion requests providing previously resolved arguments.
///
/// This enables context-aware completion where subsequent argument completions
/// can take into account the values of previously resolved arguments.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CompletionContext {
    /// Previously resolved argument values that can inform completion suggestions
    #[serde(skip_serializing_if = "Option::is_none")]
    pub arguments: Option<std::collections::HashMap<String, String>>,
}

impl CompletionContext {
    /// Create a new empty completion context
    pub fn new() -> Self {
        Self::default()
    }

    /// Create a completion context with the given arguments
    pub fn with_arguments(arguments: std::collections::HashMap<String, String>) -> Self {
        Self {
            arguments: Some(arguments),
        }
    }

    /// Get a specific argument value by name
    pub fn get_argument(&self, name: &str) -> Option<&String> {
        self.arguments.as_ref()?.get(name)
    }

    /// Check if the context has any arguments
    pub fn has_arguments(&self) -> bool {
        self.arguments.as_ref().is_some_and(|args| !args.is_empty())
    }

    /// Get all argument names
    pub fn argument_names(&self) -> impl Iterator<Item = &str> {
        self.arguments
            .as_ref()
            .into_iter()
            .flat_map(|args| args.keys())
            .map(|k| k.as_str())
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CompleteRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    pub r#ref: Reference,
    pub argument: ArgumentInfo,
    /// Optional context containing previously resolved argument values
    #[serde(skip_serializing_if = "Option::is_none")]
    pub context: Option<CompletionContext>,
}

impl CompleteRequestParams {
    /// Create a new CompleteRequestParams with required fields.
    pub fn new(r#ref: Reference, argument: ArgumentInfo) -> Self {
        Self {
            meta: None,
            r#ref,
            argument,
            context: None,
        }
    }

    /// Set the completion context
    pub fn with_context(mut self, context: CompletionContext) -> Self {
        self.context = Some(context);
        self
    }
}

impl RequestParamsMeta for CompleteRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`CompleteRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use CompleteRequestParams instead")]
pub type CompleteRequestParam = CompleteRequestParams;

pub type CompleteRequest = Request<CompleteRequestMethod, CompleteRequestParams>;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CompletionInfo {
    pub values: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub total: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub has_more: Option<bool>,
}

impl CompletionInfo {
    /// Maximum number of completion values allowed per response according to MCP specification
    pub const MAX_VALUES: usize = 100;

    /// Create a new CompletionInfo with validation for maximum values
    pub fn new(values: Vec<String>) -> Result<Self, String> {
        if values.len() > Self::MAX_VALUES {
            return Err(format!(
                "Too many completion values: {} (max: {})",
                values.len(),
                Self::MAX_VALUES
            ));
        }
        Ok(Self {
            values,
            total: None,
            has_more: None,
        })
    }

    /// Create CompletionInfo with all values and no pagination
    pub fn with_all_values(values: Vec<String>) -> Result<Self, String> {
        let completion = Self::new(values)?;
        Ok(Self {
            total: Some(completion.values.len() as u32),
            has_more: Some(false),
            ..completion
        })
    }

    /// Create CompletionInfo with pagination information
    pub fn with_pagination(
        values: Vec<String>,
        total: Option<u32>,
        has_more: bool,
    ) -> Result<Self, String> {
        let completion = Self::new(values)?;
        Ok(Self {
            total,
            has_more: Some(has_more),
            ..completion
        })
    }

    /// Check if this completion response indicates more results are available
    pub fn has_more_results(&self) -> bool {
        self.has_more.unwrap_or(false)
    }

    /// Get the total number of available completions, if known
    pub fn total_available(&self) -> Option<u32> {
        self.total
    }

    /// Validate that the completion info complies with MCP specification
    pub fn validate(&self) -> Result<(), String> {
        if self.values.len() > Self::MAX_VALUES {
            return Err(format!(
                "Too many completion values: {} (max: {})",
                self.values.len(),
                Self::MAX_VALUES
            ));
        }
        Ok(())
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CompleteResult {
    pub completion: CompletionInfo,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl CompleteResult {
    /// Create a new CompleteResult with the given completion info.
    pub fn new(completion: CompletionInfo) -> Self {
        Self {
            completion,
            meta: None,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(tag = "type")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub enum Reference {
    #[serde(rename = "ref/resource")]
    Resource(ResourceTemplateReference),
    #[serde(rename = "ref/prompt")]
    Prompt(PromptReference),
}

impl Reference {
    /// Create a prompt reference
    pub fn for_prompt(name: impl Into<String>) -> Self {
        // Not accepting `title` currently as it'll break the API
        // Until further decision, keep it `None`, modify later
        // if required, add `title` to the API
        Self::Prompt(PromptReference {
            name: name.into(),
            title: None,
        })
    }

    /// Create a resource reference
    pub fn for_resource(uri: impl Into<String>) -> Self {
        Self::Resource(ResourceTemplateReference { uri: uri.into() })
    }

    /// Get the reference type as a string
    pub fn reference_type(&self) -> &'static str {
        match self {
            Self::Prompt(_) => "ref/prompt",
            Self::Resource(_) => "ref/resource",
        }
    }

    /// Extract prompt name if this is a prompt reference
    pub fn as_prompt_name(&self) -> Option<&str> {
        match self {
            Self::Prompt(prompt_ref) => Some(&prompt_ref.name),
            _ => None,
        }
    }

    /// Extract resource URI if this is a resource reference
    pub fn as_resource_uri(&self) -> Option<&str> {
        match self {
            Self::Resource(resource_ref) => Some(&resource_ref.uri),
            _ => None,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ResourceTemplateReference {
    pub uri: String,
}

impl ResourceTemplateReference {
    pub fn new(uri: impl Into<String>) -> Self {
        Self { uri: uri.into() }
    }
}

#[deprecated(since = "2.0.0", note = "Renamed to ResourceTemplateReference")]
pub type ResourceReference = ResourceTemplateReference;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct PromptReference {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
}

impl PromptReference {
    /// Creates a new `PromptReference` with the given name. `title` defaults to `None`.
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            title: None,
        }
    }

    /// Sets the human-readable title for this prompt reference.
    pub fn with_title(mut self, title: impl Into<String>) -> Self {
        self.title = Some(title.into());
        self
    }
}

const_string!(CompleteRequestMethod = "completion/complete");
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ArgumentInfo {
    pub name: String,
    pub value: String,
}

impl ArgumentInfo {
    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            value: value.into(),
        }
    }
}

// =============================================================================
// ROOTS AND WORKSPACE MANAGEMENT
// =============================================================================

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct Root {
    pub uri: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl Root {
    /// Creates a new `Root` with the given URI. `name` defaults to `None`.
    pub fn new(uri: impl Into<String>) -> Self {
        Self {
            uri: uri.into(),
            name: None,
            meta: None,
        }
    }

    /// Sets the human-readable name for this root.
    pub fn with_name(mut self, name: impl Into<String>) -> Self {
        self.name = Some(name.into());
        self
    }

    /// Sets the protocol-level metadata for this root.
    pub fn with_meta(mut self, meta: Meta) -> Self {
        self.meta = Some(meta);
        self
    }
}

const_string!(ListRootsRequestMethod = "roots/list");
#[deprecated(
    since = "2.0.0",
    note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub type ListRootsRequest = RequestNoParam<ListRootsRequestMethod>;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Roots is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct ListRootsResult {
    pub roots: Vec<Root>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl ListRootsResult {
    /// Creates a new `ListRootsResult` with the given roots.
    pub fn new(roots: Vec<Root>) -> Self {
        Self { roots, meta: None }
    }

    /// Sets the protocol-level metadata for this result.
    pub fn with_meta(mut self, meta: Meta) -> Self {
        self.meta = Some(meta);
        self
    }
}

const_string!(RootsListChangedNotificationMethod = "notifications/roots/list_changed");
pub type RootsListChangedNotification = NotificationNoParam<RootsListChangedNotificationMethod>;

// =============================================================================
// ELICITATION (INTERACTIVE USER INPUT)
// =============================================================================

// Method constants for elicitation operations.
// Elicitation allows servers to request interactive input from users during tool execution.
const_string!(ElicitationCreateRequestMethod = "elicitation/create");
const_string!(ElicitationResponseNotificationMethod = "notifications/elicitation/response");
const_string!(ElicitationCompletionNotificationMethod = "notifications/elicitation/complete");

/// Represents the possible actions a user can take in response to an elicitation request.
///
/// When a server requests user input through elicitation, the user can:
/// - Accept: Provide the requested information and continue
/// - Decline: Refuse to provide the information but continue the operation
/// - Cancel: Stop the entire operation
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub enum ElicitationAction {
    /// User accepts the request and provides the requested information
    Accept,
    /// User declines to provide the information but allows the operation to continue
    Decline,
    /// User cancels the entire operation
    Cancel,
}

/// Helper enum for deserializing CreateElicitationRequestParam with backward compatibility.
/// When mode is missing, it defaults to FormElicitationParam.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(tag = "mode")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
enum CreateElicitationRequestParamDeserializeHelper {
    #[serde(rename = "form", rename_all = "camelCase")]
    FormElicitationParam {
        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
        meta: Option<Meta>,
        message: String,
        requested_schema: ElicitationSchema,
    },
    #[serde(rename = "url", rename_all = "camelCase")]
    UrlElicitationParam {
        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
        meta: Option<Meta>,
        message: String,
        url: String,
        elicitation_id: String,
    },
    #[serde(untagged, rename_all = "camelCase")]
    FormElicitationParamBackwardsCompat {
        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
        meta: Option<Meta>,
        message: String,
        requested_schema: ElicitationSchema,
    },
}

impl TryFrom<CreateElicitationRequestParamDeserializeHelper> for ElicitRequestParams {
    type Error = serde_json::Error;

    fn try_from(
        value: CreateElicitationRequestParamDeserializeHelper,
    ) -> Result<Self, Self::Error> {
        match value {
            CreateElicitationRequestParamDeserializeHelper::FormElicitationParam {
                meta,
                message,
                requested_schema,
            }
            | CreateElicitationRequestParamDeserializeHelper::FormElicitationParamBackwardsCompat {
                meta,
                message,
                requested_schema,
            } => Ok(ElicitRequestParams::FormElicitationParams {
                meta,
                message,
                requested_schema,
            }),
            CreateElicitationRequestParamDeserializeHelper::UrlElicitationParam {
                meta,
                message,
                url,
                elicitation_id,
            } => Ok(ElicitRequestParams::UrlElicitationParams {
                meta,
                message,
                url,
                elicitation_id,
            }),
        }
    }
}

/// Parameters for creating an elicitation request to gather user input.
///
/// This structure contains everything needed to request interactive input from a user:
/// - A human-readable message explaining what information is needed
/// - A type-safe schema defining the expected structure of the response
///
/// # Example
/// 1. Form-based elicitation request
/// ```rust
/// use rmcp::model::*;
///
/// let params = ElicitRequestParams::FormElicitationParams {
///    meta: None,
///     message: "Please provide your email".to_string(),
///     requested_schema: ElicitationSchema::builder()
///         .required_email("email")
///         .build()
///         .unwrap(),
/// };
/// ```
/// 2. URL-based elicitation request
/// ```rust
/// use rmcp::model::*;
/// let params = ElicitRequestParams::UrlElicitationParams {
///     meta: None,
///     message: "Please provide your feedback at the following URL".to_string(),
///     url: "https://example.com/feedback".to_string(),
///     elicitation_id: "unique-id-123".to_string(),
/// };
/// ```
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(
    tag = "mode",
    try_from = "CreateElicitationRequestParamDeserializeHelper"
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub enum ElicitRequestParams {
    #[serde(rename = "form", rename_all = "camelCase")]
    FormElicitationParams {
        /// Protocol-level metadata for this request (SEP-1319)
        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
        meta: Option<Meta>,
        /// Human-readable message explaining what input is needed from the user.
        /// This should be clear and provide sufficient context for the user to understand
        /// what information they need to provide.
        message: String,

        /// Type-safe schema defining the expected structure and validation rules for the user's response.
        /// This enforces the MCP 2025-06-18 specification that elicitation schemas must be objects
        /// with primitive-typed properties.
        requested_schema: ElicitationSchema,
    },
    #[serde(rename = "url", rename_all = "camelCase")]
    UrlElicitationParams {
        /// Protocol-level metadata for this request (SEP-1319)
        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
        meta: Option<Meta>,
        /// Human-readable message explaining what input is needed from the user.
        /// This should be clear and provide sufficient context for the user to understand
        /// what information they need to provide.
        message: String,

        /// The URL where the user can provide the requested information.
        /// The client should direct the user to this URL to complete the elicitation.
        url: String,
        /// The unique identifier for this elicitation request.
        elicitation_id: String,
    },
}

impl RequestParamsMeta for ElicitRequestParams {
    fn meta(&self) -> Option<&Meta> {
        match self {
            ElicitRequestParams::FormElicitationParams { meta, .. } => meta.as_ref(),
            ElicitRequestParams::UrlElicitationParams { meta, .. } => meta.as_ref(),
        }
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        match self {
            ElicitRequestParams::FormElicitationParams { meta, .. } => meta,
            ElicitRequestParams::UrlElicitationParams { meta, .. } => meta,
        }
    }
}

/// Deprecated: Use [`ElicitRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use ElicitRequestParams instead")]
pub type CreateElicitationRequestParam = ElicitRequestParams;

#[deprecated(since = "2.0.0", note = "Renamed to ElicitRequestParams")]
pub type CreateElicitationRequestParams = ElicitRequestParams;

/// The result returned by a client in response to an elicitation request.
///
/// Contains the user's decision (accept/decline/cancel) and optionally their input data
/// if they chose to accept the request.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ElicitResult {
    /// The user's decision on how to handle the elicitation request
    pub action: ElicitationAction,

    /// The actual data provided by the user, if they accepted the request.
    /// Must conform to the JSON schema specified in the original request.
    /// Only present when action is Accept.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content: Option<Value>,

    /// Optional protocol-level metadata for this result.
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl ElicitResult {
    /// Create a new ElicitResult.
    pub fn new(action: ElicitationAction) -> Self {
        Self {
            action,
            content: None,
            meta: None,
        }
    }

    /// Set the content on this result.
    pub fn with_content(mut self, content: Value) -> Self {
        self.content = Some(content);
        self
    }

    /// Set the metadata on this result.
    pub fn with_meta(mut self, meta: Meta) -> Self {
        self.meta = Some(meta);
        self
    }
}

#[deprecated(since = "2.0.0", note = "Renamed to ElicitResult")]
pub type CreateElicitationResult = ElicitResult;

/// Request type for creating an elicitation to gather user input
pub type ElicitRequest = Request<ElicitationCreateRequestMethod, ElicitRequestParams>;

#[deprecated(since = "2.0.0", note = "Renamed to ElicitRequest")]
pub type CreateElicitationRequest = ElicitRequest;

/// Notification parameters for an url elicitation completion notification.
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ElicitationResponseNotificationParam {
    pub elicitation_id: String,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl ElicitationResponseNotificationParam {
    /// Create a new ElicitationResponseNotificationParam.
    pub fn new(elicitation_id: impl Into<String>) -> Self {
        Self {
            elicitation_id: elicitation_id.into(),
            meta: None,
        }
    }
}

/// Notification sent when an url elicitation process is completed.
pub type ElicitationCompleteNotification =
    Notification<ElicitationCompletionNotificationMethod, ElicitationResponseNotificationParam>;

#[deprecated(since = "2.0.0", note = "Renamed to ElicitationCompleteNotification")]
pub type ElicitationCompletionNotification = ElicitationCompleteNotification;

// =============================================================================
// TOOL EXECUTION RESULTS
// =============================================================================

/// The result of a tool call operation.
///
/// Contains the content returned by the tool execution and an optional
/// flag indicating whether the operation resulted in an error.
#[derive(Default, Debug, Serialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CallToolResult {
    /// The content returned by the tool (text, images, etc.)
    #[serde(default)]
    pub content: Vec<ContentBlock>,
    /// An optional JSON object that represents the structured result of the tool call
    #[serde(skip_serializing_if = "Option::is_none")]
    pub structured_content: Option<Value>,
    /// Whether this result represents an error condition
    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_error: Option<bool>,
    /// Optional protocol-level metadata for this result
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

// Custom Deserialize implementation that:
// 1. Defaults `content` to `[]` when the field is missing (lenient per Postel's law)
// 2. Requires at least one known field to be present, so that `CallToolResult` doesn't
//    greedily match arbitrary JSON objects when used inside `#[serde(untagged)]` enums
//    (e.g. `ServerResult`), which would shadow `CustomResult`.
impl<'de> Deserialize<'de> for CallToolResult {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        #[derive(Deserialize)]
        #[serde(rename_all = "camelCase")]
        struct Helper {
            content: Option<Vec<ContentBlock>>,
            structured_content: Option<Value>,
            is_error: Option<bool>,
            #[serde(rename = "_meta")]
            meta: Option<Meta>,
        }

        let helper = Helper::deserialize(deserializer)?;

        if helper.content.is_none()
            && helper.structured_content.is_none()
            && helper.is_error.is_none()
            && helper.meta.is_none()
        {
            return Err(serde::de::Error::custom(
                "expected at least one known CallToolResult field \
                 (content, structuredContent, isError, or _meta)",
            ));
        }

        Ok(CallToolResult {
            content: helper.content.unwrap_or_default(),
            structured_content: helper.structured_content,
            is_error: helper.is_error,
            meta: helper.meta,
        })
    }
}

impl CallToolResult {
    /// Create a successful tool result with unstructured content
    pub fn success(content: Vec<ContentBlock>) -> Self {
        CallToolResult {
            content,
            structured_content: None,
            is_error: Some(false),
            meta: None,
        }
    }

    /// Create a tool-level error result with caller-visible content.
    ///
    /// # When to use this vs `Err(ErrorData)`
    ///
    /// MCP distinguishes two failure modes for a `call_tool` invocation, and
    /// the right one to use depends on **whose problem it is**:
    ///
    /// - **Tool-level error** — `Ok(CallToolResult::error(...))`.
    ///   The request was valid and routed to your tool, but executing the
    ///   tool failed in a way the caller should see (a query returned no
    ///   rows, an external API returned 500, the user's input is plausible
    ///   but produced no result, etc.). The caller's MCP client renders the
    ///   `content` you provide; your message reaches the user. **This is the
    ///   right choice for almost every "the tool ran and didn't work" case.**
    ///
    /// - **Protocol error** — `Err(ErrorData)` with a JSON-RPC code.
    ///   The server cannot route the request at all, or an infrastructure
    ///   error makes the server itself unusable
    ///   ([`ErrorCode::INTERNAL_ERROR`], `-32603`). MCP clients typically
    ///   render protocol errors opaquely (e.g. "Tool result missing due to
    ///   internal error") — the caller does **not** see your message.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use rmcp::model::{CallToolResult, Content, ErrorData};
    ///
    /// async fn lookup(query: &str) -> Result<CallToolResult, ErrorData> {
    ///     // Caller passed a malformed query — the server can't run anything.
    ///     // This is a protocol error, the caller's client will render it
    ///     // as -32602 invalid_params:
    ///     if query.is_empty() {
    ///         return Err(ErrorData::invalid_params("query must be non-empty", None));
    ///     }
    ///
    ///     // Tool ran, no result. Caller should see the explanation:
    ///     let rows = run_query(query).await;
    ///     if rows.is_empty() {
    ///         return Ok(CallToolResult::error(vec![ContentBlock::text(
    ///             format!("no rows matched '{query}'"),
    ///         )]));
    ///     }
    ///
    ///     Ok(CallToolResult::success(vec![ContentBlock::text(format_rows(&rows))]))
    /// }
    /// # async fn run_query(_: &str) -> Vec<&'static str> { vec![] }
    /// # fn format_rows(_: &[&str]) -> String { String::new() }
    /// ```
    pub fn error(content: Vec<ContentBlock>) -> Self {
        CallToolResult {
            content,
            structured_content: None,
            is_error: Some(true),
            meta: None,
        }
    }
    /// Create a successful tool result with structured content
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use rmcp::model::CallToolResult;
    /// use serde_json::json;
    ///
    /// let result = CallToolResult::structured(json!({
    ///     "temperature": 22.5,
    ///     "humidity": 65,
    ///     "description": "Partly cloudy"
    /// }));
    /// ```
    pub fn structured(value: Value) -> Self {
        CallToolResult {
            content: vec![ContentBlock::text(value.to_string())],
            structured_content: Some(value),
            is_error: Some(false),
            meta: None,
        }
    }
    /// Create an error tool result with structured content
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use rmcp::model::CallToolResult;
    /// use serde_json::json;
    ///
    /// let result = CallToolResult::structured_error(json!({
    ///     "error_code": "INVALID_INPUT",
    ///     "message": "Temperature value out of range",
    ///     "details": {
    ///         "min": -50,
    ///         "max": 50,
    ///         "provided": 100
    ///     }
    /// }));
    /// ```
    pub fn structured_error(value: Value) -> Self {
        CallToolResult {
            content: vec![ContentBlock::text(value.to_string())],
            structured_content: Some(value),
            is_error: Some(true),
            meta: None,
        }
    }

    /// Set the metadata on this result
    pub fn with_meta(mut self, meta: Option<Meta>) -> Self {
        self.meta = meta;
        self
    }

    /// Convert the `structured_content` part of response into a certain type.
    ///
    /// # About json schema validation
    /// Since rust is a strong type language, we don't need to do json schema validation here.
    ///
    /// But if you do have to validate the response data, you can use [`jsonschema`](https://crates.io/crates/jsonschema) crate.
    pub fn into_typed<T>(self) -> Result<T, serde_json::Error>
    where
        T: DeserializeOwned,
    {
        let raw_text = match (self.structured_content, &self.content.first()) {
            (Some(value), _) => return serde_json::from_value(value),
            (None, Some(contents)) => {
                if let Some(text) = contents.as_text() {
                    let text = &text.text;
                    Some(text)
                } else {
                    None
                }
            }
            (None, None) => None,
        };
        if let Some(text) = raw_text {
            return serde_json::from_str(text);
        }
        serde_json::from_value(serde_json::Value::Null)
    }
}

const_string!(ListToolsRequestMethod = "tools/list");
/// Request to list all available tools from a server
pub type ListToolsRequest = RequestOptionalParam<ListToolsRequestMethod, PaginatedRequestParams>;

paginated_result!(
    ListToolsResult {
        tools: Vec<Tool>
    }
);

const_string!(CallToolRequestMethod = "tools/call");
/// Parameters for calling a tool provided by an MCP server.
///
/// Contains the tool name and optional arguments needed to execute
/// the tool operation.
///
/// This implements `TaskAugmentedRequestParamsMeta` as tool calls can be
/// long-running and may benefit from task-based execution.
#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CallToolRequestParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    /// The name of the tool to call
    pub name: Cow<'static, str>,
    /// Arguments to pass to the tool (must match the tool's input schema)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub arguments: Option<JsonObject>,
    /// Task metadata for async task management (SEP-1319)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub task: Option<TaskMetadata>,
}

impl CallToolRequestParams {
    /// Creates a new `CallToolRequestParams` with the given tool name.
    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
        Self {
            meta: None,
            name: name.into(),
            arguments: None,
            task: None,
        }
    }

    /// Sets the arguments for this tool call.
    pub fn with_arguments(mut self, arguments: JsonObject) -> Self {
        self.arguments = Some(arguments);
        self
    }

    /// Sets the task metadata for this tool call.
    pub fn with_task(mut self, task: TaskMetadata) -> Self {
        self.task = Some(task);
        self
    }
}

impl RequestParamsMeta for CallToolRequestParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

impl TaskAugmentedRequestParamsMeta for CallToolRequestParams {
    fn task(&self) -> Option<&TaskMetadata> {
        self.task.as_ref()
    }
    fn task_mut(&mut self) -> &mut Option<TaskMetadata> {
        &mut self.task
    }
}

/// Deprecated: Use [`CallToolRequestParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use CallToolRequestParams instead")]
pub type CallToolRequestParam = CallToolRequestParams;

/// Request to call a specific tool
pub type CallToolRequest = Request<CallToolRequestMethod, CallToolRequestParams>;

/// Result of sampling/createMessage (SEP-1577).
/// The result of a sampling/createMessage request containing the generated response.
///
/// This structure contains the generated message along with metadata about
/// how the generation was performed and why it stopped.
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
#[deprecated(
    since = "2.0.0",
    note = "Sampling is deprecated by SEP-2577 and will be removed in a future release. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577"
)]
pub struct CreateMessageResult {
    /// The identifier of the model that generated the response
    pub model: String,
    /// The reason why generation stopped (e.g., "endTurn", "maxTokens")
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stop_reason: Option<String>,
    /// The generated message with role and content
    #[serde(flatten)]
    pub message: SamplingMessage,
}

impl CreateMessageResult {
    /// Create a new CreateMessageResult with required fields.
    pub fn new(message: SamplingMessage, model: String) -> Self {
        Self {
            message,
            model,
            stop_reason: None,
        }
    }

    pub const STOP_REASON_END_TURN: &str = "endTurn";
    pub const STOP_REASON_END_SEQUENCE: &str = "stopSequence";
    pub const STOP_REASON_END_MAX_TOKEN: &str = "maxTokens";
    pub const STOP_REASON_TOOL_USE: &str = "toolUse";

    /// Set the stop reason.
    pub fn with_stop_reason(mut self, stop_reason: impl Into<String>) -> Self {
        self.stop_reason = Some(stop_reason.into());
        self
    }

    /// Set the model identifier.
    pub fn with_model(mut self, model: impl Into<String>) -> Self {
        self.model = model.into();
        self
    }

    /// Validate the result per SEP-1577: role must be "assistant".
    pub fn validate(&self) -> Result<(), String> {
        if self.message.role != Role::Assistant {
            return Err("CreateMessageResult role must be 'assistant'".into());
        }
        Ok(())
    }
}

#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct GetPromptResult {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub messages: Vec<PromptMessage>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl GetPromptResult {
    /// Create a new GetPromptResult with required fields.
    pub fn new(messages: Vec<PromptMessage>) -> Self {
        Self {
            description: None,
            messages,
            meta: None,
        }
    }

    /// Set the description
    pub fn with_description<D: Into<String>>(mut self, description: D) -> Self {
        self.description = Some(description.into());
        self
    }
}

// =============================================================================
// TASK MANAGEMENT
// =============================================================================

const_string!(GetTaskMethod = "tasks/get");
pub type GetTaskRequest = Request<GetTaskMethod, GetTaskParams>;

#[deprecated(since = "2.0.0", note = "Renamed to GetTaskMethod")]
pub type GetTaskInfoMethod = GetTaskMethod;
#[deprecated(since = "2.0.0", note = "Renamed to GetTaskRequest")]
pub type GetTaskInfoRequest = GetTaskRequest;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct GetTaskParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    pub task_id: String,
}

impl GetTaskParams {
    pub fn new(task_id: impl Into<String>) -> Self {
        Self {
            meta: None,
            task_id: task_id.into(),
        }
    }
}

impl RequestParamsMeta for GetTaskParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

#[deprecated(since = "2.0.0", note = "Renamed to GetTaskParams")]
pub type GetTaskInfoParams = GetTaskParams;

#[deprecated(since = "0.13.0", note = "Use GetTaskParams instead")]
pub type GetTaskInfoParam = GetTaskParams;

const_string!(ListTasksMethod = "tasks/list");
pub type ListTasksRequest = RequestOptionalParam<ListTasksMethod, PaginatedRequestParams>;

const_string!(GetTaskPayloadMethod = "tasks/result");
pub type GetTaskPayloadRequest = Request<GetTaskPayloadMethod, GetTaskPayloadParams>;

#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadMethod")]
pub type GetTaskResultMethod = GetTaskPayloadMethod;
#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadRequest")]
pub type GetTaskResultRequest = GetTaskPayloadRequest;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct GetTaskPayloadParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    pub task_id: String,
}

impl GetTaskPayloadParams {
    pub fn new(task_id: impl Into<String>) -> Self {
        Self {
            meta: None,
            task_id: task_id.into(),
        }
    }
}

impl RequestParamsMeta for GetTaskPayloadParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadParams")]
pub type GetTaskResultParams = GetTaskPayloadParams;
#[deprecated(since = "2.0.0", note = "Renamed to GetTaskPayloadParams")]
pub type GetTaskResultParam = GetTaskPayloadParams;

const_string!(CancelTaskMethod = "tasks/cancel");
pub type CancelTaskRequest = Request<CancelTaskMethod, CancelTaskParams>;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct CancelTaskParams {
    /// Protocol-level metadata for this request (SEP-1319)
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    pub task_id: String,
}

impl CancelTaskParams {
    pub fn new(task_id: impl Into<String>) -> Self {
        Self {
            meta: None,
            task_id: task_id.into(),
        }
    }
}

impl RequestParamsMeta for CancelTaskParams {
    fn meta(&self) -> Option<&Meta> {
        self.meta.as_ref()
    }
    fn meta_mut(&mut self) -> &mut Option<Meta> {
        &mut self.meta
    }
}

/// Deprecated: Use [`CancelTaskParams`] instead (SEP-1319 compliance).
#[deprecated(since = "0.13.0", note = "Use CancelTaskParams instead")]
pub type CancelTaskParam = CancelTaskParams;

// ---------------------------------------------------------------------------
// Task status notification (spec `notifications/tasks/status`)
// ---------------------------------------------------------------------------
const_string!(TaskStatusNotificationMethod = "notifications/tasks/status");

/// Parameters for a task status notification (spec `TaskStatusNotificationParams`).
///
/// The task fields are flattened at the top level: `NotificationParams & Task`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct TaskStatusNotificationParam {
    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
    #[serde(flatten)]
    pub task: crate::model::Task,
}

impl TaskStatusNotificationParam {
    pub fn new(task: crate::model::Task) -> Self {
        Self { meta: None, task }
    }

    pub fn with_meta(mut self, meta: Meta) -> Self {
        self.meta = Some(meta);
        self
    }
}

impl From<crate::model::Task> for TaskStatusNotificationParam {
    fn from(task: crate::model::Task) -> Self {
        Self::new(task)
    }
}

impl Deref for TaskStatusNotificationParam {
    type Target = crate::model::Task;

    fn deref(&self) -> &Self::Target {
        &self.task
    }
}

impl DerefMut for TaskStatusNotificationParam {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.task
    }
}

pub type TaskStatusNotification =
    Notification<TaskStatusNotificationMethod, TaskStatusNotificationParam>;
/// Deprecated: Use [`GetTaskResult`] instead (spec alignment).
#[deprecated(since = "0.15.0", note = "Use GetTaskResult instead")]
pub type GetTaskInfoResult = GetTaskResult;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct ListTasksResult {
    pub tasks: Vec<crate::model::Task>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<String>,
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Meta>,
}

impl ListTasksResult {
    pub fn new(tasks: Vec<crate::model::Task>) -> Self {
        Self {
            tasks,
            next_cursor: None,
            meta: None,
        }
    }
}

// =============================================================================
// MESSAGE TYPE UNIONS
// =============================================================================

macro_rules! ts_union {
    (
        export type $U:ident =
            $($rest:tt)*
    ) => {
        ts_union!(@declare $U { $($rest)* });
        ts_union!(@impl_from $U { $($rest)* });
    };
    (@declare $U:ident { $($variant:tt)* }) => {
        ts_union!(@declare_variant $U { } {$($variant)*} );
    };
    (@declare_variant $U:ident { $($declared:tt)* } {$(|)? box $V:ident $($rest:tt)*}) => {
        ts_union!(@declare_variant $U { $($declared)* $V(Box<$V>), }  {$($rest)*});
    };
    (@declare_variant $U:ident { $($declared:tt)* } {$(|)? $V:ident $($rest:tt)*}) => {
        ts_union!(@declare_variant $U { $($declared)* $V($V), } {$($rest)*});
    };
    (@declare_variant $U:ident { $($declared:tt)* }  { ; }) => {
        ts_union!(@declare_end $U { $($declared)* } );
    };
    (@declare_end $U:ident { $($declared:tt)* }) => {
        #[derive(Debug, Serialize, Deserialize, Clone)]
        #[serde(untagged)]
        #[allow(clippy::large_enum_variant)]
        #[expect(clippy::exhaustive_enums, reason = "intentionally exhaustive")]
        #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
        pub enum $U {
            $($declared)*
        }
    };
    (@impl_from $U: ident {$(|)? box $V:ident $($rest:tt)*}) => {
        impl From<$V> for $U {
            fn from(value: $V) -> Self {
                $U::$V(Box::new(value))
            }
        }
        ts_union!(@impl_from $U {$($rest)*});
    };
    (@impl_from $U: ident {$(|)? $V:ident $($rest:tt)*}) => {
        impl From<$V> for $U {
            fn from(value: $V) -> Self {
                $U::$V(value)
            }
        }
        ts_union!(@impl_from $U {$($rest)*});
    };
    (@impl_from $U: ident  { ; }) => {};
    (@impl_from $U: ident  { }) => {};
}

ts_union!(
    export type ClientRequest =
    | PingRequest
    | InitializeRequest
    | CompleteRequest
    | SetLevelRequest
    | GetPromptRequest
    | ListPromptsRequest
    | ListResourcesRequest
    | ListResourceTemplatesRequest
    | ReadResourceRequest
    | SubscribeRequest
    | UnsubscribeRequest
    | CallToolRequest
    | ListToolsRequest
    | GetTaskRequest
    | ListTasksRequest
    | GetTaskPayloadRequest
    | CancelTaskRequest
    | CustomRequest;
);

impl ClientRequest {
    pub fn method(&self) -> &str {
        match &self {
            ClientRequest::PingRequest(r) => r.method.as_str(),
            ClientRequest::InitializeRequest(r) => r.method.as_str(),
            ClientRequest::CompleteRequest(r) => r.method.as_str(),
            ClientRequest::SetLevelRequest(r) => r.method.as_str(),
            ClientRequest::GetPromptRequest(r) => r.method.as_str(),
            ClientRequest::ListPromptsRequest(r) => r.method.as_str(),
            ClientRequest::ListResourcesRequest(r) => r.method.as_str(),
            ClientRequest::ListResourceTemplatesRequest(r) => r.method.as_str(),
            ClientRequest::ReadResourceRequest(r) => r.method.as_str(),
            ClientRequest::SubscribeRequest(r) => r.method.as_str(),
            ClientRequest::UnsubscribeRequest(r) => r.method.as_str(),
            ClientRequest::CallToolRequest(r) => r.method.as_str(),
            ClientRequest::ListToolsRequest(r) => r.method.as_str(),
            ClientRequest::GetTaskRequest(r) => r.method.as_str(),
            ClientRequest::ListTasksRequest(r) => r.method.as_str(),
            ClientRequest::GetTaskPayloadRequest(r) => r.method.as_str(),
            ClientRequest::CancelTaskRequest(r) => r.method.as_str(),
            ClientRequest::CustomRequest(r) => r.method.as_str(),
        }
    }
}

ts_union!(
    export type ClientNotification =
    | CancelledNotification
    | ProgressNotification
    | InitializedNotification
    | RootsListChangedNotification
    | TaskStatusNotification
    | CustomNotification;
);

ts_union!(
    export type ClientResult =
    box CreateMessageResult
    | ListRootsResult
    | ElicitResult
    | EmptyResult
    | CustomResult;
);

impl ClientResult {
    pub fn empty(_: ()) -> ClientResult {
        ClientResult::EmptyResult(EmptyResult {})
    }
}

pub type ClientJsonRpcMessage = JsonRpcMessage<ClientRequest, ClientResult, ClientNotification>;

ts_union!(
    export type ServerRequest =
    | PingRequest
    | CreateMessageRequest
    | ListRootsRequest
    | ElicitRequest
    | CustomRequest;
);

ts_union!(
    export type ServerNotification =
    | CancelledNotification
    | ProgressNotification
    | LoggingMessageNotification
    | ResourceUpdatedNotification
    | ResourceListChangedNotification
    | ToolListChangedNotification
    | PromptListChangedNotification
    | ElicitationCompleteNotification
    | TaskStatusNotification
    | CustomNotification;
);

ts_union!(
    export type ServerResult =
    | InitializeResult
    | CompleteResult
    | GetPromptResult
    | ListPromptsResult
    | ListResourcesResult
    | ListResourceTemplatesResult
    | ReadResourceResult
    | ListToolsResult
    | ElicitResult
    | CreateTaskResult
    | ListTasksResult
    | GetTaskResult
    | CancelTaskResult
    | CallToolResult
    | GetTaskPayloadResult
    | EmptyResult
    | CustomResult
    ;
);

impl ServerResult {
    pub fn empty(_: ()) -> ServerResult {
        ServerResult::EmptyResult(EmptyResult {})
    }
}

pub type ServerJsonRpcMessage = JsonRpcMessage<ServerRequest, ServerResult, ServerNotification>;

impl TryInto<CancelledNotification> for ServerNotification {
    type Error = ServerNotification;
    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
        if let ServerNotification::CancelledNotification(t) = self {
            Ok(t)
        } else {
            Err(self)
        }
    }
}

impl TryInto<CancelledNotification> for ClientNotification {
    type Error = ClientNotification;
    fn try_into(self) -> Result<CancelledNotification, Self::Error> {
        if let ClientNotification::CancelledNotification(t) = self {
            Ok(t)
        } else {
            Err(self)
        }
    }
}

// =============================================================================
// TESTS
// =============================================================================

#[cfg(test)]
mod tests {
    use serde_json::json;

    use super::*;

    #[test]
    #[allow(deprecated)]
    fn deprecated_aliases_still_resolve() {
        // 하위호환: 구 이름이 새 타입으로 여전히 resolve되는지 확인.
        let _: CreateElicitationResult = ElicitResult::new(ElicitationAction::Accept);
        let _: GetTaskResultParams = GetTaskPayloadParams::new("task-1");
        let _: ResourceReference = ResourceTemplateReference::new("res://x");
    }

    #[test]
    fn cancelled_notification_request_id_is_optional_on_wire() {
        // None → requestId 생략
        let p = CancelledNotificationParam::new(None, Some("user cancelled".into()));
        let v = serde_json::to_value(&p).unwrap();
        assert!(v.get("requestId").is_none());

        // Some → requestId 방출 + 라운드트립
        let p = CancelledNotificationParam::new(Some(RequestId::Number(1)), None);
        let v = serde_json::to_value(&p).unwrap();
        assert_eq!(v["requestId"], json!(1));
        let back: CancelledNotificationParam = serde_json::from_value(v).unwrap();
        assert_eq!(back.request_id, Some(RequestId::Number(1)));
    }

    #[test]
    fn test_notification_serde() {
        let raw = json!( {
            "jsonrpc": JsonRpcVersion2_0,
            "method": InitializedNotificationMethod,
        });
        let message: ClientJsonRpcMessage =
            serde_json::from_value(raw.clone()).expect("invalid notification");
        match &message {
            ClientJsonRpcMessage::Notification(JsonRpcNotification {
                notification: ClientNotification::InitializedNotification(_n),
                ..
            }) => {}
            _ => panic!("Expected Notification"),
        }
        let json = serde_json::to_value(message).expect("valid json");
        assert_eq!(json, raw);
    }

    #[test]
    fn test_custom_client_notification_roundtrip() {
        let raw = json!( {
            "jsonrpc": JsonRpcVersion2_0,
            "method": "notifications/custom",
            "params": {"foo": "bar"},
        });

        let message: ClientJsonRpcMessage =
            serde_json::from_value(raw.clone()).expect("invalid notification");
        match &message {
            ClientJsonRpcMessage::Notification(JsonRpcNotification {
                notification: ClientNotification::CustomNotification(notification),
                ..
            }) => {
                assert_eq!(notification.method, "notifications/custom");
                assert_eq!(
                    notification
                        .params
                        .as_ref()
                        .and_then(|p| p.get("foo"))
                        .expect("foo present"),
                    "bar"
                );
            }
            _ => panic!("Expected custom client notification"),
        }

        let json = serde_json::to_value(message).expect("valid json");
        assert_eq!(json, raw);
    }

    #[test]
    fn test_custom_server_notification_roundtrip() {
        let raw = json!( {
            "jsonrpc": JsonRpcVersion2_0,
            "method": "notifications/custom-server",
            "params": {"hello": "world"},
        });

        let message: ServerJsonRpcMessage =
            serde_json::from_value(raw.clone()).expect("invalid notification");
        match &message {
            ServerJsonRpcMessage::Notification(JsonRpcNotification {
                notification: ServerNotification::CustomNotification(notification),
                ..
            }) => {
                assert_eq!(notification.method, "notifications/custom-server");
                assert_eq!(
                    notification
                        .params
                        .as_ref()
                        .and_then(|p| p.get("hello"))
                        .expect("hello present"),
                    "world"
                );
            }
            _ => panic!("Expected custom server notification"),
        }

        let json = serde_json::to_value(message).expect("valid json");
        assert_eq!(json, raw);
    }

    #[test]
    fn test_custom_request_roundtrip() {
        let raw = json!( {
            "jsonrpc": JsonRpcVersion2_0,
            "id": 42,
            "method": "requests/custom",
            "params": {"foo": "bar"},
        });

        let message: ClientJsonRpcMessage =
            serde_json::from_value(raw.clone()).expect("invalid request");
        match &message {
            ClientJsonRpcMessage::Request(JsonRpcRequest { id, request, .. }) => {
                assert_eq!(id, &RequestId::Number(42));
                match request {
                    ClientRequest::CustomRequest(custom) => {
                        let expected_request = json!({
                            "method": "requests/custom",
                            "params": {"foo": "bar"},
                        });
                        let actual_request =
                            serde_json::to_value(custom).expect("serialize custom request");
                        assert_eq!(actual_request, expected_request);
                    }
                    other => panic!("Expected custom request, got: {other:?}"),
                }
            }
            other => panic!("Expected request, got: {other:?}"),
        }

        let json = serde_json::to_value(message).expect("valid json");
        assert_eq!(json, raw);
    }

    #[test]
    fn test_request_conversion() {
        let raw = json!( {
            "jsonrpc": JsonRpcVersion2_0,
            "id": 1,
            "method": "request",
            "params": {"key": "value"},
        });
        let message: JsonRpcMessage = serde_json::from_value(raw.clone()).expect("invalid request");

        match &message {
            JsonRpcMessage::Request(r) => {
                assert_eq!(r.id, RequestId::Number(1));
                assert_eq!(r.request.method, "request");
                assert_eq!(
                    &r.request.params,
                    json!({"key": "value"})
                        .as_object()
                        .expect("should be an object")
                );
            }
            _ => panic!("Expected Request"),
        }
        let json = serde_json::to_value(&message).expect("valid json");
        assert_eq!(json, raw);
    }

    #[test]
    fn test_initial_request_response_serde() {
        let request = json!({
          "jsonrpc": "2.0",
          "id": 1,
          "method": "initialize",
          "params": {
            "protocolVersion": "2024-11-05",
            "capabilities": {
              "roots": {
                "listChanged": true
              },
              "sampling": {}
            },
            "clientInfo": {
              "name": "ExampleClient",
              "version": "1.0.0"
            }
          }
        });
        let raw_response_json = json!({
          "jsonrpc": "2.0",
          "id": 1,
          "result": {
            "protocolVersion": "2024-11-05",
            "capabilities": {
              "logging": {},
              "prompts": {
                "listChanged": true
              },
              "resources": {
                "subscribe": true,
                "listChanged": true
              },
              "tools": {
                "listChanged": true
              }
            },
            "serverInfo": {
              "name": "ExampleServer",
              "version": "1.0.0"
            }
          }
        });
        let request: ClientJsonRpcMessage =
            serde_json::from_value(request.clone()).expect("invalid request");
        let (request, id) = request.into_request().expect("should be a request");
        assert_eq!(id, RequestId::Number(1));
        #[allow(deprecated)]
        match request {
            ClientRequest::InitializeRequest(Request {
                method: _,
                params:
                    InitializeRequestParam {
                        meta: _,
                        protocol_version: _,
                        capabilities,
                        client_info,
                    },
                ..
            }) => {
                assert_eq!(capabilities.roots.unwrap().list_changed, Some(true));
                let sampling = capabilities.sampling.unwrap();
                assert_eq!(sampling.tools, None);
                assert_eq!(sampling.context, None);
                assert_eq!(client_info.name, "ExampleClient");
                assert_eq!(client_info.version, "1.0.0");
            }
            _ => panic!("Expected InitializeRequest"),
        }
        let server_response: ServerJsonRpcMessage =
            serde_json::from_value(raw_response_json.clone()).expect("invalid response");
        let (response, id) = server_response
            .clone()
            .into_response()
            .expect("expect response");
        assert_eq!(id, RequestId::Number(1));
        match response {
            ServerResult::InitializeResult(InitializeResult {
                protocol_version: _,
                capabilities,
                server_info,
                instructions,
                ..
            }) => {
                assert_eq!(capabilities.logging.unwrap().len(), 0);
                assert_eq!(capabilities.prompts.unwrap().list_changed, Some(true));
                assert_eq!(
                    capabilities.resources.as_ref().unwrap().subscribe,
                    Some(true)
                );
                assert_eq!(capabilities.resources.unwrap().list_changed, Some(true));
                assert_eq!(capabilities.tools.unwrap().list_changed, Some(true));
                assert_eq!(server_info.name, "ExampleServer");
                assert_eq!(server_info.version, "1.0.0");
                assert_eq!(server_info.icons, None);
                assert_eq!(instructions, None);
            }
            other => panic!("Expected InitializeResult, got {other:?}"),
        }

        let server_response_json: Value = serde_json::to_value(&server_response).expect("msg");

        assert_eq!(server_response_json, raw_response_json);
    }

    #[test]
    fn test_negative_and_large_request_ids() {
        // Test negative ID
        let negative_id_json = json!({
            "jsonrpc": "2.0",
            "id": -1,
            "method": "test",
            "params": {}
        });

        let message: JsonRpcMessage =
            serde_json::from_value(negative_id_json.clone()).expect("Should parse negative ID");

        match &message {
            JsonRpcMessage::Request(r) => {
                assert_eq!(r.id, RequestId::Number(-1));
            }
            _ => panic!("Expected Request"),
        }

        // Test roundtrip serialization
        let serialized = serde_json::to_value(&message).expect("Should serialize");
        assert_eq!(serialized, negative_id_json);

        // Test large negative ID
        let large_negative_json = json!({
            "jsonrpc": "2.0",
            "id": -9007199254740991i64,  // JavaScript's MIN_SAFE_INTEGER
            "method": "test",
            "params": {}
        });

        let message: JsonRpcMessage = serde_json::from_value(large_negative_json.clone())
            .expect("Should parse large negative ID");

        match &message {
            JsonRpcMessage::Request(r) => {
                assert_eq!(r.id, RequestId::Number(-9007199254740991i64));
            }
            _ => panic!("Expected Request"),
        }

        // Test large positive ID (JavaScript's MAX_SAFE_INTEGER)
        let large_positive_json = json!({
            "jsonrpc": "2.0",
            "id": 9007199254740991i64,
            "method": "test",
            "params": {}
        });

        let message: JsonRpcMessage = serde_json::from_value(large_positive_json.clone())
            .expect("Should parse large positive ID");

        match &message {
            JsonRpcMessage::Request(r) => {
                assert_eq!(r.id, RequestId::Number(9007199254740991i64));
            }
            _ => panic!("Expected Request"),
        }

        // Test zero ID
        let zero_id_json = json!({
            "jsonrpc": "2.0",
            "id": 0,
            "method": "test",
            "params": {}
        });

        let message: JsonRpcMessage =
            serde_json::from_value(zero_id_json.clone()).expect("Should parse zero ID");

        match &message {
            JsonRpcMessage::Request(r) => {
                assert_eq!(r.id, RequestId::Number(0));
            }
            _ => panic!("Expected Request"),
        }
    }

    #[test]
    fn test_protocol_version_order() {
        let v1 = ProtocolVersion::V_2024_11_05;
        let v2 = ProtocolVersion::V_2025_03_26;
        let v3 = ProtocolVersion::V_2025_06_18;
        let v4 = ProtocolVersion::V_2025_11_25;
        assert!(v1 < v2);
        assert!(v2 < v3);
        assert!(v3 < v4);
    }

    #[test]
    fn test_icon_serialization() {
        let icon = Icon {
            src: "https://example.com/icon.png".to_string(),
            mime_type: Some("image/png".to_string()),
            sizes: Some(vec!["48x48".to_string()]),
            theme: Some(IconTheme::Light),
        };

        let json = serde_json::to_value(&icon).unwrap();
        assert_eq!(json["src"], "https://example.com/icon.png");
        assert_eq!(json["mimeType"], "image/png");
        assert_eq!(json["sizes"][0], "48x48");
        assert_eq!(json["theme"], "light");

        // Test deserialization
        let deserialized: Icon = serde_json::from_value(json).unwrap();
        assert_eq!(deserialized, icon);
    }

    #[test]
    fn test_icon_minimal() {
        let icon = Icon {
            src: "data:image/svg+xml;base64,PHN2Zy8+".to_string(),
            mime_type: None,
            sizes: None,
            theme: None,
        };

        let json = serde_json::to_value(&icon).unwrap();
        assert_eq!(json["src"], "data:image/svg+xml;base64,PHN2Zy8+");
        assert!(json.get("mimeType").is_none());
        assert!(json.get("sizes").is_none());
        assert!(json.get("theme").is_none());
    }

    #[test]
    fn test_implementation_with_icons() {
        let implementation = Implementation {
            name: "test-server".to_string(),
            title: Some("Test Server".to_string()),
            version: "1.0.0".to_string(),
            description: Some("A test server for unit testing".to_string()),
            icons: Some(vec![
                Icon {
                    src: "https://example.com/icon.png".to_string(),
                    mime_type: Some("image/png".to_string()),
                    sizes: Some(vec!["48x48".to_string()]),
                    theme: Some(IconTheme::Dark),
                },
                Icon {
                    src: "https://example.com/icon.svg".to_string(),
                    mime_type: Some("image/svg+xml".to_string()),
                    sizes: Some(vec!["any".to_string()]),
                    theme: Some(IconTheme::Light),
                },
            ]),
            website_url: Some("https://example.com".to_string()),
        };

        let json = serde_json::to_value(&implementation).unwrap();
        assert_eq!(json["name"], "test-server");
        assert_eq!(json["description"], "A test server for unit testing");
        assert_eq!(json["websiteUrl"], "https://example.com");
        assert!(json["icons"].is_array());
        assert_eq!(json["icons"][0]["src"], "https://example.com/icon.png");
        assert_eq!(json["icons"][0]["sizes"][0], "48x48");
        assert_eq!(json["icons"][1]["mimeType"], "image/svg+xml");
        assert_eq!(json["icons"][1]["sizes"][0], "any");
        assert_eq!(json["icons"][0]["theme"], "dark");
        assert_eq!(json["icons"][1]["theme"], "light");
    }

    #[test]
    fn test_backward_compatibility() {
        // Test that old JSON without icons still deserializes correctly
        let old_json = json!({
            "name": "legacy-server",
            "version": "0.9.0"
        });

        let implementation: Implementation = serde_json::from_value(old_json).unwrap();
        assert_eq!(implementation.name, "legacy-server");
        assert_eq!(implementation.version, "0.9.0");
        assert_eq!(implementation.description, None);
        assert_eq!(implementation.icons, None);
        assert_eq!(implementation.website_url, None);
    }

    #[test]
    fn test_initialize_with_icons() {
        let init_result = InitializeResult {
            protocol_version: ProtocolVersion::default(),
            capabilities: ServerCapabilities::default(),
            server_info: Implementation {
                name: "icon-server".to_string(),
                title: None,
                version: "2.0.0".to_string(),
                description: None,
                icons: Some(vec![Icon {
                    src: "https://example.com/server.png".to_string(),
                    mime_type: Some("image/png".to_string()),
                    sizes: Some(vec!["48x48".to_string()]),
                    theme: Some(IconTheme::Light),
                }]),
                website_url: Some("https://docs.example.com".to_string()),
            },
            instructions: None,
            meta: None,
        };

        let json = serde_json::to_value(&init_result).unwrap();
        assert!(json["serverInfo"]["icons"].is_array());
        assert_eq!(
            json["serverInfo"]["icons"][0]["src"],
            "https://example.com/server.png"
        );
        assert_eq!(json["serverInfo"]["icons"][0]["sizes"][0], "48x48");
        assert_eq!(json["serverInfo"]["icons"][0]["theme"], "light");
        assert_eq!(json["serverInfo"]["websiteUrl"], "https://docs.example.com");
    }

    #[test]
    fn test_elicitation_deserialization_untagged() {
        // Test deserialization without the "type" field (should default to FormElicitationParam)
        let json_data_without_tag = json!({
            "message": "Please provide more details.",
            "requestedSchema": {
                "title": "User Details",
                "type": "object",
                "properties": {
                    "name": { "type": "string" },
                    "age": { "type": "integer" }
                },
                "required": ["name", "age"]
            }
        });
        let elicitation: ElicitRequestParams =
            serde_json::from_value(json_data_without_tag).expect("Deserialization failed");
        if let ElicitRequestParams::FormElicitationParams {
            meta,
            message,
            requested_schema,
        } = elicitation
        {
            assert_eq!(meta, None);
            assert_eq!(message, "Please provide more details.");
            assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
            assert_eq!(requested_schema.type_, ObjectTypeConst);
        } else {
            panic!("Expected FormElicitationParam");
        }
    }

    #[test]
    fn test_elicitation_deserialization() {
        let json_data_form = json!({
            "_meta": { "meta_form_key_1": "meta form value 1" },
            "mode": "form",
            "message": "Please provide more details.",
            "requestedSchema": {
                "title": "User Details",
                "type": "object",
                "properties": {
                    "name": { "type": "string" },
                    "age": { "type": "integer" }
                },
                "required": ["name", "age"]
            }
        });
        let elicitation_form: ElicitRequestParams =
            serde_json::from_value(json_data_form).expect("Deserialization failed");
        if let ElicitRequestParams::FormElicitationParams {
            meta,
            message,
            requested_schema,
        } = elicitation_form
        {
            assert_eq!(
                meta,
                Some(Meta(object!({ "meta_form_key_1": "meta form value 1" })))
            );
            assert_eq!(message, "Please provide more details.");
            assert_eq!(requested_schema.title, Some(Cow::from("User Details")));
            assert_eq!(requested_schema.type_, ObjectTypeConst);
        } else {
            panic!("Expected FormElicitationParam");
        }

        let json_data_url = json!({
                "_meta": { "meta_url_key_1": "meta url value 1" },
            "mode": "url",
            "message": "Please fill out the form at the following URL.",
            "url": "https://example.com/form",
            "elicitationId": "elicitation-123"
        });
        let elicitation_url: ElicitRequestParams =
            serde_json::from_value(json_data_url).expect("Deserialization failed");
        if let ElicitRequestParams::UrlElicitationParams {
            meta,
            message,
            url,
            elicitation_id,
        } = elicitation_url
        {
            assert_eq!(
                meta,
                Some(Meta(object!({ "meta_url_key_1": "meta url value 1" })))
            );
            assert_eq!(message, "Please fill out the form at the following URL.");
            assert_eq!(url, "https://example.com/form");
            assert_eq!(elicitation_id, "elicitation-123");
        } else {
            panic!("Expected UrlElicitationParam");
        }
    }

    #[test]
    fn test_elicitation_serialization() {
        let form_elicitation = ElicitRequestParams::FormElicitationParams {
            meta: Some(Meta(object!({ "meta_form_key_1": "meta form value 1" }))),
            message: "Please provide more details.".to_string(),
            requested_schema: ElicitationSchema::builder()
                .title("User Details")
                .string_property("name", |s| s)
                .build()
                .expect("Valid schema"),
        };
        let json_form = serde_json::to_value(&form_elicitation).expect("Serialization failed");
        let expected_form_json = json!({
            "_meta": { "meta_form_key_1": "meta form value 1" },
            "mode": "form",
            "message": "Please provide more details.",
            "requestedSchema": {
                "title":"User Details",
                "type":"object",
                "properties":{
                    "name": { "type": "string" },
                },
            }
        });
        assert_eq!(json_form, expected_form_json);

        let url_elicitation = ElicitRequestParams::UrlElicitationParams {
            meta: Some(Meta(object!({ "meta_url_key_1": "meta url value 1" }))),
            message: "Please fill out the form at the following URL.".to_string(),
            url: "https://example.com/form".to_string(),
            elicitation_id: "elicitation-123".to_string(),
        };
        let json_url = serde_json::to_value(&url_elicitation).expect("Serialization failed");
        let expected_url_json = json!({
            "_meta": { "meta_url_key_1": "meta url value 1" },
            "mode": "url",
            "message": "Please fill out the form at the following URL.",
            "url": "https://example.com/form",
            "elicitationId": "elicitation-123"
        });
        assert_eq!(json_url, expected_url_json);
    }

    #[test]
    fn notification_without_params_should_deserialize_as_bare_jsonrpc_message() {
        let payload = b"{\"method\":\"notifications/initialized\",\"jsonrpc\":\"2.0\"}";
        let result: Result<JsonRpcMessage, _> = serde_json::from_slice(payload);
        assert!(
            matches!(result, Ok(JsonRpcMessage::Notification(_))),
            "Expected Ok(Notification), got: {:?}",
            result
        );
    }
}
