mirror of
https://github.com/NanmiCoder/claude-code-haha.git
synced 2026-10-10 11:53:10 +08:00
fix: close stale reconnect results without racing re-enable
Stale connections closed by the disabled-state guard now go through client.cleanup() so their caches are cleared by the close handler at close time, never by a post-close invalidation that could hit a connection created by a concurrent re-enable. The post-OAuth reconnect gets the same disabled check, with the config check and disabled state write kept synchronous (no await in between) so a later enable cannot be overwritten by the stale OAuth result.
This commit is contained in:
@@ -3458,6 +3458,54 @@ function runHeadlessStreaming(
|
||||
serverName,
|
||||
config,
|
||||
)
|
||||
// If the server was disabled while the reconnect was in
|
||||
// flight, close any fresh connection and keep the disabled
|
||||
// state
|
||||
if (isMcpServerDisabled(serverName)) {
|
||||
if (result.client.type === 'connected') {
|
||||
// Close the fresh connection in the background; its
|
||||
// caches are cleared by the close handler at close
|
||||
// time, so no post-close invalidation can hit a
|
||||
// connection created by a concurrent re-enable.
|
||||
void result.client.cleanup()
|
||||
}
|
||||
const prefix = getMcpPrefix(serverName)
|
||||
setAppState(prev => ({
|
||||
...prev,
|
||||
mcp: {
|
||||
...prev.mcp,
|
||||
clients: prev.mcp.clients.map(c =>
|
||||
c.name === serverName
|
||||
? {
|
||||
name: serverName,
|
||||
type: 'disabled' as const,
|
||||
config,
|
||||
}
|
||||
: c,
|
||||
),
|
||||
tools: reject(prev.mcp.tools, t =>
|
||||
t.name?.startsWith(prefix),
|
||||
),
|
||||
commands: reject(prev.mcp.commands, c =>
|
||||
commandBelongsToServer(c, serverName),
|
||||
),
|
||||
resources: omit(prev.mcp.resources, serverName),
|
||||
},
|
||||
}))
|
||||
dynamicMcpState = {
|
||||
...dynamicMcpState,
|
||||
clients: [
|
||||
...dynamicMcpState.clients.filter(
|
||||
c => c.name !== serverName,
|
||||
),
|
||||
{ name: serverName, type: 'disabled' as const, config },
|
||||
],
|
||||
tools: dynamicMcpState.tools.filter(
|
||||
t => !t.name?.startsWith(prefix),
|
||||
),
|
||||
}
|
||||
return
|
||||
}
|
||||
const prefix = getMcpPrefix(serverName)
|
||||
setAppState(prev => ({
|
||||
...prev,
|
||||
|
||||
@@ -327,10 +327,11 @@ export function useManageMCPConnections(
|
||||
}) => {
|
||||
// A connect that completes after the server was disabled (e.g. disable
|
||||
// during a reconnect request) must not resurrect the server: close any
|
||||
// fresh connection, clear its caches, and mark it disabled instead.
|
||||
// fresh connection (its caches are cleared by the close handler) and
|
||||
// mark it disabled instead.
|
||||
if (isMcpServerDisabled(client.name)) {
|
||||
if (client.type === 'connected') {
|
||||
void clearServerCache(client.name, client.config)
|
||||
void client.cleanup()
|
||||
}
|
||||
updateServer({
|
||||
name: client.name,
|
||||
|
||||
Reference in New Issue
Block a user