Skip to main content
Glama
berkayturhal38-cloud

turhal-python-runner-mcp

README.md
# Python Runner MCP Server (Turhal AI)

Python kodunu izole subprocess'lerde calistiran, `stdio` transport uzerinden
konusan, production-ready bir MCP (Model Context Protocol) sunucusu.
Python MCP SDK'nin `FastMCP` sinifi ile yazilmistir; Claude Desktop ve
OpenClaw Gateway ile dogrudan uyumludur.

## Icerik

| Dosya | Amac |
|---|---|
| `server.py` | MCP sunucusu ve `run_python` araci |
| `requirements.txt` | Python bagimliliklari |
| `Dockerfile` | Sandboxlanmis calisma ortami (Python 3.12-slim, non-root) |
| `.dockerignore` | Build context'ini kucultur |
| `docker-compose.yml` | Build/manuel test icin (bkz. notlar) |
| `openclaw.gateway.example.json` | OpenClaw Gateway / Claude Desktop icin ornek config |

## Ozellikler

- **Izolasyon**: Her `run_python` cagrisi ayri bir OS process'inde calisir.
- **Kaynak limitleri** (Linux/macOS, `resource.setrlimit` ile):
  - CPU suresi (`RUNNER_MAX_CPU_SECONDS`)
  - Bellek / adres alani (`RUNNER_MAX_MEMORY_MB`)
  - Process sayisi (`RUNNER_MAX_PROCESSES`)
  - Yazilabilir dosya boyutu (`RUNNER_MAX_FILE_SIZE_MB`)
  - Core dump kapali
- **Zaman asimi**: `asyncio.wait_for` ile duvar-saati (wall clock) timeout; asilirsa process `kill()` edilir.
- **Cikti limiti**: stdout/stderr `RUNNER_MAX_OUTPUT_CHARS` karakterde kirpilir.
- **Eszamanlilik kontrolu**: `asyncio.Semaphore` ile ayni anda calisan process sayisi `RUNNER_MAX_CONCURRENT` ile sinirlanir; sunucu tek process icinde birden fazla istegi guvenle kuyruklar.
- **Loglama**: Tum loglar `stderr`'e yazilir (stdout, MCP JSON-RPC protokolu icin ayrilmistir). Her istek `request_id` ile izlenebilir.
- **Hata yonetimi**: Beklenen ve beklenmeyen tum hatalar yakalanip kullaniciya duzgun bicimlendirilmis metin olarak donulur; sunucu process'i asla cokmez.
- **Docker-native**: Non-root kullanici, read-only dosya sistemi, `network: none`, `cap_drop: ALL` ile calisacak sekilde tasarlanmistir.

## Guvenlik kapsami ve sinirlari (onemli)

`resource.setrlimit` ve subprocess izolasyonu, **process-seviyesinde** bir
koruma sağlar (kaçak bellek/CPU tüketimini, fork bombasını, zaman aşımını
önler). Bu, çalıştırılan kodun **container dışına çıkmasını** veya **ağa
erişmesini** engellemez.

Production'da tam izolasyon icin:

1. **Bu sunucuyu mutlaka Docker container icinde, `docker-compose.yml` /
   `openclaw.gateway.example.json` ornegindeki gibi `--network=none`,
   `--read-only`, `--cap-drop=ALL` bayraklariyla calistirin.**
2. Daha yuksek guven seviyesi gerekiyorsa (coklu kiracili / multi-tenant
   sistemler), `gVisor`, `nsjail` veya `Firecracker` gibi bir OS-seviyesi
   sandbox katmani ekleyin - bu dosyalar bunu kolaylastiracak sekilde
   (ag kapali, salt-okunur FS, dusuk kaynak limitleri) hazirlanmistir ama
   bunlarin yerini tutmaz.
3. Kod, `-I -S` bayraklariyla (izole mod, site-packages'siz) calistirilir;
   yine de guvenilmeyen kullanicilardan gelen kodu calistiriyorsaniz agi
   mutlaka kapali tutun.

## Kurulum (yerel, container'siz)

```bash
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r requirements.txt
python server.py
```

Sunucu stdio uzerinden calisir; dogrudan terminalden calistirdiginizda
JSON-RPC mesaji bekleyerek beklemede kalir (bu normaldir - bir MCP istemcisi
baglanmadan cikti gormezsiniz).

## Docker ile calistirma

```bash
docker build -t turhal-ai/python-runner-mcp:latest .

docker run -i --rm \
  --network=none \
  --read-only \
  --tmpfs /tmp:size=64m,mode=1777 \
  --security-opt no-new-privileges:true \
  --cap-drop=ALL \
  --memory=512m --cpus=1.0 --pids-limit=64 \
  turhal-ai/python-runner-mcp:latest
```

Veya build/manuel test icin:

```bash
docker compose build
docker compose run --rm python-runner
```

> `docker compose up` **kullanmayin** - MCP stdio, istemcinin container'i
> `docker run -i` ile spawn edip stdin/stdout'a dogrudan baglanmasini
> gerektirir; arka planda calisan bir compose servisi bu modelle uyumlu
> degildir. `docker-compose.yml` yalnizca build/test amaclidir.

## Claude Desktop entegrasyonu

`claude_desktop_config.json` icine `openclaw.gateway.example.json`
dosyasindaki `python-runner` (yerel) veya `python-runner-docker`
(onerilen, sandboxlanmis) blogunu ekleyin ve yollari kendi ortaminiza gore
guncelleyin.

## OpenClaw Gateway entegrasyonu

`openclaw.gateway.example.json` dosyasi, Gateway'in `mcpServers` bolumune
dogrudan tasinabilecek bicimde hazirlanmistir. Docker varyanti, agi kapali
ve read-only bir container icinde calisacagi icin production'da
onerilir.

## Konfigurasyon (ortam degiskenleri)

| Degisken | Varsayilan | Aciklama |
|---|---|---|
| `RUNNER_DEFAULT_TIMEOUT_SEC` | `10` | `timeout` parametresi verilmezse kullanilir |
| `RUNNER_MAX_TIMEOUT_SEC` | `60` | Istemcinin isteyebilecegi ust timeout siniri |
| `RUNNER_MAX_OUTPUT_CHARS` | `20000` | stdout/stderr icin karakter siniri |
| `RUNNER_MAX_MEMORY_MB` | `256` | Subprocess bellek/adres alani siniri |
| `RUNNER_MAX_CPU_SECONDS` | `10` | Subprocess CPU suresi siniri |
| `RUNNER_MAX_PROCESSES` | `32` | Subprocess'in acabilecegi max process sayisi |
| `RUNNER_MAX_FILE_SIZE_MB` | `10` | Subprocess'in yazabilecegi max dosya boyutu |
| `RUNNER_MAX_CONCURRENT` | `4` | Sunucu genelinde ayni anda calisan max istek |
| `RUNNER_LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |

## `run_python` araci - kullanim

**Girdi:**
```json
{
  "code": "print(sum(range(10)))",
  "timeout": 5
}
```

**Cikti (metin):**
```
[request_id=a1b2c3d4]
--- stdout ---
45

--- exit_code: 0 | duration: 0.041s ---
```

Zaman asimi, hata ve kirpilma durumlari da ayni bicimde, `request_id` ile
izlenebilir sekilde donulur; loglarda ayni `request_id` ile eslestirilebilir.

## Test

```bash
python -c "
import asyncio
from server import _run_code_in_subprocess

async def main():
    r = await _run_code_in_subprocess('print(1+1)', timeout=5, request_id='test')
    print(r.to_text())

asyncio.run(main())
"
```