(state: State<'_, AppState>)
| 177 | |
| 178 | #[tauri::command] |
| 179 | pub async fn get_mcp_servers(state: State<'_, AppState>) -> Result<Vec<MCPServerInfo>, String> { |
| 180 | let mcp_service = state |
| 181 | .mcp_service |
| 182 | .as_ref() |
| 183 | .ok_or_else(|| "MCP service not initialized".to_string())?; |
| 184 | |
| 185 | let configs = mcp_service |
| 186 | .config_service() |
| 187 | .load_all_configs() |
| 188 | .await |
| 189 | .map_err(|e| e.to_string())?; |
| 190 | |
| 191 | let mut infos = Vec::new(); |
| 192 | let runtime_manager = RuntimeManager::new().ok(); |
| 193 | |
| 194 | for config in configs { |
| 195 | let transport = config.resolved_transport(); |
| 196 | let static_auth_configured = if matches!(config.server_type, MCPServerType::Remote) { |
| 197 | MCPConfigService::has_remote_authorization(&config) |
| 198 | } else { |
| 199 | false |
| 200 | }; |
| 201 | let oauth_enabled = matches!(config.server_type, MCPServerType::Remote); |
| 202 | let oauth_auth_configured = if oauth_enabled { |
| 203 | has_stored_oauth_credentials(&config.id) |
| 204 | .await |
| 205 | .unwrap_or(false) |
| 206 | } else { |
| 207 | false |
| 208 | }; |
| 209 | |
| 210 | let (command, command_available, command_source, command_resolved_path) = |
| 211 | if transport == bitfun_core::service::mcp::MCPServerTransport::Stdio { |
| 212 | if let Some(command) = config.command.clone() { |
| 213 | let capability = runtime_manager |
| 214 | .as_ref() |
| 215 | .map(|manager| manager.get_command_capability(&command)); |
| 216 | let available = capability.as_ref().map(|c| c.available); |
| 217 | let source = capability.and_then(|c| { |
| 218 | c.source.map(|source| match source { |
| 219 | RuntimeSource::System => "system".to_string(), |
| 220 | RuntimeSource::Managed => "managed".to_string(), |
| 221 | }) |
| 222 | }); |
| 223 | let resolved_path = runtime_manager |
| 224 | .as_ref() |
| 225 | .and_then(|manager| manager.resolve_command(&command)) |
| 226 | .and_then(|resolved| resolved.resolved_path); |
| 227 | (Some(command), available, source, resolved_path) |
| 228 | } else { |
| 229 | (None, None, None, None) |
| 230 | } |
| 231 | } else { |
| 232 | (None, None, None, None) |
| 233 | }; |
| 234 | |
| 235 | let (start_supported, start_disabled_reason) = match config.server_type { |
| 236 | MCPServerType::Remote if transport.as_str() == "sse" => ( |
nothing calls this directly
no test coverage detected