fix: cleanup zombie processes for child process client (#156)
* feat(client): cleanup of zombie processes in child process client Using process wrap library, Process Group for Unix and Job Object for Windows * fix: install extra dep based on feature, update examples take owned command Install process-wrap if transport-child-process feature is enabled. Update examples to take ownership of the command instead of mutable reference * fix: update other examples, comments and readme to take ownership of command Updated more examples, comments and readme to take command instead of mutable ref. Also small fix in cargo toml of example to use local path. * refactor: add configure command ext Added configure command ext to tokio process command so that you can use .configure() to use inline commands for mcp stdio client. Added warning if start kill process fails
This commit is contained in:
parent
68ddea3ad5
commit
64995cc40c
5 changed files with 115 additions and 77 deletions
|
|
@ -1,7 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use rmcp::{model::CallToolRequestParam, service::ServiceExt, transport::TokioChildProcess};
|
||||
use rmcp::{
|
||||
model::CallToolRequestParam,
|
||||
service::ServiceExt,
|
||||
transport::{ConfigureCommandExt, TokioChildProcess},
|
||||
};
|
||||
use tokio::process::Command;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
|
|
@ -20,9 +24,11 @@ async fn main() -> Result<()> {
|
|||
for idx in 0..10 {
|
||||
let service = ()
|
||||
.into_dyn()
|
||||
.serve(TokioChildProcess::new(
|
||||
Command::new("uvx").arg("mcp-server-git"),
|
||||
)?)
|
||||
.serve(TokioChildProcess::new(Command::new("uvx").configure(
|
||||
|cmd| {
|
||||
cmd.arg("mcp-client-git");
|
||||
},
|
||||
))?)
|
||||
.await?;
|
||||
client_list.insert(idx, service);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rmcp::{
|
|||
ServiceExt,
|
||||
model::{CallToolRequestParam, GetPromptRequestParam, ReadResourceRequestParam},
|
||||
object,
|
||||
transport::TokioChildProcess,
|
||||
transport::{ConfigureCommandExt, TokioChildProcess},
|
||||
};
|
||||
use tokio::process::Command;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
|
@ -21,11 +21,11 @@ async fn main() -> Result<()> {
|
|||
|
||||
// Start server
|
||||
let service = ()
|
||||
.serve(TokioChildProcess::new(
|
||||
Command::new("npx")
|
||||
.arg("-y")
|
||||
.arg("@modelcontextprotocol/server-everything"),
|
||||
)?)
|
||||
.serve(TokioChildProcess::new(Command::new("npx").configure(
|
||||
|cmd| {
|
||||
cmd.arg("-y").arg("@modelcontextprotocol/server-everything");
|
||||
},
|
||||
))?)
|
||||
.await?;
|
||||
|
||||
// Initialize
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
use anyhow::Result;
|
||||
use rmcp::{model::CallToolRequestParam, service::ServiceExt, transport::TokioChildProcess};
|
||||
use rmcp::{
|
||||
model::CallToolRequestParam,
|
||||
service::ServiceExt,
|
||||
transport::{ConfigureCommandExt, TokioChildProcess},
|
||||
};
|
||||
use tokio::process::Command;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
|
|
@ -14,17 +18,14 @@ async fn main() -> Result<()> {
|
|||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
let service = ()
|
||||
.serve(TokioChildProcess::new(
|
||||
Command::new("uvx").arg("mcp-server-git"),
|
||||
)?)
|
||||
.serve(TokioChildProcess::new(Command::new("uvx").configure(
|
||||
|cmd| {
|
||||
cmd.arg("mcp-server-git");
|
||||
},
|
||||
))?)
|
||||
.await?;
|
||||
|
||||
// or
|
||||
// serve_client(
|
||||
// (),
|
||||
// TokioChildProcess::new(Command::new("uvx").arg("mcp-server-git"))?,
|
||||
// )
|
||||
// .await?;
|
||||
// or serve_client((), TokioChildProcess::new(cmd)?).await?;
|
||||
|
||||
// Initialize
|
||||
let server_info = service.peer_info();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{collections::HashMap, process::Stdio};
|
||||
|
||||
use rmcp::{RoleClient, ServiceExt, service::RunningService};
|
||||
use rmcp::{RoleClient, ServiceExt, service::RunningService, transport::ConfigureCommandExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::mcp_adaptor::McpManager;
|
||||
|
|
@ -70,10 +70,9 @@ impl McpServerTransportConfig {
|
|||
envs,
|
||||
} => {
|
||||
let transport = rmcp::transport::TokioChildProcess::new(
|
||||
tokio::process::Command::new(command)
|
||||
.args(args)
|
||||
.envs(envs)
|
||||
.stderr(Stdio::null()),
|
||||
tokio::process::Command::new(command).configure(|cmd| {
|
||||
cmd.args(args).envs(envs).stderr(Stdio::null());
|
||||
}),
|
||||
)?;
|
||||
().serve(transport).await?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::HashMap, path::Path, process::Stdio};
|
||||
|
||||
use anyhow::Result;
|
||||
use rmcp::{RoleClient, ServiceExt, service::RunningService};
|
||||
use rmcp::{RoleClient, ServiceExt, service::RunningService, transport::ConfigureCommandExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
|
@ -55,11 +55,12 @@ impl McpServerTransportConfig {
|
|||
envs,
|
||||
} => {
|
||||
let transport = rmcp::transport::child_process::TokioChildProcess::new(
|
||||
tokio::process::Command::new(command)
|
||||
.args(args)
|
||||
.envs(envs)
|
||||
.stderr(Stdio::inherit())
|
||||
.stdout(Stdio::inherit()),
|
||||
tokio::process::Command::new(command).configure(|cmd| {
|
||||
cmd.args(args)
|
||||
.envs(envs)
|
||||
.stderr(Stdio::inherit())
|
||||
.stdout(Stdio::inherit());
|
||||
}),
|
||||
)?;
|
||||
().serve(transport).await?
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue