Skip to main content

systemprompt_models/mcp/
server.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use std::path::{Path, PathBuf};
4
5use crate::ai::ToolModelConfig;
6use crate::auth::{AuthenticatedUser, Permission};
7
8pub const RUNNING: &str = "running";
9pub const ERROR: &str = "error";
10pub const STOPPED: &str = "stopped";
11pub const STARTING: &str = "starting";
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct McpServerConfig {
15    pub name: String,
16    pub binary: String,
17    pub enabled: bool,
18    pub display_in_web: bool,
19    pub port: u16,
20    #[serde(
21        serialize_with = "serialize_path",
22        deserialize_with = "deserialize_path"
23    )]
24    pub crate_path: PathBuf,
25    pub display_name: String,
26    pub description: String,
27    pub capabilities: Vec<String>,
28    #[serde(default)]
29    pub schemas: Vec<super::deployment::SchemaDefinition>,
30    pub oauth: super::deployment::OAuthRequirement,
31    #[serde(default)]
32    pub tools: HashMap<String, super::deployment::ToolMetadata>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub model_config: Option<ToolModelConfig>,
35    #[serde(default)]
36    pub env_vars: Vec<String>,
37    pub version: String,
38    pub host: String,
39    pub module_name: String,
40    pub protocol: String,
41}
42
43fn serialize_path<S>(path: &Path, serializer: S) -> Result<S::Ok, S::Error>
44where
45    S: serde::Serializer,
46{
47    path.to_string_lossy().serialize(serializer)
48}
49
50fn deserialize_path<'de, D>(deserializer: D) -> Result<PathBuf, D::Error>
51where
52    D: serde::Deserializer<'de>,
53{
54    let s = String::deserialize(deserializer)?;
55    Ok(PathBuf::from(s))
56}
57
58impl McpServerConfig {
59    pub fn endpoint(&self, api_server_url: &str) -> String {
60        format!("{}/api/v1/mcp/{}/mcp", api_server_url, self.name)
61    }
62}
63
64/// Authentication state for MCP connections
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub enum McpAuthState {
67    Authenticated(AuthenticatedUser),
68    Anonymous,
69}
70
71impl McpAuthState {
72    pub const fn is_authenticated(&self) -> bool {
73        matches!(self, Self::Authenticated(_))
74    }
75
76    pub const fn is_anonymous(&self) -> bool {
77        matches!(self, Self::Anonymous)
78    }
79
80    pub const fn user(&self) -> Option<&AuthenticatedUser> {
81        match self {
82            Self::Authenticated(user) => Some(user),
83            Self::Anonymous => None,
84        }
85    }
86
87    pub fn has_permission(&self, permission: Permission) -> bool {
88        match self {
89            Self::Authenticated(user) => user.has_permission(permission),
90            Self::Anonymous => permission == Permission::Anonymous,
91        }
92    }
93
94    pub fn username(&self) -> String {
95        match self {
96            Self::Authenticated(user) => user.username.clone(),
97            Self::Anonymous => "anonymous".to_string(),
98        }
99    }
100}