use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::error::Result;
use crate::prompt::{PromptDefinitionMetadata, PromptMessage};
use crate::resource::{ResourceContent, ResourceDefinitionMetadata};
use crate::server::{FastMcpServer, ServerMetadata};
use crate::tool::{ToolDefinitionMetadata, ToolResponse};
#[derive(Debug, Deserialize)]
#[serde(tag = "command", rename_all = "snake_case")]
pub enum ServerCommand {
Metadata,
ListTools,
CallTool {
name: String,
#[serde(default)]
arguments: Value,
},
ListResources,
ReadResource {
uri: String,
},
ListPrompts,
InstantiatePrompt {
name: String,
#[serde(default)]
arguments: Option<Value>,
},
Shutdown,
}
#[derive(Debug, Serialize, Clone)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CommandResult {
Metadata {
data: ServerMetadata,
},
Tools {
data: Vec<ToolDefinitionMetadata>,
},
ToolInvocation {
data: ToolResponse,
},
Resources {
data: Vec<ResourceDefinitionMetadata>,
},
Resource {
data: ResourceContent,
},
Prompts {
data: Vec<PromptDefinitionMetadata>,
},
PromptInstantiation {
data: Vec<PromptMessage>,
},
Ack {
message: String,
},
}
impl CommandResult {
pub fn shutdown_ack() -> Self {
Self::Ack {
message: "shutdown".into(),
}
}
pub fn event_kind(&self) -> &'static str {
match self {
CommandResult::Metadata { .. } => "metadata",
CommandResult::Tools { .. } => "tools",
CommandResult::ToolInvocation { .. } => "tool_invocation",
CommandResult::Resources { .. } => "resources",
CommandResult::Resource { .. } => "resource",
CommandResult::Prompts { .. } => "prompts",
CommandResult::PromptInstantiation { .. } => "prompt_instantiation",
CommandResult::Ack { .. } => "ack",
}
}
}
pub async fn execute_command(
server: &FastMcpServer,
command: ServerCommand,
) -> Result<(CommandResult, bool)> {
let result = match command {
ServerCommand::Metadata => CommandResult::Metadata {
data: server.metadata(),
},
ServerCommand::ListTools => CommandResult::Tools {
data: server.list_tools(),
},
ServerCommand::CallTool { name, arguments } => CommandResult::ToolInvocation {
data: server.call_tool(&name, arguments).await?,
},
ServerCommand::ListResources => CommandResult::Resources {
data: server.list_resources(),
},
ServerCommand::ReadResource { uri } => CommandResult::Resource {
data: server.read_resource(&uri).await?,
},
ServerCommand::ListPrompts => CommandResult::Prompts {
data: server.list_prompts(),
},
ServerCommand::InstantiatePrompt { name, arguments } => {
CommandResult::PromptInstantiation {
data: server.instantiate_prompt(&name, arguments.as_ref())?,
}
}
ServerCommand::Shutdown => {
return Ok((CommandResult::shutdown_ack(), true));
}
};
Ok((result, false))
}