fix: improve MCP server initialization error handling #3196 #2346 #2555 (#3243)

• I have signed the CLA by commenting the required sentence and
triggered recheck.
• Local checks are all green (fmt / clippy / test).
• Could you please approve the pending GitHub Actions workflows
(first-time contributor), and when convenient, help with one approving
review so I can proceed? Thanks!

  ## Summary
- Catch and log task panics during server initialization instead of
propagating JoinError
- Handle tool listing failures gracefully, allowing partial server
initialization
- Improve error resilience on macOS where init timeouts are more common

  ## Test plan
  - [x] Test MCP server initialization with timeout scenarios
  - [x] Verify graceful handling of tool listing failures
  - [x] Confirm improved error messages and logging
  - [x] Test on macOS 

 ## Fix issue  #3196 #2346 #2555
### fix before:
<img width="851" height="363" alt="image"
src="https://github.com/user-attachments/assets/e1f9c749-71fd-4873-a04f-d3fc4cbe0ae6"
/>

<img width="775" height="108" alt="image"
src="https://github.com/user-attachments/assets/4e4748bd-9dd6-42b5-b38b-8bfe9341a441"
/>

### fix improved:
<img width="966" height="528" alt="image"
src="https://github.com/user-attachments/assets/418324f3-e37a-4a3c-8bdd-934f9ff21dfb"
/>

---------

Co-authored-by: Michael Bolin <mbolin@openai.com>
This commit is contained in:
Biturd
2025-09-09 00:28:12 +08:00
committed by GitHub
parent e2b3053b2b
commit cad37009e1

View File

@@ -187,7 +187,13 @@ impl McpConnectionManager {
let mut clients: HashMap<String, ManagedClient> = HashMap::with_capacity(join_set.len());
while let Some(res) = join_set.join_next().await {
let (server_name, client_res) = res?; // JoinError propagation
let (server_name, client_res) = match res {
Ok((server_name, client_res)) => (server_name, client_res),
Err(e) => {
warn!("Task panic when starting MCP server: {e:#}");
continue;
}
};
match client_res {
Ok((client, startup_timeout)) => {
@@ -205,7 +211,13 @@ impl McpConnectionManager {
}
}
let all_tools = list_all_tools(&clients).await?;
let all_tools = match list_all_tools(&clients).await {
Ok(tools) => tools,
Err(e) => {
warn!("Failed to list tools from some MCP servers: {e:#}");
Vec::new()
}
};
let tools = qualify_tools(all_tools);
@@ -270,8 +282,19 @@ async fn list_all_tools(clients: &HashMap<String, ManagedClient>) -> Result<Vec<
let mut aggregated: Vec<ToolInfo> = Vec::with_capacity(join_set.len());
while let Some(join_res) = join_set.join_next().await {
let (server_name, list_result) = join_res?;
let list_result = list_result?;
let (server_name, list_result) = if let Ok(result) = join_res {
result
} else {
warn!("Task panic when listing tools for MCP server: {join_res:#?}");
continue;
};
let list_result = if let Ok(result) = list_result {
result
} else {
warn!("Failed to list tools for MCP server '{server_name}': {list_result:#?}");
continue;
};
for tool in list_result.tools {
let tool_info = ToolInfo {