1use serde_json::{json, Value};
2use tokio_postgres::Client;
3use crate::errors::Result as MCPResult;
4
5const MAX_SETTING_NAME_LEN: usize = 255;
6
7pub async fn show_all_settings(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
9 let rows = client
10 .query(
11 "SELECT name, setting, unit, short_desc, context
12 FROM pg_settings
13 WHERE context NOT LIKE 'internal%'
14 ORDER BY name",
15 &[],
16 )
17 .await?;
18
19 let settings: Vec<Value> = rows
20 .iter()
21 .map(|row| {
22 json!({
23 "name": row.get::<_, String>(0),
24 "value": row.get::<_, Option<String>>(1),
25 "unit": row.get::<_, Option<String>>(2),
26 "description": row.get::<_, String>(3),
27 "context": row.get::<_, String>(4),
28 })
29 })
30 .collect();
31
32 Ok(json!({ "settings": settings }))
33}
34
35pub async fn get_setting(client: &Client, params: &Option<&Value>) -> MCPResult<Value> {
37 let setting_name = params
38 .as_ref()
39 .and_then(|p| p.get("setting").and_then(|v| v.as_str()).map(|s| s.to_string()))
40 .ok_or_else(|| crate::errors::MCPError::InvalidParams("Missing 'setting' parameter".into()))?;
41
42 if setting_name.is_empty() || setting_name.len() > MAX_SETTING_NAME_LEN {
43 return Err(crate::errors::MCPError::InvalidParams(
44 format!("'setting' must be 1-{MAX_SETTING_NAME_LEN} characters")
45 ));
46 }
47
48 let rows = client
49 .query(
50 "SELECT name, setting, unit, short_desc, context, vartype, source
51 FROM pg_settings
52 WHERE name = $1",
53 &[&setting_name],
54 )
55 .await?;
56
57 if rows.is_empty() {
58 return Err(crate::errors::MCPError::InvalidParams(format!("Setting not found: {}", setting_name)));
59 }
60
61 let row = &rows[0];
62
63 Ok(json!({
64 "name": row.get::<_, String>(0),
65 "value": row.get::<_, Option<String>>(1),
66 "unit": row.get::<_, Option<String>>(2),
67 "description": row.get::<_, String>(3),
68 "context": row.get::<_, String>(4),
69 "type": row.get::<_, String>(5),
70 "source": row.get::<_, String>(6),
71 }))
72}
73
74pub async fn show_memory_settings(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
76 let rows = client
77 .query(
78 "SELECT name, setting, unit
79 FROM pg_settings
80 WHERE name IN ('shared_buffers', 'effective_cache_size', 'work_mem',
81 'maintenance_work_mem', 'wal_buffers', 'random_page_cost',
82 'effective_io_concurrency')
83 ORDER BY name",
84 &[],
85 )
86 .await?;
87
88 let settings: Vec<Value> = rows
89 .iter()
90 .map(|row| {
91 json!({
92 "name": row.get::<_, String>(0),
93 "value": row.get::<_, Option<String>>(1),
94 "unit": row.get::<_, Option<String>>(2),
95 })
96 })
97 .collect();
98
99 Ok(json!({ "memory_settings": settings }))
100}
101
102pub async fn show_performance_settings(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
104 let rows = client
105 .query(
106 "SELECT name, setting, unit
107 FROM pg_settings
108 WHERE name IN ('max_connections', 'checkpoint_timeout', 'checkpoint_completion_target',
109 'wal_level', 'max_wal_senders', 'wal_keep_size', 'synchronous_commit',
110 'constraint_exclusion')
111 ORDER BY name",
112 &[],
113 )
114 .await?;
115
116 let settings: Vec<Value> = rows
117 .iter()
118 .map(|row| {
119 json!({
120 "name": row.get::<_, String>(0),
121 "value": row.get::<_, Option<String>>(1),
122 "unit": row.get::<_, Option<String>>(2),
123 })
124 })
125 .collect();
126
127 Ok(json!({ "performance_settings": settings }))
128}
129
130pub async fn show_log_settings(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
132 let rows = client
133 .query(
134 "SELECT name, setting, unit
135 FROM pg_settings
136 WHERE name LIKE 'log%'
137 ORDER BY name",
138 &[],
139 )
140 .await?;
141
142 let settings: Vec<Value> = rows
143 .iter()
144 .map(|row| {
145 json!({
146 "name": row.get::<_, String>(0),
147 "value": row.get::<_, Option<String>>(1),
148 "unit": row.get::<_, Option<String>>(2),
149 })
150 })
151 .collect();
152
153 Ok(json!({ "log_settings": settings }))
154}