mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
feat: MCP Roots support (#7790)
This commit is contained in:
Generated
+12
-11
@@ -4327,7 +4327,7 @@ dependencies = [
|
||||
"rayon",
|
||||
"regex",
|
||||
"reqwest 0.13.2",
|
||||
"rmcp 1.1.0",
|
||||
"rmcp 1.2.0",
|
||||
"rubato",
|
||||
"sacp",
|
||||
"schemars 1.2.1",
|
||||
@@ -4399,7 +4399,7 @@ dependencies = [
|
||||
"goose-test-support",
|
||||
"http-body-util",
|
||||
"regex",
|
||||
"rmcp 1.1.0",
|
||||
"rmcp 1.2.0",
|
||||
"sacp",
|
||||
"schemars 1.2.1",
|
||||
"serde",
|
||||
@@ -4453,7 +4453,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"reqwest 0.13.2",
|
||||
"rmcp 1.1.0",
|
||||
"rmcp 1.2.0",
|
||||
"rustyline",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4497,7 +4497,7 @@ dependencies = [
|
||||
"rayon",
|
||||
"regex",
|
||||
"reqwest 0.13.2",
|
||||
"rmcp 1.1.0",
|
||||
"rmcp 1.2.0",
|
||||
"schemars 1.2.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4551,13 +4551,14 @@ dependencies = [
|
||||
"rand 0.9.2",
|
||||
"rcgen",
|
||||
"reqwest 0.13.2",
|
||||
"rmcp 1.1.0",
|
||||
"rmcp 1.2.0",
|
||||
"rustls 0.23.36",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_yaml",
|
||||
"socket2 0.6.2",
|
||||
"subtle",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
@@ -4589,7 +4590,7 @@ name = "goose-test-support"
|
||||
version = "1.27.0"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"rmcp 1.1.0",
|
||||
"rmcp 1.2.0",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
@@ -8154,9 +8155,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmcp"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cb14cb9278a12eae884c9f3c0cfeca2cc28f361211206424a1d7abed95f090"
|
||||
checksum = "ba6b9d2f0efe2258b23767f1f9e0054cfbcac9c2d6f81a031214143096d7864f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
@@ -8172,7 +8173,7 @@ dependencies = [
|
||||
"process-wrap",
|
||||
"rand 0.10.0",
|
||||
"reqwest 0.13.2",
|
||||
"rmcp-macros 1.1.0",
|
||||
"rmcp-macros 1.2.0",
|
||||
"schemars 1.2.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -8215,9 +8216,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmcp-macros"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02ea81d9482b07e1fe156ac7cf98b6823d51fb84531936a5e1cbb4eec31ad5"
|
||||
checksum = "ab9d95d7ed26ad8306352b0d5f05b593222b272790564589790d210aa15caa9e"
|
||||
dependencies = [
|
||||
"darling 0.23.0",
|
||||
"proc-macro2",
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ uninlined_format_args = "allow"
|
||||
string_slice = "warn"
|
||||
|
||||
[workspace.dependencies]
|
||||
rmcp = { version = "1.1.0", features = ["schemars", "auth"] }
|
||||
rmcp = { version = "1.2.0", features = ["schemars", "auth"] }
|
||||
sacp = "10.1.0"
|
||||
anyhow = "1.0"
|
||||
async-stream = "0.3"
|
||||
|
||||
@@ -1172,10 +1172,20 @@ impl GooseAcpAgent {
|
||||
}
|
||||
self.session_manager
|
||||
.update(&req.session_id)
|
||||
.working_dir(path)
|
||||
.working_dir(path.clone())
|
||||
.apply()
|
||||
.await
|
||||
.map_err(|e| sacp::Error::internal_error().data(e.to_string()))?;
|
||||
|
||||
// Notify MCP servers so roots stay in sync with the new working directory.
|
||||
if let Some(session) = self.sessions.lock().await.get(&req.session_id) {
|
||||
session
|
||||
.agent
|
||||
.extension_manager
|
||||
.update_working_dir(&path)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(EmptyResponse {})
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ async fn child_process_client(
|
||||
mut command: Command,
|
||||
timeout: &Option<u64>,
|
||||
provider: SharedProvider,
|
||||
working_dir: Option<&PathBuf>,
|
||||
working_dir: &PathBuf,
|
||||
docker_container: Option<String>,
|
||||
client_name: String,
|
||||
capabilities: GooseMcpClientCapabilities,
|
||||
@@ -244,21 +244,14 @@ async fn child_process_client(
|
||||
command.env("PATH", path);
|
||||
}
|
||||
|
||||
// Use explicitly passed working_dir, falling back to GOOSE_WORKING_DIR env var
|
||||
let effective_working_dir = working_dir
|
||||
.map(|p| p.to_path_buf())
|
||||
.or_else(|| std::env::var("GOOSE_WORKING_DIR").ok().map(PathBuf::from));
|
||||
|
||||
if let Some(ref dir) = effective_working_dir {
|
||||
if dir.exists() && dir.is_dir() {
|
||||
tracing::info!("Setting MCP process working directory: {:?}", dir);
|
||||
command.current_dir(dir);
|
||||
} else {
|
||||
tracing::warn!(
|
||||
"Working directory doesn't exist or isn't a directory: {:?}",
|
||||
dir
|
||||
);
|
||||
}
|
||||
if working_dir.exists() && working_dir.is_dir() {
|
||||
tracing::info!("Setting MCP process working directory: {:?}", working_dir);
|
||||
command.current_dir(working_dir);
|
||||
} else {
|
||||
tracing::warn!(
|
||||
"Working directory doesn't exist or isn't a directory: {:?}",
|
||||
working_dir
|
||||
);
|
||||
}
|
||||
|
||||
let (transport, mut stderr) = TokioChildProcess::builder(command)
|
||||
@@ -281,6 +274,7 @@ async fn child_process_client(
|
||||
docker_container,
|
||||
client_name,
|
||||
capabilities,
|
||||
working_dir.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -402,6 +396,7 @@ pub(crate) fn substitute_env_vars(value: &str, env_map: &HashMap<String, String>
|
||||
const GOOSE_USER_AGENT: reqwest::header::HeaderValue =
|
||||
reqwest::header::HeaderValue::from_static(concat!("goose/", env!("CARGO_PKG_VERSION")));
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn create_streamable_http_client(
|
||||
uri: &str,
|
||||
timeout: Option<u64>,
|
||||
@@ -410,6 +405,7 @@ async fn create_streamable_http_client(
|
||||
provider: SharedProvider,
|
||||
client_name: String,
|
||||
capabilities: GooseMcpClientCapabilities,
|
||||
roots_dir: &std::path::Path,
|
||||
) -> ExtensionResult<Box<dyn McpClientTrait>> {
|
||||
let mut default_headers = HeaderMap::new();
|
||||
|
||||
@@ -447,6 +443,7 @@ async fn create_streamable_http_client(
|
||||
provider.clone(),
|
||||
client_name.clone(),
|
||||
capabilities.clone(),
|
||||
roots_dir.to_path_buf(),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -477,6 +474,7 @@ async fn create_streamable_http_client(
|
||||
provider,
|
||||
client_name,
|
||||
capabilities,
|
||||
roots_dir.to_path_buf(),
|
||||
)
|
||||
.await?,
|
||||
))
|
||||
@@ -563,6 +561,11 @@ impl ExtensionManager {
|
||||
|
||||
let mut temp_dir = None;
|
||||
|
||||
let effective_working_dir = working_dir
|
||||
.clone()
|
||||
.or_else(|| std::env::var("GOOSE_WORKING_DIR").ok().map(PathBuf::from))
|
||||
.unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
|
||||
|
||||
let client: Box<dyn McpClientTrait> = match &config {
|
||||
ExtensionConfig::Sse { .. } => {
|
||||
return Err(ExtensionError::ConfigError(
|
||||
@@ -597,6 +600,7 @@ impl ExtensionManager {
|
||||
self.provider.clone(),
|
||||
self.client_name.clone(),
|
||||
capability,
|
||||
&effective_working_dir,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
@@ -646,10 +650,6 @@ impl ExtensionManager {
|
||||
.arg(&normalized_name);
|
||||
});
|
||||
|
||||
let effective_working_dir = working_dir
|
||||
.clone()
|
||||
.unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
|
||||
|
||||
let capabilities = GooseMcpClientCapabilities {
|
||||
mcpui: self.capabilities.mcpui,
|
||||
};
|
||||
@@ -658,7 +658,7 @@ impl ExtensionManager {
|
||||
command,
|
||||
&Some(timeout_secs),
|
||||
self.provider.clone(),
|
||||
Some(&effective_working_dir),
|
||||
&effective_working_dir,
|
||||
Some(container_id.to_string()),
|
||||
self.client_name.clone(),
|
||||
capabilities,
|
||||
@@ -681,6 +681,7 @@ impl ExtensionManager {
|
||||
self.provider.clone(),
|
||||
self.client_name.clone(),
|
||||
capabilities,
|
||||
effective_working_dir.clone(),
|
||||
)
|
||||
.await?,
|
||||
)
|
||||
@@ -729,9 +730,6 @@ impl ExtensionManager {
|
||||
})
|
||||
};
|
||||
|
||||
let effective_working_dir = working_dir
|
||||
.clone()
|
||||
.unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
|
||||
let capabilities = GooseMcpClientCapabilities {
|
||||
mcpui: self.capabilities.mcpui,
|
||||
};
|
||||
@@ -739,7 +737,7 @@ impl ExtensionManager {
|
||||
command,
|
||||
timeout,
|
||||
self.provider.clone(),
|
||||
Some(&effective_working_dir),
|
||||
&effective_working_dir,
|
||||
container.map(|c| c.id().to_string()),
|
||||
self.client_name.clone(),
|
||||
capabilities,
|
||||
@@ -767,11 +765,6 @@ impl ExtensionManager {
|
||||
command.arg("python").arg(file_path.to_str().unwrap());
|
||||
});
|
||||
|
||||
// Compute working_dir for InlinePython (runs as child process via uvx)
|
||||
let effective_working_dir = working_dir
|
||||
.clone()
|
||||
.unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
|
||||
|
||||
let capabilities = GooseMcpClientCapabilities {
|
||||
mcpui: self.capabilities.mcpui,
|
||||
};
|
||||
@@ -780,7 +773,7 @@ impl ExtensionManager {
|
||||
command,
|
||||
timeout,
|
||||
self.provider.clone(),
|
||||
Some(&effective_working_dir),
|
||||
&effective_working_dir,
|
||||
container.map(|c| c.id().to_string()),
|
||||
self.client_name.clone(),
|
||||
capabilities,
|
||||
@@ -854,6 +847,15 @@ impl ExtensionManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_working_dir(&self, new_dir: &std::path::Path) {
|
||||
let extensions = self.extensions.lock().await;
|
||||
for (name, ext) in extensions.iter() {
|
||||
if let Err(e) = ext.client.update_working_dir(new_dir.to_path_buf()).await {
|
||||
tracing::warn!(extension = %name, error = %e, "failed to update roots");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_extension_and_tool_counts(&self, session_id: &str) -> (usize, usize) {
|
||||
let enabled_extensions_count = self.extensions.lock().await.len();
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ use crate::agents::types::SharedProvider;
|
||||
use crate::session_context::{SESSION_ID_HEADER, WORKING_DIR_HEADER};
|
||||
use rmcp::model::{
|
||||
CreateElicitationRequestParams, CreateElicitationResult, ElicitationAction, ErrorCode,
|
||||
ExtensionCapabilities, Extensions, JsonObject, LoggingMessageNotification, Meta,
|
||||
SamplingMessageContent,
|
||||
ExtensionCapabilities, Extensions, JsonObject, ListRootsResult, LoggingMessageNotification,
|
||||
Meta, Root, SamplingMessageContent,
|
||||
};
|
||||
/// MCP client implementation for Goose
|
||||
use rmcp::{
|
||||
@@ -25,7 +25,7 @@ use rmcp::{
|
||||
ClientHandler, ErrorData, Peer, RoleClient, ServiceError, ServiceExt,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use std::{path::PathBuf, sync::Arc, time::Duration};
|
||||
use tokio::sync::{
|
||||
mpsc::{self, Sender},
|
||||
Mutex,
|
||||
@@ -100,17 +100,19 @@ pub trait McpClientTrait: Send + Sync {
|
||||
async fn get_moim(&self, _session_id: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
async fn update_working_dir(&self, _new_dir: PathBuf) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GooseClient {
|
||||
notification_handlers: Arc<Mutex<Vec<Sender<ServerNotification>>>>,
|
||||
provider: SharedProvider,
|
||||
/// Fallback session_id for server-initiated callbacks (e.g. sampling/createMessage)
|
||||
/// that don't include the session_id in their MCP extensions metadata.
|
||||
/// Set once on first request; never cleared (the id is invariant per McpClient).
|
||||
session_id: Mutex<Option<String>>,
|
||||
client_name: String,
|
||||
capabilities: GooseMcpClientCapabilities,
|
||||
working_dir: Arc<tokio::sync::RwLock<PathBuf>>,
|
||||
}
|
||||
|
||||
impl GooseClient {
|
||||
@@ -119,6 +121,7 @@ impl GooseClient {
|
||||
provider: SharedProvider,
|
||||
client_name: String,
|
||||
capabilities: GooseMcpClientCapabilities,
|
||||
working_dir: PathBuf,
|
||||
) -> Self {
|
||||
GooseClient {
|
||||
notification_handlers: handlers,
|
||||
@@ -126,9 +129,14 @@ impl GooseClient {
|
||||
session_id: Mutex::new(None),
|
||||
client_name,
|
||||
capabilities,
|
||||
working_dir: Arc::new(tokio::sync::RwLock::new(working_dir)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shared_working_dir(&self) -> Arc<tokio::sync::RwLock<PathBuf>> {
|
||||
self.working_dir.clone()
|
||||
}
|
||||
|
||||
async fn set_session_id(&self, session_id: &str) {
|
||||
let mut slot = self.session_id.lock().await;
|
||||
assert!(
|
||||
@@ -158,7 +166,21 @@ impl GooseClient {
|
||||
}
|
||||
}
|
||||
|
||||
fn working_dir_roots(dir: &std::path::Path) -> ListRootsResult {
|
||||
let uri = url::Url::from_file_path(dir)
|
||||
.map(|u| u.to_string())
|
||||
.unwrap_or_else(|()| format!("file://{}", dir.display()));
|
||||
ListRootsResult::new(vec![Root::new(uri).with_name("working_directory")])
|
||||
}
|
||||
|
||||
impl ClientHandler for GooseClient {
|
||||
async fn list_roots(
|
||||
&self,
|
||||
_context: RequestContext<RoleClient>,
|
||||
) -> Result<ListRootsResult, ErrorData> {
|
||||
Ok(working_dir_roots(&self.working_dir.read().await))
|
||||
}
|
||||
|
||||
async fn on_progress(
|
||||
&self,
|
||||
params: rmcp::model::ProgressNotificationParam,
|
||||
@@ -337,6 +359,7 @@ impl ClientHandler for GooseClient {
|
||||
|
||||
InitializeRequestParams::new(
|
||||
ClientCapabilities::builder()
|
||||
.enable_roots()
|
||||
.enable_extensions_with(extensions)
|
||||
.enable_sampling()
|
||||
.enable_elicitation()
|
||||
@@ -372,6 +395,7 @@ impl McpClient {
|
||||
provider: SharedProvider,
|
||||
client_name: String,
|
||||
capabilities: GooseMcpClientCapabilities,
|
||||
working_dir: PathBuf,
|
||||
) -> Result<Self, ClientInitializeError>
|
||||
where
|
||||
T: IntoTransport<RoleClient, E, A>,
|
||||
@@ -384,6 +408,7 @@ impl McpClient {
|
||||
None,
|
||||
client_name,
|
||||
capabilities,
|
||||
working_dir,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -395,6 +420,7 @@ impl McpClient {
|
||||
docker_container: Option<String>,
|
||||
client_name: String,
|
||||
capabilities: GooseMcpClientCapabilities,
|
||||
working_dir: PathBuf,
|
||||
) -> Result<Self, ClientInitializeError>
|
||||
where
|
||||
T: IntoTransport<RoleClient, E, A>,
|
||||
@@ -408,6 +434,7 @@ impl McpClient {
|
||||
provider,
|
||||
client_name.clone(),
|
||||
capabilities.clone(),
|
||||
working_dir,
|
||||
);
|
||||
let client: rmcp::service::RunningService<rmcp::RoleClient, GooseClient> =
|
||||
client.serve(transport).await?;
|
||||
@@ -426,6 +453,14 @@ impl McpClient {
|
||||
self.docker_container.as_deref()
|
||||
}
|
||||
|
||||
async fn do_update_working_dir(&self, new_dir: PathBuf) -> Result<(), Error> {
|
||||
let client = self.client.lock().await;
|
||||
let shared = client.service().shared_working_dir();
|
||||
*shared.write().await = new_dir;
|
||||
client.peer().notify_roots_list_changed().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_request_with_context(
|
||||
&self,
|
||||
session_id: &str,
|
||||
@@ -639,6 +674,10 @@ impl McpClientTrait for McpClient {
|
||||
self.notification_subscribers.lock().await.push(tx);
|
||||
rx
|
||||
}
|
||||
|
||||
async fn update_working_dir(&self, new_dir: PathBuf) -> Result<(), Error> {
|
||||
self.do_update_working_dir(new_dir).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Injects the given session_id and working_dir into Extensions._meta.
|
||||
@@ -736,6 +775,7 @@ mod tests {
|
||||
Arc::new(Mutex::new(None)),
|
||||
platform.to_string(),
|
||||
capabilities,
|
||||
std::env::current_dir().unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -946,4 +986,23 @@ mod tests {
|
||||
|
||||
assert_eq!(mime_types, &json!(["text/html;profile=mcp-app"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_capabilities_advertise_roots() {
|
||||
let client = new_client(GoosePlatform::GooseCli);
|
||||
let info = ClientHandler::get_info(&client);
|
||||
assert!(
|
||||
info.capabilities.roots.is_some(),
|
||||
"client should advertise roots capability"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_working_dir_roots_returns_current_dir_as_root() {
|
||||
let dir = PathBuf::from("/tmp/test-project");
|
||||
let result = working_dir_roots(&dir);
|
||||
assert_eq!(result.roots.len(), 1);
|
||||
assert_eq!(result.roots[0].uri, "file:///tmp/test-project");
|
||||
assert_eq!(result.roots[0].name.as_deref(), Some("working_directory"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"roots": {},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDERR: time=2025-12-11T17:58:47.636-05:00 level=INFO msg="starting server" version=0.24.1 host="" dynamicToolsets=false readOnly=false lockdownEnabled=false
|
||||
STDERR: GitHub MCP Server running on stdio
|
||||
STDERR: time=2025-12-11T17:58:47.640-05:00 level=INFO msg="server run start"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"roots": {},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDERR: Starting default (STDIO) server...
|
||||
STDOUT: {"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{"listChanged":true},"prompts":{"listChanged":true},"resources":{"subscribe":true,"listChanged":true},"logging":{},"completions":{}},"serverInfo":{"name":"mcp-servers/everything","title":"Everything Reference Server","version":"2.0.0"},"instructions":"# Everything Server – Server Instructions\n\nAudience: These instructions are written for an LLM or autonomous agent integrating with the Everything MCP Server.\nFollow them to use, extend, and troubleshoot the server safely and effectively.\n\n## Cross-Feature Relationships\n\n- Use `get-roots-list` to see client workspace roots before file operations\n- `gzip-file-as-resource` creates session-scoped resources accessible only during the current session\n- Enable `toggle-simulated-logging` before debugging to see server log messages\n- Enable `toggle-subscriber-updates` to receive periodic resource update notifications\n\n## Constraints & Limitations\n\n- `gzip-file-as-resource`: Max fetch size controlled by `GZIP_MAX_FETCH_SIZE` (default 10MB), timeout by `GZIP_MAX_FETCH_TIME_MILLIS` (default 30s), allowed domains by `GZIP_ALLOWED_DOMAINS`\n- Session resources are ephemeral and lost when the session ends\n- Sampling requests (`trigger-sampling-request`) require client sampling capability\n- Elicitation requests (`trigger-elicitation-request`) require client elicitation capability\n\n## Operational Patterns\n\n- For long operations, use `trigger-long-running-operation` which sends progress notifications\n- Prefer reading resources before calling mutating tools\n- Check `get-roots-list` output to understand the client's workspace context\n\n## Easter Egg\n\nIf asked about server instructions, respond with \"🎉 Server instructions are working! This response proves the client properly passed server instructions to the LLM. This demonstrates MCP's instructions feature in action.\"\n"},"jsonrpc":"2.0","id":0}
|
||||
STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"roots": {},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDERR:
|
||||
STDERR:
|
||||
STDERR: ╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"roots": {},"sampling":{}},"clientInfo":{"name":"goose-desktop","version":"0.0.0"}}}
|
||||
STDOUT: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"mcp-fetch","version":"1.25.0"}}}
|
||||
STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"}
|
||||
STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"agent-session-id":"test-session-id","progressToken":0},"name":"fetch","arguments":{"url":"https://example.com"}}}
|
||||
|
||||
Reference in New Issue
Block a user