feat: upgrade to rmcp 0.12.0 and sacp 10.0.0 by removing SSE transport (#6304)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
@@ -302,6 +302,7 @@ impl McpClientTrait for ChatRecallClient {
|
||||
Ok(ListToolsResult {
|
||||
tools: Self::get_tools(),
|
||||
next_cursor: None,
|
||||
meta: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -835,6 +835,7 @@ impl McpClientTrait for CodeExecutionClient {
|
||||
}),
|
||||
],
|
||||
next_cursor: None,
|
||||
meta: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -233,27 +233,18 @@ impl Envs {
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema, PartialEq)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ExtensionConfig {
|
||||
/// Server-sent events client with a URI endpoint
|
||||
/// SSE transport is no longer supported - kept only for config file compatibility
|
||||
#[serde(rename = "sse")]
|
||||
Sse {
|
||||
/// The name used to identify this extension
|
||||
#[serde(default)]
|
||||
#[schema(required)]
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_null_with_default")]
|
||||
#[schema(required)]
|
||||
description: String,
|
||||
uri: String,
|
||||
#[serde(default)]
|
||||
envs: Envs,
|
||||
#[serde(default)]
|
||||
env_keys: Vec<String>,
|
||||
// NOTE: set timeout to be optional for compatibility.
|
||||
// However, new configurations should include this field.
|
||||
timeout: Option<u64>,
|
||||
#[serde(default)]
|
||||
bundled: Option<bool>,
|
||||
#[serde(default)]
|
||||
available_tools: Vec<String>,
|
||||
uri: Option<String>,
|
||||
},
|
||||
/// Standard I/O client with command and arguments
|
||||
#[serde(rename = "stdio")]
|
||||
@@ -379,19 +370,6 @@ impl Default for ExtensionConfig {
|
||||
}
|
||||
|
||||
impl ExtensionConfig {
|
||||
pub fn sse<S: Into<String>, T: Into<u64>>(name: S, uri: S, description: S, timeout: T) -> Self {
|
||||
Self::Sse {
|
||||
name: name.into(),
|
||||
uri: uri.into(),
|
||||
envs: Envs::default(),
|
||||
env_keys: Vec::new(),
|
||||
description: description.into(),
|
||||
timeout: Some(timeout.into()),
|
||||
bundled: None,
|
||||
available_tools: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn streamable_http<S: Into<String>, T: Into<u64>>(
|
||||
name: S,
|
||||
uri: S,
|
||||
@@ -499,10 +477,8 @@ impl ExtensionConfig {
|
||||
/// Check if a tool should be available to the LLM
|
||||
pub fn is_tool_available(&self, tool_name: &str) -> bool {
|
||||
let available_tools = match self {
|
||||
Self::Sse {
|
||||
available_tools, ..
|
||||
}
|
||||
| Self::StreamableHttp {
|
||||
Self::Sse { .. } => return false, // SSE is unsupported
|
||||
Self::StreamableHttp {
|
||||
available_tools, ..
|
||||
}
|
||||
| Self::Stdio {
|
||||
@@ -531,7 +507,9 @@ impl ExtensionConfig {
|
||||
impl std::fmt::Display for ExtensionConfig {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ExtensionConfig::Sse { name, uri, .. } => write!(f, "SSE({}: {})", name, uri),
|
||||
ExtensionConfig::Sse { name, .. } => {
|
||||
write!(f, "SSE({}: unsupported)", name)
|
||||
}
|
||||
ExtensionConfig::StreamableHttp { name, uri, .. } => {
|
||||
write!(f, "StreamableHttp({}: {})", name, uri)
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ use rmcp::transport::streamable_http_client::{
|
||||
AuthRequiredError, StreamableHttpClientTransportConfig, StreamableHttpError,
|
||||
};
|
||||
use rmcp::transport::{
|
||||
ConfigureCommandExt, DynamicTransportError, SseClientTransport, StreamableHttpClientTransport,
|
||||
TokioChildProcess,
|
||||
ConfigureCommandExt, DynamicTransportError, StreamableHttpClientTransport, TokioChildProcess,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::option::Option;
|
||||
@@ -481,25 +480,10 @@ impl ExtensionManager {
|
||||
let mut temp_dir = None;
|
||||
|
||||
let client: Box<dyn McpClientTrait> = match &config {
|
||||
ExtensionConfig::Sse { uri, timeout, .. } => {
|
||||
let transport = SseClientTransport::start(uri.to_string()).await.map_err(
|
||||
|transport_error| {
|
||||
ClientInitializeError::transport::<SseClientTransport<reqwest::Client>>(
|
||||
transport_error,
|
||||
"connect",
|
||||
)
|
||||
},
|
||||
)?;
|
||||
Box::new(
|
||||
McpClient::connect(
|
||||
transport,
|
||||
Duration::from_secs(
|
||||
timeout.unwrap_or(crate::config::DEFAULT_EXTENSION_TIMEOUT),
|
||||
),
|
||||
self.provider.clone(),
|
||||
)
|
||||
.await?,
|
||||
)
|
||||
ExtensionConfig::Sse { .. } => {
|
||||
return Err(ExtensionError::ConfigError(
|
||||
"SSE is unsupported, migrate to streamable_http".to_string(),
|
||||
));
|
||||
}
|
||||
ExtensionConfig::StreamableHttp {
|
||||
uri,
|
||||
@@ -1243,8 +1227,8 @@ impl ExtensionManager {
|
||||
description
|
||||
}
|
||||
}
|
||||
ExtensionConfig::Sse { .. } => "SSE extension (unsupported)",
|
||||
ExtensionConfig::Platform { description, .. }
|
||||
| ExtensionConfig::Sse { description, .. }
|
||||
| ExtensionConfig::StreamableHttp { description, .. }
|
||||
| ExtensionConfig::Stdio { description, .. }
|
||||
| ExtensionConfig::Frontend { description, .. }
|
||||
@@ -1419,6 +1403,7 @@ mod tests {
|
||||
),
|
||||
],
|
||||
next_cursor: None,
|
||||
meta: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -410,6 +410,7 @@ impl McpClientTrait for ExtensionManagerClient {
|
||||
Ok(ListToolsResult {
|
||||
tools: self.get_tools().await,
|
||||
next_cursor: None,
|
||||
meta: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -292,6 +292,7 @@ impl McpClientTrait for SkillsClient {
|
||||
Ok(ListToolsResult {
|
||||
tools,
|
||||
next_cursor: None,
|
||||
meta: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ impl McpClientTrait for TodoClient {
|
||||
Ok(ListToolsResult {
|
||||
tools: Self::get_tools(),
|
||||
next_cursor: None,
|
||||
meta: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ fn get_extensions_map() -> IndexMap<String, ExtensionEntry> {
|
||||
let mut extensions_map = IndexMap::with_capacity(raw.len());
|
||||
for (k, v) in raw {
|
||||
match (k, serde_yaml::from_value::<ExtensionEntry>(v)) {
|
||||
(serde_yaml::Value::String(s), Ok(entry)) => {
|
||||
extensions_map.insert(s, entry);
|
||||
(serde_yaml::Value::String(key), Ok(entry)) => {
|
||||
extensions_map.insert(key, entry);
|
||||
}
|
||||
(k, v) => {
|
||||
warn!(
|
||||
@@ -134,3 +134,24 @@ pub fn get_enabled_extensions() -> Vec<ExtensionConfig> {
|
||||
.map(|ext| ext.config)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_warnings() -> Vec<String> {
|
||||
let raw: Mapping = Config::global()
|
||||
.get_param(EXTENSIONS_CONFIG_KEY)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut warnings = Vec::new();
|
||||
for (k, v) in raw {
|
||||
if let (serde_yaml::Value::String(key), Ok(entry)) =
|
||||
(k, serde_yaml::from_value::<ExtensionEntry>(v))
|
||||
{
|
||||
if matches!(entry.config, ExtensionConfig::Sse { .. }) {
|
||||
warnings.push(format!(
|
||||
"'{}': SSE is unsupported, migrate to streamable_http",
|
||||
key
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
warnings
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ pub use declarative_providers::DeclarativeProviderConfig;
|
||||
pub use experiments::ExperimentManager;
|
||||
pub use extensions::{
|
||||
get_all_extension_names, get_all_extensions, get_enabled_extensions, get_extension_by_name,
|
||||
is_extension_enabled, remove_extension, set_extension, set_extension_enabled, ExtensionEntry,
|
||||
get_warnings, is_extension_enabled, remove_extension, set_extension, set_extension_enabled,
|
||||
ExtensionEntry,
|
||||
};
|
||||
pub use goose_mode::GooseMode;
|
||||
pub use permission::PermissionManager;
|
||||
|
||||
@@ -7,22 +7,6 @@ use std::collections::HashMap;
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
enum RecipeExtensionConfigInternal {
|
||||
#[serde(rename = "sse")]
|
||||
Sse {
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
description: Option<String>,
|
||||
uri: String,
|
||||
#[serde(default)]
|
||||
envs: Envs,
|
||||
#[serde(default)]
|
||||
env_keys: Vec<String>,
|
||||
timeout: Option<u64>,
|
||||
#[serde(default)]
|
||||
bundled: Option<bool>,
|
||||
#[serde(default)]
|
||||
available_tools: Vec<String>,
|
||||
},
|
||||
#[serde(rename = "stdio")]
|
||||
Stdio {
|
||||
name: String,
|
||||
@@ -127,15 +111,7 @@ macro_rules! map_recipe_extensions {
|
||||
impl From<RecipeExtensionConfigInternal> for ExtensionConfig {
|
||||
fn from(internal_variant: RecipeExtensionConfigInternal) -> Self {
|
||||
map_recipe_extensions!(
|
||||
internal_variant;
|
||||
Sse {
|
||||
uri,
|
||||
envs,
|
||||
env_keys,
|
||||
timeout,
|
||||
bundled,
|
||||
available_tools
|
||||
},
|
||||
internal_variant;
|
||||
Stdio {
|
||||
cmd,
|
||||
args,
|
||||
@@ -187,12 +163,7 @@ where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let remotes = Option::<Vec<RecipeExtensionConfigInternal>>::deserialize(deserializer)?;
|
||||
Ok(remotes.map(|items| {
|
||||
items
|
||||
.into_iter()
|
||||
.map(ExtensionConfig::from)
|
||||
.collect::<Vec<_>>()
|
||||
}))
|
||||
Ok(remotes.map(|items| items.into_iter().map(ExtensionConfig::from).collect()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user