Agentic Server Primer: Llama.cpp MCP Lesson 3: Adding Python Tooling Capability To your HouseLLM.

Agentic Server Primer: Llama.cpp MCP Lesson 3: Python

Agentic Server Primer: Llama.cpp MCP Lesson 3: Adding Python Tooling Capability To your HouseLLM.
We made some significant updates to this model 

Environment Evolution is Powerful

  • Not only will your LLM use this tool - it can self-adapt and build the environment to suite any type of python project you may work with.  It literally will both update the system inside the docker image AND pip install whatever it needs before it runs the python execution tests.

In the previous two lessons we showed how to make a MCP calculator for your LLM, and then how to Dockerize it so that it ran in it's own container.  Dockerization now will become very important because you are literally going to let your LLM execute commands.  

This image can be pulled and ran easily now:

docker pull cnmcdee/mcp-python:latest
docker run -d --name mcp-python --restart unless-stopped -e "FLASH_ENV=production" -p 0.0.0.0:5015:5015 cnmcdee/mcp-python:latest
  • Now we will build a python docker container so it can run it's own unit tests on the code that it writes!

If you need a primer on docker / python etc consider these two guides that explain it in detail:

Agentic Server Primer: Llama.cpp MCP Lesson 2: Dockerization.
Agentic Server Primer: Llama.cpp MCP Lesson 2: Dockerization.
EasyBake Oven Guide To Installing Pycharm, venvs and Pycharm.
The EasyBake Oven Guide To Installing Pycharm, venvs and Pycharm.

Let's get started!

Make a file named l_super_python.py  and put inside it:

import io
import subprocess
import traceback
import sys
import os
import re
import time
from pathlib import Path
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware
import uvicorn
from fastmcp import FastMCP

# ── Configuration ────────────────────────────────────────────────────────
VENV_DIR = os.path.join(os.path.dirname(__file__), ".venv")
PYTHON_EXECUTABLE = os.path.join(VENV_DIR, "bin", "python3") if sys.platform != "win32" else os.path.join(VENV_DIR, "Scripts", "python.exe")
SUPPORT_REQUIREMENTS = os.path.join(os.path.dirname(__file__), "support_requirements.txt")


# ── Markdown Cleaning ────────────────────────────────────────────────────
def clean_markdown_code(code: str) -> str:
    """Remove markdown formatting while preserving Python indentation."""
    if not code or not isinstance(code, str):
        return ""

    cleaned = re.sub(
        r'```[\w]*\s*\n(.*?)\n```',
        r'\1',
        code,
        flags=re.DOTALL | re.IGNORECASE
    )
    cleaned = re.sub(
        r'```[\w]*\s*\n(.*?)(?:\n```|\Z)',
        r'\1',
        cleaned,
        flags=re.DOTALL | re.IGNORECASE
    )
    cleaned = re.sub(r'`([^`]+)`', r'\1', cleaned)

    lines = cleaned.split('\n')
    while lines and not lines[0].strip():
        lines.pop(0)
    while lines and not lines[-1].strip():
        lines.pop()

    return '\n'.join(lines).strip('\n')


# ── VENV & Support Library Management ───────────────────────────────────
def create_venv():
    """Create virtual environment and ensure pip is installed."""
    if os.path.exists(VENV_DIR):
        # Ensure pip exists even if venv was previously broken
        if not _pip_available():
            print("Pip missing in existing venv. Repairing...")
            _ensure_pip()
        return

    print(f"Creating venv at {VENV_DIR}...")
    subprocess.run([sys.executable, "-m", "venv", VENV_DIR], check=True, capture_output=True)
    _ensure_pip()


def _pip_available() -> bool:
    """Check if pip is available in the venv."""
    try:
        python = get_venv_python()
        result = subprocess.run([python, "-m", "pip", "--version"],
                                capture_output=True, text=True, timeout=10)
        return result.returncode == 0
    except Exception:
        return False


def _ensure_pip():
    """Bootstrap or upgrade pip in the venv."""
    python = get_venv_python()
    print("Ensuring pip is available...")

    # Method 1: ensurepip
    try:
        subprocess.run([python, "-m", "ensurepip", "--upgrade"], check=True, capture_output=True)
        print("Pip installed via ensurepip.")
        return
    except Exception:
        pass

    # Method 2: Get pip from official bootstrap
    try:
        subprocess.run([python, "-m", "pip", "install", "--upgrade", "pip"], check=True, capture_output=True)
        print("Pip upgraded successfully.")
    except Exception as e:
        print(f"Warning: Could not fully bootstrap pip: {e}")


def get_venv_python() -> str:
    """Get path to venv Python interpreter."""
    if os.path.exists(PYTHON_EXECUTABLE):
        return PYTHON_EXECUTABLE
    alt = Path(VENV_DIR) / "Scripts" / "python.exe"
    if alt.exists():
        return str(alt)
    raise FileNotFoundError(f"Venv Python not found at {PYTHON_EXECUTABLE}")


def install_dependency(package: str) -> bool:
    """Install package in venv and update support library."""
    try:
        create_venv()
        python = get_venv_python()
        result = subprocess.run(
            [python, "-m", "pip", "install", package, "--quiet"],
            check=True,
            capture_output=True,
            text=True
        )
        print(f"Successfully installed {package}")

        with open(SUPPORT_REQUIREMENTS, "a", encoding="utf-8") as f:
            f.write(f"{package}\n")
        return True
    except subprocess.CalledProcessError as e:
        print(f"Failed to install {package}: {e.stderr.strip() or e.stdout.strip()}")
        return False
    except Exception as e:
        print(f"Error installing {package}: {e}")
        return False


def get_installed_packages() -> set:
    """Get installed packages in venv."""
    try:
        python = get_venv_python()
        result = subprocess.run(
            [python, "-m", "pip", "list", "--format=freeze"],
            capture_output=True, text=True, check=True, timeout=15
        )
        packages = set()
        for line in result.stdout.strip().split('\n'):
            if line and not line.startswith('#'):
                pkg = line.split('==')[0].strip().lower()
                if pkg:
                    packages.add(pkg)
        return packages
    except Exception as e:
        print(f"Warning: Could not list packages: {e}")
        return set()


def parse_python_imports(code: str) -> list[str]:
    """Extract top-level module names from import statements."""
    imports = set()
    patterns = [
        r'^\s*import\s+([^\s,]+)',
        r'^\s*import\s+([^\s,]+)\s+as',
        r'^\s*from\s+([^\s.]+)',
    ]
    for pattern in patterns:
        for match in re.finditer(pattern, code, re.MULTILINE):
            module = match.group(1).split('.')[0].strip()
            if module and module.isidentifier():
                imports.add(module)
    return list(imports)


def ensure_dependencies(code: str):
    """Initial dependency installation from static imports."""
    create_venv()
    needed = set(parse_python_imports(code))
    stdlib_skip = {'os', 'sys', 'io', 're', 'pathlib', 'json', 'math', 'subprocess',
                   'traceback', 'time', 'datetime', 'typing', 'collections', 'itertools',
                   'builtins', 'contextlib', 'PIL', 'pytesseract'}  # common false positives
    needed -= stdlib_skip

    if not needed:
        return

    print(f"Pre-installing packages: {needed}")
    installed = get_installed_packages()
    for pkg in (needed - installed):
        install_dependency(pkg)


def extract_missing_module(error_msg: str) -> str | None:
    """Extract missing module name from ImportError / ModuleNotFoundError."""
    patterns = [
        r"No module named ['\"]([^'\"]+)['\"]",
        r"ModuleNotFoundError: No module named ['\"]([^'\"]+)['\"]",
    ]
    for pattern in patterns:
        match = re.search(pattern, error_msg, re.IGNORECASE)
        if match:
            module = match.group(1).split('.')[0].strip()
            if module and module.isidentifier():
                return module
    return None


# ── Enhanced Python Code Execution ───────────────────────────────────────
mcp = FastMCP("Python Executor Enhanced")


@mcp.tool()
def install_python_package(package: str) -> str:
    """Install a Python package into the project's virtual environment.
    Use this whenever a ModuleNotFoundError occurs or before running code that needs new libraries."""
    try:
        create_venv()  # ensures venv exists and pip is up-to-date
        python = get_venv_python()

        # Upgrade pip first (fast)
        subprocess.run(
            [python, "-m", "pip", "install", "--upgrade", "--no-cache-dir", "pip"],
            check=True, capture_output=True, timeout=30
        )

        # Install the package
        result = subprocess.run(
            [python, "-m", "pip", "install", "--no-cache-dir", package],
            check=True, capture_output=True, text=True, timeout=60
        )

        # Update support_requirements.txt
        with open(SUPPORT_REQUIREMENTS, "a", encoding="utf-8") as f:
            f.write(f"{package}\n")

        return f"Successfully installed {package} into venv."

    except subprocess.CalledProcessError as e:
        return f"Failed to install {package}: {e.stderr.strip() or e.stdout.strip()}"
    except Exception as e:
        return f"Error installing {package}: {str(e)}"


@mcp.tool()
def get_environment_info() -> str:
    """Returns current Python environment details."""
    return f"Venv Python: {get_venv_python()}\nSupport requirements: {SUPPORT_REQUIREMENTS}"


@mcp.tool
def execute_python_enhanced(code: str) -> dict:
    """Executes Python code with automatic dependency handling using the project venv."""
    start_time = time.time()
    result = {
        "success": False,
        "stdout": "",
        "stderr": "",
        "exit_code": 1,
        "warnings": [],
        "execution_time_ms": 0,
        "execution_result": None,
        "install_attempts": 0
    }

    if not code or not isinstance(code, str):
        result["stderr"] = "No code provided"
        return result

    # Clean the code first
    cleaned_code = clean_markdown_code(code)
    if cleaned_code != code:
        result["warnings"].append("Markdown formatting removed")

    try:
        ensure_dependencies(cleaned_code)  # Pre-install from static imports

        python_path = get_venv_python()
        max_attempts = 4  # Reduced for efficiency

        for attempt in range(1, max_attempts + 1):
            result["install_attempts"] = attempt

            temp_file = Path("/tmp") / f"mcp_exec_{int(time.time() * 1000)}.py"
            temp_file.write_text(cleaned_code, encoding="utf-8")

            proc = subprocess.run(
                [python_path, str(temp_file)],
                capture_output=True,
                text=True,
                timeout=45
            )

            temp_file.unlink(missing_ok=True)

            if proc.returncode == 0:
                result.update({
                    "stdout": proc.stdout.strip(),
                    "stderr": proc.stderr.strip(),
                    "success": True,
                    "exit_code": 0,
                })
                break

            last_error = (proc.stderr or proc.stdout).strip()
            missing = extract_missing_module(last_error)

            if missing:
                print(f"Attempt {attempt}: Missing '{missing}'. Installing...")
                install_result = install_python_package(missing)
                result["warnings"].append(install_result)
                time.sleep(0.5)
                continue
            else:
                result["stderr"] = last_error
                break
        else:
            result["stderr"] = f"Max attempts reached. Last error: {last_error}"

    except Exception as e:
        tb = traceback.format_exc()
        result["stderr"] = f"{type(e).__name__}: {str(e)}\n{tb}"

    result["execution_time_ms"] = int((time.time() - start_time) * 1000)
    return result


@mcp.tool()
def install_python_package(package: str) -> str:
    """Install a Python package into the project's virtual environment.
    Use this whenever you encounter a ModuleNotFoundError."""
    try:
        create_venv()  # Ensures venv + latest pip

        python = get_venv_python()

        # Upgrade pip first
        subprocess.run(
            [python, "-m", "pip", "install", "--upgrade", "--no-cache-dir", "pip"],
            check=True, capture_output=True, timeout=30
        )

        # Install requested package
        result = subprocess.run(
            [python, "-m", "pip", "install", "--no-cache-dir", package],
            check=True, capture_output=True, text=True, timeout=90
        )

        # Log to support file
        with open(SUPPORT_REQUIREMENTS, "a", encoding="utf-8") as f:
            f.write(f"{package}\n")

        return f"Successfully installed {package} into venv."

    except subprocess.CalledProcessError as e:
        return f"Failed to install {package}: {e.stderr.strip() or e.stdout.strip()}"
    except Exception as e:
        return f"Error installing {package}: {str(e)}"

# ...

@mcp.tool()
def install_system_dependencies(packages: list[str]) -> str:
    """Install system packages via apt (safe, non-interactive)."""
    import subprocess
    try:
        cmd = [
            "apt-get", "update",
            "&&", "apt-get", "install", "-y", "--no-install-recommends"
        ] + packages + [
            "&&", "rm", "-rf", "/var/lib/apt/lists/*"
        ]
        result = subprocess.run(" ".join(cmd), shell=True, capture_output=True, text=True)
        return f"Success: {result.stdout}" if result.returncode == 0 else f"Error: {result.stderr}"
    except Exception as e:
        return f"Failed: {str(e)}"

@mcp.tool
def execute_python_enhanced(code: str) -> dict:
    """Executes Python code with automatic recursive dependency installation."""
    start_time = time.time()
    result = {
        "success": False,
        "stdout": "",
        "stderr": "",
        "exit_code": 1,
        "warnings": [],
        "execution_time_ms": 0,
        "execution_result": None,
        "install_attempts": 0
    }

    if not code or not isinstance(code, str):
        result["stderr"] = "No code provided"
        return result

    cleaned_code = clean_markdown_code(code)
    if cleaned_code != code:
        result["warnings"].append("Markdown formatting removed")

    try:
        ensure_dependencies(cleaned_code)
        python_path = get_venv_python()

        max_attempts = 8
        attempt = 0
        last_error = ""

        while attempt < max_attempts:
            attempt += 1
            result["install_attempts"] = attempt

            temp_file = Path("/tmp") / f"mcp_exec_{int(time.time() * 1000)}.py"
            temp_file.write_text(cleaned_code, encoding="utf-8")

            proc = subprocess.run(
                [python_path, str(temp_file)],
                capture_output=True,
                text=True,
                timeout=45
            )

            temp_file.unlink(missing_ok=True)

            if proc.returncode == 0:
                result.update({
                    "stdout": proc.stdout.strip(),
                    "stderr": proc.stderr.strip(),
                    "success": True,
                    "exit_code": 0,
                })
                break

            last_error = (proc.stderr or proc.stdout).strip()
            missing = extract_missing_module(last_error)

            if missing:
                print(f"Attempt {attempt}: Missing '{missing}'. Installing...")
                result["warnings"].append(f"Installed missing dependency: {missing}")
                if not install_dependency(missing):
                    result["stderr"] = f"Failed to install {missing}. {last_error}"
                    break
                time.sleep(0.8)
                continue
            else:
                result["stderr"] = last_error
                break

        else:
            result["stderr"] = f"Max attempts reached. Last error: {last_error}"

    except Exception as e:
        tb = traceback.format_exc()
        result["stderr"] = f"{type(e).__name__}: {str(e)}\n{tb}"

    result["execution_time_ms"] = int((time.time() - start_time) * 1000)
    return result


# ── Server Startup ───────────────────────────────────────────────────────
if __name__ == "__main__":
    middleware = [
        Middleware(
            CORSMiddleware,
            allow_origins=["*"],
            allow_credentials=True,
            allow_methods=["GET", "POST", "OPTIONS"],
            allow_headers=["*"],
            expose_headers=["*"],
        )
    ]

    app = mcp.http_app(path="/mcp", middleware=middleware)

    uvicorn.run(app, host="0.0.0.0", port=5015, log_level="info")

At this point you can test it temporarily just be careful not to use anything delete related - it is executing commands in your system. So run the program, it will look something like this:

  • We have put this docker at port 5015..

When you specify the end point on the server it must have the /mcp url ending as:

http://192.168.1.3:5015/mcp

If you Llama.cpp detects and integrates it correctly it will look something like this:

If you notice and click on the updated 4 tools available - it will be derived from the comments, and it runs inside an isolated namespace, next we test it:

All the tools your LLM needs to super-charge your MCP agent.
  • install_python_package - pretty straightforward - but it's actually more deep than that. A lot of packages will require an update to the system itself.
  • get_environment_info - is a powerful standard method to see what is going on in the current venv
  • execute_python_enhanced - will allow it to still write and compile it's own code.
  • install_system_dependencies - This is very import as some larger packages such as numpy may require driver support, library support or what have you.
  • Your LLM can now add its own tools, and even update the docker container to support whatever tools it needs.

Dockerization

  • Pretty much everything will need to be dockerized. So stop your l_super_python.py and put it in it's own directory.
  • Add a file named Dockerfile and put into it:
FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    DEBIAN_FRONTEND=noninteractive

WORKDIR /app

# System dependencies
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        build-essential \
        python3-dev \
        libx11-dev \
        libxtst-dev \
        libxkbcommon-dev \
        xclip \
        git && \
    rm -rf /var/lib/apt/lists/*

# Create and activate virtual environment
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# Copy and install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt

COPY . .

RUN chmod +x *.py 2>/dev/null || true

EXPOSE 5015

CMD ["python", "l_super_python.py"]
  • Next make a requirements.txt and put into that:

pip

fastmcp>=3.0.0
pynput==1.7.6
requests==2.32.3

# Web framework (updated for MCP compatibility)
fastapi>=0.115.0
uvicorn>=0.30.0
httpx>=0.27.0

# MCP (Model Context Protocol)
mcp>=1.0.0

# LangChain (updated to reduce conflicts)
langchain-core>=0.2.0
langchain>=0.2.0

# Data processing
pydantic>=2.8.0
pyyaml>=6.0.1
python-dotenv>=1.0.0

# Async
asyncio-mqtt==0.16.1
websockets>=12.0

# Dev tools (optional, can be in dev requirements)
# pytest==7.4.3
# etc.

Now we will build the docker image, and it will look as the following if it works:

Once that is done we can build a image for our docker ecosystem

docker build -t mcp-python:latest .

And it can be run with:

docker run -d --name mcp-python --restart unless-stopped -e "FLASH_ENV=production" -p 0.0.0.0:5015:5015 mcp-python:latest

Conclusion

We have added agentic tooling now for python!  This is powerful, not only can it write it's own code - it can safely test it.  The python tool is in it's own container, that keeps it safe in case the LLM hallucinates or does whatever..

Save your Context and Come Back

This process manager is very powerful in that your LLM can now save it's work and spread it across many contexts.

Agentic Server Primer: Llama.cpp MCP Lesson 8: Process Manager Web Enabled Research Assistant w/ Code Drop.
Agentic Server Primer: Llama.cpp MCP Lesson 8: Process Manager Web Enabled Research Assistant

Get your LLM coding all Night! LLMQP

This LLM will enable you to queue multiple prompts which will execute one after another.

LLMQP Drops! A New Queue Dispatcher. Let your LLM CODE ALL NIGHT.
LLM Queue Dispatcher. A Powerful Harness Drop will queue your localLLM all night and keep it working!
Linux Rocks Every Day