"""All writes target one named tutorial Deployment in a dedicated kind context.""" import json, os, subprocess, urllib.request, urllib.parse from mcp.server.fastmcp import FastMCP NS, NAME = "opspilot-lab", "pending-lab" mcp = FastMCP("kind-diagnostics") def kube(*args, writer=False): identity = "repair" if writer else "observe" cmd = ["kubectl","--context","kind-handbook-lab","-n",NS, "--as",f"system:serviceaccount:{NS}:{identity}","--request-timeout=7s",*args] if os.getenv("OPS_IN_CLUSTER")=="1":cmd=["kubectl","--kubeconfig",os.path.join(os.path.dirname(__file__),"incluster.json"),*cmd[3:]] credential=os.getenv("OPS_WRITE_KUBECONFIG" if writer else "OPS_READ_KUBECONFIG") if credential: cmd=["kubectl","--kubeconfig",credential,"-n",NS,"--request-timeout=7s",*args] p = subprocess.run(cmd, capture_output=True, text=True, timeout=10) if p.returncode: raise ValueError(p.stderr[-500:]) return p.stdout @mcp.tool() def evidence(source: str) -> dict: """Read one bounded observation about pending-lab, without executing user commands.""" if source == "deployment": d=json.loads(kube("get","deployment",NAME,"-o","json")) return {"uid":d["metadata"]["uid"],"generation":d["metadata"]["generation"], "selector":d["spec"]["template"]["spec"].get("nodeSelector",{}),"status":d.get("status",{})} if source == "pods": pods=json.loads(kube("get","pod","-l","app="+NAME,"-o","json"))["items"] return {"pods":[{"name":p["metadata"]["name"],"uid":p["metadata"]["uid"],"phase":p["status"]["phase"], "conditions":p["status"].get("conditions",[]),"containers":p["status"].get("containerStatuses",[])} for p in pods[:5]]} if source in ("events","logs"): pods=evidence("pods")["pods"]; items=[] for p in pods[:3]: if source=="logs": items.append(kube("logs",p["name"],"--tail=20","--limit-bytes=2000") if p["phase"]=="Running" else "no running container") else: ev=json.loads(kube("get","events","--field-selector","involvedObject.uid="+p["uid"],"-o","json"))["items"] items.extend([{"reason":x["reason"],"message":x.get("message","")[:1000]} for x in ev[-8:]]) return {"items":items} if source=="nodes": nodes=json.loads(kube("get","nodes","-o","json"))["items"] return {"nodes":[{"name":x["metadata"]["name"],"gpu":x["status"]["allocatable"].get("nvidia.com/gpu","0"),"pool":x["metadata"]["labels"].get("lab.invalid/pool")} for x in nodes[:10]]} if source=="endpoints": return {"service_exists":bool(kube("get","service",NAME,"--ignore-not-found","-o","name").strip()),"items":json.loads(kube("get","endpointslices","-l","kubernetes.io/service-name="+NAME,"-o","json"))["items"][:2]} if source=="metrics": url=os.environ.get("PROMETHEUS_URL","http://127.0.0.1:9090")+"/api/v1/query?"+urllib.parse.urlencode({"query":'sum(kube_pod_status_phase{namespace="opspilot-lab",phase="Pending"})'}) with urllib.request.urlopen(url,timeout=3) as r:return json.loads(r.read(32768)) raise ValueError("unknown evidence source") def patch_plan(d,uid,generation,operation): m=d["metadata"];spec=d["spec"]["template"]["spec"] if m["uid"]!=uid:raise ValueError("Deployment replaced") if m.get("annotations",{}).get("lab.modeldock.dev/last-operation")==operation:return [] if m["generation"]!=generation or spec.get("nodeSelector")!={"lab.invalid/pool":"absent"}:raise ValueError("stale or out-of-policy plan") return [{"op":"test","path":"/metadata/uid","value":uid},{"op":"test","path":"/metadata/resourceVersion","value":m["resourceVersion"]}, {"op":"test","path":"/spec/template/spec/nodeSelector","value":{"lab.invalid/pool":"absent"}}, {"op":"remove","path":"/spec/template/spec/nodeSelector"}, {"op":"add","path":"/metadata/annotations","value":{**m.get("annotations",{}),"lab.modeldock.dev/last-operation":operation}}] @mcp.tool() def release_selector(uid:str,generation:int,operation:str)->dict: """Only remove the exact injected selector from the dedicated lab Deployment.""" d=json.loads(kube("get","deploy",NAME,"-o","json",writer=True)) patch=patch_plan(d,uid,generation,operation) if patch:kube("patch","deploy",NAME,"--type=json","-p",json.dumps(patch),writer=True) return {"operation":operation,"replay":not bool(patch)} if __name__=="__main__": mcp.remove_tool("evidence" if os.getenv("OPS_TOOL_ROLE")=="write" else "release_selector") mcp.run(transport="stdio")