@@ -8,6 +8,8 @@ import type { MCPConfigService } from "@/node/services/mcpConfigService";
88import { createRuntime } from "@/node/runtime/runtimeFactory" ;
99
1010const TEST_TIMEOUT_MS = 10_000 ;
11+ const IDLE_TIMEOUT_MS = 10 * 60 * 1000 ; // 10 minutes
12+ const IDLE_CHECK_INTERVAL_MS = 60 * 1000 ; // Check every minute
1113
1214/**
1315 * MCP CallToolResult content types (from @ai-sdk/mcp)
@@ -181,12 +183,38 @@ interface MCPServerInstance {
181183interface WorkspaceServers {
182184 configSignature : string ;
183185 instances : Map < string , MCPServerInstance > ;
186+ lastActivity : number ;
184187}
185188
186189export class MCPServerManager {
187190 private readonly workspaceServers = new Map < string , WorkspaceServers > ( ) ;
191+ private readonly idleCheckInterval : ReturnType < typeof setInterval > ;
188192
189- constructor ( private readonly configService : MCPConfigService ) { }
193+ constructor ( private readonly configService : MCPConfigService ) {
194+ this . idleCheckInterval = setInterval ( ( ) => this . cleanupIdleServers ( ) , IDLE_CHECK_INTERVAL_MS ) ;
195+ }
196+
197+ /**
198+ * Stop the idle cleanup interval. Call when shutting down.
199+ */
200+ dispose ( ) : void {
201+ clearInterval ( this . idleCheckInterval ) ;
202+ }
203+
204+ private cleanupIdleServers ( ) : void {
205+ const now = Date . now ( ) ;
206+ for ( const [ workspaceId , entry ] of this . workspaceServers ) {
207+ if ( entry . instances . size === 0 ) continue ;
208+ const idleMs = now - entry . lastActivity ;
209+ if ( idleMs >= IDLE_TIMEOUT_MS ) {
210+ log . info ( "[MCP] Stopping idle servers" , {
211+ workspaceId,
212+ idleMinutes : Math . round ( idleMs / 60_000 ) ,
213+ } ) ;
214+ void this . stopServers ( workspaceId ) ;
215+ }
216+ }
217+ }
190218
191219 /**
192220 * List configured MCP servers for a project (name -> command).
@@ -209,6 +237,8 @@ export class MCPServerManager {
209237
210238 const existing = this . workspaceServers . get ( workspaceId ) ;
211239 if ( existing ?. configSignature === signature ) {
240+ // Update activity timestamp to prevent idle cleanup
241+ existing . lastActivity = Date . now ( ) ;
212242 log . debug ( "[MCP] Using cached servers" , { workspaceId, serverCount : serverNames . length } ) ;
213243 return this . collectTools ( existing . instances ) ;
214244 }
@@ -222,6 +252,7 @@ export class MCPServerManager {
222252 this . workspaceServers . set ( workspaceId , {
223253 configSignature : signature ,
224254 instances,
255+ lastActivity : Date . now ( ) ,
225256 } ) ;
226257 return this . collectTools ( instances ) ;
227258 }
0 commit comments