jumperless-mcp 0.1.0

MCP server for the Jumperless V5 — persistent USB-serial bridge exposing the firmware API to LLMs
//! Standard CLI flags shared by every subsystem MCP.
//!
//! Subsystem crates compose by flattening [`CommonCli`] into their own clap struct:
//!
//! ```rust,ignore
//! #[derive(clap::Parser)]
//! struct JumperlessCli {
//!     #[command(flatten)]
//!     common: ygg_mcp_base::CommonCli,
//!
//!     /// Jumperless-specific — skip the Raw REPL handshake (debug)
//!     #[arg(long)]
//!     pub skip_handshake: bool,
//! }
//! ```

use clap::Parser;
use serde::{Deserialize, Serialize};

/// Logging level for `--log-level`. Strongly-typed alternative to a raw string.
///
/// Implements `clap::ValueEnum` so it integrates with the CLI parser directly.
/// Call [`as_filter`](LogLevel::as_filter) to get the `tracing_subscriber`-compatible
/// string when initialising the subscriber.
#[derive(clap::ValueEnum, Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
    Trace,
    Debug,
    #[default]
    Info,
    Warn,
    Error,
}

impl LogLevel {
    /// Convert to a `tracing_subscriber`-compatible filter string.
    pub fn as_filter(self) -> &'static str {
        match self {
            LogLevel::Trace => "trace",
            LogLevel::Debug => "debug",
            LogLevel::Info => "info",
            LogLevel::Warn => "warn",
            LogLevel::Error => "error",
        }
    }
}

/// Standard CLI flags inherited by every subsystem-specific MCP.
///
/// Covers the flags that apply uniformly across all subsystems. Subsystem
/// crates flatten this into their own [`clap::Parser`] struct and add
/// device-specific flags alongside.
#[derive(Parser, Debug, Clone)]
pub struct CommonCli {
    /// Override automatic discovery with an explicit serial port path.
    ///
    /// Examples: COM3, /dev/ttyACM0
    /// When omitted, the server auto-discovers the device.
    #[arg(long, value_name = "PATH")]
    pub port: Option<String>,

    /// Logging level filter.
    ///
    /// Overridden by the per-subsystem env var (e.g., `JUMPERLESS_LOG=debug`).
    #[arg(long, default_value = "info")]
    pub log_level: LogLevel,

    /// MCP transport. v1 only supports stdio; tcp/ws are reserved for future phases.
    #[arg(long, default_value = "stdio")]
    pub transport: McpTransport,
}

/// MCP transport variant. Controls how the MCP server accepts connections.
///
/// `Stdio` is the only variant wired up in v1. `Tcp` and `Ws` are reserved
/// for Phase B (remote bench-brain access over Tailscale).
#[derive(clap::ValueEnum, Debug, Clone, Serialize, Deserialize)]
pub enum McpTransport {
    /// Standard I/O transport (Claude Code / claude desktop / most clients).
    Stdio,
    /// TCP socket. Future variant — not implemented in v1.
    Tcp,
    /// WebSocket. Future variant — not implemented in v1.
    Ws,
}