systemprompt_models/mcp/
server.rs1use 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#[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}