Skip to content

Commit 1a33a20

Browse files
committed
fmt
1 parent a14e985 commit 1a33a20

File tree

1 file changed

+82
-82
lines changed

1 file changed

+82
-82
lines changed

crates/q_chat/src/mcp.rs

Lines changed: 82 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use eyre::{
77
bail,
88
};
99
use fig_os_shim::Context;
10-
use futures::future::ok;
1110
use tracing::warn;
1211

1312
use crate::cli::{
@@ -43,33 +42,37 @@ pub async fn execute_mcp(args: Mcp) -> Result<ExitCode> {
4342
}
4443

4544
pub async fn add_mcp_server(ctx: &Context, args: McpAdd) -> Result<()> {
45+
let scope = args.scope.unwrap_or(Scope::Workspace);
4646
let config_path = resolve_scope_profile(ctx, args.scope, args.profile.as_ref())?;
4747
let mut config: McpServerConfig = serde_json::from_str(&ctx.fs().read_to_string(&config_path).await?)?;
48-
let merged_env = if args.env.is_empty() {
49-
None
50-
} else {
51-
let mut map = HashMap::new();
52-
for m in args.env {
53-
map.extend(m);
54-
}
55-
Some(map)
56-
};
57-
let val: CustomToolConfig = serde_json::from_value(serde_json::json!({
48+
let merged_env = args.env.into_iter().flatten().collect::<HashMap<_, _>>();
49+
50+
let tool: CustomToolConfig = serde_json::from_value(serde_json::json!({
5851
"command": args.command,
5952
"env": merged_env,
6053
"timeout": args.timeout,
6154
}))?;
62-
config.mcp_servers.insert(args.name, val);
55+
config.mcp_servers.insert(args.name.clone(), tool);
6356
config.save_to_file(ctx, &config_path).await?;
6457

58+
println!(
59+
"✓ Added MCP server '{}' to {scope}",
60+
args.name,
61+
scope = scope_display(&scope, &args.profile)
62+
);
6563
Ok(())
6664
}
6765

6866
pub async fn remove_mcp_server(ctx: &Context, args: McpRemove) -> Result<()> {
67+
let scope = args.scope.unwrap_or(Scope::Workspace);
6968
let config_path = resolve_scope_profile(ctx, args.scope, args.profile.as_ref())?;
70-
let mut config = McpServerConfig::load_from_file(ctx, &config_path).await?;
7169

72-
let scope = args.scope.unwrap_or(Scope::Workspace);
70+
if !ctx.fs().exists(&config_path) {
71+
println!("No MCP configuration at {}", config_path.display());
72+
return Ok(());
73+
}
74+
75+
let mut config = McpServerConfig::load_from_file(ctx, &config_path).await?;
7376
match config.mcp_servers.remove(&args.name) {
7477
Some(_) => {
7578
config.save_to_file(ctx, &config_path).await?;
@@ -79,9 +82,7 @@ pub async fn remove_mcp_server(ctx: &Context, args: McpRemove) -> Result<()> {
7982
scope_display(&scope, &args.profile)
8083
);
8184
},
82-
None => {
83-
warn!(?args, "No MCP server found");
84-
},
85+
None => println!("No MCP server named '{}' found in {}", args.name, scope_display(&scope, &args.profile)),
8586
}
8687
Ok(())
8788
}
@@ -94,6 +95,7 @@ pub async fn list_mcp_server(ctx: &Context, args: McpList) -> Result<()> {
9495
}
9596

9697
for (scope, profile, path, cfg_opt) in configs {
98+
println!();
9799
println!("{}:", scope_display(&scope, &profile));
98100
println!(" {}", path.display());
99101
match cfg_opt {
@@ -103,13 +105,66 @@ pub async fn list_mcp_server(ctx: &Context, args: McpList) -> Result<()> {
103105
}
104106
},
105107
_ => {
106-
println!(" null");
108+
println!(" (empty)");
107109
},
108110
}
109111
}
110112
Ok(())
111113
}
112114

115+
pub async fn import_mcp_server(ctx: &Context, args: McpImport) -> Result<()> {
116+
let scope: Scope = args.scope.unwrap_or(Scope::Workspace);
117+
let config_path = resolve_scope_profile(ctx, args.scope, args.profile.as_ref())?;
118+
let mut dst_cfg: McpServerConfig = if ctx.fs().exists(&config_path) {
119+
McpServerConfig::load_from_file(ctx, &config_path).await?
120+
} else {
121+
McpServerConfig::default()
122+
};
123+
let src_path = expand_path(ctx, &args.file)?;
124+
let src_cfg: McpServerConfig = serde_json::from_str(&ctx.fs().read_to_string(&src_path).await?)?;
125+
126+
let before = dst_cfg.mcp_servers.len();
127+
for (name, cfg) in src_cfg.mcp_servers {
128+
if dst_cfg.mcp_servers.insert(name.clone(), cfg).is_some() {
129+
warn!(%name, "Overwriting existing MCP server configuration");
130+
}
131+
}
132+
let added = dst_cfg.mcp_servers.len() - before;
133+
dst_cfg.save_to_file(ctx, &config_path).await?;
134+
135+
println!(
136+
"✓ Imported {added} MCP server(s) into {:?} scope",
137+
scope_display(&scope, &args.profile)
138+
);
139+
Ok(())
140+
}
141+
142+
pub async fn get_mcp_server_status(ctx: &Context, name: String) -> Result<()> {
143+
let configs = get_mcp_server_configs(ctx, None, None).await?;
144+
145+
for (_, _, _, cfg_opt) in configs {
146+
if let Some(cfg) = cfg_opt {
147+
if let Some(tool_cfg) = cfg.mcp_servers.get(&name) {
148+
println!("MCP Server: {name}");
149+
println!("Command : {}", tool_cfg.command);
150+
println!("Timeout : {} ms", tool_cfg.timeout);
151+
println!(
152+
"Env Vars : {}",
153+
tool_cfg
154+
.env
155+
.as_ref()
156+
.map(|e| e.keys().cloned().collect::<Vec<_>>().join(", "))
157+
.unwrap_or_else(|| "(none)".into())
158+
);
159+
// todo yifan how can I know the server status
160+
println!("Status : ");
161+
return Ok(());
162+
}
163+
}
164+
}
165+
bail!("No MCP server named '{name}' found\n")
166+
}
167+
113168
async fn get_mcp_server_configs(
114169
ctx: &Context,
115170
scope: Option<Scope>,
@@ -160,70 +215,6 @@ fn scope_display(scope: &Scope, profile: &Option<String>) -> String {
160215
}
161216
}
162217

163-
pub async fn import_mcp_server(ctx: &Context, args: McpImport) -> Result<()> {
164-
let config_path = resolve_scope_profile(ctx, args.scope, args.profile.as_ref())?;
165-
let mut dst_cfg = if ctx.fs().exists(&config_path) {
166-
McpServerConfig::load_from_file(ctx, &config_path).await?
167-
} else {
168-
McpServerConfig::default()
169-
};
170-
let expanded = shellexpand::tilde(&args.file);
171-
let mut src_path = std::path::PathBuf::from(expanded.as_ref());
172-
if src_path.is_relative() {
173-
src_path = ctx.env().current_dir()?.join(src_path);
174-
}
175-
176-
let src_content = ctx
177-
.fs()
178-
.read_to_string(&src_path)
179-
.await
180-
.map_err(|e| eyre::eyre!("Failed to read source file '{}': {e}", src_path.display()))?;
181-
let src_cfg: McpServerConfig = serde_json::from_str(&src_content)
182-
.map_err(|e| eyre::eyre!("Invalid MCP JSON in '{}': {e}", src_path.display()))?;
183-
184-
let before = dst_cfg.mcp_servers.len();
185-
for (name, cfg) in src_cfg.mcp_servers {
186-
if dst_cfg.mcp_servers.insert(name.clone(), cfg).is_some() {
187-
warn!(server = %name, "Overwriting existing MCP server configuration");
188-
}
189-
}
190-
let added = dst_cfg.mcp_servers.len() - before;
191-
192-
dst_cfg.save_to_file(ctx, &config_path).await?;
193-
194-
let scope = args.scope.unwrap_or(Scope::Workspace);
195-
println!(
196-
"✓ Imported {added} MCP server(s) into {:?} scope",
197-
scope_display(&scope, &args.profile)
198-
);
199-
Ok(())
200-
}
201-
202-
pub async fn get_mcp_server_status(ctx: &Context, name: String) -> Result<()> {
203-
let configs = get_mcp_server_configs(ctx, None, None).await?;
204-
for (_, _, _, cfg_opt) in configs {
205-
if let Some(cfg) = cfg_opt {
206-
if let Some(tool_cfg) = cfg.mcp_servers.get(&name) {
207-
println!("MCP Server: {name}");
208-
println!("Command : {}", tool_cfg.command);
209-
println!("Timeout : {} ms", tool_cfg.timeout);
210-
println!(
211-
"Env Vars : {}",
212-
tool_cfg
213-
.env
214-
.as_ref()
215-
.map(|e| e.keys().cloned().collect::<Vec<_>>().join(", "))
216-
.unwrap_or_else(|| "(none)".into())
217-
);
218-
// todo yifan how can I know the server status
219-
println!("Status : ");
220-
return Ok(());
221-
}
222-
}
223-
}
224-
bail!("No MCP server named '{name}' found\n")
225-
}
226-
227218
fn resolve_scope_profile(ctx: &Context, scope: Option<Scope>, profile: Option<&impl AsRef<str>>) -> Result<PathBuf> {
228219
Ok(match (scope, profile) {
229220
(None | Some(Scope::Workspace), _) => workspace_mcp_config_path(ctx)?,
@@ -233,6 +224,15 @@ fn resolve_scope_profile(ctx: &Context, scope: Option<Scope>, profile: Option<&i
233224
})
234225
}
235226

227+
fn expand_path(ctx: &Context, p: &str) -> Result<PathBuf> {
228+
let p = shellexpand::tilde(p);
229+
let mut path = PathBuf::from(p.as_ref());
230+
if path.is_relative() {
231+
path = ctx.env().current_dir()?.join(path);
232+
}
233+
Ok(path)
234+
}
235+
236236
#[cfg(test)]
237237
mod tests {
238238
use super::*;

0 commit comments

Comments
 (0)