use crate::errors::BoxedError;
use futures::future::BoxFuture;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone)]
#[allow(clippy::type_complexity)]
pub enum MCPInit<TCtx>
where
TCtx: Send + Sync + 'static,
{
Params(MCPParams),
Func(Arc<dyn Fn(&TCtx) -> Result<MCPParams, BoxedError> + Send + Sync>),
AsyncFunc(
Arc<dyn Fn(&TCtx) -> BoxFuture<'static, Result<MCPParams, BoxedError>> + Send + Sync>,
),
}
impl<TCtx> MCPInit<TCtx>
where
TCtx: Send + Sync + 'static,
{
#[must_use]
pub fn from_params(params: MCPParams) -> Self {
Self::Params(params)
}
pub fn from_fn<F>(func: F) -> Self
where
F: Fn(&TCtx) -> Result<MCPParams, BoxedError> + Send + Sync + 'static,
{
Self::Func(Arc::new(func))
}
pub fn from_async_fn<F, Fut>(func: F) -> Self
where
F: Fn(&TCtx) -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = Result<MCPParams, BoxedError>> + Send + 'static,
{
Self::AsyncFunc(Arc::new(move |ctx| Box::pin(func(ctx))))
}
pub(crate) async fn resolve(&self, context: &TCtx) -> Result<MCPParams, BoxedError> {
match self {
Self::Params(params) => Ok(params.clone()),
Self::Func(func) => func(context),
Self::AsyncFunc(func) => func(context).await,
}
}
}
impl<TCtx> From<MCPParams> for MCPInit<TCtx>
where
TCtx: Send + Sync + 'static,
{
fn from(value: MCPParams) -> Self {
Self::from_params(value)
}
}
impl<TCtx, F> From<F> for MCPInit<TCtx>
where
TCtx: Send + Sync + 'static,
F: Fn(&TCtx) -> Result<MCPParams, BoxedError> + Send + Sync + 'static,
{
fn from(value: F) -> Self {
Self::from_fn(value)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum MCPParams {
Stdio(MCPStdioParams),
StreamableHttp(MCPStreamableHTTPParams),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MCPStdioParams {
pub command: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub args: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MCPStreamableHTTPParams {
pub url: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub authorization: Option<String>,
}