eigent/server/app/controller/mcp/user_controller.py
2025-10-10 16:09:16 +05:30

141 lines
5.4 KiB
Python

import os
from typing import List, Optional
from fastapi import Depends, HTTPException, Query, Response, APIRouter
from sqlmodel import Session, select
from app.component.database import session
from app.component.auth import Auth, auth_must
from fastapi_babel import _
from app.model.mcp.mcp_user import McpUser, McpUserIn, McpUserOut, McpUserUpdate, Status
from app.model.mcp.mcp import Mcp
from camel.toolkits.mcp_toolkit import MCPToolkit
from app.component.environment import env
import traceroot
logger = traceroot.get_logger("server_mcp_user_controller")
router = APIRouter(tags=["McpUser Management"])
async def pre_instantiate_mcp_toolkit(config_dict: dict) -> bool:
"""
Pre-instantiate MCP toolkit to complete authentication process
Args:
config_dict: MCP server configuration dictionary
Returns:
bool: Whether successfully instantiated and connected
"""
try:
# Ensure unified auth directory for all mcp servers
for server_config in config_dict.get("mcpServers", {}).values():
if "env" not in server_config:
server_config["env"] = {}
# Set global auth directory to persist authentication across tasks
if "MCP_REMOTE_CONFIG_DIR" not in server_config["env"]:
server_config["env"]["MCP_REMOTE_CONFIG_DIR"] = env(
"MCP_REMOTE_CONFIG_DIR",
os.path.expanduser("~/.mcp-auth")
)
# Create MCP toolkit and attempt to connect
mcp_toolkit = MCPToolkit(config_dict=config_dict, timeout=30)
await mcp_toolkit.connect()
# Get tools list to ensure connection is successful
tools = mcp_toolkit.get_tools()
logger.info(f"Successfully pre-instantiated MCP toolkit with {len(tools)} tools")
# Disconnect, authentication info is already saved
await mcp_toolkit.disconnect()
return True
except Exception as e:
logger.warning(f"Failed to pre-instantiate MCP toolkit: {e!r}")
return False
@router.get("/mcp/users", name="list mcp users", response_model=List[McpUserOut])
async def list_mcp_users(
mcp_id: Optional[int] = None,
session: Session = Depends(session),
auth: Auth = Depends(auth_must),
):
user_id = auth.user.id
query = select(McpUser)
if mcp_id is not None:
query = query.where(McpUser.mcp_id == mcp_id)
if user_id is not None:
query = query.where(McpUser.user_id == user_id)
mcp_users = session.exec(query).all()
return mcp_users
@router.get("/mcp/users/{mcp_user_id}", name="get mcp user", response_model=McpUserOut)
async def get_mcp_user(mcp_user_id: int, session: Session = Depends(session), auth: Auth = Depends(auth_must)):
query = select(McpUser).where(McpUser.id == mcp_user_id)
mcp_user = session.exec(query).first()
if not mcp_user:
raise HTTPException(status_code=404, detail=_("McpUser not found"))
return mcp_user
@router.post("/mcp/users", name="create mcp user", response_model=McpUserOut)
async def create_mcp_user(mcp_user: McpUserIn, session: Session = Depends(session), auth: Auth = Depends(auth_must)):
exists = session.exec(
select(McpUser).where(McpUser.mcp_id == mcp_user.mcp_id, McpUser.user_id == auth.user.id)
).first()
if exists:
raise HTTPException(status_code=400, detail=_("mcp is installed"))
# Get MCP configuration from the main Mcp table
mcp = session.get(Mcp, mcp_user.mcp_id)
if mcp and mcp.install_command:
# Pre-instantiate MCP toolkit for authentication
config_dict = {
"mcpServers": {
mcp.key: mcp.install_command
}
}
try:
success = await pre_instantiate_mcp_toolkit(config_dict)
if not success:
logger.warning(f"Pre-instantiation failed for MCP {mcp.key}, but continuing with user creation")
except Exception as e:
logger.warning(f"Exception during pre-instantiation for MCP {mcp.key}: {e}")
db_mcp_user = McpUser(mcp_id=mcp_user.mcp_id, user_id=auth.user.id, env=mcp_user.env)
session.add(db_mcp_user)
session.commit()
session.refresh(db_mcp_user)
return db_mcp_user
@router.put("/mcp/users/{id}", name="update mcp user")
async def update_mcp_user(
id: int,
update_item: McpUserUpdate,
session: Session = Depends(session),
auth: Auth = Depends(auth_must),
):
model = session.get(McpUser, id)
if not model:
raise HTTPException(status_code=404, detail=_("Mcp Info not found"))
if model.user_id != auth.user.id:
raise HTTPException(status_code=400, detail=_("current user have no permission to modify"))
update_data = update_item.model_dump(exclude_unset=True)
model.update_fields(update_data)
model.save(session)
session.refresh(model)
return model
@router.delete("/mcp/users/{mcp_user_id}", name="delete mcp user")
async def delete_mcp_user(mcp_user_id: int, session: Session = Depends(session), auth: Auth = Depends(auth_must)):
db_mcp_user = session.get(McpUser, mcp_user_id)
if not db_mcp_user:
raise HTTPException(status_code=404, detail=_("Mcp Info not found"))
session.delete(db_mcp_user)
session.commit()
return Response(status_code=204)