mirror of
https://github.com/instructkr/claude-code.git
synced 2026-05-16 10:56:45 +00:00
omx(team): auto-checkpoint worker-1 [1]
This commit is contained in:
@@ -4188,6 +4188,7 @@ fn mcp_server_details_json(config: &McpServerConfig) -> Value {
|
||||
fn mcp_server_json(name: &str, server: &ScopedMcpServerConfig) -> Value {
|
||||
json!({
|
||||
"name": name,
|
||||
"required": server.required,
|
||||
"scope": config_source_json(server.scope),
|
||||
"transport": mcp_transport_json(&server.config),
|
||||
"summary": mcp_server_summary(&server.config),
|
||||
|
||||
@@ -101,6 +101,7 @@ pub struct McpConfigCollection {
|
||||
/// MCP server config paired with the scope that defined it.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ScopedMcpServerConfig {
|
||||
pub required: bool,
|
||||
pub scope: ConfigSource,
|
||||
pub config: McpServerConfig,
|
||||
}
|
||||
@@ -752,6 +753,12 @@ fn merge_mcp_servers(
|
||||
target.insert(
|
||||
name.clone(),
|
||||
ScopedMcpServerConfig {
|
||||
required: optional_bool(
|
||||
expect_object(value, &format!("{}: mcpServers.{name}", path.display()))?,
|
||||
"required",
|
||||
&format!("{}: mcpServers.{name}", path.display()),
|
||||
)?
|
||||
.unwrap_or(false),
|
||||
scope: source,
|
||||
config: parsed,
|
||||
},
|
||||
|
||||
@@ -275,10 +275,12 @@ mod tests {
|
||||
oauth: None,
|
||||
});
|
||||
let user = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::User,
|
||||
config: base_config.clone(),
|
||||
};
|
||||
let local = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: base_config,
|
||||
};
|
||||
@@ -288,6 +290,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let changed = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Http(McpRemoteServerConfig {
|
||||
url: "https://vendor.example/v2/mcp".to_string(),
|
||||
|
||||
@@ -143,6 +143,7 @@ mod tests {
|
||||
#[test]
|
||||
fn bootstraps_stdio_servers_into_transport_targets() {
|
||||
let config = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::User,
|
||||
config: McpServerConfig::Stdio(McpStdioServerConfig {
|
||||
command: "uvx".to_string(),
|
||||
@@ -176,6 +177,7 @@ mod tests {
|
||||
#[test]
|
||||
fn bootstraps_remote_servers_with_oauth_auth() {
|
||||
let config = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Project,
|
||||
config: McpServerConfig::Http(McpRemoteServerConfig {
|
||||
url: "https://vendor.example/mcp".to_string(),
|
||||
@@ -213,6 +215,7 @@ mod tests {
|
||||
#[test]
|
||||
fn bootstraps_websocket_and_sdk_transports_without_oauth() {
|
||||
let ws = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Ws(McpWebSocketServerConfig {
|
||||
url: "wss://vendor.example/mcp".to_string(),
|
||||
@@ -221,6 +224,7 @@ mod tests {
|
||||
}),
|
||||
};
|
||||
let sdk = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Sdk(McpSdkServerConfig {
|
||||
name: "sdk-server".to_string(),
|
||||
|
||||
@@ -230,6 +230,7 @@ pub struct ManagedMcpTool {
|
||||
pub struct UnsupportedMcpServer {
|
||||
pub server_name: String,
|
||||
pub transport: McpTransport,
|
||||
pub required: bool,
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
@@ -237,6 +238,7 @@ pub struct UnsupportedMcpServer {
|
||||
pub struct McpDiscoveryFailure {
|
||||
pub server_name: String,
|
||||
pub phase: McpLifecyclePhase,
|
||||
pub required: bool,
|
||||
pub error: String,
|
||||
pub recoverable: bool,
|
||||
pub context: BTreeMap<String, String>,
|
||||
@@ -366,7 +368,7 @@ impl McpServerManagerError {
|
||||
) && matches!(self, Self::Transport { .. } | Self::Timeout { .. })
|
||||
}
|
||||
|
||||
fn discovery_failure(&self, server_name: &str) -> McpDiscoveryFailure {
|
||||
fn discovery_failure(&self, server_name: &str, required: bool) -> McpDiscoveryFailure {
|
||||
let phase = self.lifecycle_phase();
|
||||
let recoverable = self.recoverable();
|
||||
let context = self.error_context();
|
||||
@@ -374,6 +376,7 @@ impl McpServerManagerError {
|
||||
McpDiscoveryFailure {
|
||||
server_name: server_name.to_string(),
|
||||
phase,
|
||||
required,
|
||||
error: self.to_string(),
|
||||
recoverable,
|
||||
context,
|
||||
@@ -447,7 +450,10 @@ fn unsupported_server_failed_server(server: &UnsupportedMcpServer) -> McpFailedS
|
||||
McpLifecyclePhase::ServerRegistration,
|
||||
Some(server.server_name.clone()),
|
||||
server.reason.clone(),
|
||||
BTreeMap::from([("transport".to_string(), format!("{:?}", server.transport))]),
|
||||
BTreeMap::from([
|
||||
("transport".to_string(), format!("{:?}", server.transport)),
|
||||
("required".to_string(), server.required.to_string()),
|
||||
]),
|
||||
false,
|
||||
),
|
||||
}
|
||||
@@ -464,14 +470,16 @@ struct ManagedMcpServer {
|
||||
bootstrap: McpClientBootstrap,
|
||||
process: Option<McpStdioProcess>,
|
||||
initialized: bool,
|
||||
required: bool,
|
||||
}
|
||||
|
||||
impl ManagedMcpServer {
|
||||
fn new(bootstrap: McpClientBootstrap) -> Self {
|
||||
fn new(bootstrap: McpClientBootstrap, required: bool) -> Self {
|
||||
Self {
|
||||
bootstrap,
|
||||
process: None,
|
||||
initialized: false,
|
||||
required,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,11 +506,15 @@ impl McpServerManager {
|
||||
for (server_name, server_config) in servers {
|
||||
if server_config.transport() == McpTransport::Stdio {
|
||||
let bootstrap = McpClientBootstrap::from_scoped_config(server_name, server_config);
|
||||
managed_servers.insert(server_name.clone(), ManagedMcpServer::new(bootstrap));
|
||||
managed_servers.insert(
|
||||
server_name.clone(),
|
||||
ManagedMcpServer::new(bootstrap, server_config.required),
|
||||
);
|
||||
} else {
|
||||
unsupported_servers.push(UnsupportedMcpServer {
|
||||
server_name: server_name.clone(),
|
||||
transport: server_config.transport(),
|
||||
required: server_config.required,
|
||||
reason: format!(
|
||||
"transport {:?} is not supported by McpServerManager",
|
||||
server_config.transport()
|
||||
@@ -576,7 +588,11 @@ impl McpServerManager {
|
||||
}
|
||||
Err(error) => {
|
||||
self.clear_routes_for_server(&server_name);
|
||||
failed_servers.push(error.discovery_failure(&server_name));
|
||||
let required = self
|
||||
.servers
|
||||
.get(&server_name)
|
||||
.is_some_and(|server| server.required);
|
||||
failed_servers.push(error.discovery_failure(&server_name, required));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,7 +606,11 @@ impl McpServerManager {
|
||||
failure.phase,
|
||||
Some(failure.server_name.clone()),
|
||||
failure.error.clone(),
|
||||
failure.context.clone(),
|
||||
{
|
||||
let mut context = failure.context.clone();
|
||||
context.insert("required".to_string(), failure.required.to_string());
|
||||
context
|
||||
},
|
||||
failure.recoverable,
|
||||
),
|
||||
})
|
||||
@@ -1765,6 +1785,7 @@ mod tests {
|
||||
|
||||
fn sample_bootstrap(script_path: &Path) -> McpClientBootstrap {
|
||||
let config = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Stdio(McpStdioServerConfig {
|
||||
command: "/bin/sh".to_string(),
|
||||
@@ -1832,6 +1853,7 @@ mod tests {
|
||||
]);
|
||||
env.extend(extra_env);
|
||||
ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Stdio(McpStdioServerConfig {
|
||||
command: "python3".to_string(),
|
||||
@@ -1874,6 +1896,7 @@ mod tests {
|
||||
#[test]
|
||||
fn rejects_non_stdio_bootstrap() {
|
||||
let config = ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Sdk(crate::config::McpSdkServerConfig {
|
||||
name: "sdk-server".to_string(),
|
||||
@@ -2310,6 +2333,7 @@ mod tests {
|
||||
let servers = BTreeMap::from([(
|
||||
"slow".to_string(),
|
||||
ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Stdio(McpStdioServerConfig {
|
||||
command: "python3".to_string(),
|
||||
@@ -2363,6 +2387,7 @@ mod tests {
|
||||
let servers = BTreeMap::from([(
|
||||
"broken".to_string(),
|
||||
ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Stdio(McpStdioServerConfig {
|
||||
command: "python3".to_string(),
|
||||
@@ -2777,6 +2802,7 @@ mod tests {
|
||||
(
|
||||
"http".to_string(),
|
||||
ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Http(McpRemoteServerConfig {
|
||||
url: "https://example.test/mcp".to_string(),
|
||||
@@ -2789,6 +2815,7 @@ mod tests {
|
||||
(
|
||||
"sdk".to_string(),
|
||||
ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Sdk(McpSdkServerConfig {
|
||||
name: "sdk-server".to_string(),
|
||||
@@ -2798,6 +2825,7 @@ mod tests {
|
||||
(
|
||||
"ws".to_string(),
|
||||
ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Ws(McpWebSocketServerConfig {
|
||||
url: "wss://example.test/mcp".to_string(),
|
||||
|
||||
@@ -442,6 +442,7 @@ mod tests {
|
||||
log_path: &Path,
|
||||
) -> ScopedMcpServerConfig {
|
||||
ScopedMcpServerConfig {
|
||||
required: false,
|
||||
scope: ConfigSource::Local,
|
||||
config: McpServerConfig::Stdio(McpStdioServerConfig {
|
||||
command: "python3".to_string(),
|
||||
|
||||
@@ -4542,7 +4542,10 @@ impl RuntimeMcpState {
|
||||
runtime::McpLifecyclePhase::ToolDiscovery,
|
||||
Some(failure.server_name.clone()),
|
||||
failure.error.clone(),
|
||||
std::collections::BTreeMap::new(),
|
||||
std::collections::BTreeMap::from([(
|
||||
"required".to_string(),
|
||||
failure.required.to_string(),
|
||||
)]),
|
||||
true,
|
||||
),
|
||||
})
|
||||
@@ -4557,6 +4560,9 @@ impl RuntimeMcpState {
|
||||
std::collections::BTreeMap::from([(
|
||||
"transport".to_string(),
|
||||
format!("{:?}", server.transport).to_ascii_lowercase(),
|
||||
), (
|
||||
"required".to_string(),
|
||||
server.required.to_string(),
|
||||
)]),
|
||||
false,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user