Fix Edit/Save not applying to an already-connected External MCP server

ExternalMCPManager.reconfigure() only started brand-new clients — a
server ID that already had a client (in ANY state, including .crashed)
was silently skipped even when its settings had just changed. Editing a
server in Settings and clicking Save persisted correctly but never
reached the live connection, which just kept running with its old
(often broken) config until the next app launch. Rune hit this directly
editing Obsidian's URL/token after the toggle-fields bug corrupted it.

Added ExternalMCPServer: Equatable so reconfigure can detect a changed
config for a still-enabled server and restart it fresh (extracted the
restart-attempt-reset logic already used by retryClient into a shared
restartFresh helper).
This commit is contained in:
2026-08-26 14:12:28 +02:00
parent 57b3477903
commit 41f0b8f083
3 changed files with 45 additions and 6 deletions
+22
View File
@@ -213,3 +213,25 @@ struct MissingCommandDetectionTests {
#expect(SettingsView.missingCommand(from: state) == "npx")
}
}
@Suite("ExternalMCPServer.Equatable")
struct ExternalMCPServerEquatableTests {
@Test("Two servers with identical fields are equal")
func identicalServersAreEqual() {
let id = UUID()
let createdAt = Date()
let a = ExternalMCPServer(id: id, name: "Obsidian", transportKind: .http, url: "http://127.0.0.1:27123/mcp/", bearerToken: "tok", timeout: 30, createdAt: createdAt)
let b = ExternalMCPServer(id: id, name: "Obsidian", transportKind: .http, url: "http://127.0.0.1:27123/mcp/", bearerToken: "tok", timeout: 30, createdAt: createdAt)
#expect(a == b)
}
@Test("A changed URL/bearerToken makes servers unequal — this is what ExternalMCPManager.reconfigure uses to detect an edit")
func editedFieldsMakeServersUnequal() {
let id = UUID()
let createdAt = Date()
let original = ExternalMCPServer(id: id, name: "Obsidian", transportKind: .http, url: "http://127.0.0.1:27123/mcp/", bearerToken: "old-token", timeout: 30, createdAt: createdAt)
let edited = ExternalMCPServer(id: id, name: "Obsidian", transportKind: .http, url: "http://127.0.0.1:27123/mcp/", bearerToken: "new-token", timeout: 30, createdAt: createdAt)
#expect(original != edited)
}
}