Skip to content

Commit 84c4015

Browse files
authored
feat: Add MCP CLI subcommands (#1792)
1 parent 19bc0b0 commit 84c4015

File tree

6 files changed

+670
-4
lines changed

6 files changed

+670
-4
lines changed

crates/chat-cli/src/cli/chat/cli.rs

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
use clap::Parser;
1+
use std::collections::HashMap;
2+
3+
use clap::{
4+
Args,
5+
Parser,
6+
Subcommand,
7+
ValueEnum,
8+
};
29

310
#[derive(Debug, Clone, PartialEq, Eq, Default, Parser)]
411
pub struct Chat {
@@ -23,3 +30,127 @@ pub struct Chat {
2330
#[arg(long, value_delimiter = ',', value_name = "TOOL_NAMES")]
2431
pub trust_tools: Option<Vec<String>>,
2532
}
33+
34+
#[derive(Debug, Clone, PartialEq, Eq, Subcommand)]
35+
pub enum Mcp {
36+
/// Add or replace a configured server
37+
Add(McpAdd),
38+
/// Remove a server from the MCP configuration
39+
#[command(alias = "rm")]
40+
Remove(McpRemove),
41+
/// List configured servers
42+
List(McpList),
43+
/// Import a server configuration from another file
44+
Import(McpImport),
45+
/// Get the status of a configured server
46+
Status {
47+
#[arg(long)]
48+
name: String,
49+
},
50+
}
51+
52+
#[derive(Debug, Clone, PartialEq, Eq, Args)]
53+
pub struct McpAdd {
54+
/// Name for the server
55+
#[arg(long)]
56+
pub name: String,
57+
/// The command used to launch the server
58+
#[arg(long)]
59+
pub command: String,
60+
/// Where to add the server to. For profile scope, the name of the profile must specified with
61+
/// --profile.
62+
#[arg(long, value_enum)]
63+
pub scope: Option<Scope>,
64+
/// Name of the profile to add the server config to. Not compatible with workspace scope or
65+
/// global scope.
66+
#[arg(long)]
67+
pub profile: Option<String>,
68+
/// Environment variables to use when launching the server
69+
#[arg(long, value_parser = parse_env_vars)]
70+
pub env: Vec<HashMap<String, String>>,
71+
/// Server launch timeout, in milliseconds
72+
#[arg(long)]
73+
pub timeout: Option<u64>,
74+
/// Overwrite an existing server with the same name
75+
#[arg(long, default_value_t = false)]
76+
pub force: bool,
77+
}
78+
79+
#[derive(Debug, Clone, PartialEq, Eq, Args)]
80+
pub struct McpRemove {
81+
#[arg(long)]
82+
pub name: String,
83+
#[arg(long, value_enum)]
84+
pub scope: Option<Scope>,
85+
#[arg(long)]
86+
pub profile: Option<String>,
87+
}
88+
89+
#[derive(Debug, Clone, PartialEq, Eq, Args)]
90+
pub struct McpList {
91+
#[arg(value_enum)]
92+
pub scope: Option<Scope>,
93+
#[arg(long)]
94+
pub profile: Option<String>,
95+
}
96+
97+
#[derive(Debug, Clone, PartialEq, Eq, Args)]
98+
pub struct McpImport {
99+
#[arg(long)]
100+
pub file: String,
101+
#[arg(value_enum)]
102+
pub scope: Option<Scope>,
103+
#[arg(long)]
104+
pub profile: Option<String>,
105+
/// Overwrite an existing server with the same name
106+
#[arg(long, default_value_t = false)]
107+
pub force: bool,
108+
}
109+
110+
#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)]
111+
pub enum Scope {
112+
Workspace,
113+
Profile,
114+
Global,
115+
}
116+
117+
impl std::fmt::Display for Scope {
118+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119+
match self {
120+
Scope::Workspace => write!(f, "workspace"),
121+
Scope::Profile => write!(f, "profile"),
122+
Scope::Global => write!(f, "global"),
123+
}
124+
}
125+
}
126+
127+
#[derive(Debug)]
128+
struct EnvVarParseError(String);
129+
130+
impl std::fmt::Display for EnvVarParseError {
131+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132+
write!(f, "Failed to parse environment variables: {}", self.0)
133+
}
134+
}
135+
136+
impl std::error::Error for EnvVarParseError {}
137+
138+
fn parse_env_vars(arg: &str) -> Result<HashMap<String, String>, EnvVarParseError> {
139+
let mut vars = HashMap::new();
140+
141+
for pair in arg.split(",") {
142+
match pair.split_once('=') {
143+
Some((key, value)) => {
144+
vars.insert(key.trim().to_string(), value.trim().to_string());
145+
},
146+
None => {
147+
return Err(EnvVarParseError(format!(
148+
"Invalid environment variable '{}'. Expected 'name=value'",
149+
pair
150+
)));
151+
},
152+
}
153+
}
154+
155+
Ok(vars)
156+
}

0 commit comments

Comments
 (0)