Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ description = "An AI agent"
uninlined_format_args = "allow"

[workspace.dependencies]
rmcp = { version = "0.6.2", features = ["schemars", "auth"] }
rmcp = { version = "0.7.0", features = ["schemars", "auth"] }

# Patch for Windows cross-compilation issue with crunchy
[patch.crates-io]
Expand Down
2 changes: 2 additions & 0 deletions crates/goose-cli/src/session/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,11 +458,13 @@ mod tests {
name: "required_arg".to_string(),
description: Some("A required argument".to_string()),
required: Some(true),
title: None,
},
PromptArgument {
name: "optional_arg".to_string(),
description: Some("An optional argument".to_string()),
required: Some(false),
title: None,
},
];

Expand Down
2 changes: 1 addition & 1 deletion crates/goose-mcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ workspace = true
[dependencies]
goose = { path = "../goose" }
mcp-core = { path = "../mcp-core" }
rmcp = { version = "0.6.0", features = ["server", "client", "transport-io", "macros"] }
rmcp = { version = "0.7.0", features = ["server", "client", "transport-io", "macros"] }
anyhow = "1.0.94"
tokio = { version = "1", features = ["full"] }
tokio-stream = { version = "0.1", features = ["io-util"] }
Expand Down
9 changes: 6 additions & 3 deletions crates/goose-mcp/src/autovisualiser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@ impl ServerHandler for AutoVisualiserRouter {
server_info: Implementation {
name: "goose-autovisualiser".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
icons: None,
website_url: None,
},
capabilities: ServerCapabilities::builder().enable_tools().build(),
instructions: Some(self.instructions.clone()),
Expand Down Expand Up @@ -458,7 +461,7 @@ impl AutoVisualiserRouter {
/// show a Sankey diagram from flow data
#[tool(
name = "render_sankey",
description = r#"show a Sankey diagram from flow data
description = r#"show a Sankey diagram from flow data
The data must contain:
- nodes: Array of objects with 'name' and optional 'category' properties
- links: Array of objects with 'source', 'target', and 'value' properties
Expand Down Expand Up @@ -537,7 +540,7 @@ Example:
/// show a radar chart (spider chart) for multi-dimensional data comparison
#[tool(
name = "render_radar",
description = r#"show a radar chart (spider chart) for multi-dimensional data comparison
description = r#"show a radar chart (spider chart) for multi-dimensional data comparison

The data must contain:
- labels: Array of strings representing the dimensions/axes
Expand All @@ -552,7 +555,7 @@ Example:
"data": [85, 70, 90, 75, 80]
},
{
"label": "Player 2",
"label": "Player 2",
"data": [75, 85, 80, 90, 70]
}
]
Expand Down
24 changes: 12 additions & 12 deletions crates/goose-mcp/src/computercontroller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use reqwest::{Client, Url};
use rmcp::{
handler::server::{router::tool::ToolRouter, wrapper::Parameters},
model::{
CallToolResult, Content, ErrorCode, ErrorData, Implementation, ListResourcesResult,
PaginatedRequestParam, RawResource, ReadResourceRequestParam, ReadResourceResult, Resource,
ResourceContents, ServerCapabilities, ServerInfo,
AnnotateAble, CallToolResult, Content, ErrorCode, ErrorData, Implementation,
ListResourcesResult, PaginatedRequestParam, RawResource, ReadResourceRequestParam,
ReadResourceResult, Resource, ResourceContents, ServerCapabilities, ServerInfo,
},
schemars::JsonSchema,
service::RequestContext,
Expand Down Expand Up @@ -1293,6 +1293,9 @@ impl ServerHandler for ComputerControllerServer {
server_info: Implementation {
name: "goose-computercontroller".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
icons: None,
website_url: None,
},
capabilities: ServerCapabilities::builder()
.enable_tools()
Expand All @@ -1311,15 +1314,12 @@ impl ServerHandler for ComputerControllerServer {
let active_resources = self.active_resources.lock().unwrap();
let resources: Vec<Resource> = active_resources
.keys()
.map(|uri| Resource {
raw: RawResource {
name: uri.split('/').next_back().unwrap_or("").to_string(),
uri: uri.clone(),
description: None,
mime_type: None,
size: None,
},
annotations: None,
.map(|uri| {
RawResource::new(
uri.clone(),
uri.split('/').next_back().unwrap_or("").to_string(),
)
.no_annotation()
})
.collect();
Ok(ListResourcesResult {
Expand Down
4 changes: 4 additions & 0 deletions crates/goose-mcp/src/developer/rmcp_developer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ fn load_prompt_files() -> HashMap<String, Prompt> {
name: arg.name,
description: arg.description,
required: arg.required,
title: None,
})
.collect::<Vec<PromptArgument>>();

Expand Down Expand Up @@ -377,6 +378,9 @@ impl ServerHandler for DeveloperServer {
server_info: Implementation {
name: "goose-developer".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
icons: None,
website_url: None,
},
capabilities: ServerCapabilities::builder()
.enable_tools()
Expand Down
3 changes: 3 additions & 0 deletions crates/goose-mcp/src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,9 @@ impl ServerHandler for MemoryServer {
server_info: Implementation {
name: "goose-memory".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
icons: None,
website_url: None,
},
capabilities: ServerCapabilities::builder().enable_tools().build(),
instructions: Some(self.instructions.clone()),
Expand Down
3 changes: 3 additions & 0 deletions crates/goose-mcp/src/tutorial/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ impl ServerHandler for TutorialServer {
server_info: Implementation {
name: "goose-tutorial".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
icons: None,
website_url: None,
},
capabilities: ServerCapabilities::builder().enable_tools().build(),
instructions: Some(self.instructions.clone()),
Expand Down
36 changes: 7 additions & 29 deletions crates/goose-server/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata};
use goose::session::info::SessionInfo;
use goose::session::SessionMetadata;
use rmcp::model::{
Annotations, Content, EmbeddedResource, ImageContent, RawEmbeddedResource, RawImageContent,
RawResource, RawTextContent, ResourceContents, Role, TextContent, Tool, ToolAnnotations,
Annotations, Content, EmbeddedResource, Icon, ImageContent, RawAudioContent,
RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ResourceContents, Role,
TextContent, Tool, ToolAnnotations,
};
use utoipa::{OpenApi, ToSchema};

Expand Down Expand Up @@ -319,38 +320,14 @@ derive_utoipa!(ImageContent as ImageContentSchema);
derive_utoipa!(TextContent as TextContentSchema);
derive_utoipa!(RawTextContent as RawTextContentSchema);
derive_utoipa!(RawImageContent as RawImageContentSchema);
derive_utoipa!(RawAudioContent as RawAudioContentSchema);
derive_utoipa!(RawEmbeddedResource as RawEmbeddedResourceSchema);
derive_utoipa!(RawResource as RawResourceSchema);
derive_utoipa!(Tool as ToolSchema);
derive_utoipa!(ToolAnnotations as ToolAnnotationsSchema);
derive_utoipa!(Annotations as AnnotationsSchema);
derive_utoipa!(ResourceContents as ResourceContentsSchema);

// Create a manual schema for the generic Annotated type
// We manually define this to avoid circular references from RawContent::Audio(AudioContent)
// where AudioContent = Annotated<RawAudioContent>
struct AnnotatedSchema {}

impl<'__s> ToSchema<'__s> for AnnotatedSchema {
fn schema() -> (&'__s str, utoipa::openapi::RefOr<utoipa::openapi::Schema>) {
// Create a oneOf schema with only the variants we actually use in the API
// This avoids the circular reference from RawContent::Audio(AudioContent)
let schema = Schema::OneOf(
OneOfBuilder::new()
.item(RefOr::Ref(Ref::new("#/components/schemas/RawTextContent")))
.item(RefOr::Ref(Ref::new("#/components/schemas/RawImageContent")))
.item(RefOr::Ref(Ref::new(
"#/components/schemas/RawEmbeddedResource",
)))
.build(),
);
("Annotated", RefOr::T(schema))
}

fn aliases() -> Vec<(&'__s str, utoipa::openapi::schema::Schema)> {
Vec::new()
}
}
derive_utoipa!(Icon as IconSchema);

#[allow(dead_code)] // Used by utoipa for OpenAPI generation
#[derive(OpenApi)]
Expand Down Expand Up @@ -430,9 +407,9 @@ impl<'__s> ToSchema<'__s> for AnnotatedSchema {
TextContentSchema,
RawTextContentSchema,
RawImageContentSchema,
RawAudioContentSchema,
RawEmbeddedResourceSchema,
RawResourceSchema,
AnnotatedSchema,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this just not used in the frontend?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in prior versions of rmcp, the audiocontent enum variant was the annotated type, not the raw type (fixed here: modelcontextprotocol/rust-sdk@1b70f5b#diff-289d941b1f937b4f5adddf8e939caa1a7e93b41e09afa6517bbee4238a5dff5cL69) which made our schema gen a bit weird, but now that it's a RawAudioContent we don't need this

ToolResponse,
ToolRequest,
ToolConfirmationRequest,
Expand All @@ -456,6 +433,7 @@ impl<'__s> ToSchema<'__s> for AnnotatedSchema {
ModelInfo,
SessionInfo,
SessionMetadata,
IconSchema,
goose::session::ExtensionData,
super::routes::schedule::CreateScheduleRequest,
super::routes::schedule::UpdateScheduleRequest,
Expand Down
38 changes: 17 additions & 21 deletions crates/goose/src/agents/extension_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,8 @@ impl ExtensionManager {
input_schema: tool.input_schema,
annotations: tool.annotations,
output_schema: tool.output_schema,
icons: None,
title: None,
});
}
}
Expand Down Expand Up @@ -1117,27 +1119,21 @@ mod tests {
use std::sync::Arc;
Ok(ListToolsResult {
tools: vec![
Tool {
name: "tool".into(),
description: Some("A basic tool".into()),
input_schema: Arc::new(json!({}).as_object().unwrap().clone()),
annotations: None,
output_schema: None,
},
Tool {
name: "available_tool".into(),
description: Some("An available tool".into()),
input_schema: Arc::new(json!({}).as_object().unwrap().clone()),
annotations: None,
output_schema: None,
},
Tool {
name: "hidden_tool".into(),
description: Some("A hidden tool".into()),
input_schema: Arc::new(json!({}).as_object().unwrap().clone()),
annotations: None,
output_schema: None,
},
Tool::new(
"tool".to_string(),
"A basic tool".to_string(),
Arc::new(json!({}).as_object().unwrap().clone()),
),
Tool::new(
"available_tool".to_string(),
"An available tool".to_string(),
Arc::new(json!({}).as_object().unwrap().clone()),
),
Tool::new(
"hidden_tool".to_string(),
"hidden tool".to_string(),
Arc::new(json!({}).as_object().unwrap().clone()),
),
],
next_cursor: None,
})
Expand Down
16 changes: 9 additions & 7 deletions crates/goose/src/oauth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ const CALLBACK_TEMPLATE: &str = include_str!("oauth_callback.html");

#[derive(Clone)]
struct AppState {
code_receiver: Arc<Mutex<Option<oneshot::Sender<String>>>>,
code_receiver: Arc<Mutex<Option<oneshot::Sender<CallbackParams>>>>,
}

#[derive(Debug, Deserialize)]
struct CallbackParams {
code: String,
#[allow(dead_code)]
state: Option<String>,
state: String,
}

pub async fn oauth_flow(
Expand All @@ -45,7 +44,7 @@ pub async fn oauth_flow(
}
}

let (code_sender, code_receiver) = oneshot::channel::<String>();
let (code_sender, code_receiver) = oneshot::channel::<CallbackParams>();
let app_state = AppState {
code_receiver: Arc::new(Mutex::new(Some(code_sender))),
};
Expand All @@ -55,7 +54,7 @@ pub async fn oauth_flow(
let rendered = rendered.clone();
async move {
if let Some(sender) = state.code_receiver.lock().await.take() {
let _ = sender.send(params.code);
let _ = sender.send(params);
}
Html(rendered)
}
Expand Down Expand Up @@ -86,8 +85,11 @@ pub async fn oauth_flow(
eprintln!(" {}", authorization_url);
}

let auth_code = code_receiver.await?;
oauth_state.handle_callback(&auth_code).await?;
let CallbackParams {
code: auth_code,
state: csrf_token,
} = code_receiver.await?;
oauth_state.handle_callback(&auth_code, &csrf_token).await?;

if let Err(e) = save_credentials(name, &oauth_state).await {
warn!("Failed to save credentials: {}", e);
Expand Down
3 changes: 3 additions & 0 deletions crates/mcp-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ impl ClientHandler for GooseClient {
client_info: Implementation {
name: "goose".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
icons: None,
title: None,
website_url: None,
},
}
}
Expand Down
Loading
Loading