use clap::{Args, Parser, Subcommand, ValueEnum};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(
name = "turbomcp-cli",
version,
about = "Comprehensive CLI for MCP servers - complete protocol support with rich UX",
long_about = "TurboMCP CLI provides comprehensive access to MCP (Model Context Protocol) servers.\n\
Supports all MCP operations: tools, resources, prompts, completions, sampling, and more.\n\
Multiple transports: stdio, HTTP SSE, WebSocket, TCP, Unix sockets.\n\n\
SECURITY WARNINGS:\n\
- STDIO transport executes arbitrary commands on your system\n\
- Only use --command with trusted MCP servers from verified sources\n\
- Auth tokens passed via --auth or MCP_AUTH may be logged or exposed\n\
- Consider using environment variables or config files for sensitive credentials\n\
- Review server permissions before executing tools that modify data"
)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
#[arg(long, short = 'f', global = true, value_enum, default_value = "human")]
pub format: OutputFormat,
#[arg(long, short = 'v', global = true)]
pub verbose: bool,
#[arg(long, short = 'c', global = true)]
pub connection: Option<String>,
#[arg(long, global = true)]
pub no_color: bool,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
#[command(subcommand)]
Tools(ToolCommands),
#[command(subcommand)]
Resources(ResourceCommands),
#[command(subcommand)]
Prompts(PromptCommands),
#[command(subcommand)]
Complete(CompletionCommands),
#[command(subcommand)]
Server(ServerCommands),
#[command(subcommand)]
Sample(SamplingCommands),
Connect(Connection),
Status(Connection),
Dev(DevArgs),
Install(InstallArgs),
Build(BuildArgs),
Deploy(DeployArgs),
New(NewArgs),
}
#[derive(Subcommand, Debug)]
pub enum ToolCommands {
List {
#[command(flatten)]
conn: Connection,
},
Call {
#[command(flatten)]
conn: Connection,
name: String,
#[arg(long, short = 'a', default_value = "{}")]
arguments: String,
},
Schema {
#[command(flatten)]
conn: Connection,
name: Option<String>,
},
Export {
#[command(flatten)]
conn: Connection,
#[arg(long, short = 'o')]
output: PathBuf,
},
}
#[derive(Subcommand, Debug)]
pub enum ResourceCommands {
List {
#[command(flatten)]
conn: Connection,
},
Read {
#[command(flatten)]
conn: Connection,
uri: String,
},
Templates {
#[command(flatten)]
conn: Connection,
},
Subscribe {
#[command(flatten)]
conn: Connection,
uri: String,
},
Unsubscribe {
#[command(flatten)]
conn: Connection,
uri: String,
},
}
#[derive(Subcommand, Debug)]
pub enum PromptCommands {
List {
#[command(flatten)]
conn: Connection,
},
Get {
#[command(flatten)]
conn: Connection,
name: String,
#[arg(long, short = 'a', default_value = "{}")]
arguments: String,
},
Schema {
#[command(flatten)]
conn: Connection,
name: String,
},
}
#[derive(Subcommand, Debug)]
pub enum CompletionCommands {
Get {
#[command(flatten)]
conn: Connection,
#[arg(value_enum)]
ref_type: RefType,
ref_value: String,
#[arg(long)]
argument: Option<String>,
},
}
#[derive(Subcommand, Debug)]
pub enum ServerCommands {
Info {
#[command(flatten)]
conn: Connection,
},
Ping {
#[command(flatten)]
conn: Connection,
},
LogLevel {
#[command(flatten)]
conn: Connection,
#[arg(value_enum)]
level: LogLevel,
},
Roots {
#[command(flatten)]
conn: Connection,
},
}
#[derive(Subcommand, Debug)]
pub enum SamplingCommands {
Create {
#[command(flatten)]
conn: Connection,
messages: String,
#[arg(long)]
model_preferences: Option<String>,
#[arg(long)]
system_prompt: Option<String>,
#[arg(long)]
max_tokens: Option<u32>,
},
}
#[derive(Args, Debug, Clone, Serialize, Deserialize)]
pub struct Connection {
#[arg(long, value_enum)]
pub transport: Option<TransportKind>,
#[arg(long, env = "MCP_URL", default_value = "http://localhost:8080/mcp")]
pub url: String,
#[arg(long, env = "MCP_COMMAND")]
pub command: Option<String>,
#[arg(long, env = "MCP_AUTH")]
pub auth: Option<String>,
#[arg(long, default_value = "30")]
pub timeout: u64,
}
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TransportKind {
Stdio,
Http,
Ws,
Tcp,
Unix,
}
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
pub enum OutputFormat {
Human,
Json,
Yaml,
Table,
Compact,
}
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
pub enum RefType {
Prompt,
Resource,
}
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
pub enum LogLevel {
Debug,
Info,
Warning,
Error,
}
impl From<LogLevel> for turbomcp_protocol::types::LogLevel {
fn from(level: LogLevel) -> Self {
match level {
LogLevel::Debug => turbomcp_protocol::types::LogLevel::Debug,
LogLevel::Info => turbomcp_protocol::types::LogLevel::Info,
LogLevel::Warning => turbomcp_protocol::types::LogLevel::Warning,
LogLevel::Error => turbomcp_protocol::types::LogLevel::Error,
}
}
}
#[derive(Args, Debug, Clone)]
pub struct DevArgs {
pub path: PathBuf,
#[arg(long, short = 'w')]
pub watch: bool,
#[arg(last = true)]
pub server_args: Vec<String>,
#[arg(long, short = 'r')]
pub release: bool,
#[arg(long)]
pub inspector: bool,
#[arg(long, default_value = "5173")]
pub inspector_port: u16,
}
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
pub enum InstallTarget {
ClaudeDesktop,
Cursor,
}
#[derive(Args, Debug, Clone)]
pub struct InstallArgs {
#[arg(value_enum)]
pub target: InstallTarget,
pub server_path: PathBuf,
#[arg(long, short = 'n')]
pub name: Option<String>,
#[arg(long, short = 'e')]
pub env: Vec<String>,
#[arg(long, short = 'a')]
pub args: Vec<String>,
#[arg(long, short = 'f')]
pub force: bool,
}
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
pub enum WasmPlatform {
CloudflareWorkers,
DenoWorkers,
Wasm32,
}
impl std::fmt::Display for WasmPlatform {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::CloudflareWorkers => write!(f, "cloudflare-workers"),
Self::DenoWorkers => write!(f, "deno-workers"),
Self::Wasm32 => write!(f, "wasm32"),
}
}
}
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
pub enum ProjectTemplate {
Minimal,
Full,
CloudflareWorkers,
CloudflareWorkersOauth,
CloudflareWorkersDurableObjects,
}
impl std::fmt::Display for ProjectTemplate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Minimal => write!(f, "minimal"),
Self::Full => write!(f, "full"),
Self::CloudflareWorkers => write!(f, "cloudflare-workers"),
Self::CloudflareWorkersOauth => write!(f, "cloudflare-workers-oauth"),
Self::CloudflareWorkersDurableObjects => {
write!(f, "cloudflare-workers-durable-objects")
}
}
}
}
#[derive(Args, Debug, Clone)]
pub struct BuildArgs {
#[arg(default_value = ".")]
pub path: PathBuf,
#[arg(long, value_enum)]
pub platform: Option<WasmPlatform>,
#[arg(long)]
pub target: Option<String>,
#[arg(long, short = 'r')]
pub release: bool,
#[arg(long)]
pub optimize: bool,
#[arg(long, short = 'F')]
pub features: Vec<String>,
#[arg(long)]
pub no_default_features: bool,
#[arg(long, short = 'o')]
pub output: Option<PathBuf>,
}
#[derive(Args, Debug, Clone)]
pub struct DeployArgs {
#[arg(default_value = ".")]
pub path: PathBuf,
#[arg(long, value_enum, default_value = "cloudflare-workers")]
pub platform: WasmPlatform,
#[arg(long, short = 'e')]
pub env: Option<String>,
#[arg(long)]
pub wrangler_config: Option<PathBuf>,
#[arg(long, short = 'r', default_value = "true")]
pub release: bool,
#[arg(long, default_value = "true")]
pub optimize: bool,
#[arg(long)]
pub skip_build: bool,
#[arg(long)]
pub dry_run: bool,
}
#[derive(Args, Debug, Clone)]
pub struct NewArgs {
pub name: String,
#[arg(long, short = 't', value_enum, default_value = "minimal")]
pub template: ProjectTemplate,
#[arg(long, short = 'o')]
pub output: Option<PathBuf>,
#[arg(long, default_value = "true")]
pub git: bool,
#[arg(long, short = 'd')]
pub description: Option<String>,
#[arg(long)]
pub author: Option<String>,
}