sqlserver_mcp_catalog/prompts/
mod.rs1pub mod router;
7
8use rmcp::schemars;
9use serde::Deserialize;
10
11#[derive(Debug, Deserialize, schemars::JsonSchema)]
12pub struct MasterWorkflowArgs {
13 pub goal: Option<String>,
15}
16
17#[derive(Debug, Deserialize, schemars::JsonSchema)]
18pub struct SqlAgentJobsArgs {
19 pub job_name: Option<String>,
21 pub database: Option<String>,
23}
24
25#[derive(Debug, Deserialize, schemars::JsonSchema)]
26pub struct IndexesConstraintsArgs {
27 pub database: Option<String>,
29 pub schema: Option<String>,
31 pub table: Option<String>,
33}
34
35#[derive(Debug, Deserialize, schemars::JsonSchema)]
36pub struct IndexTuningRecommendationsArgs {
37 pub database: Option<String>,
39 pub schema: Option<String>,
41 pub table: Option<String>,
43}
44
45#[derive(Debug, Deserialize, schemars::JsonSchema)]
46pub struct SecurityProvisioningArgs {
47 pub login_name: Option<String>,
49 pub database: Option<String>,
51 pub role_name: Option<String>,
53}
54
55pub(crate) fn render_context_header(fields: &[(&str, Option<&str>)]) -> String {
62 if fields.is_empty() {
63 return String::new();
64 }
65
66 let mut provided = Vec::new();
67 let mut missing = Vec::new();
68 for (label, value) in fields {
69 match value {
70 Some(v) => provided.push(format!("- {label}: {v}")),
71 None => missing.push(format!("- {label}")),
72 }
73 }
74
75 let render_list = |items: &[String]| {
76 if items.is_empty() {
77 "(none)".to_string()
78 } else {
79 items.join("\n")
80 }
81 };
82
83 format!(
84 "Context already provided:\n{}\n\nStill missing (ask the user before proceeding, if needed):\n{}\n",
85 render_list(&provided),
86 render_list(&missing),
87 )
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn empty_fields_render_nothing() {
96 assert_eq!(render_context_header(&[]), "");
97 }
98
99 #[test]
100 fn all_supplied_lists_no_missing_fields() {
101 let header = render_context_header(&[("goal", Some("explore schema"))]);
102 assert!(header.contains("- goal: explore schema"));
103 assert!(header.contains("Still missing"));
104 assert!(header.ends_with("(none)\n"));
105 }
106
107 #[test]
108 fn all_missing_lists_no_provided_fields() {
109 let header = render_context_header(&[("goal", None)]);
110 assert!(header.starts_with("Context already provided:\n(none)"));
111 assert!(header.contains("- goal"));
112 }
113
114 #[test]
115 fn mixed_supplied_and_missing_are_both_listed() {
116 let header =
117 render_context_header(&[("job_name", Some("nightly_backup")), ("database", None)]);
118 assert!(header.contains("- job_name: nightly_backup"));
119 assert!(header.contains("- database"));
120 assert!(!header.contains("- database: "));
121 }
122}