Skip to content
6 changes: 6 additions & 0 deletions crates/goose-cli/src/commands/configure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub async fn handle_configure() -> Result<(), Box<dyn Error>> {
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: Some(true),
description: None,
available_tools: Vec::new(),
},
})?;
}
Expand Down Expand Up @@ -771,6 +772,7 @@ pub fn configure_extensions_dialog() -> Result<(), Box<dyn Error>> {
timeout: Some(timeout),
bundled: Some(true),
description: None,
available_tools: Vec::new(),
},
})?;

Expand Down Expand Up @@ -878,6 +880,7 @@ pub fn configure_extensions_dialog() -> Result<(), Box<dyn Error>> {
description,
timeout: Some(timeout),
bundled: None,
available_tools: Vec::new(),
},
})?;

Expand Down Expand Up @@ -980,6 +983,7 @@ pub fn configure_extensions_dialog() -> Result<(), Box<dyn Error>> {
description,
timeout: Some(timeout),
bundled: None,
available_tools: Vec::new(),
},
})?;

Expand Down Expand Up @@ -1107,6 +1111,7 @@ pub fn configure_extensions_dialog() -> Result<(), Box<dyn Error>> {
description,
timeout: Some(timeout),
bundled: None,
available_tools: Vec::new(),
},
})?;

Expand Down Expand Up @@ -1736,6 +1741,7 @@ pub async fn handle_openrouter_auth() -> Result<(), Box<dyn Error>> {
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: Some(true),
description: None,
available_tools: Vec::new(),
},
}) {
Ok(_) => println!("✓ Developer extension enabled"),
Expand Down
6 changes: 6 additions & 0 deletions crates/goose-cli/src/recipes/secret_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ mod tests {
description: None,
timeout: None,
bundled: None,
available_tools: Vec::new(),
},
ExtensionConfig::Stdio {
name: "slack-mcp".to_string(),
Expand All @@ -153,13 +154,15 @@ mod tests {
timeout: None,
description: None,
bundled: None,
available_tools: Vec::new(),
},
ExtensionConfig::Builtin {
name: "builtin-ext".to_string(),
display_name: None,
description: None,
timeout: None,
bundled: None,
available_tools: Vec::new(),
},
]),
context: None,
Expand Down Expand Up @@ -237,6 +240,7 @@ mod tests {
description: None,
timeout: None,
bundled: None,
available_tools: Vec::new(),
},
ExtensionConfig::Stdio {
name: "service-b".to_string(),
Expand All @@ -247,6 +251,7 @@ mod tests {
timeout: None,
description: None,
bundled: None,
available_tools: Vec::new(),
},
]),
context: None,
Expand Down Expand Up @@ -294,6 +299,7 @@ mod tests {
description: None,
timeout: None,
bundled: None,
available_tools: Vec::new(),
}]),
sub_recipes: Some(vec![SubRecipe {
name: "child-recipe".to_string(),
Expand Down
4 changes: 4 additions & 0 deletions crates/goose-cli/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ impl Session {
// TODO: should set timeout
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: None,
available_tools: Vec::new(),
};

self.agent
Expand Down Expand Up @@ -244,6 +245,7 @@ impl Session {
// TODO: should set timeout
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: None,
available_tools: Vec::new(),
};

self.agent
Expand Down Expand Up @@ -278,6 +280,7 @@ impl Session {
// TODO: should set timeout
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: None,
available_tools: Vec::new(),
};

self.agent
Expand All @@ -304,6 +307,7 @@ impl Session {
timeout: Some(goose::config::DEFAULT_EXTENSION_TIMEOUT),
bundled: None,
description: None,
available_tools: Vec::new(),
};
self.agent
.add_extension(config)
Expand Down
5 changes: 5 additions & 0 deletions crates/goose-server/src/routes/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ async fn add_extension(
description: None,
timeout,
bundled: None,
available_tools: Vec::new(),
},
ExtensionConfigRequest::StreamableHttp {
name,
Expand All @@ -211,6 +212,7 @@ async fn add_extension(
description: None,
timeout,
bundled: None,
available_tools: Vec::new(),
},
ExtensionConfigRequest::Stdio {
name,
Expand Down Expand Up @@ -241,6 +243,7 @@ async fn add_extension(
env_keys,
timeout,
bundled: None,
available_tools: Vec::new(),
}
}
ExtensionConfigRequest::Builtin {
Expand All @@ -253,6 +256,7 @@ async fn add_extension(
timeout,
bundled: None,
description: None,
available_tools: Vec::new(),
},
ExtensionConfigRequest::Frontend {
name,
Expand All @@ -263,6 +267,7 @@ async fn add_extension(
tools,
instructions,
bundled: None,
available_tools: Vec::new(),
},
};

Expand Down
1 change: 1 addition & 0 deletions crates/goose/src/agents/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ impl Agent {
tools,
instructions,
bundled: _,
available_tools: _,
} => {
// For frontend tools, just store them in the frontend_tools map
let mut frontend_tools = self.frontend_tools.lock().await;
Expand Down
47 changes: 47 additions & 0 deletions crates/goose/src/agents/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ pub enum ExtensionConfig {
/// Whether this extension is bundled with Goose
#[serde(default)]
bundled: Option<bool>,
#[serde(default)]
available_tools: Vec<String>,
},
/// Standard I/O client with command and arguments
#[serde(rename = "stdio")]
Expand All @@ -180,6 +182,8 @@ pub enum ExtensionConfig {
/// Whether this extension is bundled with Goose
#[serde(default)]
bundled: Option<bool>,
#[serde(default)]
available_tools: Vec<String>,
},
/// Built-in extension that is part of the goose binary
#[serde(rename = "builtin")]
Expand All @@ -192,6 +196,8 @@ pub enum ExtensionConfig {
/// Whether this extension is bundled with Goose
#[serde(default)]
bundled: Option<bool>,
#[serde(default)]
available_tools: Vec<String>,
},
/// Streamable HTTP client with a URI endpoint using MCP Streamable HTTP specification
#[serde(rename = "streamable_http")]
Expand All @@ -212,6 +218,8 @@ pub enum ExtensionConfig {
/// Whether this extension is bundled with Goose
#[serde(default)]
bundled: Option<bool>,
#[serde(default)]
available_tools: Vec<String>,
},
/// Frontend-provided tools that will be called through the frontend
#[serde(rename = "frontend")]
Expand All @@ -225,6 +233,8 @@ pub enum ExtensionConfig {
/// Whether this extension is bundled with Goose
#[serde(default)]
bundled: Option<bool>,
#[serde(default)]
available_tools: Vec<String>,
},
/// Inline Python code that will be executed using uvx
#[serde(rename = "inline_python")]
Expand All @@ -240,6 +250,8 @@ pub enum ExtensionConfig {
/// Python package dependencies required by this extension
#[serde(default)]
dependencies: Option<Vec<String>>,
#[serde(default)]
available_tools: Vec<String>,
},
}

Expand All @@ -251,6 +263,7 @@ impl Default for ExtensionConfig {
description: None,
timeout: Some(config::DEFAULT_EXTENSION_TIMEOUT),
bundled: Some(true),
available_tools: Vec::new(),
}
}
}
Expand All @@ -265,6 +278,7 @@ impl ExtensionConfig {
description: Some(description.into()),
timeout: Some(timeout.into()),
bundled: None,
available_tools: Vec::new(),
}
}

Expand All @@ -283,6 +297,7 @@ impl ExtensionConfig {
description: Some(description.into()),
timeout: Some(timeout.into()),
bundled: None,
available_tools: Vec::new(),
}
}

Expand All @@ -301,6 +316,7 @@ impl ExtensionConfig {
description: Some(description.into()),
timeout: Some(timeout.into()),
bundled: None,
available_tools: Vec::new(),
}
}

Expand All @@ -316,6 +332,7 @@ impl ExtensionConfig {
description: Some(description.into()),
timeout: Some(timeout.into()),
dependencies: None,
available_tools: Vec::new(),
}
}

Expand All @@ -333,6 +350,7 @@ impl ExtensionConfig {
timeout,
description,
bundled,
available_tools,
..
} => Self::Stdio {
name,
Expand All @@ -343,6 +361,7 @@ impl ExtensionConfig {
description,
timeout,
bundled,
available_tools,
},
other => other,
}
Expand All @@ -365,6 +384,34 @@ impl ExtensionConfig {
}
.to_string()
}

/// 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 {
available_tools, ..
}
| Self::Stdio {
available_tools, ..
}
| Self::Builtin {
available_tools, ..
}
| Self::InlinePython {
available_tools, ..
}
| Self::Frontend {
available_tools, ..
} => available_tools,
};

// If no tools are specified, all tools are available
// If tools are specified, only those tools are available
available_tools.is_empty() || available_tools.contains(&tool_name.to_string())
}
}

impl std::fmt::Display for ExtensionConfig {
Expand Down
Loading