v0.1.4-p2

main
mula.liu 2026-03-15 16:47:08 +08:00
parent bee2d8294b
commit 44792a02ac
1 changed files with 58 additions and 5 deletions

View File

@ -1036,7 +1036,7 @@ def _normalize_mcp_servers(raw: Any) -> Dict[str, Dict[str, Any]]:
rows: Dict[str, Dict[str, Any]] = {}
for server_name, server_cfg in raw.items():
name = str(server_name or "").strip()
if not name or not _MCP_SERVER_NAME_RE.match(name):
if not name or not _MCP_SERVER_NAME_RE.fullmatch(name):
continue
if not isinstance(server_cfg, dict):
continue
@ -1074,6 +1074,44 @@ def _normalize_mcp_servers(raw: Any) -> Dict[str, Dict[str, Any]]:
return rows
def _merge_mcp_servers_preserving_extras(
current_raw: Any,
normalized: Dict[str, Dict[str, Any]],
) -> Dict[str, Dict[str, Any]]:
"""Preserve unknown per-server fields already present in config.json.
Dashboard only edits a subset of MCP fields (type/url/headers/toolTimeout).
Some MCP providers may rely on additional keys; dropping them can break startup.
"""
current_map = current_raw if isinstance(current_raw, dict) else {}
merged: Dict[str, Dict[str, Any]] = {}
for name, normalized_cfg in normalized.items():
base = current_map.get(name)
base_cfg = dict(base) if isinstance(base, dict) else {}
next_cfg = dict(base_cfg)
next_cfg.update(normalized_cfg)
merged[name] = next_cfg
return merged
def _sanitize_mcp_servers_in_config_data(config_data: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
"""Normalize tools.mcpServers and drop hidden invalid entries safely.
Returns the sanitized mcpServers map written into config_data["tools"]["mcpServers"].
"""
if not isinstance(config_data, dict):
return {}
tools_cfg = config_data.get("tools")
if not isinstance(tools_cfg, dict):
tools_cfg = {}
current_raw = tools_cfg.get("mcpServers")
normalized = _normalize_mcp_servers(current_raw)
merged = _merge_mcp_servers_preserving_extras(current_raw, normalized)
tools_cfg["mcpServers"] = merged
config_data["tools"] = tools_cfg
return merged
def _probe_mcp_server(cfg: Dict[str, Any], bot_id: Optional[str] = None) -> Dict[str, Any]:
transport_type = str(cfg.get("type") or "streamableHttp").strip()
if transport_type not in {"streamableHttp", "sse"}:
@ -1397,7 +1435,9 @@ def _probe_mcp_server_for_start(cfg: Dict[str, Any], image_tag: str) -> Dict[str
def _preflight_mcp_servers_for_start(bot_id: str, image_tag: str) -> List[str]:
config_data = _read_bot_config(bot_id)
tools_cfg = config_data.get("tools") if isinstance(config_data, dict) else {}
if not isinstance(config_data, dict):
return []
tools_cfg = config_data.get("tools")
if not isinstance(tools_cfg, dict):
return []
mcp_servers = _normalize_mcp_servers(tools_cfg.get("mcpServers"))
@ -2401,6 +2441,16 @@ async def start_bot(bot_id: str, session: Session = Depends(get_session)):
if not bot:
raise HTTPException(status_code=404, detail="Bot not found")
_sync_workspace_channels(session, bot_id)
mcp_preflight_failures = _preflight_mcp_servers_for_start(bot_id, image_tag=bot.image_tag)
if mcp_preflight_failures:
bot.docker_status = "STOPPED"
session.add(bot)
session.commit()
_invalidate_bot_detail_cache(bot_id)
raise HTTPException(
status_code=400,
detail="MCP precheck failed: " + " | ".join(mcp_preflight_failures[:5]),
)
runtime_snapshot = _read_bot_runtime_snapshot(bot)
env_params = _read_env_store(bot_id)
@ -2566,15 +2616,18 @@ def update_bot_mcp_config(bot_id: str, payload: BotMcpConfigUpdateRequest, sessi
tools_cfg = config_data.get("tools")
if not isinstance(tools_cfg, dict):
tools_cfg = {}
mcp_servers = _normalize_mcp_servers(payload.mcp_servers or {})
tools_cfg["mcpServers"] = mcp_servers
normalized_mcp_servers = _normalize_mcp_servers(payload.mcp_servers or {})
current_mcp_servers = tools_cfg.get("mcpServers")
merged_mcp_servers = _merge_mcp_servers_preserving_extras(current_mcp_servers, normalized_mcp_servers)
tools_cfg["mcpServers"] = merged_mcp_servers
config_data["tools"] = tools_cfg
sanitized_after_save = _sanitize_mcp_servers_in_config_data(config_data)
_write_bot_config(bot_id, config_data)
_invalidate_bot_detail_cache(bot_id)
return {
"status": "updated",
"bot_id": bot_id,
"mcp_servers": mcp_servers,
"mcp_servers": _normalize_mcp_servers(sanitized_after_save),
"locked_servers": [],
"restart_required": True,
}