1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::error::Result;
5use crate::prompt::{PromptDefinitionMetadata, PromptMessage};
6use crate::resource::{ResourceContent, ResourceDefinitionMetadata};
7use crate::server::{FastMcpServer, ServerMetadata};
8use crate::tool::{ToolDefinitionMetadata, ToolResponse};
9
10#[derive(Debug, Deserialize)]
11#[serde(tag = "command", rename_all = "snake_case")]
12pub enum ServerCommand {
13 Metadata,
14 ListTools,
15 CallTool {
16 name: String,
17 #[serde(default)]
18 arguments: Value,
19 },
20 ListResources,
21 ReadResource {
22 uri: String,
23 },
24 ListPrompts,
25 InstantiatePrompt {
26 name: String,
27 #[serde(default)]
28 arguments: Option<Value>,
29 },
30 Shutdown,
31}
32
33#[derive(Debug, Serialize, Clone)]
34#[serde(tag = "type", rename_all = "snake_case")]
35pub enum CommandResult {
36 Metadata {
37 data: ServerMetadata,
38 },
39 Tools {
40 data: Vec<ToolDefinitionMetadata>,
41 },
42 ToolInvocation {
43 data: ToolResponse,
44 },
45 Resources {
46 data: Vec<ResourceDefinitionMetadata>,
47 },
48 Resource {
49 data: ResourceContent,
50 },
51 Prompts {
52 data: Vec<PromptDefinitionMetadata>,
53 },
54 PromptInstantiation {
55 data: Vec<PromptMessage>,
56 },
57 Ack {
58 message: String,
59 },
60}
61
62impl CommandResult {
63 pub fn shutdown_ack() -> Self {
64 Self::Ack {
65 message: "shutdown".into(),
66 }
67 }
68
69 pub fn event_kind(&self) -> &'static str {
70 match self {
71 CommandResult::Metadata { .. } => "metadata",
72 CommandResult::Tools { .. } => "tools",
73 CommandResult::ToolInvocation { .. } => "tool_invocation",
74 CommandResult::Resources { .. } => "resources",
75 CommandResult::Resource { .. } => "resource",
76 CommandResult::Prompts { .. } => "prompts",
77 CommandResult::PromptInstantiation { .. } => "prompt_instantiation",
78 CommandResult::Ack { .. } => "ack",
79 }
80 }
81}
82
83pub async fn execute_command(
84 server: &FastMcpServer,
85 command: ServerCommand,
86) -> Result<(CommandResult, bool)> {
87 let result = match command {
88 ServerCommand::Metadata => CommandResult::Metadata {
89 data: server.metadata(),
90 },
91 ServerCommand::ListTools => CommandResult::Tools {
92 data: server.list_tools(),
93 },
94 ServerCommand::CallTool { name, arguments } => CommandResult::ToolInvocation {
95 data: server.call_tool(&name, arguments).await?,
96 },
97 ServerCommand::ListResources => CommandResult::Resources {
98 data: server.list_resources(),
99 },
100 ServerCommand::ReadResource { uri } => CommandResult::Resource {
101 data: server.read_resource(&uri).await?,
102 },
103 ServerCommand::ListPrompts => CommandResult::Prompts {
104 data: server.list_prompts(),
105 },
106 ServerCommand::InstantiatePrompt { name, arguments } => {
107 CommandResult::PromptInstantiation {
108 data: server.instantiate_prompt(&name, arguments.as_ref())?,
109 }
110 }
111 ServerCommand::Shutdown => {
112 return Ok((CommandResult::shutdown_ack(), true));
113 }
114 };
115
116 Ok((result, false))
117}