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