Skip to content

Commit 354fe10

Browse files
committed
fix(search): recheck for the provider server after a failed pre-approval lookup
1 parent 40a3a24 commit 354fe10

2 files changed

Lines changed: 26 additions & 8 deletions

File tree

‎apps/sim/lib/knowledge/__integration__/search-mcp-setup.integration.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,15 @@ describe('atomic organization live Search MCP setup', () => {
188188
expect((await snapshot()).servers).toEqual(before)
189189
})
190190

191+
it('approves a provider a concurrent approval configured while this lookup failed', async () => {
192+
vi.mocked(dns.resolveHostAddresses).mockImplementationOnce(async () => {
193+
await approve('fireflies')
194+
throw new Error('DNS unavailable')
195+
})
196+
await approve('fireflies')
197+
expect((await snapshot()).servers).toHaveLength(1)
198+
})
199+
191200
it('serializes concurrent approvals into one group and one server per provider', async () => {
192201
const providers = ['fireflies', 'granola', 'notion']
193202
const results = await Promise.all(

‎apps/sim/lib/sim-search/live/member-setup.ts‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,10 @@ function toSetupError(error: unknown): never {
3232
throw error
3333
}
3434

35-
/**
36-
* Runs before source approval opens its transaction. A provider whose server does not exist yet
37-
* has that server checked here, because the check resolves DNS and must not run while the
38-
* transaction holds the accounts lock; an already-configured provider needs no check.
39-
*/
40-
export async function prepareSearchMcpProvider(
35+
async function hasProviderServer(
4136
organizationId: string,
4237
provider: ManagedSearchMcpProvider
43-
): Promise<SearchMcpProviderSetup> {
38+
): Promise<boolean> {
4439
const [existing] = await db
4540
.select({ id: mcpServers.id })
4641
.from(mcpServers)
@@ -54,13 +49,27 @@ export async function prepareSearchMcpProvider(
5449
)
5550
)
5651
.limit(1)
57-
if (existing) return { provider, validated: null }
52+
return existing !== undefined
53+
}
54+
55+
/**
56+
* Runs before source approval opens its transaction. A provider whose server does not exist yet
57+
* has that server checked here, because the check resolves DNS and must not run while the
58+
* transaction holds the accounts lock; an already-configured provider needs no check. A failed
59+
* check looks again first, since a concurrent approval may have created the server meanwhile.
60+
*/
61+
export async function prepareSearchMcpProvider(
62+
organizationId: string,
63+
provider: ManagedSearchMcpProvider
64+
): Promise<SearchMcpProviderSetup> {
65+
if (await hasProviderServer(organizationId, provider)) return { provider, validated: null }
5866
try {
5967
return {
6068
provider,
6169
validated: await validateManagedMcpConnectorInput({ connectorId: provider }),
6270
}
6371
} catch (error) {
72+
if (await hasProviderServer(organizationId, provider)) return { provider, validated: null }
6473
toSetupError(error)
6574
}
6675
}

0 commit comments

Comments
 (0)