mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-17 14:14:26 +01:00
feat: Handle MCP server notification messages (#2613)
Co-authored-by: Michael Neale <michael.neale@gmail.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
use mcp_client::{
|
||||
client::{ClientCapabilities, ClientInfo, McpClient, McpClientTrait},
|
||||
transport::{SseTransport, StdioTransport, Transport},
|
||||
McpService,
|
||||
};
|
||||
use rand::Rng;
|
||||
use rand::SeedableRng;
|
||||
@@ -20,18 +19,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let transport1 = StdioTransport::new("uvx", vec!["mcp-server-git".to_string()], HashMap::new());
|
||||
let handle1 = transport1.start().await?;
|
||||
let service1 = McpService::with_timeout(handle1, Duration::from_secs(30));
|
||||
let client1 = McpClient::new(service1);
|
||||
let client1 = McpClient::connect(handle1, Duration::from_secs(30)).await?;
|
||||
|
||||
let transport2 = StdioTransport::new("uvx", vec!["mcp-server-git".to_string()], HashMap::new());
|
||||
let handle2 = transport2.start().await?;
|
||||
let service2 = McpService::with_timeout(handle2, Duration::from_secs(30));
|
||||
let client2 = McpClient::new(service2);
|
||||
let client2 = McpClient::connect(handle2, Duration::from_secs(30)).await?;
|
||||
|
||||
let transport3 = SseTransport::new("http://localhost:8000/sse", HashMap::new());
|
||||
let handle3 = transport3.start().await?;
|
||||
let service3 = McpService::with_timeout(handle3, Duration::from_secs(10));
|
||||
let client3 = McpClient::new(service3);
|
||||
let client3 = McpClient::connect(handle3, Duration::from_secs(10)).await?;
|
||||
|
||||
// Initialize both clients
|
||||
let mut clients: Vec<Box<dyn McpClientTrait>> =
|
||||
|
||||
122
crates/mcp-client/examples/integration_test.rs
Normal file
122
crates/mcp-client/examples/integration_test.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use anyhow::Result;
|
||||
use futures::lock::Mutex;
|
||||
use mcp_client::client::{ClientCapabilities, ClientInfo, McpClient, McpClientTrait};
|
||||
use mcp_client::transport::{SseTransport, Transport};
|
||||
use mcp_client::StdioTransport;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// Initialize logging
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
EnvFilter::from_default_env()
|
||||
.add_directive("mcp_client=debug".parse().unwrap())
|
||||
.add_directive("eventsource_client=info".parse().unwrap()),
|
||||
)
|
||||
.init();
|
||||
|
||||
test_transport(sse_transport().await?).await?;
|
||||
test_transport(stdio_transport().await?).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sse_transport() -> Result<SseTransport> {
|
||||
let port = "60053";
|
||||
|
||||
tokio::process::Command::new("npx")
|
||||
.env("PORT", port)
|
||||
.arg("@modelcontextprotocol/server-everything")
|
||||
.arg("sse")
|
||||
.spawn()?;
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
Ok(SseTransport::new(
|
||||
format!("http://localhost:{}/sse", port),
|
||||
HashMap::new(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn stdio_transport() -> Result<StdioTransport> {
|
||||
Ok(StdioTransport::new(
|
||||
"npx",
|
||||
vec!["@modelcontextprotocol/server-everything"]
|
||||
.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect(),
|
||||
HashMap::new(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn test_transport<T>(transport: T) -> Result<()>
|
||||
where
|
||||
T: Transport + Send + 'static,
|
||||
{
|
||||
// Start transport
|
||||
let handle = transport.start().await?;
|
||||
|
||||
// Create client
|
||||
let mut client = McpClient::connect(handle, Duration::from_secs(10)).await?;
|
||||
println!("Client created\n");
|
||||
|
||||
let mut receiver = client.subscribe().await;
|
||||
let events = Arc::new(Mutex::new(Vec::new()));
|
||||
let events_clone = events.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some(event) = receiver.recv().await {
|
||||
println!("Received event: {event:?}");
|
||||
events_clone.lock().await.push(event);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize
|
||||
let server_info = client
|
||||
.initialize(
|
||||
ClientInfo {
|
||||
name: "test-client".into(),
|
||||
version: "1.0.0".into(),
|
||||
},
|
||||
ClientCapabilities::default(),
|
||||
)
|
||||
.await?;
|
||||
println!("Connected to server: {server_info:?}\n");
|
||||
|
||||
// Sleep for 100ms to allow the server to start - surprisingly this is required!
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
// List tools
|
||||
let tools = client.list_tools(None).await?;
|
||||
println!("Available tools: {tools:#?}\n");
|
||||
|
||||
// Call tool
|
||||
let tool_result = client
|
||||
.call_tool("echo", serde_json::json!({ "message": "honk" }))
|
||||
.await?;
|
||||
println!("Tool result: {tool_result:#?}\n");
|
||||
|
||||
let collected_eventes_before = events.lock().await.len();
|
||||
let n_steps = 5;
|
||||
let long_op = client
|
||||
.call_tool(
|
||||
"longRunningOperation",
|
||||
serde_json::json!({ "duration": 3, "steps": n_steps }),
|
||||
)
|
||||
.await?;
|
||||
println!("Long op result: {long_op:#?}\n");
|
||||
let collected_events_after = events.lock().await.len();
|
||||
assert_eq!(collected_events_after - collected_eventes_before, n_steps);
|
||||
|
||||
// List resources
|
||||
let resources = client.list_resources(None).await?;
|
||||
println!("Resources: {resources:#?}\n");
|
||||
|
||||
// Read resource
|
||||
let resource = client.read_resource("test://static/resource/1").await?;
|
||||
println!("Resource: {resource:#?}\n");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use mcp_client::client::{ClientCapabilities, ClientInfo, McpClient, McpClientTrait};
|
||||
use mcp_client::transport::{SseTransport, Transport};
|
||||
use mcp_client::McpService;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
@@ -23,11 +22,8 @@ async fn main() -> Result<()> {
|
||||
// Start transport
|
||||
let handle = transport.start().await?;
|
||||
|
||||
// Create the service with timeout middleware
|
||||
let service = McpService::with_timeout(handle, Duration::from_secs(3));
|
||||
|
||||
// Create client
|
||||
let mut client = McpClient::new(service);
|
||||
let mut client = McpClient::connect(handle, Duration::from_secs(3)).await?;
|
||||
println!("Client created\n");
|
||||
|
||||
// Initialize
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use mcp_client::{
|
||||
ClientCapabilities, ClientInfo, Error as ClientError, McpClient, McpClientTrait, McpService,
|
||||
ClientCapabilities, ClientInfo, Error as ClientError, McpClient, McpClientTrait,
|
||||
StdioTransport, Transport,
|
||||
};
|
||||
use std::time::Duration;
|
||||
@@ -25,11 +25,8 @@ async fn main() -> Result<(), ClientError> {
|
||||
// 2) Start the transport to get a handle
|
||||
let transport_handle = transport.start().await?;
|
||||
|
||||
// 3) Create the service with timeout middleware
|
||||
let service = McpService::with_timeout(transport_handle, Duration::from_secs(10));
|
||||
|
||||
// 4) Create the client with the middleware-wrapped service
|
||||
let mut client = McpClient::new(service);
|
||||
// 3) Create the client with the middleware-wrapped service
|
||||
let mut client = McpClient::connect(transport_handle, Duration::from_secs(10)).await?;
|
||||
|
||||
// Initialize
|
||||
let server_info = client
|
||||
|
||||
@@ -5,7 +5,6 @@ use mcp_client::client::{
|
||||
ClientCapabilities, ClientInfo, Error as ClientError, McpClient, McpClientTrait,
|
||||
};
|
||||
use mcp_client::transport::{StdioTransport, Transport};
|
||||
use mcp_client::McpService;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
@@ -34,11 +33,8 @@ async fn main() -> Result<(), ClientError> {
|
||||
// Start the transport to get a handle
|
||||
let transport_handle = transport.start().await.unwrap();
|
||||
|
||||
// Create the service with timeout middleware
|
||||
let service = McpService::with_timeout(transport_handle, Duration::from_secs(10));
|
||||
|
||||
// Create client
|
||||
let mut client = McpClient::new(service);
|
||||
let mut client = McpClient::connect(transport_handle, Duration::from_secs(10)).await?;
|
||||
|
||||
// Initialize
|
||||
let server_info = client
|
||||
|
||||
Reference in New Issue
Block a user