package cc.unitmesh.agent.config import kotlinx.serialization.Serializable /** * Platform-specific function to get current time in milliseconds */ expect fun getCurrentTimeMillis(): Long /** * Represents the loading state of an individual MCP server */ @Serializable enum class McpServerLoadingStatus { /** Server has not started loading yet */ AVAILABLE, /** Server is currently loading tools */ LOADING, /** Server has successfully loaded tools */ LOADED, /** Server failed to load tools */ ERROR, /** Server is disabled */ DISABLED } /** * Represents the loading state and tools for a single MCP server */ @Serializable data class McpServerState( val serverName: String, val status: McpServerLoadingStatus, val tools: List = emptyList(), val errorMessage: String? = null, val loadingStartTime: Long? = null, val loadingEndTime: Long? = null ) { val isLoading: Boolean get() = status == McpServerLoadingStatus.LOADING val isLoaded: Boolean get() = status == McpServerLoadingStatus.LOADED val hasError: Boolean get() = status == McpServerLoadingStatus.ERROR val isDisabled: Boolean get() = status == McpServerLoadingStatus.DISABLED val loadingDuration: Long? get() = if (loadingStartTime != null && loadingEndTime != null) { loadingEndTime - loadingStartTime } else null } /** * Represents the overall loading state of all MCP servers */ @Serializable data class McpLoadingState( val servers: Map = emptyMap(), val builtinToolsLoaded: Boolean = false ) { val allServersLoaded: Boolean get() = servers.values.all { it.status != McpServerLoadingStatus.LOADING } val hasAnyErrors: Boolean get() = servers.values.any { it.hasError } val loadingServers: List get() = servers.values.filter { it.isLoading }.map { it.serverName } val loadedServers: List get() = servers.values.filter { it.isLoaded }.map { it.serverName } val errorServers: List get() = servers.values.filter { it.hasError }.map { it.serverName } val totalTools: Int get() = servers.values.sumOf { it.tools.size } val enabledTools: Int get() = servers.values.sumOf { serverState -> serverState.tools.count { it.enabled } } fun getServerState(serverName: String): McpServerState? = servers[serverName] fun updateServerState(serverName: String, newState: McpServerState): McpLoadingState { return copy(servers = servers + (serverName to newState)) } fun updateServerStatus( serverName: String, status: McpServerLoadingStatus, errorMessage: String? = null ): McpLoadingState { val currentState = servers[serverName] ?: McpServerState(serverName, McpServerLoadingStatus.AVAILABLE) val updatedState = currentState.copy( status = status, errorMessage = errorMessage, loadingStartTime = if (status == McpServerLoadingStatus.LOADING) getCurrentTimeMillis() else currentState.loadingStartTime, loadingEndTime = if (status == McpServerLoadingStatus.LOADED || status == McpServerLoadingStatus.ERROR) getCurrentTimeMillis() else null ) return updateServerState(serverName, updatedState) } fun updateServerTools(serverName: String, tools: List): McpLoadingState { val currentState = servers[serverName] ?: McpServerState(serverName, McpServerLoadingStatus.AVAILABLE) val updatedState = currentState.copy( tools = tools, status = McpServerLoadingStatus.LOADED, loadingEndTime = getCurrentTimeMillis() ) return updateServerState(serverName, updatedState) } } /** * Callback interface for MCP loading state updates */ interface McpLoadingStateCallback { /** * Called when a server's loading state changes */ fun onServerStateChanged(serverName: String, state: McpServerState) /** * Called when the overall loading state changes */ fun onLoadingStateChanged(loadingState: McpLoadingState) /** * Called when builtin tools are loaded */ fun onBuiltinToolsLoaded(tools: List) }