Skip to main content

fastmcp_rs/
command.rs

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}