From 54909d4215debf6c6119ef2d9f7345a8ad57a3e9 Mon Sep 17 00:00:00 2001 From: Louis Knight-Webb Date: Wed, 5 Nov 2025 11:48:41 +0000 Subject: [PATCH] Increase the time before auto shutdown of dev server (vibe-kanban 8b5175a7) Increase from 60s to 120s, allow to be overriden with CLI --- README.md | 6 +++--- src/lib.rs | 5 +++-- src/main.rs | 6 ++++-- src/manager.rs | 9 ++++----- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index ede2372..5263b5f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MCP Dev Server Manager -A daemon that accepts requests from MCP clients to start dev servers, allocating unique ports to avoid collisions and shutting down idle connections after 60s of inactivity. +A daemon that accepts requests from MCP clients to start dev servers, allocating unique ports to avoid collisions and shutting down idle connections after 120s of inactivity. ## Example @@ -16,7 +16,7 @@ A daemon that accepts requests from MCP clients to start dev servers, allocating - **Avoid port collisions**: when working with websites, it's often necessary to specify different ports if you want to run multiple dev servers - **Automatic port allocation** starting at 3010 with reuse - **Log capture** with 512KB ring buffers per server -- **Auto-cleanup** of idle sessions after 60 seconds +- **Auto-cleanup** of idle sessions after 120 seconds (configurable via `--idle-timeout`) ## Installation & Usage @@ -129,7 +129,7 @@ Get stdout/stderr logs for a development server session. - Single `Arc` shared across all client connections - Each connection gets a fresh `DevManagerService` instance - Mutex-protected HashMap for session storage -- Background sweeper runs every 5 seconds to clean up idle sessions (>60s) +- Background sweeper runs every 5 seconds to clean up idle sessions (>120s by default) ### Session Keys diff --git a/src/lib.rs b/src/lib.rs index f6c0472..25073bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ use serde_json::Value; use service::DevManagerService; use std::net::{Ipv4Addr, SocketAddr}; use std::sync::Arc; +use std::time::Duration; use tokio::sync::mpsc; fn inject_cwd_if_start_tool( @@ -48,8 +49,8 @@ fn inject_cwd_if_start_tool( msg } -pub async fn run_daemon(port: u16) -> Result<()> { - let manager = Arc::new(Manager::new()); +pub async fn run_daemon(port: u16, idle_timeout_secs: u64) -> Result<()> { + let manager = Arc::new(Manager::new(Duration::from_secs(idle_timeout_secs))); let bind = SocketAddr::from((Ipv4Addr::LOCALHOST, port)); println!("MCP daemon listening on {}", bind); diff --git a/src/main.rs b/src/main.rs index f2725a4..6333a99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,8 @@ enum Command { Daemon { #[arg(long, env = "PORT", default_value_t = 3009)] port: u16, + #[arg(long, env = "MCP_IDLE_TIMEOUT", default_value_t = 120)] + idle_timeout: u64, }, #[command(about = "Run as STDIO proxy that connects to daemon")] Stdio { @@ -30,8 +32,8 @@ enum Command { async fn main() -> anyhow::Result<()> { let cli = Cli::parse(); - match cli.command.unwrap_or(Command::Daemon { port: 3009 }) { - Command::Daemon { port } => dev_manager_mcp::run_daemon(port).await, + match cli.command.unwrap_or(Command::Daemon { port: 3009, idle_timeout: 120 }) { + Command::Daemon { port, idle_timeout } => dev_manager_mcp::run_daemon(port, idle_timeout).await, Command::Stdio { daemon_url } => dev_manager_mcp::run_stdio_proxy(&daemon_url).await, } } diff --git a/src/manager.rs b/src/manager.rs index 596d6d2..3e2199d 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -10,7 +10,6 @@ use tokio::process::Command; type SessionKey = String; const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; -const RUNNING_IDLE_SECS: u64 = 60; const EXITED_RETENTION_SECS: u64 = 600; fn generate_session_key() -> String { @@ -31,7 +30,7 @@ pub struct Manager { } impl Manager { - pub fn new() -> Self { + pub fn new(idle_timeout: Duration) -> Self { let manager = Self { inner: Arc::new(Mutex::new(ManagerInner { servers: HashMap::new(), @@ -39,11 +38,11 @@ impl Manager { })), }; - manager.start_sweeper(); + manager.start_sweeper(idle_timeout); manager } - fn start_sweeper(&self) { + fn start_sweeper(&self, idle_timeout: Duration) { let inner = self.inner.clone(); tokio::spawn(async move { let mut interval = tokio::time::interval(Duration::from_secs(5)); @@ -57,7 +56,7 @@ impl Manager { }; let now = Instant::now(); - let idle_threshold = Duration::from_secs(RUNNING_IDLE_SECS); + let idle_threshold = idle_timeout; let retention_threshold = Duration::from_secs(EXITED_RETENTION_SECS); let mut to_stop = Vec::new();