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]] = {}
|
rows: Dict[str, Dict[str, Any]] = {}
|
||||||
for server_name, server_cfg in raw.items():
|
for server_name, server_cfg in raw.items():
|
||||||
name = str(server_name or "").strip()
|
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
|
continue
|
||||||
if not isinstance(server_cfg, dict):
|
if not isinstance(server_cfg, dict):
|
||||||
continue
|
continue
|
||||||
|
|
@ -1074,6 +1074,44 @@ def _normalize_mcp_servers(raw: Any) -> Dict[str, Dict[str, Any]]:
|
||||||
return rows
|
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]:
|
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()
|
transport_type = str(cfg.get("type") or "streamableHttp").strip()
|
||||||
if transport_type not in {"streamableHttp", "sse"}:
|
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]:
|
def _preflight_mcp_servers_for_start(bot_id: str, image_tag: str) -> List[str]:
|
||||||
config_data = _read_bot_config(bot_id)
|
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):
|
if not isinstance(tools_cfg, dict):
|
||||||
return []
|
return []
|
||||||
mcp_servers = _normalize_mcp_servers(tools_cfg.get("mcpServers"))
|
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:
|
if not bot:
|
||||||
raise HTTPException(status_code=404, detail="Bot not found")
|
raise HTTPException(status_code=404, detail="Bot not found")
|
||||||
_sync_workspace_channels(session, bot_id)
|
_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)
|
runtime_snapshot = _read_bot_runtime_snapshot(bot)
|
||||||
env_params = _read_env_store(bot_id)
|
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")
|
tools_cfg = config_data.get("tools")
|
||||||
if not isinstance(tools_cfg, dict):
|
if not isinstance(tools_cfg, dict):
|
||||||
tools_cfg = {}
|
tools_cfg = {}
|
||||||
mcp_servers = _normalize_mcp_servers(payload.mcp_servers or {})
|
normalized_mcp_servers = _normalize_mcp_servers(payload.mcp_servers or {})
|
||||||
tools_cfg["mcpServers"] = mcp_servers
|
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
|
config_data["tools"] = tools_cfg
|
||||||
|
sanitized_after_save = _sanitize_mcp_servers_in_config_data(config_data)
|
||||||
_write_bot_config(bot_id, config_data)
|
_write_bot_config(bot_id, config_data)
|
||||||
_invalidate_bot_detail_cache(bot_id)
|
_invalidate_bot_detail_cache(bot_id)
|
||||||
return {
|
return {
|
||||||
"status": "updated",
|
"status": "updated",
|
||||||
"bot_id": bot_id,
|
"bot_id": bot_id,
|
||||||
"mcp_servers": mcp_servers,
|
"mcp_servers": _normalize_mcp_servers(sanitized_after_save),
|
||||||
"locked_servers": [],
|
"locked_servers": [],
|
||||||
"restart_required": True,
|
"restart_required": True,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue