Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
1,521 changes: 1,085 additions & 436 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion crates/goose-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ goose = { path = "../goose" }
goose-bench = { path = "../goose-bench" }
goose-mcp = { path = "../goose-mcp" }
mcp-client = { path = "../mcp-client" }
mcp-server = { path = "../mcp-server" }
mcp-core = { path = "../mcp-core" }
rmcp = { workspace = true }
agent-client-protocol = "0.1.1"
Expand Down
96 changes: 40 additions & 56 deletions crates/goose-cli/src/commands/mcp.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
use anyhow::{anyhow, Result};
use anyhow::Result;
use goose_mcp::{
AutoVisualiserRouter, ComputerControllerRouter, DeveloperServer, MemoryRouter, TutorialRouter,
AutoVisualiserServer, ComputerControllerServer, DeveloperServer, MemoryServer, TutorialServer,
};
use mcp_server::router::RouterService;
use mcp_server::{BoundedService, ByteTransport, Server};
use rmcp::{transport::stdio, ServiceExt};
use tokio::io::{stdin, stdout};

use std::sync::Arc;
use tokio::sync::Notify;

#[cfg(unix)]
use nix::sys::signal::{kill, Signal};
#[cfg(unix)]
use nix::unistd::getpgrp;
#[cfg(unix)]
use nix::unistd::Pid;

pub async fn run_server(name: &str) -> Result<()> {
crate::logging::setup_logging(Some(&format!("mcp-{name}")), None)?;

if name == "googledrive" || name == "google_drive" {
return Err(anyhow!(
"the built-in Google Drive extension has been removed"
));
}

tracing::info!("Starting MCP server");

if name == "developer" {
Expand All @@ -39,44 +20,47 @@ pub async fn run_server(name: &str) -> Result<()> {
service.waiting().await?;
return Ok(());
}
if name == "tutorial" {
let service = TutorialServer::new()
.serve(stdio())
.await
.inspect_err(|e| {
tracing::error!("serving error: {:?}", e);
})?;

let router: Option<Box<dyn BoundedService>> = match name {
"computercontroller" => Some(Box::new(RouterService(ComputerControllerRouter::new()))),
"autovisualiser" => Some(Box::new(RouterService(AutoVisualiserRouter::new()))),
"memory" => Some(Box::new(RouterService(MemoryRouter::new()))),
"tutorial" => Some(Box::new(RouterService(TutorialRouter::new()))),
_ => None,
};

let shutdown = Arc::new(Notify::new());
let shutdown_clone = shutdown.clone();

tokio::spawn(async move {
crate::signal::shutdown_signal().await;
shutdown_clone.notify_one();
});
service.waiting().await?;
return Ok(());
}
if name == "memory" {
let service = MemoryServer::new().serve(stdio()).await.inspect_err(|e| {
tracing::error!("serving error: {:?}", e);
})?;

let server = Server::new(router.unwrap_or_else(|| panic!("Unknown server requested {}", name)));
let transport = ByteTransport::new(stdin(), stdout());
service.waiting().await?;
return Ok(());
}
if name == "computercontroller" {
let service = ComputerControllerServer::new()
.serve(stdio())
.await
.inspect_err(|e| {
tracing::error!("serving error: {:?}", e);
})?;

tracing::info!("Server initialized and ready to handle requests");
service.waiting().await?;
return Ok(());
}
if name == "autovisualiser" {
let service = AutoVisualiserServer::new()
.serve(stdio())
.await
.inspect_err(|e| {
tracing::error!("serving error: {:?}", e);
})?;

tokio::select! {
result = server.run(transport) => {
Ok(result?)
}
_ = shutdown.notified() => {
// On Unix systems, kill the entire process group
#[cfg(unix)]
{
fn terminate_process_group() {
let pgid = getpgrp();
kill(Pid::from_raw(-pgid.as_raw()), Signal::SIGTERM)
.expect("Failed to send SIGTERM to process group");
}
terminate_process_group();
}
Ok(())
}
service.waiting().await?;
return Ok(());
}

panic!("Unknown server requested {}", name);
}
3 changes: 1 addition & 2 deletions crates/goose-mcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ workspace = true

[dependencies]
mcp-core = { path = "../mcp-core" }
mcp-server = { path = "../mcp-server" }
rmcp = { version = "0.6.0", features = ["server", "client", "transport-io", "macros"] }
anyhow = "1.0.94"
tokio = { version = "1", features = ["full"] }
Expand All @@ -29,7 +28,7 @@ schemars = "1.0"
lazy_static = "1.5"
shellexpand = "3.1.0"
indoc = "2.0.5"
xcap = "0.0.14"
xcap = "0.7.0"
reqwest = { version = "0.11", features = [
"json",
"rustls-tls-native-roots",
Expand Down
23 changes: 10 additions & 13 deletions crates/goose-mcp/examples/mcp.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// An example script to run an MCP server
// An example script to run an MCP server using the rmcp SDK
use anyhow::Result;
use goose_mcp::MemoryRouter;
use mcp_server::router::RouterService;
use mcp_server::{ByteTransport, Server};
use tokio::io::{stdin, stdout};
use goose_mcp::MemoryServer;
use rmcp::{transport::stdio, ServiceExt};
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_subscriber::{self, EnvFilter};

Expand All @@ -22,15 +20,14 @@ async fn main() -> Result<()> {
.with_line_number(true)
.init();

tracing::info!("Starting MCP server");
tracing::info!("Starting MCP server using rmcp SDK");

// Create an instance of our counter router
let router = RouterService(MemoryRouter::new());
// Create an instance of our memory server
let memory_server = MemoryServer::new();

// Create and run the server
let server = Server::new(router);
let transport = ByteTransport::new(stdin(), stdout());
// Create the transport and run the server
let (stdin, stdout) = stdio();
memory_server.serve((stdin, stdout)).await?;

tracing::info!("Server initialized and ready to handle requests");
Ok(server.run(transport).await?)
Ok(())
}
Loading
Loading