CherryHQ/cherry-studio · warning · Error
MCP runtime is stopping
Error message
MCP runtime is stopping
What it means
Thrown by `getOrCreateClient` when the MCP runtime is in the process of shutting down. The guard checks three flags — `stopping`, `isStopped`, `isDestroyed` — and aborts client creation immediately to prevent new connections during teardown. This is a lifecycle error, not a configuration error.
Source
Thrown at src/main/ai/mcp/McpRuntimeService.ts:396
}
public async getServerLogs(serverId: string): Promise<McpServerLogEntry[]> {
const server = this.getServerById(serverId)
return this.serverLogs.get(this.getServerKey(server))
}
public async withClient<T>(
serverId: string,
operation: (client: Client, server: McpServer) => Promise<T>
): Promise<T> {
const server = this.getServerById(serverId)
const client = await this.getOrCreateClient(server)
return operation(client, server)
}
private async getOrCreateClient(server: McpServer): Promise<Client> {
if (this.stopping || this.isStopped || this.isDestroyed) {
throw new Error('MCP runtime is stopping')
}
if (!server.isActive) {
this.setServerStatus(server.id, 'disabled')
throw new Error(`MCP server ${server.name} is disabled`)
}
const serverKey = this.getServerKey(server)
// If there's a pending initialization, wait for it
const pendingClient = this.pendingClients.get(serverKey)
if (pendingClient) {
this.setServerStatus(server.id, 'connecting')
getServerLogger(server).silly(`Waiting for pending client initialization`)
return pendingClient
}
// Check if we already have a client for this server configurationView on GitHub (pinned to 726446b54c)
Solutions
- Catch this error in the calling layer and treat it as a non-retryable lifecycle cancellation, not a tool failure
- Ensure the caller checks runtime liveness before initiating MCP operations if cancellation is common
- If restarting, drain in-flight operations before calling stop/destroy
- Surface a user-facing message like 'MCP server is shutting down' rather than a raw error
Defensive patterns
Strategy: try-catch
Validate before calling
// Check runtime liveness before operations
if (runtime.isStopped || runtime.isDestroyed) {
throw new Error('Cannot perform MCP operation: runtime is stopped')
} Type guard
function isRuntimeAlive(runtime: McpRuntimeService): boolean {
return !runtime.stopping && !runtime.isStopped && !runtime.isDestroyed
} Try / catch
try {
await runtime.callToolByServer({ server, name, args })
} catch (e) {
if (e instanceof Error && e.message === 'MCP runtime is stopping') {
// Non-retryable — the app is shutting down. Abort gracefully.
return { cancelled: true }
}
throw e
} Prevention
- Drain in-flight MCP operations before calling runtime.stop() or destroy()
- Check runtime liveness flags before initiating long-running MCP operations
- Distinguish lifecycle errors from operational errors in your error handling layer
When it happens
Trigger: An in-flight operation (tool call, list tools, ping) reaches `getOrCreateClient` while the runtime is concurrently stopped (e.g. application quit, window close, or runtime restart). The race between the operation and shutdown is caught at the client-acquisition boundary.
Common situations: Application is closing and a pending AI request triggers a tool call; the user disables all MCP servers during an active session; a runtime restart races with concurrent tool invocations.
Related errors
- Client is not connected
- Bot is not connected
- Bot is not connected
- ${packageLabel} file not found
- ErrorCode.InternalError
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/18338e2802a076a8.
Report an issue: GitHub.