1use std::sync::Arc;
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use uuid::Uuid;
7
8use crate::error::Result;
9use crate::prompt::{PromptDefinitionMetadata, PromptManager, PromptTemplate};
10use crate::resource::{
11 ResourceContent, ResourceDefinition, ResourceDefinitionMetadata, ResourceManager,
12};
13use crate::tool::{
14 DuplicateBehavior, ToolDefinition, ToolDefinitionMetadata, ToolManager, ToolResponse,
15};
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
19pub struct ServerMetadata {
20 pub id: Uuid,
21 pub name: String,
22 #[serde(default, skip_serializing_if = "Option::is_none")]
23 pub instructions: Option<String>,
24 pub version: String,
25 pub created_at: DateTime<Utc>,
26}
27
28impl ServerMetadata {
29 pub fn new(
30 name: impl Into<String>,
31 instructions: Option<String>,
32 version: impl Into<String>,
33 ) -> Self {
34 Self {
35 id: Uuid::new_v4(),
36 name: name.into(),
37 instructions,
38 version: version.into(),
39 created_at: Utc::now(),
40 }
41 }
42}
43
44pub struct FastMcpServer {
45 metadata: ServerMetadata,
46 tool_manager: ToolManager,
47 resource_manager: ResourceManager,
48 prompt_manager: PromptManager,
49}
50
51impl FastMcpServer {
52 pub fn builder() -> FastMcpServerBuilder {
53 FastMcpServerBuilder::default()
54 }
55
56 pub fn metadata(&self) -> ServerMetadata {
57 self.metadata.clone()
58 }
59
60 pub fn register_tool(&self, tool: ToolDefinition) -> Result<()> {
61 self.tool_manager.register(tool)
62 }
63
64 pub fn list_tools(&self) -> Vec<ToolDefinitionMetadata> {
65 self.tool_manager.list()
66 }
67
68 pub async fn call_tool(&self, name: &str, arguments: Value) -> Result<ToolResponse> {
69 self.tool_manager.call(name, arguments).await
70 }
71
72 pub fn register_resource(&self, resource: ResourceDefinition) -> Result<()> {
73 self.resource_manager.register(resource)
74 }
75
76 pub fn list_resources(&self) -> Vec<ResourceDefinitionMetadata> {
77 self.resource_manager.list()
78 }
79
80 pub async fn read_resource(&self, uri: &str) -> Result<ResourceContent> {
81 self.resource_manager.read(uri).await
82 }
83
84 pub fn register_prompt(&self, prompt: PromptTemplate) -> Result<()> {
85 self.prompt_manager.register(prompt)
86 }
87
88 pub fn list_prompts(&self) -> Vec<PromptDefinitionMetadata> {
89 self.prompt_manager.list()
90 }
91
92 pub fn instantiate_prompt(
93 &self,
94 name: &str,
95 arguments: Option<&Value>,
96 ) -> Result<Vec<crate::prompt::PromptMessage>> {
97 let prompt = self.prompt_manager.get(name)?;
98 prompt.instantiate(arguments)
99 }
100
101 pub fn into_shared(self) -> Arc<Self> {
102 Arc::new(self)
103 }
104}
105
106#[derive(Default)]
107pub struct FastMcpServerBuilder {
108 name: Option<String>,
109 instructions: Option<String>,
110 version: Option<String>,
111 tool_duplicates: DuplicateBehavior,
112 resource_duplicates: DuplicateBehavior,
113 prompt_duplicates: DuplicateBehavior,
114}
115
116impl FastMcpServerBuilder {
117 pub fn name(mut self, name: impl Into<String>) -> Self {
118 self.name = Some(name.into());
119 self
120 }
121
122 pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
123 self.instructions = Some(instructions.into());
124 self
125 }
126
127 pub fn version(mut self, version: impl Into<String>) -> Self {
128 self.version = Some(version.into());
129 self
130 }
131
132 pub fn tool_duplicates(mut self, behavior: DuplicateBehavior) -> Self {
133 self.tool_duplicates = behavior;
134 self
135 }
136
137 pub fn resource_duplicates(mut self, behavior: DuplicateBehavior) -> Self {
138 self.resource_duplicates = behavior;
139 self
140 }
141
142 pub fn prompt_duplicates(mut self, behavior: DuplicateBehavior) -> Self {
143 self.prompt_duplicates = behavior;
144 self
145 }
146
147 pub fn build(self) -> FastMcpServer {
148 let name = self
149 .name
150 .unwrap_or_else(|| format!("fastmcp-{}", Uuid::new_v4()));
151 let version = self.version.unwrap_or_else(|| "0.1.0-preview".into());
152 let server = FastMcpServer {
153 metadata: ServerMetadata::new(name, self.instructions, version),
154 tool_manager: ToolManager::new(self.tool_duplicates),
155 resource_manager: ResourceManager::new(self.resource_duplicates),
156 prompt_manager: PromptManager::new(self.prompt_duplicates),
157 };
158
159 #[cfg(feature = "auto-register")]
160 {
161 crate::tool::register_discovered_tools(&server);
162 }
163
164 server
165 }
166}