SSE transport has been removed from the MCP specification in favor of streamable HTTP. This removes all SSE-specific transport code: - Remove `transport-sse-client` and `transport-sse-server` features - Remove `SseClientTransport` and `SseServer` types - Remove SSE-specific examples (`counter_sse`, `counter_sse_directly`) - Migrate auth examples from SSE to streamable HTTP - Update tests to remove SSE transport usage - Update documentation BREAKING CHANGE: The following have been removed: - `transport-sse-client` feature - `transport-sse-client-reqwest` feature - `transport-sse-server` feature - `SseClientTransport` type - `SseServer` type - `sse_client` and `sse_server` modules Users should migrate to streamable HTTP transport which provides equivalent functionality. See `StreamableHttpClientTransport` and `StreamableHttpService` for the replacement APIs. Ref: https://github.com/modelcontextprotocol/rust-sdk/pull/561#issuecomment-3576551699
93 lines
2.7 KiB
Rust
93 lines
2.7 KiB
Rust
use std::{collections::HashMap, path::Path, process::Stdio};
|
|
|
|
use anyhow::Result;
|
|
use rmcp::{RoleClient, ServiceExt, service::RunningService, transport::ConfigureCommandExt};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct Config {
|
|
pub openai_key: Option<String>,
|
|
pub chat_url: Option<String>,
|
|
pub mcp: Option<McpConfig>,
|
|
pub model_name: Option<String>,
|
|
pub proxy: Option<bool>,
|
|
pub support_tool: Option<bool>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct McpConfig {
|
|
pub server: Vec<McpServerConfig>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct McpServerConfig {
|
|
pub name: String,
|
|
#[serde(flatten)]
|
|
pub transport: McpServerTransportConfig,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
#[serde(tag = "protocol", rename_all = "lowercase")]
|
|
pub enum McpServerTransportConfig {
|
|
Streamable {
|
|
url: String,
|
|
},
|
|
Stdio {
|
|
command: String,
|
|
#[serde(default)]
|
|
args: Vec<String>,
|
|
#[serde(default)]
|
|
envs: HashMap<String, String>,
|
|
},
|
|
}
|
|
|
|
impl McpServerTransportConfig {
|
|
pub async fn start(&self) -> Result<RunningService<RoleClient, ()>> {
|
|
let client = match self {
|
|
McpServerTransportConfig::Streamable { url } => {
|
|
let transport =
|
|
rmcp::transport::StreamableHttpClientTransport::from_uri(url.to_string());
|
|
().serve(transport).await?
|
|
}
|
|
McpServerTransportConfig::Stdio {
|
|
command,
|
|
args,
|
|
envs,
|
|
} => {
|
|
let transport = rmcp::transport::child_process::TokioChildProcess::new(
|
|
tokio::process::Command::new(command).configure(|cmd| {
|
|
cmd.args(args)
|
|
.envs(envs)
|
|
.stderr(Stdio::inherit())
|
|
.stdout(Stdio::inherit());
|
|
}),
|
|
)?;
|
|
().serve(transport).await?
|
|
}
|
|
};
|
|
Ok(client)
|
|
}
|
|
}
|
|
|
|
impl Config {
|
|
pub async fn load(path: impl AsRef<Path>) -> Result<Self> {
|
|
let content = tokio::fs::read_to_string(path).await?;
|
|
let config: Self = toml::from_str(&content)?;
|
|
Ok(config)
|
|
}
|
|
|
|
pub async fn create_mcp_clients(
|
|
&self,
|
|
) -> Result<HashMap<String, RunningService<RoleClient, ()>>> {
|
|
let mut clients = HashMap::new();
|
|
|
|
if let Some(mcp_config) = &self.mcp {
|
|
for server in &mcp_config.server {
|
|
let client = server.transport.start().await?;
|
|
clients.insert(server.name.clone(), client);
|
|
}
|
|
}
|
|
|
|
Ok(clients)
|
|
}
|
|
}
|