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
|
/// 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.
|
/// to provide Gitea repository access through Zed's AI assistant.
|
||||||
///
|
///
|
||||||
/// Binary Resolution Strategy:
|
/// Configuration Requirements:
|
||||||
/// 1. If `gitea_mcp_binary_path` is set in settings, use that exact path
|
/// - EITHER set `gitea_mcp_binary_path` to the full path of the gitea-mcp binary
|
||||||
/// 2. If `use_docker` is true, use Docker to run the gitea-mcp image
|
/// - OR set `use_docker: true` to run gitea-mcp in Docker
|
||||||
/// 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
|
|
||||||
///
|
///
|
||||||
/// Transport modes:
|
/// WASM Limitation: This extension runs in a WebAssembly sandbox which cannot:
|
||||||
/// - STDIO (default, recommended): Direct stdin/stdout communication
|
/// - Detect the host operating system
|
||||||
/// Works with Zed's extension API and gitea-mcp binary
|
/// - Access PATH environment variable reliably
|
||||||
/// - Docker: Runs gitea-mcp in a Docker container
|
/// - Check if files exist on the filesystem
|
||||||
/// Useful when binary isn't available on host system
|
///
|
||||||
|
/// 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;
|
struct GiteaModelContextExtension;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, JsonSchema)]
|
#[derive(Debug, Deserialize, JsonSchema)]
|
||||||
@@ -237,150 +237,70 @@ fn build_docker_command(settings: &GiteaContextServerSettings) -> Result<Command
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the docker binary in common locations
|
/// Find the docker binary
|
||||||
/// Returns the full absolute path to the docker executable
|
/// Returns "docker" and relies on the system's PATH to find it
|
||||||
/// Tries: which command → /usr/bin/docker → /usr/local/bin/docker
|
/// This is more reliable across platforms than trying to detect docker location in WASM
|
||||||
fn find_docker_binary() -> Result<String> {
|
fn find_docker_binary() -> Result<String> {
|
||||||
// Try using 'which' to find docker in PATH
|
// Just return "docker" - the system will find it in PATH
|
||||||
if let Ok(output) = std::process::Command::new("which").arg("docker").output() {
|
// If docker isn't installed or not in PATH, the execution will fail with a clear error
|
||||||
if output.status.success() {
|
Ok("docker".to_string())
|
||||||
if let Ok(path) = String::from_utf8(output.stdout) {
|
|
||||||
let path = path.trim();
|
|
||||||
if !path.is_empty() {
|
|
||||||
return Ok(path.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard docker locations as fallback
|
/// Resolve the gitea-mcp binary path
|
||||||
// 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
|
|
||||||
///
|
///
|
||||||
/// Resolution strategy:
|
/// WASM Limitation: WebAssembly sandbox cannot reliably:
|
||||||
/// 1. If explicit path provided in settings, use it directly
|
/// - Detect host OS (macOS vs Linux vs Windows)
|
||||||
/// 2. Search PATH environment variable for gitea-mcp or gitea-mcp-server
|
/// - Access PATH environment variable
|
||||||
/// 3. Try common installation locations as fallback
|
/// - Check if files exist
|
||||||
/// 4. Return error with helpful instructions if not found
|
/// - Spawn commands like 'which'
|
||||||
///
|
///
|
||||||
/// Note: WASM sandbox restricts process spawning and filesystem checks,
|
/// Therefore, this function REQUIRES explicit configuration.
|
||||||
/// but we CAN read environment variables and construct paths.
|
/// 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> {
|
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 {
|
if let Some(path) = explicit_path {
|
||||||
return Ok(path.clone());
|
return Ok(path.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to search PATH environment variable manually
|
// No path provided - return clear error with platform-specific instructions
|
||||||
// WASM can't spawn 'which', but CAN read env vars
|
Err("gitea-mcp binary path not configured.\n\
|
||||||
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\
|
|
||||||
\n\
|
\n\
|
||||||
Examples:\n\
|
Due to WebAssembly sandbox limitations, automatic binary detection is not possible.\n\
|
||||||
• macOS: \"gitea_mcp_binary_path\": \"/opt/homebrew/bin/gitea-mcp-server\"\n\
|
Please add ONE of the following to your Zed settings:\n\
|
||||||
• Linux: \"gitea_mcp_binary_path\": \"/usr/local/bin/gitea-mcp\"\n\
|
|
||||||
\n\
|
\n\
|
||||||
Or use Docker: \"use_docker\": true"
|
Option 1 - Specify binary path explicitly:\n\
|
||||||
.into(),
|
{\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
|
// Register the extension with Zed
|
||||||
|
|||||||
Reference in New Issue
Block a user