leinier310 commited on
Commit
fa353c8
·
verified ·
1 Parent(s): 0e58df2

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -0
app.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import threading
3
+ import time
4
+ import subprocess
5
+ from pathlib import Path
6
+ from typing import List
7
+
8
+ from fastapi import FastAPI, HTTPException, Query
9
+ from pydantic import BaseModel
10
+
11
+ BASE_DIR = Path("./public_files").resolve()
12
+ BASE_DIR.mkdir(parents=True, exist_ok=True)
13
+
14
+ app = FastAPI(title="Minimal MCP File Manager")
15
+
16
+ class ModifyRequest(BaseModel):
17
+ filename: str
18
+ mode: str # 'replace' | 'line_edit'
19
+ content: str
20
+ start_line: int = None
21
+ end_line: int = None
22
+
23
+ class ExecRequest(BaseModel):
24
+ command: List[str]
25
+
26
+ # ----------------- Endpoints -----------------
27
+ @app.post("/modify")
28
+ def modify_file(req: ModifyRequest):
29
+ path = BASE_DIR / req.filename
30
+ if not path.exists() or path.is_dir():
31
+ raise HTTPException(status_code=404, detail="Archivo no encontrado o es un directorio")
32
+
33
+ if req.mode == "replace":
34
+ path.write_text(req.content)
35
+ return {"status": "replaced", "path": str(path)}
36
+
37
+ elif req.mode == "line_edit":
38
+ if req.start_line is None or req.end_line is None:
39
+ raise HTTPException(status_code=400, detail="start_line y end_line requeridos para line_edit")
40
+ lines = path.read_text().splitlines()
41
+ s = max(1, req.start_line) - 1
42
+ e = max(0, req.end_line)
43
+ new_lines = lines[:s] + req.content.splitlines() + lines[e:]
44
+ path.write_text("\n".join(new_lines) + ("\n" if req.content.endswith("\n") else ""))
45
+ return {"status": "line_edited", "path": str(path)}
46
+
47
+ else:
48
+ raise HTTPException(status_code=400, detail="mode desconocido")
49
+
50
+ @app.post("/exec")
51
+ def exec_command(req: ExecRequest):
52
+ if not req.command:
53
+ raise HTTPException(status_code=400, detail="Comando vacío")
54
+ try:
55
+ res = subprocess.run(req.command, cwd=str(BASE_DIR), capture_output=True, timeout=15)
56
+ return {
57
+ "returncode": res.returncode,
58
+ "stdout": res.stdout.decode(errors="ignore"),
59
+ "stderr": res.stderr.decode(errors="ignore"),
60
+ }
61
+ except subprocess.TimeoutExpired:
62
+ raise HTTPException(status_code=500, detail="Execution timeout")
63
+
64
+ @app.get("/disk_usage")
65
+ def disk_usage():
66
+ import shutil
67
+ usage = shutil.disk_usage(str(BASE_DIR))
68
+ total_size = sum(f.stat().st_size for f in BASE_DIR.rglob('*') if f.is_file())
69
+ return {
70
+ "fs_total": usage.total,
71
+ "fs_used": usage.used,
72
+ "fs_free": usage.free,
73
+ "dir_size": total_size,
74
+ }
75
+
76
+ # ----------------- Keep-alive -----------------
77
+ def keep_alive_thread():
78
+ import requests
79
+ while True:
80
+ try:
81
+ requests.get("http://127.0.0.1:7860/disk_usage", timeout=2)
82
+ except:
83
+ pass
84
+ time.sleep(300)
85
+
86
+ threading.Thread(target=keep_alive_thread, daemon=True).start()