Skip to main content

turbomcp_cli/
cli.rs

1//! CLI argument parsing and configuration types - Enhanced version
2
3use clap::{Args, Parser, Subcommand, ValueEnum};
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7/// Main CLI application structure
8#[derive(Parser, Debug)]
9#[command(
10    name = "turbomcp-cli",
11    version,
12    about = "Comprehensive CLI for MCP servers - complete protocol support with rich UX",
13    long_about = "TurboMCP CLI provides comprehensive access to MCP (Model Context Protocol) servers.\n\
14                  Supports all MCP operations: tools, resources, prompts, completions, sampling, and more.\n\
15                  Multiple transports: stdio, HTTP SSE, WebSocket, TCP, Unix sockets.\n\n\
16                  SECURITY WARNINGS:\n\
17                  - STDIO transport executes arbitrary commands on your system\n\
18                  - Only use --command with trusted MCP servers from verified sources\n\
19                  - Auth tokens passed via --auth or MCP_AUTH may be logged or exposed\n\
20                  - Consider using environment variables or config files for sensitive credentials\n\
21                  - Review server permissions before executing tools that modify data"
22)]
23pub struct Cli {
24    /// Subcommand to run
25    #[command(subcommand)]
26    pub command: Commands,
27
28    /// Output format
29    #[arg(long, short = 'f', global = true, value_enum, default_value = "human")]
30    pub format: OutputFormat,
31
32    /// Enable verbose output
33    #[arg(long, short = 'v', global = true)]
34    pub verbose: bool,
35
36    /// Connection config name (from ~/.turbomcp/config.yaml)
37    #[arg(long, short = 'c', global = true)]
38    pub connection: Option<String>,
39
40    /// Disable colored output
41    #[arg(long, global = true)]
42    pub no_color: bool,
43}
44
45/// Available CLI subcommands - Complete MCP coverage
46#[derive(Subcommand, Debug)]
47pub enum Commands {
48    /// Tool operations
49    #[command(subcommand)]
50    Tools(ToolCommands),
51
52    /// Resource operations
53    #[command(subcommand)]
54    Resources(ResourceCommands),
55
56    /// Prompt operations
57    #[command(subcommand)]
58    Prompts(PromptCommands),
59
60    /// Completion operations
61    #[command(subcommand)]
62    Complete(CompletionCommands),
63
64    /// Server management
65    #[command(subcommand)]
66    Server(ServerCommands),
67
68    /// Sampling operations (advanced)
69    #[command(subcommand)]
70    Sample(SamplingCommands),
71
72    /// Interactive connection wizard
73    Connect(Connection),
74
75    /// Connection status
76    Status(Connection),
77
78    /// Development server with hot reload
79    Dev(DevArgs),
80
81    /// Install MCP server to Claude Desktop or Cursor
82    Install(InstallArgs),
83
84    /// Build an MCP server (supports WASM targets)
85    Build(BuildArgs),
86
87    /// Deploy an MCP server to cloud platforms
88    Deploy(DeployArgs),
89
90    /// Create a new MCP server project from a template
91    New(NewArgs),
92}
93
94/// Tool-related commands
95#[derive(Subcommand, Debug)]
96pub enum ToolCommands {
97    /// List available tools
98    List {
99        #[command(flatten)]
100        conn: Connection,
101    },
102
103    /// Call a tool
104    Call {
105        #[command(flatten)]
106        conn: Connection,
107
108        /// Tool name
109        name: String,
110
111        /// Arguments as JSON object
112        #[arg(long, short = 'a', default_value = "{}")]
113        arguments: String,
114    },
115
116    /// Get tool schema
117    Schema {
118        #[command(flatten)]
119        conn: Connection,
120
121        /// Tool name (omit to get all schemas)
122        name: Option<String>,
123    },
124
125    /// Export all tool schemas
126    Export {
127        #[command(flatten)]
128        conn: Connection,
129
130        /// Output directory
131        #[arg(long, short = 'o')]
132        output: PathBuf,
133    },
134}
135
136/// Resource-related commands
137#[derive(Subcommand, Debug)]
138pub enum ResourceCommands {
139    /// List resources
140    List {
141        #[command(flatten)]
142        conn: Connection,
143    },
144
145    /// Read resource content
146    Read {
147        #[command(flatten)]
148        conn: Connection,
149
150        /// Resource URI
151        uri: String,
152    },
153
154    /// List resource templates
155    Templates {
156        #[command(flatten)]
157        conn: Connection,
158    },
159
160    /// Subscribe to resource updates
161    Subscribe {
162        #[command(flatten)]
163        conn: Connection,
164
165        /// Resource URI
166        uri: String,
167    },
168
169    /// Unsubscribe from resource updates
170    Unsubscribe {
171        #[command(flatten)]
172        conn: Connection,
173
174        /// Resource URI
175        uri: String,
176    },
177}
178
179/// Prompt-related commands
180#[derive(Subcommand, Debug)]
181pub enum PromptCommands {
182    /// List prompts
183    List {
184        #[command(flatten)]
185        conn: Connection,
186    },
187
188    /// Get prompt with arguments
189    Get {
190        #[command(flatten)]
191        conn: Connection,
192
193        /// Prompt name
194        name: String,
195
196        /// Arguments as JSON object
197        #[arg(long, short = 'a', default_value = "{}")]
198        arguments: String,
199    },
200
201    /// Get prompt schema
202    Schema {
203        #[command(flatten)]
204        conn: Connection,
205
206        /// Prompt name
207        name: String,
208    },
209}
210
211/// Completion commands
212#[derive(Subcommand, Debug)]
213pub enum CompletionCommands {
214    /// Get completions for a reference
215    Get {
216        #[command(flatten)]
217        conn: Connection,
218
219        /// Reference type (prompt, resource, etc.)
220        #[arg(value_enum)]
221        ref_type: RefType,
222
223        /// Reference value
224        ref_value: String,
225
226        /// Argument name (for prompt arguments)
227        #[arg(long)]
228        argument: Option<String>,
229    },
230}
231
232/// Server management commands
233#[derive(Subcommand, Debug)]
234pub enum ServerCommands {
235    /// Get server info
236    Info {
237        #[command(flatten)]
238        conn: Connection,
239    },
240
241    /// Ping server
242    Ping {
243        #[command(flatten)]
244        conn: Connection,
245    },
246
247    /// Set server log level
248    LogLevel {
249        #[command(flatten)]
250        conn: Connection,
251
252        /// Log level
253        #[arg(value_enum)]
254        level: LogLevel,
255    },
256
257    /// List roots
258    Roots {
259        #[command(flatten)]
260        conn: Connection,
261    },
262}
263
264/// Sampling commands (advanced)
265#[derive(Subcommand, Debug)]
266pub enum SamplingCommands {
267    /// Create a message sample
268    Create {
269        #[command(flatten)]
270        conn: Connection,
271
272        /// Messages as JSON array
273        messages: String,
274
275        /// Model preferences
276        #[arg(long)]
277        model_preferences: Option<String>,
278
279        /// System prompt
280        #[arg(long)]
281        system_prompt: Option<String>,
282
283        /// Max tokens
284        #[arg(long)]
285        max_tokens: Option<u32>,
286    },
287}
288
289/// Connection configuration
290#[derive(Args, Debug, Clone, Serialize, Deserialize)]
291pub struct Connection {
292    /// Transport protocol (auto-detected if not specified)
293    #[arg(long, value_enum)]
294    pub transport: Option<TransportKind>,
295
296    /// Server URL or command
297    #[arg(long, env = "MCP_URL", default_value = "http://localhost:8080/mcp")]
298    pub url: String,
299
300    /// Command for stdio transport (overrides --url)
301    #[arg(long, env = "MCP_COMMAND")]
302    pub command: Option<String>,
303
304    /// Bearer token or API key
305    #[arg(long, env = "MCP_AUTH")]
306    pub auth: Option<String>,
307
308    /// Connection timeout in seconds
309    #[arg(long, default_value = "30")]
310    pub timeout: u64,
311}
312
313/// Transport types - Extended
314#[derive(Debug, Clone, ValueEnum, PartialEq, Eq, Serialize, Deserialize)]
315#[serde(rename_all = "lowercase")]
316pub enum TransportKind {
317    /// Standard input/output
318    Stdio,
319    /// HTTP with Server-Sent Events
320    Http,
321    /// WebSocket
322    Ws,
323    /// TCP socket
324    Tcp,
325    /// Unix domain socket
326    Unix,
327}
328
329/// Output formats
330#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
331pub enum OutputFormat {
332    /// Human-readable with colors
333    Human,
334    /// JSON output
335    Json,
336    /// YAML output
337    Yaml,
338    /// Table format
339    Table,
340    /// Compact JSON (no pretty print)
341    Compact,
342}
343
344/// Reference types for completions
345#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
346pub enum RefType {
347    /// Prompt reference
348    Prompt,
349    /// Resource reference
350    Resource,
351}
352
353/// Log levels
354#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
355pub enum LogLevel {
356    Debug,
357    Info,
358    Warning,
359    Error,
360}
361
362impl From<LogLevel> for turbomcp_protocol::types::LogLevel {
363    fn from(level: LogLevel) -> Self {
364        match level {
365            LogLevel::Debug => turbomcp_protocol::types::LogLevel::Debug,
366            LogLevel::Info => turbomcp_protocol::types::LogLevel::Info,
367            LogLevel::Warning => turbomcp_protocol::types::LogLevel::Warning,
368            LogLevel::Error => turbomcp_protocol::types::LogLevel::Error,
369        }
370    }
371}
372
373/// Development server arguments
374#[derive(Args, Debug, Clone)]
375pub struct DevArgs {
376    /// Path to the server binary or cargo project
377    pub path: PathBuf,
378
379    /// Enable hot reload with cargo-watch
380    #[arg(long, short = 'w')]
381    pub watch: bool,
382
383    /// Additional arguments to pass to the server
384    #[arg(last = true)]
385    pub server_args: Vec<String>,
386
387    /// Build in release mode
388    #[arg(long, short = 'r')]
389    pub release: bool,
390
391    /// Enable MCP Inspector integration
392    #[arg(long)]
393    pub inspector: bool,
394
395    /// Port for the inspector (default: 5173)
396    #[arg(long, default_value = "5173")]
397    pub inspector_port: u16,
398}
399
400/// Install target applications
401#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
402pub enum InstallTarget {
403    /// Claude Desktop application
404    ClaudeDesktop,
405    /// Cursor IDE
406    Cursor,
407}
408
409/// Install command arguments
410#[derive(Args, Debug, Clone)]
411pub struct InstallArgs {
412    /// Target application to install to
413    #[arg(value_enum)]
414    pub target: InstallTarget,
415
416    /// Path to the MCP server binary
417    pub server_path: PathBuf,
418
419    /// Name for the MCP server (defaults to binary name)
420    #[arg(long, short = 'n')]
421    pub name: Option<String>,
422
423    /// Additional environment variables (KEY=VALUE)
424    #[arg(long, short = 'e')]
425    pub env: Vec<String>,
426
427    /// Additional arguments to pass to the server
428    #[arg(long, short = 'a')]
429    pub args: Vec<String>,
430
431    /// Force overwrite if server already exists
432    #[arg(long, short = 'f')]
433    pub force: bool,
434}
435
436// ============================================================================
437// WASM Build, Deploy, and New Commands
438// ============================================================================
439
440/// Target platform for WASM builds
441#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
442pub enum WasmPlatform {
443    /// Cloudflare Workers
444    CloudflareWorkers,
445    /// Deno Deploy
446    DenoWorkers,
447    /// Generic WASM32
448    Wasm32,
449}
450
451impl std::fmt::Display for WasmPlatform {
452    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
453        match self {
454            Self::CloudflareWorkers => write!(f, "cloudflare-workers"),
455            Self::DenoWorkers => write!(f, "deno-workers"),
456            Self::Wasm32 => write!(f, "wasm32"),
457        }
458    }
459}
460
461/// Project template for new MCP server
462#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
463pub enum ProjectTemplate {
464    /// Minimal MCP server (tools only)
465    Minimal,
466    /// Full-featured MCP server (tools, resources, prompts)
467    Full,
468    /// MCP server for Cloudflare Workers
469    CloudflareWorkers,
470    /// Cloudflare Workers with OAuth 2.1
471    CloudflareWorkersOauth,
472    /// Cloudflare Workers with Durable Objects
473    CloudflareWorkersDurableObjects,
474}
475
476impl std::fmt::Display for ProjectTemplate {
477    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
478        match self {
479            Self::Minimal => write!(f, "minimal"),
480            Self::Full => write!(f, "full"),
481            Self::CloudflareWorkers => write!(f, "cloudflare-workers"),
482            Self::CloudflareWorkersOauth => write!(f, "cloudflare-workers-oauth"),
483            Self::CloudflareWorkersDurableObjects => {
484                write!(f, "cloudflare-workers-durable-objects")
485            }
486        }
487    }
488}
489
490/// Build command arguments
491#[derive(Args, Debug, Clone)]
492pub struct BuildArgs {
493    /// Path to the Cargo project (default: current directory)
494    #[arg(default_value = ".")]
495    pub path: PathBuf,
496
497    /// Target platform for WASM builds
498    #[arg(long, value_enum)]
499    pub platform: Option<WasmPlatform>,
500
501    /// Rust target triple (e.g., wasm32-unknown-unknown)
502    #[arg(long)]
503    pub target: Option<String>,
504
505    /// Build in release mode
506    #[arg(long, short = 'r')]
507    pub release: bool,
508
509    /// Optimize WASM binary with wasm-opt
510    #[arg(long)]
511    pub optimize: bool,
512
513    /// Additional features to enable
514    #[arg(long, short = 'F')]
515    pub features: Vec<String>,
516
517    /// Disable default features
518    #[arg(long)]
519    pub no_default_features: bool,
520
521    /// Output directory for the built artifacts
522    #[arg(long, short = 'o')]
523    pub output: Option<PathBuf>,
524}
525
526/// Deploy command arguments
527#[derive(Args, Debug, Clone)]
528pub struct DeployArgs {
529    /// Path to the Cargo project (default: current directory)
530    #[arg(default_value = ".")]
531    pub path: PathBuf,
532
533    /// Target platform for deployment
534    #[arg(long, value_enum, default_value = "cloudflare-workers")]
535    pub platform: WasmPlatform,
536
537    /// Deployment environment (e.g., staging, production)
538    #[arg(long, short = 'e')]
539    pub env: Option<String>,
540
541    /// Path to wrangler.toml config (for Cloudflare Workers)
542    #[arg(long)]
543    pub wrangler_config: Option<PathBuf>,
544
545    /// Build in release mode before deploying
546    #[arg(long, short = 'r', default_value = "true")]
547    pub release: bool,
548
549    /// Optimize WASM binary with wasm-opt before deploying
550    #[arg(long, default_value = "true")]
551    pub optimize: bool,
552
553    /// Skip the build step (deploy existing artifacts)
554    #[arg(long)]
555    pub skip_build: bool,
556
557    /// Dry run (show what would be deployed without actually deploying)
558    #[arg(long)]
559    pub dry_run: bool,
560}
561
562/// New project command arguments
563#[derive(Args, Debug, Clone)]
564pub struct NewArgs {
565    /// Name of the new project
566    pub name: String,
567
568    /// Project template to use
569    #[arg(long, short = 't', value_enum, default_value = "minimal")]
570    pub template: ProjectTemplate,
571
572    /// Output directory (default: `./<name>`)
573    #[arg(long, short = 'o')]
574    pub output: Option<PathBuf>,
575
576    /// Initialize git repository
577    #[arg(long, default_value = "true")]
578    pub git: bool,
579
580    /// MCP server description
581    #[arg(long, short = 'd')]
582    pub description: Option<String>,
583
584    /// Package author
585    #[arg(long)]
586    pub author: Option<String>,
587}