Skip to main content

fraiseql_cli/config/toml_schema/
server_settings.rs

1//! Server settings configuration for TOML schema (validation, debug, MCP).
2
3use serde::{Deserialize, Serialize};
4
5/// MCP (Model Context Protocol) server configuration.
6///
7/// Enables AI/LLM tools to interact with FraiseQL queries and mutations
8/// through the standardized Model Context Protocol.
9#[derive(Debug, Clone, Deserialize, Serialize)]
10#[serde(default, deny_unknown_fields)]
11pub struct McpConfig {
12    /// Enable MCP server endpoint.
13    pub enabled:      bool,
14    /// Transport mode: "http", "stdio", or "both".
15    pub transport:    String,
16    /// HTTP path for MCP endpoint (e.g., "/mcp").
17    pub path:         String,
18    /// Require authentication for MCP requests.
19    pub require_auth: bool,
20    /// Whitelist of query/mutation names to expose (empty = all).
21    #[serde(default)]
22    pub include:      Vec<String>,
23    /// Blacklist of query/mutation names to hide.
24    #[serde(default)]
25    pub exclude:      Vec<String>,
26    /// Read-only exposure: when `true`, no mutation is ever exposed as an MCP tool,
27    /// regardless of `include`/`exclude` (fail-closed for AI callers). Recommended
28    /// unless you deliberately expose mutations.
29    #[serde(default)]
30    pub read_only:    bool,
31}
32
33impl Default for McpConfig {
34    fn default() -> Self {
35        Self {
36            enabled:      false,
37            transport:    "http".to_string(),
38            path:         "/mcp".to_string(),
39            require_auth: true,
40            include:      Vec::new(),
41            exclude:      Vec::new(),
42            read_only:    false,
43        }
44    }
45}
46
47/// Query validation limits (depth and complexity).
48///
49/// ```toml
50/// [validation]
51/// max_query_depth = 10
52/// max_query_complexity = 100
53/// ```
54#[derive(Debug, Clone, Default, Deserialize, Serialize)]
55#[serde(default, deny_unknown_fields)]
56pub struct ValidationConfig {
57    /// Maximum allowed query nesting depth. `None` uses the server default (10).
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub max_query_depth: Option<u32>,
60
61    /// Maximum allowed query complexity score. `None` uses the server default (100).
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub max_query_complexity: Option<u32>,
64
65    /// Maximum rows a top-level `first`/`last`/`limit` argument may request,
66    /// guarding against unbounded-pagination denial of service (#421). `None`
67    /// uses the server default (1000); the server also honours the
68    /// `FRAISEQL_MAX_PAGE_SIZE` environment variable as an override.
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub max_page_size: Option<u32>,
71}
72
73/// Debug/development configuration.
74///
75/// Controls features that should only be enabled during development or
76/// in trusted environments. All flags default to off.
77///
78/// ```toml
79/// [debug]
80/// enabled = true
81/// database_explain = true
82/// expose_sql = true
83/// ```
84#[derive(Debug, Clone, Deserialize, Serialize)]
85#[serde(default, deny_unknown_fields)]
86pub struct DebugConfig {
87    /// Master switch — all debug features require this to be `true`.
88    pub enabled: bool,
89
90    /// When `true`, the explain endpoint will also run `EXPLAIN` against the
91    /// database and include the query plan in the response.
92    pub database_explain: bool,
93
94    /// When `true`, the explain endpoint includes the generated SQL in the
95    /// response. Defaults to `true` (SQL is shown even without
96    /// `database_explain`).
97    pub expose_sql: bool,
98}
99
100impl Default for DebugConfig {
101    fn default() -> Self {
102        Self {
103            enabled:          false,
104            database_explain: false,
105            expose_sql:       true,
106        }
107    }
108}