v0.1.4-p2
parent
bee2d8294b
commit
44792a02ac
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue