mcp-my-mac
import json
import os
import platform
import subprocess
from pathlib import Path
def find_conda_executable():
"""Find the conda executable path even when conda is not activated."""
# Common paths where conda might be installed on macOS
possible_conda_paths = [
# Standard Anaconda/Miniconda locations
os.path.expanduser("~/miniconda3/bin/conda"),
os.path.expanduser("~/anaconda3/bin/conda"),
os.path.expanduser("~/opt/miniconda3/bin/conda"),
os.path.expanduser("~/opt/anaconda3/bin/conda"),
"/opt/miniconda3/bin/conda",
"/opt/anaconda3/bin/conda",
# Add miniforge/mambaforge common paths
os.path.expanduser("~/miniforge3/bin/conda"),
os.path.expanduser("~/mambaforge/bin/conda"),
# Applications directory on macOS
"/Applications/anaconda3/bin/conda",
"/Applications/miniconda3/bin/conda",
# Add M1/M2 Mac specific paths
"/opt/homebrew/anaconda3/bin/conda",
"/opt/homebrew/miniconda3/bin/conda",
]
found_paths = []
# First check if conda is in PATH
try:
result = subprocess.run(["which", "conda"], capture_output=True, text=True)
if result.returncode == 0 and result.stdout.strip():
path = result.stdout.strip()
found_paths.append(f"Found in PATH: {path}")
# Extract the actual path if it's a function
if "conda ()" in path:
# Try to find the actual executable by inspecting shell aliases
try:
alias_result = subprocess.run(
["type", "conda"], capture_output=True, text=True, shell=True
)
if alias_result.returncode == 0:
path_lines = alias_result.stdout.strip().split("\n")
for line in path_lines:
if "/conda" in line and (
"bin/" in line or "Scripts/" in line
):
potential_path = (
line.split("'")[-2]
if "'" in line
else line.split()[-1]
)
if os.path.isfile(potential_path):
found_paths.append(
f"Extracted from alias: {potential_path}"
)
return potential_path
except Exception as e:
found_paths.append(f"Error analyzing conda alias: {str(e)}")
else:
# Direct path found in PATH
return path
except Exception as e:
found_paths.append(f"Error checking PATH: {str(e)}")
# Check common installation paths
for path in possible_conda_paths:
if os.path.isfile(path):
found_paths.append(f"Found in common paths: {path}")
return path
# Check for Conda installed via Homebrew
try:
result = subprocess.run(
["brew", "--prefix", "conda"], capture_output=True, text=True
)
if result.returncode == 0 and result.stdout.strip():
brew_path = os.path.join(result.stdout.strip(), "bin", "conda")
if os.path.isfile(brew_path):
found_paths.append(f"Found via Homebrew: {brew_path}")
return brew_path
except Exception as e:
found_paths.append(f"Error checking Homebrew: {str(e)}")
# Look for conda-related files in the home directory
try:
home = Path.home()
for conda_dir in home.glob("*conda*"):
if conda_dir.is_dir():
bin_dir = conda_dir / "bin"
if bin_dir.is_dir():
conda_path = bin_dir / "conda"
if conda_path.is_file():
found_paths.append(
f"Found in home directory: {str(conda_path)}"
)
return str(conda_path)
except Exception as e:
found_paths.append(f"Error searching home directory: {str(e)}")
# If we reach here, we didn't find conda
return None
def load_conda_info():
"""Get basic conda info if available."""
conda_path = find_conda_executable()
if not conda_path:
return "Conda not found"
try:
result = subprocess.run([conda_path, "info"], capture_output=True, text=True)
if result.returncode == 0:
return result.stdout
else:
return f"Error getting conda info: {result.stderr}"
except Exception as e:
return f"Error: {str(e)}"
def load_conda_env_list():
"""Get conda environment list with improved detection."""
conda_path = find_conda_executable()
if not conda_path:
# Provide more detailed information about the system
system_info = (
f"System: {platform.system()} {platform.release()} ({platform.machine()})\n"
)
paths_info = "PATH directories:\n" + "\n".join(
[f"- {p}" for p in os.environ.get("PATH", "").split(":")]
)
error_message = "Conda executable not found. Please ensure Conda is installed."
return f"{error_message}\n{system_info}\n{paths_info}"
try:
# First try the JSON format for better parsing
result = subprocess.run(
[conda_path, "env", "list", "--json"], capture_output=True, text=True
)
if result.returncode == 0 and result.stdout.strip():
try:
env_data = json.loads(result.stdout)
output = f"Conda found at: {conda_path}\n\nConda Environments:\n"
for env in env_data.get("envs", []):
env_name = (
os.path.basename(env) if not env.endswith("base") else "base"
)
output += f"- {env_name} ({env})\n"
return output
except json.JSONDecodeError:
pass
# Fallback to standard format if JSON fails
result = subprocess.run(
[conda_path, "env", "list"], capture_output=True, text=True
)
if result.returncode == 0:
output = f"Conda found at: {conda_path}\n\n{result.stdout}"
if not result.stdout.strip():
return f"Conda found at: {conda_path}\n\nNo conda environments found."
return output
else:
return (
f"Conda found at: {conda_path}\n\n"
f"Error listing conda environments: {result.stderr}"
)
except Exception as e:
return f"Error retrieving conda environments: {str(e)}"
def load_conda_env_package_list(env_name: str):
"""Get the list of packages in the specified conda environment."""
conda_path = find_conda_executable()
# Validate environment name for security
if not env_name:
return "Environment name cannot be empty."
# Sanitize input to prevent command injection
if not (
env_name.startswith("/")
or env_name.isalnum()
or all(c.isalnum() or c in "_-." for c in env_name)
):
return "Invalid environment name. Use alphanumeric characters, _, -, or . only."
# Path validation for security
if env_name.startswith("/"):
# Extra validation for paths to prevent traversal attacks
normalized_path = os.path.normpath(env_name)
if ".." in normalized_path or not os.path.exists(normalized_path):
return f"Invalid or non-existent environment path: {env_name}"
if not conda_path:
return "Conda executable not found. Please ensure Conda is installed."
try:
if env_name.startswith("/"):
# Use --prefix for paths
result = subprocess.run(
[conda_path, "list", "--prefix", env_name],
capture_output=True,
text=True,
)
else:
# Use --name for named environments
result = subprocess.run(
[conda_path, "list", "--name", env_name], capture_output=True, text=True
)
if result.returncode == 0:
return result.stdout
else:
return f"Error listing packages in {env_name}: {result.stderr}"
except Exception as e:
return f"Error: {str(e)}"