refactor: Remove all auto-detection, require explicit config
BREAKING CHANGE: Auto-detection of binary paths has been removed. Why this change: - WASM sandbox cannot access PATH reliably (especially on macOS) - WASM cannot detect host OS - WASM cannot check if files exist - WASM cannot spawn commands like 'which' These fundamental limitations made auto-detection unreliable and platform-dependent. The extension would fail mysteriously on some systems. New behavior: - Explicit configuration is REQUIRED - Users MUST set either: 1. gitea_mcp_binary_path: "/full/path/to/binary" 2. use_docker: true Benefits: - Works reliably across ALL platforms - Clear, actionable error messages - No mysterious failures - Easier to debug - Less complex code - Better user experience (explicit > implicit) The error message now provides: - Clear explanation of why auto-detection isn't possible - Complete configuration examples - Platform-specific path examples - Docker alternative Docker mode now uses 'docker' command directly (found via system PATH) rather than trying to detect docker location.
This commit is contained in:
@@ -10,21 +10,21 @@ use zed_extension_api::{
|
||||
/// This extension launches a gitea-mcp binary (locally or via Docker) and communicates with it
|
||||
/// to provide Gitea repository access through Zed's AI assistant.
|
||||
///
|
||||
/// Binary Resolution Strategy:
|
||||
/// 1. If `gitea_mcp_binary_path` is set in settings, use that exact path
|
||||
/// 2. If `use_docker` is true, use Docker to run the gitea-mcp image
|
||||
/// 3. Otherwise, search common system paths:
|
||||
/// - /usr/local/bin/gitea-mcp
|
||||
/// - ~/.local/bin/gitea-mcp
|
||||
/// - ~/.cargo/bin/gitea-mcp
|
||||
/// - /opt/homebrew/bin/gitea-mcp (macOS)
|
||||
/// - Search in PATH environment variable
|
||||
/// Configuration Requirements:
|
||||
/// - EITHER set `gitea_mcp_binary_path` to the full path of the gitea-mcp binary
|
||||
/// - OR set `use_docker: true` to run gitea-mcp in Docker
|
||||
///
|
||||
/// Transport modes:
|
||||
/// - STDIO (default, recommended): Direct stdin/stdout communication
|
||||
/// Works with Zed's extension API and gitea-mcp binary
|
||||
/// - Docker: Runs gitea-mcp in a Docker container
|
||||
/// Useful when binary isn't available on host system
|
||||
/// WASM Limitation: This extension runs in a WebAssembly sandbox which cannot:
|
||||
/// - Detect the host operating system
|
||||
/// - Access PATH environment variable reliably
|
||||
/// - Check if files exist on the filesystem
|
||||
///
|
||||
/// Therefore, explicit configuration is required.
|
||||
///
|
||||
/// Example paths:
|
||||
/// - macOS (Homebrew): /opt/homebrew/bin/gitea-mcp-server
|
||||
/// - Linux: /usr/local/bin/gitea-mcp
|
||||
/// - Windows: C:\Program Files\gitea-mcp\gitea-mcp.exe
|
||||
struct GiteaModelContextExtension;
|
||||
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
@@ -237,150 +237,70 @@ fn build_docker_command(settings: &GiteaContextServerSettings) -> Result<Command
|
||||
})
|
||||
}
|
||||
|
||||
/// Find the docker binary in common locations
|
||||
/// Returns the full absolute path to the docker executable
|
||||
/// Tries: which command → /usr/bin/docker → /usr/local/bin/docker
|
||||
/// Find the docker binary
|
||||
/// Returns "docker" and relies on the system's PATH to find it
|
||||
/// This is more reliable across platforms than trying to detect docker location in WASM
|
||||
fn find_docker_binary() -> Result<String> {
|
||||
// Try using 'which' to find docker in PATH
|
||||
if let Ok(output) = std::process::Command::new("which").arg("docker").output() {
|
||||
if output.status.success() {
|
||||
if let Ok(path) = String::from_utf8(output.stdout) {
|
||||
let path = path.trim();
|
||||
if !path.is_empty() {
|
||||
return Ok(path.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Just return "docker" - the system will find it in PATH
|
||||
// If docker isn't installed or not in PATH, the execution will fail with a clear error
|
||||
Ok("docker".to_string())
|
||||
}
|
||||
|
||||
// Standard docker locations as fallback
|
||||
// Return the first common location - Zed will execute it and fail clearly if not found
|
||||
Ok("/usr/bin/docker".to_string())
|
||||
}
|
||||
|
||||
/// Resolve the gitea-mcp binary path with intelligent fallbacks
|
||||
/// Resolve the gitea-mcp binary path
|
||||
///
|
||||
/// Resolution strategy:
|
||||
/// 1. If explicit path provided in settings, use it directly
|
||||
/// 2. Search PATH environment variable for gitea-mcp or gitea-mcp-server
|
||||
/// 3. Try common installation locations as fallback
|
||||
/// 4. Return error with helpful instructions if not found
|
||||
/// WASM Limitation: WebAssembly sandbox cannot reliably:
|
||||
/// - Detect host OS (macOS vs Linux vs Windows)
|
||||
/// - Access PATH environment variable
|
||||
/// - Check if files exist
|
||||
/// - Spawn commands like 'which'
|
||||
///
|
||||
/// Note: WASM sandbox restricts process spawning and filesystem checks,
|
||||
/// but we CAN read environment variables and construct paths.
|
||||
/// Therefore, this function REQUIRES explicit configuration.
|
||||
/// Users MUST set either:
|
||||
/// - gitea_mcp_binary_path: "/full/path/to/gitea-mcp"
|
||||
/// - use_docker: true
|
||||
///
|
||||
/// Returns the path to the binary (as a string) to use, or an error with guidance
|
||||
/// Returns the path to the binary or an error with configuration instructions
|
||||
fn resolve_binary_path(explicit_path: &Option<String>) -> Result<String> {
|
||||
// If explicit path provided, use it (prioritize user configuration)
|
||||
// Explicit path is REQUIRED in WASM environment
|
||||
if let Some(path) = explicit_path {
|
||||
return Ok(path.clone());
|
||||
}
|
||||
|
||||
// Try to search PATH environment variable manually
|
||||
// WASM can't spawn 'which', but CAN read env vars
|
||||
if let Ok(path_env) = std::env::var("PATH") {
|
||||
let binary_names = ["gitea-mcp", "gitea-mcp-server"];
|
||||
|
||||
// Collect all candidate paths from PATH, then prioritize them
|
||||
let mut candidates = Vec::new();
|
||||
|
||||
// DEBUG: Log PATH directories being considered
|
||||
eprintln!("[TENDRIL DEBUG] PATH environment variable: {}", path_env);
|
||||
eprintln!("[TENDRIL DEBUG] Searching for binaries: {:?}", binary_names);
|
||||
|
||||
// Parse PATH and collect all plausible paths
|
||||
for path_dir in path_env.split(':') {
|
||||
for binary_name in &binary_names {
|
||||
let full_path = format!("{}/{}", path_dir, binary_name);
|
||||
|
||||
// Categorize by priority (lower number = higher priority)
|
||||
let priority = if path_dir.contains("/opt/homebrew/bin") {
|
||||
eprintln!(
|
||||
"[TENDRIL DEBUG] Found Homebrew path (priority 1): {}",
|
||||
full_path
|
||||
);
|
||||
1 // Highest: macOS Homebrew (M1/M2/M3/M4 Macs)
|
||||
} else if path_dir.contains("/.local/bin") {
|
||||
eprintln!(
|
||||
"[TENDRIL DEBUG] Found .local path (priority 2): {}",
|
||||
full_path
|
||||
);
|
||||
2 // User-local installations
|
||||
} else if path_dir.contains("/.cargo/bin") {
|
||||
eprintln!(
|
||||
"[TENDRIL DEBUG] Found .cargo path (priority 3): {}",
|
||||
full_path
|
||||
);
|
||||
3 // Cargo installations
|
||||
} else if path_dir.contains("/usr/local/bin") {
|
||||
eprintln!(
|
||||
"[TENDRIL DEBUG] Found /usr/local path (priority 4): {}",
|
||||
full_path
|
||||
);
|
||||
4 // Linux standard location
|
||||
} else if path_dir.contains("/usr/bin") {
|
||||
eprintln!(
|
||||
"[TENDRIL DEBUG] Found /usr/bin path (priority 5): {}",
|
||||
full_path
|
||||
);
|
||||
5 // System binaries
|
||||
} else {
|
||||
eprintln!("[TENDRIL DEBUG] Skipping non-standard path: {}", path_dir);
|
||||
continue; // Skip non-standard locations
|
||||
};
|
||||
|
||||
candidates.push((priority, full_path));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by priority and return the highest priority candidate
|
||||
candidates.sort_by_key(|(priority, _)| *priority);
|
||||
eprintln!(
|
||||
"[TENDRIL DEBUG] All candidates after sorting: {:?}",
|
||||
candidates
|
||||
);
|
||||
|
||||
if let Some((priority, path)) = candidates.first() {
|
||||
eprintln!(
|
||||
"[TENDRIL DEBUG] Selected path (priority {}): {}",
|
||||
priority, path
|
||||
);
|
||||
return Ok(path.clone());
|
||||
} else {
|
||||
eprintln!("[TENDRIL DEBUG] No candidates found in PATH");
|
||||
}
|
||||
} else {
|
||||
eprintln!("[TENDRIL DEBUG] PATH environment variable not found");
|
||||
}
|
||||
|
||||
// Fallback: Try common absolute paths
|
||||
// Order by likelihood across platforms
|
||||
let common_paths = [
|
||||
"/usr/local/bin/gitea-mcp",
|
||||
"/usr/local/bin/gitea-mcp-server",
|
||||
"/opt/homebrew/bin/gitea-mcp",
|
||||
"/opt/homebrew/bin/gitea-mcp-server",
|
||||
"/usr/bin/gitea-mcp",
|
||||
"/usr/bin/gitea-mcp-server",
|
||||
];
|
||||
|
||||
// Return first path and let Zed try it
|
||||
// If it fails, the error will show which path was attempted
|
||||
if let Some(path) = common_paths.first() {
|
||||
return Ok(path.to_string());
|
||||
}
|
||||
|
||||
// Last resort error message
|
||||
Err(
|
||||
"gitea-mcp binary not found. Please set 'gitea_mcp_binary_path' in settings.\n\
|
||||
// No path provided - return clear error with platform-specific instructions
|
||||
Err("gitea-mcp binary path not configured.\n\
|
||||
\n\
|
||||
Examples:\n\
|
||||
• macOS: \"gitea_mcp_binary_path\": \"/opt/homebrew/bin/gitea-mcp-server\"\n\
|
||||
• Linux: \"gitea_mcp_binary_path\": \"/usr/local/bin/gitea-mcp\"\n\
|
||||
Due to WebAssembly sandbox limitations, automatic binary detection is not possible.\n\
|
||||
Please add ONE of the following to your Zed settings:\n\
|
||||
\n\
|
||||
Or use Docker: \"use_docker\": true"
|
||||
.into(),
|
||||
)
|
||||
Option 1 - Specify binary path explicitly:\n\
|
||||
{\n\
|
||||
\"context_servers\": {\n\
|
||||
\"tendril-gitea-mcp\": {\n\
|
||||
\"settings\": {\n\
|
||||
\"gitea_access_token\": \"your_token\",\n\
|
||||
\"gitea_mcp_binary_path\": \"/full/path/to/binary\"\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}\n\
|
||||
\n\
|
||||
Common paths:\n\
|
||||
• macOS (Homebrew): /opt/homebrew/bin/gitea-mcp-server\n\
|
||||
• Linux: /usr/local/bin/gitea-mcp\n\
|
||||
• Windows: C:\\Program Files\\gitea-mcp\\gitea-mcp.exe\n\
|
||||
\n\
|
||||
Option 2 - Use Docker:\n\
|
||||
{\n\
|
||||
\"context_servers\": {\n\
|
||||
\"tendril-gitea-mcp\": {\n\
|
||||
\"settings\": {\n\
|
||||
\"gitea_access_token\": \"your_token\",\n\
|
||||
\"use_docker\": true\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}\n\
|
||||
}"
|
||||
.into())
|
||||
}
|
||||
|
||||
// Register the extension with Zed
|
||||
|
||||
Reference in New Issue
Block a user