Skip to main content
Glama
python.py9.54 kB
""" Python execution tools for Pwno MCP Provides tools for running Python scripts with a shared virtual environment preconfigured with common security research packages. """ import logging import os import subprocess import tempfile import json from typing import Dict, Any, Optional, List logger = logging.getLogger(__name__) class PythonTools: """Tools for Python script execution with a shared preconfigured venv""" # Common packages for security research DEFAULT_PACKAGES = [ "requests", "numpy", "ipython", "hexdump", "pwntools", ] def __init__(self): """ Initialize Python tools with a single shared venv. """ self.workspace_dir = os.path.join(tempfile.gettempdir(), "pwno_python_workspace") os.makedirs(self.workspace_dir, exist_ok=True) self.venv_path = os.path.join(self.workspace_dir, "shared_venv") logger.info(f"Python workspace initialized at: {self.workspace_dir}") # Initialize the shared venv self._initialize_venv() def _initialize_venv(self): """ Initialize the shared venv and install default packages. * This will avoid initalizing if the venv already exists (Dockerfile) """ if not os.path.exists(self.venv_path): logger.info("Creating shared Python environment...") # Create venv using UV cmd = ["uv", "venv", self.venv_path] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode == 0: logger.info("Installing default packages...") # Install default packages install_cmd = ["uv", "pip", "install", "--python", self.venv_path] + self.DEFAULT_PACKAGES install_result = subprocess.run(install_cmd, capture_output=True, text=True) if install_result.returncode == 0: logger.info("Default packages installed successfully") else: logger.warning(f"Some packages failed to install: {install_result.stderr}") else: logger.error(f"Failed to create venv: {result.stderr}") else: logger.info("Using existing shared Python environment") def execute_script(self, script_path: str, args: Optional[List[str]] = None, cwd: Optional[str] = None, timeout: float = 300.0) -> Dict[str, Any]: """ Execute a Python script in the shared venv. :param script_path: Path to the Python script to execute :param args: Arguments to pass to the script :param cwd: Working directory for script execution :param timeout: Execution timeout in seconds :returns: Execution results with stdout, stderr, and status """ try: # Build command python_exe = os.path.join(self.venv_path, "bin", "python") cmd = [python_exe, script_path] if args: cmd.extend(args) logger.info(f"Executing Python script: {script_path}") # Execute script result = subprocess.run( cmd, cwd=cwd, capture_output=True, text=True, timeout=timeout ) return { "success": result.returncode == 0, "script": script_path, "venv_path": self.venv_path, "returncode": result.returncode, "stdout": result.stdout, "stderr": result.stderr, "command": " ".join(cmd), "cwd": cwd or os.getcwd() } except subprocess.TimeoutExpired: return { "success": False, "script": script_path, "error": f"Script execution timed out after {timeout} seconds" } except Exception as e: logger.error(f"Failed to execute script: {e}") return { "success": False, "script": script_path, "error": str(e), "type": type(e).__name__ } def execute_code(self, code: str, cwd: Optional[str] = None, timeout: float = 300.0) -> Dict[str, Any]: """ Execute Python code directly. :param code: Python code to execute :param cwd: Working directory for execution :param timeout: Execution timeout in seconds :returns: Execution results """ try: # Create temporary script file fd, script_path = tempfile.mkstemp(suffix=".py", prefix="pwno_script_") with os.fdopen(fd, 'w') as f: f.write(code) # Execute using execute_script result = self.execute_script( script_path, cwd=cwd, timeout=timeout ) # Clean up temp file os.unlink(script_path) result["code_preview"] = code[:200] + "..." if len(code) > 200 else code return result except Exception as e: logger.error(f"Failed to execute code: {e}") return { "success": False, "error": str(e), "type": type(e).__name__ } def install_packages(self, packages: List[str], upgrade: bool = False) -> Dict[str, Any]: """ Install additional Python packages using UV. :param packages: List of packages to install :param upgrade: Whether to upgrade existing packages :returns: Installation results """ try: # Build UV pip install command cmd = ["uv", "pip", "install", "--python", self.venv_path] if upgrade: cmd.append("--upgrade") cmd.extend(packages) logger.info(f"Installing packages: {packages}") # Run installation result = subprocess.run( cmd, capture_output=True, text=True, timeout=300 ) if result.returncode == 0: return { "success": True, "packages": packages, "venv_path": self.venv_path, "stdout": result.stdout, "stderr": result.stderr } else: return { "success": False, "packages": packages, "error": "Installation failed", "stdout": result.stdout, "stderr": result.stderr, "returncode": result.returncode } except subprocess.TimeoutExpired: return { "success": False, "error": "Installation timed out", "packages": packages } except Exception as e: logger.error(f"Failed to install packages: {e}") return { "success": False, "error": str(e), "type": type(e).__name__, "packages": packages } def get_installed_packages(self) -> Dict[str, Any]: """ Get list of installed packages in the shared venv. :returns: List of installed packages """ try: cmd = ["uv", "pip", "list", "--python", self.venv_path] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode == 0: return { "success": True, "packages": result.stdout, "venv_path": self.venv_path } else: return { "success": False, "error": "Failed to list packages", "stderr": result.stderr } except Exception as e: logger.error(f"Failed to list packages: {e}") return { "success": False, "error": str(e), "type": type(e).__name__ } def get_python_executable(self) -> str: """ Return absolute path to the Python executable in the shared venv. :returns: Path to Python interpreter inside the managed environment """ return os.path.join(self.venv_path, "bin", "python") def create_temp_script(self, code: str) -> str: """ Create a temporary Python script file containing the provided code. :param code: Python code to write to a temporary file :returns: Path to the created temporary .py file """ fd, script_path = tempfile.mkstemp(suffix=".py", prefix="pwno_script_") with os.fdopen(fd, 'w') as f: f.write(code) return script_path

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/0xSensei/pwno-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server