Skip to main content

ddb_core/mcp/
resources.rs

1//! MCP Resource implementations for DDB
2
3use crate::config::{Config, TableCatalog};
4use anyhow::{anyhow, Result};
5use serde_json::{json, Value};
6use std::sync::Arc;
7use tokio::sync::RwLock;
8
9pub struct ResourceHandler {
10    config: Arc<RwLock<Config>>,
11    catalog: Arc<RwLock<TableCatalog>>,
12}
13
14impl ResourceHandler {
15    pub fn new(config: Arc<RwLock<Config>>, catalog: Arc<RwLock<TableCatalog>>) -> Self {
16        Self { config, catalog }
17    }
18
19    pub async fn list_resources(&self) -> Result<Vec<Value>> {
20        let catalog = self.catalog.read().await;
21        let mut resources = vec![
22            json!({
23                "uri": "ddb://config",
24                "name": "DDB Configuration",
25                "description": "Current DDB configuration settings",
26                "mimeType": "application/json"
27            }),
28        ];
29
30        for table_name in catalog.list_tables() {
31            resources.push(json!({
32                "uri": format!("ddb://tables/{}/schema", table_name),
33                "name": format!("Schema for {}", table_name),
34                "description": format!("Table schema for {}", table_name),
35                "mimeType": "application/json"
36            }));
37        }
38
39        Ok(resources)
40    }
41
42    pub async fn read_resource(&self, uri: &str) -> Result<Value> {
43        if uri == "ddb://config" {
44            let config = self.config.read().await;
45            return Ok(json!({
46                "default_database": config.default_database,
47                "default_delimiter": config.default_delimiter.to_string()
48            }));
49        }
50
51        if uri.starts_with("ddb://tables/") && uri.ends_with("/schema") {
52            let table_name = uri
53                .trim_start_matches("ddb://tables/")
54                .trim_end_matches("/schema");
55
56            let catalog = self.catalog.read().await;
57            let table = catalog.get_table(table_name).ok_or_else(|| anyhow!("Table not found"))?;
58
59            let columns: Vec<Value> = table.columns.iter().enumerate().map(|(i, col)| {
60                json!({
61                    "index": i,
62                    "name": col.name,
63                    "type": format!("{:?}", col.data_type),
64                    "nullable": col.nullable
65                })
66            }).collect();
67
68            return Ok(json!({
69                "table": table.name,
70                "database": table.database,
71                "file": table.data_file,
72                "columns": columns
73            }));
74        }
75
76        Err(anyhow!("Resource not found: {}", uri))
77    }
78}