1use clap::{Args, Parser, Subcommand, ValueEnum};
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7#[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 #[command(subcommand)]
26 pub command: Commands,
27
28 #[arg(long, short = 'f', global = true, value_enum, default_value = "human")]
30 pub format: OutputFormat,
31
32 #[arg(long, short = 'v', global = true)]
34 pub verbose: bool,
35
36 #[arg(long, short = 'c', global = true)]
38 pub connection: Option<String>,
39
40 #[arg(long, global = true)]
42 pub no_color: bool,
43}
44
45#[derive(Subcommand, Debug)]
47pub enum Commands {
48 #[command(subcommand)]
50 Tools(ToolCommands),
51
52 #[command(subcommand)]
54 Resources(ResourceCommands),
55
56 #[command(subcommand)]
58 Prompts(PromptCommands),
59
60 #[command(subcommand)]
62 Complete(CompletionCommands),
63
64 #[command(subcommand)]
66 Server(ServerCommands),
67
68 #[command(subcommand)]
70 Sample(SamplingCommands),
71
72 Connect(Connection),
74
75 Status(Connection),
77
78 Dev(DevArgs),
80
81 Install(InstallArgs),
83
84 Build(BuildArgs),
86
87 Deploy(DeployArgs),
89
90 New(NewArgs),
92}
93
94#[derive(Subcommand, Debug)]
96pub enum ToolCommands {
97 List {
99 #[command(flatten)]
100 conn: Connection,
101 },
102
103 Call {
105 #[command(flatten)]
106 conn: Connection,
107
108 name: String,
110
111 #[arg(long, short = 'a', default_value = "{}")]
113 arguments: String,
114 },
115
116 Schema {
118 #[command(flatten)]
119 conn: Connection,
120
121 name: Option<String>,
123 },
124
125 Export {
127 #[command(flatten)]
128 conn: Connection,
129
130 #[arg(long, short = 'o')]
132 output: PathBuf,
133 },
134}
135
136#[derive(Subcommand, Debug)]
138pub enum ResourceCommands {
139 List {
141 #[command(flatten)]
142 conn: Connection,
143 },
144
145 Read {
147 #[command(flatten)]
148 conn: Connection,
149
150 uri: String,
152 },
153
154 Templates {
156 #[command(flatten)]
157 conn: Connection,
158 },
159
160 Subscribe {
162 #[command(flatten)]
163 conn: Connection,
164
165 uri: String,
167 },
168
169 Unsubscribe {
171 #[command(flatten)]
172 conn: Connection,
173
174 uri: String,
176 },
177}
178
179#[derive(Subcommand, Debug)]
181pub enum PromptCommands {
182 List {
184 #[command(flatten)]
185 conn: Connection,
186 },
187
188 Get {
190 #[command(flatten)]
191 conn: Connection,
192
193 name: String,
195
196 #[arg(long, short = 'a', default_value = "{}")]
198 arguments: String,
199 },
200
201 Schema {
203 #[command(flatten)]
204 conn: Connection,
205
206 name: String,
208 },
209}
210
211#[derive(Subcommand, Debug)]
213pub enum CompletionCommands {
214 Get {
216 #[command(flatten)]
217 conn: Connection,
218
219 #[arg(value_enum)]
221 ref_type: RefType,
222
223 ref_value: String,
225
226 #[arg(long)]
228 argument: Option<String>,
229 },
230}
231
232#[derive(Subcommand, Debug)]
234pub enum ServerCommands {
235 Info {
237 #[command(flatten)]
238 conn: Connection,
239 },
240
241 Ping {
243 #[command(flatten)]
244 conn: Connection,
245 },
246
247 LogLevel {
249 #[command(flatten)]
250 conn: Connection,
251
252 #[arg(value_enum)]
254 level: LogLevel,
255 },
256
257 Roots {
259 #[command(flatten)]
260 conn: Connection,
261 },
262}
263
264#[derive(Subcommand, Debug)]
266pub enum SamplingCommands {
267 Create {
269 #[command(flatten)]
270 conn: Connection,
271
272 messages: String,
274
275 #[arg(long)]
277 model_preferences: Option<String>,
278
279 #[arg(long)]
281 system_prompt: Option<String>,
282
283 #[arg(long)]
285 max_tokens: Option<u32>,
286 },
287}
288
289#[derive(Args, Debug, Clone, Serialize, Deserialize)]
291pub struct Connection {
292 #[arg(long, value_enum)]
294 pub transport: Option<TransportKind>,
295
296 #[arg(long, env = "MCP_URL", default_value = "http://localhost:8080/mcp")]
298 pub url: String,
299
300 #[arg(long, env = "MCP_COMMAND")]
302 pub command: Option<String>,
303
304 #[arg(long, env = "MCP_AUTH")]
306 pub auth: Option<String>,
307
308 #[arg(long, default_value = "30")]
310 pub timeout: u64,
311}
312
313#[derive(Debug, Clone, ValueEnum, PartialEq, Eq, Serialize, Deserialize)]
315#[serde(rename_all = "lowercase")]
316pub enum TransportKind {
317 Stdio,
319 Http,
321 Ws,
323 Tcp,
325 Unix,
327}
328
329#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
331pub enum OutputFormat {
332 Human,
334 Json,
336 Yaml,
338 Table,
340 Compact,
342}
343
344#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
346pub enum RefType {
347 Prompt,
349 Resource,
351}
352
353#[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#[derive(Args, Debug, Clone)]
375pub struct DevArgs {
376 pub path: PathBuf,
378
379 #[arg(long, short = 'w')]
381 pub watch: bool,
382
383 #[arg(last = true)]
385 pub server_args: Vec<String>,
386
387 #[arg(long, short = 'r')]
389 pub release: bool,
390
391 #[arg(long)]
393 pub inspector: bool,
394
395 #[arg(long, default_value = "5173")]
397 pub inspector_port: u16,
398}
399
400#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
402pub enum InstallTarget {
403 ClaudeDesktop,
405 Cursor,
407}
408
409#[derive(Args, Debug, Clone)]
411pub struct InstallArgs {
412 #[arg(value_enum)]
414 pub target: InstallTarget,
415
416 pub server_path: PathBuf,
418
419 #[arg(long, short = 'n')]
421 pub name: Option<String>,
422
423 #[arg(long, short = 'e')]
425 pub env: Vec<String>,
426
427 #[arg(long, short = 'a')]
429 pub args: Vec<String>,
430
431 #[arg(long, short = 'f')]
433 pub force: bool,
434}
435
436#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
442pub enum WasmPlatform {
443 CloudflareWorkers,
445 DenoWorkers,
447 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#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
463pub enum ProjectTemplate {
464 Minimal,
466 Full,
468 CloudflareWorkers,
470 CloudflareWorkersOauth,
472 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#[derive(Args, Debug, Clone)]
492pub struct BuildArgs {
493 #[arg(default_value = ".")]
495 pub path: PathBuf,
496
497 #[arg(long, value_enum)]
499 pub platform: Option<WasmPlatform>,
500
501 #[arg(long)]
503 pub target: Option<String>,
504
505 #[arg(long, short = 'r')]
507 pub release: bool,
508
509 #[arg(long)]
511 pub optimize: bool,
512
513 #[arg(long, short = 'F')]
515 pub features: Vec<String>,
516
517 #[arg(long)]
519 pub no_default_features: bool,
520
521 #[arg(long, short = 'o')]
523 pub output: Option<PathBuf>,
524}
525
526#[derive(Args, Debug, Clone)]
528pub struct DeployArgs {
529 #[arg(default_value = ".")]
531 pub path: PathBuf,
532
533 #[arg(long, value_enum, default_value = "cloudflare-workers")]
535 pub platform: WasmPlatform,
536
537 #[arg(long, short = 'e')]
539 pub env: Option<String>,
540
541 #[arg(long)]
543 pub wrangler_config: Option<PathBuf>,
544
545 #[arg(long, short = 'r', default_value = "true")]
547 pub release: bool,
548
549 #[arg(long, default_value = "true")]
551 pub optimize: bool,
552
553 #[arg(long)]
555 pub skip_build: bool,
556
557 #[arg(long)]
559 pub dry_run: bool,
560}
561
562#[derive(Args, Debug, Clone)]
564pub struct NewArgs {
565 pub name: String,
567
568 #[arg(long, short = 't', value_enum, default_value = "minimal")]
570 pub template: ProjectTemplate,
571
572 #[arg(long, short = 'o')]
574 pub output: Option<PathBuf>,
575
576 #[arg(long, default_value = "true")]
578 pub git: bool,
579
580 #[arg(long, short = 'd')]
582 pub description: Option<String>,
583
584 #[arg(long)]
586 pub author: Option<String>,
587}