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 /// Keep per-thread working state across an agent's tool calls, in the
32 /// `[session_state]` store (#967). Off by default; requires an authenticated
33 /// caller and a configured `[session_state]` backend.
34 #[serde(default)]
35 pub session_state: bool,
36}
37
38impl Default for McpConfig {
39 fn default() -> Self {
40 Self {
41 enabled: false,
42 transport: "http".to_string(),
43 path: "/mcp".to_string(),
44 require_auth: true,
45 include: Vec::new(),
46 exclude: Vec::new(),
47 read_only: false,
48 session_state: false,
49 }
50 }
51}
52
53/// Query validation limits (depth and complexity).
54///
55/// ```toml
56/// [validation]
57/// max_query_depth = 10
58/// max_query_complexity = 100
59/// ```
60#[derive(Debug, Clone, Default, Deserialize, Serialize)]
61#[serde(default, deny_unknown_fields)]
62pub struct ValidationConfig {
63 /// Maximum allowed query nesting depth. `None` uses the server default (10).
64 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub max_query_depth: Option<u32>,
66
67 /// Maximum allowed query complexity score. `None` uses the server default (100).
68 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub max_query_complexity: Option<u32>,
70
71 /// Maximum bytes a single read may deliver, measured on the rows returned.
72 ///
73 /// Depth and complexity score the request; this bounds the answer, which is
74 /// the only cost a read from a materialised view actually has. `None` leaves
75 /// reads unbounded by size.
76 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub max_response_bytes: Option<u64>,
78
79 /// Maximum rows a top-level `first`/`last`/`limit` argument may request,
80 /// guarding against unbounded-pagination denial of service (#421). `None`
81 /// uses the server default (1000); the server also honours the
82 /// `FRAISEQL_MAX_PAGE_SIZE` environment variable as an override.
83 #[serde(default, skip_serializing_if = "Option::is_none")]
84 pub max_page_size: Option<u32>,
85}
86
87/// Debug/development configuration.
88///
89/// Controls features that should only be enabled during development or
90/// in trusted environments. All flags default to off.
91///
92/// ```toml
93/// [debug]
94/// enabled = true
95/// database_explain = true
96/// expose_sql = true
97/// ```
98#[derive(Debug, Clone, Deserialize, Serialize)]
99#[serde(default, deny_unknown_fields)]
100pub struct DebugConfig {
101 /// Master switch — all debug features require this to be `true`.
102 pub enabled: bool,
103
104 /// When `true`, the explain endpoint will also run `EXPLAIN` against the
105 /// database and include the query plan in the response.
106 pub database_explain: bool,
107
108 /// When `true`, the explain endpoint includes the generated SQL in the
109 /// response. Defaults to `true` (SQL is shown even without
110 /// `database_explain`).
111 pub expose_sql: bool,
112}
113
114impl Default for DebugConfig {
115 fn default() -> Self {
116 Self {
117 enabled: false,
118 database_explain: false,
119 expose_sql: true,
120 }
121 }
122}