1c9a7c0b05
Co-authored-by: Michael Neale <michael.neale@gmail.com> Co-authored-by: Wendy Tang <wendytang@squareup.com> Co-authored-by: Jarrod Sibbison <72240382+jsibbison-square@users.noreply.github.com> Co-authored-by: Alex Hancock <alex.hancock@example.com> Co-authored-by: Alex Hancock <alexhancock@block.xyz> Co-authored-by: Lifei Zhou <lifei@squareup.com> Co-authored-by: Wes <141185334+wesrblock@users.noreply.github.com> Co-authored-by: Max Novich <maksymstepanenko1990@gmail.com> Co-authored-by: Zaki Ali <zaki@squareup.com> Co-authored-by: Salman Mohammed <smohammed@squareup.com> Co-authored-by: Kalvin C <kalvinnchau@users.noreply.github.com> Co-authored-by: Alec Thomas <alec@swapoff.org> Co-authored-by: lily-de <119957291+lily-de@users.noreply.github.com> Co-authored-by: kalvinnchau <kalvin@block.xyz> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rizel Scarlett <rizel@squareup.com> Co-authored-by: bwrage <bwrage@squareup.com> Co-authored-by: Kalvin Chau <kalvin@squareup.com> Co-authored-by: Alice Hau <110418948+ahau-square@users.noreply.github.com> Co-authored-by: Alistair Gray <ajgray@stripe.com> Co-authored-by: Nahiyan Khan <nahiyan.khan@gmail.com> Co-authored-by: Alex Hancock <alexhancock@squareup.com> Co-authored-by: Nahiyan Khan <nahiyan@squareup.com> Co-authored-by: marcelle <1852848+laanak08@users.noreply.github.com> Co-authored-by: Yingjie He <yingjiehe@block.xyz> Co-authored-by: Yingjie He <yingjiehe@squareup.com> Co-authored-by: Lily Delalande <ldelalande@block.xyz> Co-authored-by: Adewale Abati <acekyd01@gmail.com> Co-authored-by: Ebony Louis <ebony774@gmail.com> Co-authored-by: Angie Jones <jones.angie@gmail.com> Co-authored-by: Ebony Louis <55366651+EbonyLouis@users.noreply.github.com>
159 lines
4.3 KiB
Rust
159 lines
4.3 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use mcp_client::client::Error as ClientError;
|
|
use serde::{Deserialize, Serialize};
|
|
use thiserror::Error;
|
|
|
|
/// Errors from Extension operation
|
|
#[derive(Error, Debug)]
|
|
pub enum ExtensionError {
|
|
#[error("Failed to start the MCP server from configuration `{0}` `{1}`")]
|
|
Initialization(ExtensionConfig, ClientError),
|
|
#[error("Failed a client call to an MCP server: {0}")]
|
|
Client(#[from] ClientError),
|
|
#[error("User Message exceeded context-limit. History could not be truncated to accomodate.")]
|
|
ContextLimit,
|
|
#[error("Transport error: {0}")]
|
|
Transport(#[from] mcp_client::transport::Error),
|
|
}
|
|
|
|
pub type ExtensionResult<T> = Result<T, ExtensionError>;
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
|
pub struct Envs {
|
|
/// A map of environment variables to set, e.g. API_KEY -> some_secret, HOST -> host
|
|
#[serde(default)]
|
|
#[serde(flatten)]
|
|
map: HashMap<String, String>,
|
|
}
|
|
|
|
impl Envs {
|
|
pub fn new(map: HashMap<String, String>) -> Self {
|
|
Self { map }
|
|
}
|
|
|
|
pub fn get_env(&self) -> HashMap<String, String> {
|
|
self.map
|
|
.iter()
|
|
.map(|(k, v)| (k.to_string(), v.to_string()))
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
/// Represents the different types of MCP extensions that can be added to the manager
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
#[serde(tag = "type")]
|
|
pub enum ExtensionConfig {
|
|
/// Server-sent events client with a URI endpoint
|
|
#[serde(rename = "sse")]
|
|
Sse {
|
|
/// The name used to identify this extension
|
|
name: String,
|
|
uri: String,
|
|
#[serde(default)]
|
|
envs: Envs,
|
|
},
|
|
/// Standard I/O client with command and arguments
|
|
#[serde(rename = "stdio")]
|
|
Stdio {
|
|
/// The name used to identify this extension
|
|
name: String,
|
|
cmd: String,
|
|
args: Vec<String>,
|
|
#[serde(default)]
|
|
envs: Envs,
|
|
},
|
|
/// Built-in extension that is part of the goose binary
|
|
#[serde(rename = "builtin")]
|
|
Builtin {
|
|
/// The name used to identify this extension
|
|
name: String,
|
|
},
|
|
}
|
|
|
|
impl Default for ExtensionConfig {
|
|
fn default() -> Self {
|
|
Self::Builtin {
|
|
name: String::from("default"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ExtensionConfig {
|
|
pub fn sse<S: Into<String>>(name: S, uri: S) -> Self {
|
|
Self::Sse {
|
|
name: name.into(),
|
|
uri: uri.into(),
|
|
envs: Envs::default(),
|
|
}
|
|
}
|
|
|
|
pub fn stdio<S: Into<String>>(name: S, cmd: S) -> Self {
|
|
Self::Stdio {
|
|
name: name.into(),
|
|
cmd: cmd.into(),
|
|
args: vec![],
|
|
envs: Envs::default(),
|
|
}
|
|
}
|
|
|
|
pub fn with_args<I, S>(self, args: I) -> Self
|
|
where
|
|
I: IntoIterator<Item = S>,
|
|
S: Into<String>,
|
|
{
|
|
match self {
|
|
Self::Stdio {
|
|
name, cmd, envs, ..
|
|
} => Self::Stdio {
|
|
name,
|
|
cmd,
|
|
envs,
|
|
args: args.into_iter().map(Into::into).collect(),
|
|
},
|
|
other => other,
|
|
}
|
|
}
|
|
|
|
/// Get the extension name regardless of variant
|
|
pub fn name(&self) -> &str {
|
|
match self {
|
|
Self::Sse { name, .. } => name,
|
|
Self::Stdio { name, .. } => name,
|
|
Self::Builtin { name } => name,
|
|
}
|
|
}
|
|
}
|
|
|
|
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::Stdio {
|
|
name, cmd, args, ..
|
|
} => {
|
|
write!(f, "Stdio({}: {} {})", name, cmd, args.join(" "))
|
|
}
|
|
ExtensionConfig::Builtin { name } => write!(f, "Builtin({})", name),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Information about the extension used for building prompts
|
|
#[derive(Clone, Debug, Serialize)]
|
|
pub struct ExtensionInfo {
|
|
name: String,
|
|
instructions: String,
|
|
has_resources: bool,
|
|
}
|
|
|
|
impl ExtensionInfo {
|
|
pub fn new(name: &str, instructions: &str, has_resources: bool) -> Self {
|
|
Self {
|
|
name: name.to_string(),
|
|
instructions: instructions.to_string(),
|
|
has_resources,
|
|
}
|
|
}
|
|
}
|