Skip to main content

systemprompt_models/mcp/
deployment.rs

1use crate::ai::ToolModelConfig;
2use crate::auth::{JwtAudience, Permission};
3use crate::mcp::capabilities::ToolVisibility;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
8pub enum McpServerType {
9    #[default]
10    #[serde(rename = "internal")]
11    Internal,
12    #[serde(rename = "external")]
13    External,
14}
15
16impl McpServerType {
17    pub const fn as_str(&self) -> &'static str {
18        match self {
19            Self::Internal => "internal",
20            Self::External => "external",
21        }
22    }
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, Default)]
26pub struct ToolUiConfig {
27    #[serde(default = "default_resource_uri_template")]
28    pub resource_uri_template: String,
29    #[serde(default = "default_visibility_enum")]
30    pub visibility: Vec<ToolVisibility>,
31}
32
33fn default_resource_uri_template() -> String {
34    "ui://systemprompt/{artifact_id}".to_string()
35}
36
37fn default_visibility_enum() -> Vec<ToolVisibility> {
38    vec![ToolVisibility::Model, ToolVisibility::App]
39}
40
41impl ToolUiConfig {
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    pub fn with_template(mut self, template: impl Into<String>) -> Self {
47        self.resource_uri_template = template.into();
48        self
49    }
50
51    pub fn model_only(mut self) -> Self {
52        self.visibility = vec![ToolVisibility::Model];
53        self
54    }
55
56    pub fn model_and_app(mut self) -> Self {
57        self.visibility = vec![ToolVisibility::Model, ToolVisibility::App];
58        self
59    }
60
61    pub fn to_meta_json(&self) -> serde_json::Value {
62        serde_json::json!({
63            "ui": {
64                "resourceUri": self.resource_uri_template,
65                "visibility": self.visibility
66            }
67        })
68    }
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, Default)]
72pub struct ToolMetadata {
73    #[serde(default)]
74    pub terminal_on_success: bool,
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub model_config: Option<ToolModelConfig>,
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub ui: Option<ToolUiConfig>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct DeploymentConfig {
83    pub deployments: HashMap<String, Deployment>,
84    pub settings: Settings,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct Deployment {
89    #[serde(default, alias = "type")]
90    pub server_type: McpServerType,
91    pub binary: String,
92    pub package: Option<String>,
93    pub port: u16,
94    pub endpoint: String,
95    pub enabled: bool,
96    pub display_in_web: bool,
97    #[serde(default)]
98    pub dev_only: bool,
99    #[serde(default)]
100    pub schemas: Vec<SchemaDefinition>,
101    pub oauth: OAuthRequirement,
102    #[serde(default)]
103    pub tools: HashMap<String, ToolMetadata>,
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub model_config: Option<ToolModelConfig>,
106    #[serde(default)]
107    pub env_vars: Vec<String>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct SchemaDefinition {
112    pub file: String,
113    pub table: String,
114    pub required_columns: Vec<String>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct OAuthRequirement {
119    pub required: bool,
120    pub scopes: Vec<Permission>,
121    pub audience: JwtAudience,
122    pub client_id: Option<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct Settings {
127    pub auto_build: bool,
128    pub build_timeout: u64,
129    pub health_check_timeout: u64,
130    #[serde(default = "default_base_port")]
131    pub base_port: u16,
132    #[serde(default = "default_working_dir")]
133    pub working_dir: String,
134}
135
136const fn default_base_port() -> u16 {
137    5000
138}
139
140fn default_working_dir() -> String {
141    "/app".to_string()
142}