fraiseql-cli 2.16.0

CLI tools for FraiseQL v2 - Schema compilation and development utilities
Documentation
//! Server settings configuration for TOML schema (validation, debug, MCP).

use serde::{Deserialize, Serialize};

/// MCP (Model Context Protocol) server configuration.
///
/// Enables AI/LLM tools to interact with FraiseQL queries and mutations
/// through the standardized Model Context Protocol.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct McpConfig {
    /// Enable MCP server endpoint.
    pub enabled:       bool,
    /// Transport mode: "http", "stdio", or "both".
    pub transport:     String,
    /// HTTP path for MCP endpoint (e.g., "/mcp").
    pub path:          String,
    /// Require authentication for MCP requests.
    pub require_auth:  bool,
    /// Whitelist of query/mutation names to expose (empty = all).
    #[serde(default)]
    pub include:       Vec<String>,
    /// Blacklist of query/mutation names to hide.
    #[serde(default)]
    pub exclude:       Vec<String>,
    /// Read-only exposure: when `true`, no mutation is ever exposed as an MCP tool,
    /// regardless of `include`/`exclude` (fail-closed for AI callers). Recommended
    /// unless you deliberately expose mutations.
    #[serde(default)]
    pub read_only:     bool,
    /// Keep per-thread working state across an agent's tool calls, in the
    /// `[session_state]` store (#967). Off by default; requires an authenticated
    /// caller and a configured `[session_state]` backend.
    #[serde(default)]
    pub session_state: bool,
}

impl Default for McpConfig {
    fn default() -> Self {
        Self {
            enabled:       false,
            transport:     "http".to_string(),
            path:          "/mcp".to_string(),
            require_auth:  true,
            include:       Vec::new(),
            exclude:       Vec::new(),
            read_only:     false,
            session_state: false,
        }
    }
}

/// Query validation limits (depth and complexity).
///
/// ```toml
/// [validation]
/// max_query_depth = 10
/// max_query_complexity = 100
/// ```
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ValidationConfig {
    /// Maximum allowed query nesting depth. `None` uses the server default (10).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_query_depth: Option<u32>,

    /// Maximum allowed query complexity score. `None` uses the server default (100).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_query_complexity: Option<u32>,

    /// Maximum bytes a single read may deliver, measured on the rows returned.
    ///
    /// Depth and complexity score the request; this bounds the answer, which is
    /// the only cost a read from a materialised view actually has. `None` leaves
    /// reads unbounded by size.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_response_bytes: Option<u64>,

    /// Maximum rows a top-level `first`/`last`/`limit` argument may request,
    /// guarding against unbounded-pagination denial of service (#421). `None`
    /// uses the server default (1000); the server also honours the
    /// `FRAISEQL_MAX_PAGE_SIZE` environment variable as an override.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub max_page_size: Option<u32>,
}

/// Debug/development configuration.
///
/// Controls features that should only be enabled during development or
/// in trusted environments. All flags default to off.
///
/// ```toml
/// [debug]
/// enabled = true
/// database_explain = true
/// expose_sql = true
/// ```
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfig {
    /// Master switch — all debug features require this to be `true`.
    pub enabled: bool,

    /// When `true`, the explain endpoint will also run `EXPLAIN` against the
    /// database and include the query plan in the response.
    pub database_explain: bool,

    /// When `true`, the explain endpoint includes the generated SQL in the
    /// response. Defaults to `true` (SQL is shown even without
    /// `database_explain`).
    pub expose_sql: bool,
}

impl Default for DebugConfig {
    fn default() -> Self {
        Self {
            enabled:          false,
            database_explain: false,
            expose_sql:       true,
        }
    }
}