rust-sdk/examples/clients/src/everything_stdio.rs
Humberto Yusta Gómez 64995cc40c
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
2025-05-18 18:38:47 +08:00

98 lines
3 KiB
Rust

use anyhow::Result;
use rmcp::{
ServiceExt,
model::{CallToolRequestParam, GetPromptRequestParam, ReadResourceRequestParam},
object,
transport::{ConfigureCommandExt, TokioChildProcess},
};
use tokio::process::Command;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| format!("info,{}=debug", env!("CARGO_CRATE_NAME")).into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
// Start server
let service = ()
.serve(TokioChildProcess::new(Command::new("npx").configure(
|cmd| {
cmd.arg("-y").arg("@modelcontextprotocol/server-everything");
},
))?)
.await?;
// Initialize
let server_info = service.peer_info();
tracing::info!("Connected to server: {server_info:#?}");
// List tools
let tools = service.list_all_tools().await?;
tracing::info!("Available tools: {tools:#?}");
// Call tool echo
let tool_result = service
.call_tool(CallToolRequestParam {
name: "echo".into(),
arguments: Some(object!({ "message": "hi from rmcp" })),
})
.await?;
tracing::info!("Tool result for echo: {tool_result:#?}");
// Call tool longRunningOperation
let tool_result = service
.call_tool(CallToolRequestParam {
name: "longRunningOperation".into(),
arguments: Some(object!({ "duration": 3, "steps": 1 })),
})
.await?;
tracing::info!("Tool result for longRunningOperation: {tool_result:#?}");
// List resources
let resources = service.list_all_resources().await?;
tracing::info!("Available resources: {resources:#?}");
// Read resource
let resource = service
.read_resource(ReadResourceRequestParam {
uri: "test://static/resource/3".into(),
})
.await?;
tracing::info!("Resource: {resource:#?}");
// List prompts
let prompts = service.list_all_prompts().await?;
tracing::info!("Available prompts: {prompts:#?}");
// Get simple prompt
let prompt = service
.get_prompt(GetPromptRequestParam {
name: "simple_prompt".into(),
arguments: None,
})
.await?;
tracing::info!("Prompt - simple: {prompt:#?}");
// Get complex prompt (returns text & image)
let prompt = service
.get_prompt(GetPromptRequestParam {
name: "complex_prompt".into(),
arguments: Some(object!({ "temperature": "0.5", "style": "formal" })),
})
.await?;
tracing::info!("Prompt - complex: {prompt:#?}");
// List resource templates
let resource_templates = service.list_all_resource_templates().await?;
tracing::info!("Available resource templates: {resource_templates:#?}");
service.cancel().await?;
Ok(())
}