Add MCP server management + fix OAuth

This commit is contained in:
Zac Gaetano 2026-04-04 23:50:16 -04:00
parent 05397ceffc
commit 70a12093e9

View file

@ -623,6 +623,100 @@ async def auth_logout():
return {"status": "error", "message": str(e)}
# ============ MCP Server Management ============
@app.get("/api/mcp/servers")
async def list_mcp_servers():
"""List configured MCP servers"""
try:
proc = await asyncio.create_subprocess_exec(
"claude", "mcp", "list",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=10)
output = stdout.decode(errors="replace").strip()
# Parse the output — claude mcp list shows servers in a table or JSON
servers = []
if "No MCP servers configured" in output:
return {"servers": [], "raw": output}
# Try JSON parse first
try:
import json as _json
data = _json.loads(output)
if isinstance(data, list):
servers = data
elif isinstance(data, dict):
servers = list(data.values()) if data else []
except Exception:
# Parse text output line by line
for line in output.split("\n"):
line = line.strip()
if line and not line.startswith("-") and not line.startswith("Name"):
parts = line.split()
if len(parts) >= 1:
servers.append({"name": parts[0], "details": " ".join(parts[1:])})
return {"servers": servers, "raw": output}
except Exception as e:
return {"servers": [], "error": str(e)}
class McpServerAdd(BaseModel):
name: str
server_type: str = "sse" # sse | stdio
url: Optional[str] = None
command: Optional[str] = None
args: Optional[List[str]] = None
@app.post("/api/mcp/servers")
async def add_mcp_server(server: McpServerAdd):
"""Add an MCP server"""
try:
cmd = ["claude", "mcp", "add", server.name]
if server.server_type == "sse" and server.url:
cmd.extend(["--transport", "sse", server.url])
elif server.server_type == "stdio" and server.command:
cmd.extend(["--transport", "stdio", server.command])
if server.args:
cmd.extend(server.args)
proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=15)
output = stdout.decode(errors="replace") + stderr.decode(errors="replace")
return {
"status": "ok" if proc.returncode == 0 else "error",
"message": output.strip(),
"name": server.name
}
except Exception as e:
return {"status": "error", "message": str(e)}
@app.delete("/api/mcp/servers/{name}")
async def remove_mcp_server(name: str):
"""Remove an MCP server"""
try:
proc = await asyncio.create_subprocess_exec(
"claude", "mcp", "remove", name,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=10)
output = stdout.decode(errors="replace") + stderr.decode(errors="replace")
return {"status": "ok" if proc.returncode == 0 else "error", "message": output.strip()}
except Exception as e:
return {"status": "error", "message": str(e)}
# Serve static frontend
app.mount("/", StaticFiles(directory="/app/frontend/dist", html=True), name="static")