diff --git a/Cargo.toml b/Cargo.toml index e34f4bf4..6d129665 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ rmcp = { version = "0.8.0", features = [ "transport-streamable-http-server", ] } percent-encoding = "2.3" -reqwest = { version = "0.12", features = ["json", "blocking"] } +reqwest = { version = "0.12", features = ["json"] } tempfile = "3" tokio = { version = "1.43", features = ["full"] } log = "0.4" @@ -30,3 +30,6 @@ terminal_size = "0.4.3" url = "2.5.8" axum = { version = "0.8.8", features = ["tokio"] } subtle = "2.6.1" + +[dev-dependencies] +reqwest = { version = "0.12", features = ["blocking"] } diff --git a/src/compile/onees.rs b/src/compile/onees.rs index ad0cf94a..8d06d5dd 100644 --- a/src/compile/onees.rs +++ b/src/compile/onees.rs @@ -244,7 +244,7 @@ fn generate_mcp_configuration(mcps: &HashMap) -> String { .filter_map(|(name, config)| { let (is_enabled, opts) = match config { McpConfig::Enabled(enabled) => (*enabled, None), - McpConfig::WithOptions(o) => (true, Some(o)), + McpConfig::WithOptions(o) => (o.enabled.unwrap_or(true), Some(o)), }; if !is_enabled { diff --git a/src/compile/standalone.rs b/src/compile/standalone.rs index 7867c5ae..bc36487c 100644 --- a/src/compile/standalone.rs +++ b/src/compile/standalone.rs @@ -452,7 +452,7 @@ pub fn generate_mcpg_config(front_matter: &FrontMatter) -> McpgConfig { let (is_enabled, options) = match config { McpConfig::Enabled(enabled) => (*enabled, None), - McpConfig::WithOptions(opts) => (true, Some(opts)), + McpConfig::WithOptions(opts) => (opts.enabled.unwrap_or(true), Some(opts)), }; if !is_enabled { diff --git a/src/compile/types.rs b/src/compile/types.rs index 1b438398..1279af05 100644 --- a/src/compile/types.rs +++ b/src/compile/types.rs @@ -352,6 +352,9 @@ pub enum McpConfig { /// Detailed MCP options #[derive(Debug, Deserialize, Clone, Default)] pub struct McpOptions { + /// Whether this MCP is enabled (default: true) + #[serde(default)] + pub enabled: Option, /// Custom command (if present, it's a custom MCP - standalone only) #[serde(default)] pub command: Option, diff --git a/src/mcp.rs b/src/mcp.rs index 7b04bde1..85eef965 100644 --- a/src/mcp.rs +++ b/src/mcp.rs @@ -942,12 +942,20 @@ pub async fn run_http( return next.run(req).await; } - // Check Bearer token with constant-time comparison + // Constant-time comparison to prevent timing side-channels. + // Pad to equal length so ct_eq compares all bytes even when lengths differ. if let Some(auth) = req.headers().get("authorization") { if let Ok(auth_str) = auth.to_str() { let expected_header = format!("Bearer {}", expected); use subtle::ConstantTimeEq; - if auth_str.as_bytes().ct_eq(expected_header.as_bytes()).into() { + let expected_bytes = expected_header.as_bytes(); + let provided_bytes = auth_str.as_bytes(); + let len = expected_bytes.len().max(provided_bytes.len()); + let mut e = vec![0u8; len]; + let mut p = vec![0u8; len]; + e[..expected_bytes.len()].copy_from_slice(expected_bytes); + p[..provided_bytes.len()].copy_from_slice(provided_bytes); + if e.ct_eq(&p).into() { return next.run(req).await; } }