Skip to content

Commit 9df87d9

Browse files
authored
fix(mcp): remove client-side cache and reduce server cache from 5m to 30s (#2182)
* fix(mcp): remove client-side cache and reduce server cache from 5m to 30s * ack PR comments
1 parent c864d17 commit 9df87d9

File tree

3 files changed

+22
-76
lines changed

3 files changed

+22
-76
lines changed

apps/sim/lib/mcp/client.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,14 @@ export class McpClient {
4444

4545
/**
4646
* Creates a new MCP client
47+
*
48+
* No session ID parameter (we disconnect after each operation).
49+
* The SDK handles session management automatically via Mcp-Session-Id header.
50+
*
4751
* @param config - Server configuration
4852
* @param securityPolicy - Optional security policy
49-
* @param sessionId - Optional session ID for session restoration (from previous connection)
5053
*/
51-
constructor(config: McpServerConfig, securityPolicy?: McpSecurityPolicy, sessionId?: string) {
54+
constructor(config: McpServerConfig, securityPolicy?: McpSecurityPolicy) {
5255
this.config = config
5356
this.connectionStatus = { connected: false }
5457
this.securityPolicy = securityPolicy ?? {
@@ -65,7 +68,6 @@ export class McpClient {
6568
requestInit: {
6669
headers: this.config.headers,
6770
},
68-
sessionId,
6971
})
7072

7173
this.client = new Client(

apps/sim/lib/mcp/service.ts

Lines changed: 15 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -42,42 +42,17 @@ interface CacheStats {
4242

4343
class McpService {
4444
private toolCache = new Map<string, ToolCache>()
45-
private readonly cacheTimeout = MCP_CONSTANTS.CACHE_TIMEOUT
46-
private readonly maxCacheSize = 1000
45+
private readonly cacheTimeout = MCP_CONSTANTS.CACHE_TIMEOUT // 30 seconds
46+
private readonly maxCacheSize = MCP_CONSTANTS.MAX_CACHE_SIZE // 1000
4747
private cleanupInterval: NodeJS.Timeout | null = null
4848
private cacheHits = 0
4949
private cacheMisses = 0
5050
private entriesEvicted = 0
5151

52-
private sessionCache = new Map<string, string>()
53-
5452
constructor() {
5553
this.startPeriodicCleanup()
5654
}
5755

58-
/**
59-
* Get cached session ID for a server
60-
*/
61-
private getCachedSessionId(serverId: string): string | undefined {
62-
return this.sessionCache.get(serverId)
63-
}
64-
65-
/**
66-
* Cache session ID for a server
67-
*/
68-
private cacheSessionId(serverId: string, sessionId: string): void {
69-
this.sessionCache.set(serverId, sessionId)
70-
logger.debug(`Cached session ID for server ${serverId}`)
71-
}
72-
73-
/**
74-
* Clear cached session ID for a server
75-
*/
76-
private clearCachedSessionId(serverId: string): void {
77-
this.sessionCache.delete(serverId)
78-
logger.debug(`Cleared cached session ID for server ${serverId}`)
79-
}
80-
8156
/**
8257
* Start periodic cleanup of expired cache entries
8358
*/
@@ -341,49 +316,9 @@ class McpService {
341316
allowedOrigins: config.url ? [new URL(config.url).origin] : undefined,
342317
}
343318

344-
const cachedSessionId = this.getCachedSessionId(config.id)
345-
346-
const client = new McpClient(config, securityPolicy, cachedSessionId)
347-
348-
try {
349-
await client.connect()
350-
351-
const newSessionId = client.getSessionId()
352-
if (newSessionId) {
353-
this.cacheSessionId(config.id, newSessionId)
354-
}
355-
356-
return client
357-
} catch (error) {
358-
if (cachedSessionId && this.isSessionError(error)) {
359-
logger.debug(`Session restoration failed for server ${config.id}, retrying fresh`)
360-
this.clearCachedSessionId(config.id)
361-
362-
const freshClient = new McpClient(config, securityPolicy)
363-
await freshClient.connect()
364-
365-
const freshSessionId = freshClient.getSessionId()
366-
if (freshSessionId) {
367-
this.cacheSessionId(config.id, freshSessionId)
368-
}
369-
370-
return freshClient
371-
}
372-
373-
throw error
374-
}
375-
}
376-
377-
private isSessionError(error: unknown): boolean {
378-
if (error instanceof Error) {
379-
const message = error.message.toLowerCase()
380-
return (
381-
message.includes('no valid session') ||
382-
message.includes('invalid session') ||
383-
message.includes('session expired')
384-
)
385-
}
386-
return false
319+
const client = new McpClient(config, securityPolicy)
320+
await client.connect()
321+
return client
387322
}
388323

389324
/**
@@ -466,21 +401,29 @@ class McpService {
466401
})
467402
)
468403

404+
let failedCount = 0
469405
results.forEach((result, index) => {
470406
if (result.status === 'fulfilled') {
471407
allTools.push(...result.value)
472408
} else {
409+
failedCount++
473410
logger.warn(
474411
`[${requestId}] Failed to discover tools from server ${servers[index].name}:`,
475412
result.reason
476413
)
477414
}
478415
})
479416

480-
this.setCacheEntry(cacheKey, allTools)
417+
if (failedCount === 0) {
418+
this.setCacheEntry(cacheKey, allTools)
419+
} else {
420+
logger.warn(
421+
`[${requestId}] Skipping cache due to ${failedCount} failed server(s) - will retry on next request`
422+
)
423+
}
481424

482425
logger.info(
483-
`[${requestId}] Discovered ${allTools.length} tools from ${servers.length} servers`
426+
`[${requestId}] Discovered ${allTools.length} tools from ${servers.length - failedCount}/${servers.length} servers`
484427
)
485428
return allTools
486429
} catch (error) {

apps/sim/lib/mcp/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import type { McpApiResponse } from '@/lib/mcp/types'
66
*/
77
export const MCP_CONSTANTS = {
88
EXECUTION_TIMEOUT: 60000,
9-
CACHE_TIMEOUT: 5 * 60 * 1000,
9+
CACHE_TIMEOUT: 30 * 1000,
1010
DEFAULT_RETRIES: 3,
1111
DEFAULT_CONNECTION_TIMEOUT: 30000,
12+
MAX_CACHE_SIZE: 1000,
1213
} as const
1314

1415
/**

0 commit comments

Comments
 (0)