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())
"
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues