Skip to content

Commit b9dfe48

Browse files
committed
Address PR review feedback (#5754)
1 parent 0fb9a4e commit b9dfe48

4 files changed

Lines changed: 55 additions & 6 deletions

File tree

apps/sim/app/api/mcp/servers/[id]/refresh/route.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,48 @@ describe('MCP server refresh route', () => {
375375
}
376376
)
377377

378+
it('does not sync published tools after a newer cache invalidation', async () => {
379+
const publicationOrder = new Date(initialServer.lastToolsRefresh.getTime() + 30_000)
380+
mockDiscoverServerTools.mockResolvedValueOnce({
381+
tools: [
382+
{
383+
name: 'stale-search',
384+
description: 'Search tool published before invalidation',
385+
inputSchema: {},
386+
serverId: 'server-1',
387+
serverName: 'OAuth Server',
388+
},
389+
],
390+
state: 'published',
391+
publicationOrder,
392+
})
393+
const cacheInvalidatedServer = {
394+
...initialServer,
395+
lastConnected: publicationOrder,
396+
lastToolsRefresh: new Date(publicationOrder.getTime() + 30_000),
397+
toolCount: 0,
398+
}
399+
mockSelect.mockReturnValueOnce(selectRows([cacheInvalidatedServer]))
400+
401+
const request = new Request('http://localhost/api/mcp/servers/server-1/refresh', {
402+
method: 'POST',
403+
}) as NextRequest
404+
const response = await POST(request, { params: Promise.resolve({ id: 'server-1' }) })
405+
const body = await response.json()
406+
407+
expect(body.data).toEqual(
408+
expect.objectContaining({
409+
status: 'connected',
410+
error: null,
411+
toolCount: 0,
412+
workflowsUpdated: 0,
413+
updatedWorkflowIds: [],
414+
})
415+
)
416+
expect(mockSelect).toHaveBeenCalledTimes(2)
417+
expect(mockUpdate).not.toHaveBeenCalled()
418+
})
419+
378420
it('preserves a newer successful refresh when discovery is superseded', async () => {
379421
mockDiscoverServerTools.mockResolvedValueOnce({
380422
tools: [],

apps/sim/app/api/mcp/servers/[id]/refresh/route.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ export const POST = withRouteHandler(
194194
let syncResult: SyncResult = { updatedCount: 0, updatedWorkflowIds: [] }
195195
let discoveredTools: McpTool[] = []
196196
let discoveryState: McpServerDiscoveryState | null = null
197+
let discoveryPublicationOrder: Date | null = null
197198
let discoveryError: string | null = null
198199
let oauthAuthorizationRequired = false
199200

@@ -206,6 +207,7 @@ export const POST = withRouteHandler(
206207
)
207208
discoveredTools = discovery.tools
208209
discoveryState = discovery.state
210+
discoveryPublicationOrder = discovery.publicationOrder ?? null
209211
logger.info(
210212
`[${requestId}] Discovered ${discoveredTools.length} tools from server ${serverId}`
211213
)
@@ -240,7 +242,12 @@ export const POST = withRouteHandler(
240242
)
241243
.limit(1)
242244

243-
if (discoveryError === null && discoveryState === 'published') {
245+
const publicationBaseline = discoveryPublicationOrder ?? server.lastToolsRefresh
246+
const newerPublicationWonRace =
247+
refreshedServer?.lastToolsRefresh != null &&
248+
(publicationBaseline == null || refreshedServer.lastToolsRefresh > publicationBaseline)
249+
250+
if (discoveryError === null && discoveryState === 'published' && !newerPublicationWonRace) {
244251
try {
245252
syncResult = await syncToolSchemasToWorkflows(
246253
workspaceId,
@@ -265,10 +272,6 @@ export const POST = withRouteHandler(
265272
let connectionStatus = refreshedServer?.connectionStatus ?? 'error'
266273
let lastError = refreshedServer ? refreshedServer.lastError : discoveryError
267274
let toolCount = refreshedServer?.toolCount ?? discoveredTools.length
268-
const newerPublicationWonRace =
269-
refreshedServer?.lastToolsRefresh != null &&
270-
(server.lastToolsRefresh == null ||
271-
refreshedServer.lastToolsRefresh > server.lastToolsRefresh)
272275
const newerSuccessWonRace =
273276
connectionStatus === 'connected' &&
274277
newerPublicationWonRace &&

apps/sim/lib/mcp/service.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ describe('McpService.discoverTools per-server caching', () => {
966966
).resolves.toEqual({
967967
tools: [tool('still-valid', 'mcp-a')],
968968
state: 'published',
969+
publicationOrder: expect.any(Date),
969970
})
970971

971972
const successfulStatusWrites = mockUpdateSet.mock.calls
@@ -1553,6 +1554,7 @@ describe('McpService.discoverTools per-server caching', () => {
15531554
await expect(discovery).resolves.toEqual({
15541555
tools: [tool('retry-winner', 'mcp-a')],
15551556
state: 'published',
1557+
publicationOrder: expect.any(Date),
15561558
})
15571559

15581560
expect(mockCacheAdapter.beginMutation).toHaveBeenCalledTimes(3)

apps/sim/lib/mcp/service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export type McpServerDiscoveryState =
8585
export interface McpServerDiscoveryResult {
8686
tools: McpTool[]
8787
state: McpServerDiscoveryState
88+
publicationOrder?: Date
8889
}
8990

9091
type DiscoveryOutcome =
@@ -1216,7 +1217,8 @@ class McpService {
12161217
}
12171218
return { tools, state: 'unavailable' }
12181219
}
1219-
return { tools, state: 'published' }
1220+
if (!mutation) return { tools, state: 'unavailable' }
1221+
return { tools, state: 'published', publicationOrder: new Date(mutation.id) }
12201222
} finally {
12211223
await client.disconnect()
12221224
}

0 commit comments

Comments
 (0)