Skip to main content

mcp_postgres/actions/
connections.rs

1use serde_json::{json, Value};
2use tokio_postgres::Client;
3use crate::errors::Result as MCPResult;
4
5/// 16. List connections
6pub async fn list_connections(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
7    let rows = client
8        .query(
9            "SELECT pid, usename::text, application_name, state,
10                    state_change::text, backend_start::text, query_start::text
11             FROM pg_stat_activity
12             WHERE pid != pg_backend_pid()
13             ORDER BY backend_start DESC",
14            &[],
15        )
16        .await?;
17
18    let connections: Vec<Value> = rows
19        .iter()
20        .map(|row| {
21            json!({
22                "pid": row.get::<_, i32>(0),
23                "user": row.get::<_, Option<String>>(1),
24                "application": row.get::<_, Option<String>>(2),
25                "state": row.get::<_, Option<String>>(3),
26                "state_change": row.get::<_, Option<String>>(4),
27                "backend_start": row.get::<_, Option<String>>(5),
28                "query_start": row.get::<_, Option<String>>(6),
29            })
30        })
31        .collect();
32
33    Ok(json!({ "connections": connections }))
34}
35
36/// 18. Show current user
37pub async fn show_current_user(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
38    let rows = client
39        .query("SELECT current_user, current_database(), version()", &[])
40        .await?;
41
42    let row = &rows[0];
43
44    Ok(json!({
45        "user": row.get::<_, String>(0),
46        "database": row.get::<_, String>(1),
47        "version": row.get::<_, String>(2),
48    }))
49}
50
51/// 19. Show running queries
52pub async fn show_running_queries(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
53    let rows = client
54        .query(
55            "SELECT pid, usename, application_name, state, query, query_start
56             FROM pg_stat_activity
57             WHERE state != 'idle' AND pid != pg_backend_pid()
58             ORDER BY query_start DESC",
59            &[],
60        )
61        .await?;
62
63    let queries: Vec<Value> = rows
64        .iter()
65        .map(|row| {
66            json!({
67                "pid": row.get::<_, i32>(0),
68                "user": row.get::<_, String>(1),
69                "application": row.get::<_, Option<String>>(2),
70                "state": row.get::<_, String>(3),
71                "query": row.get::<_, Option<String>>(4),
72                "query_start": row.get::<_, Option<String>>(5),
73            })
74        })
75        .collect();
76
77    Ok(json!({ "queries": queries }))
78}
79
80/// 20. Show connection summary
81pub async fn show_connection_summary(client: &Client, _params: &Option<&Value>) -> MCPResult<Value> {
82    let rows = client
83        .query(
84            "SELECT state, count(*) as count
85             FROM pg_stat_activity
86             GROUP BY state
87             ORDER BY count DESC",
88            &[],
89        )
90        .await?;
91
92    let summary: Vec<Value> = rows
93        .iter()
94        .map(|row| {
95            json!({
96                "state": row.get::<_, Option<String>>(0).unwrap_or_else(|| "unknown".to_string()),
97                "count": row.get::<_, i64>(1),
98            })
99        })
100        .collect();
101
102    Ok(json!({ "summary": summary }))
103}