From 4a1c6b4cfa82c4d2a6c2f635b57bbc4f2b66e7c8 Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 15 Apr 2026 23:42:46 +0000 Subject: [PATCH] huskies: merge 585_bug_bot_not_aware_of_actual_running_port_defaults_to_3001 --- server/src/http/mcp/diagnostics.rs | 5 +++-- server/src/http/mcp/mod.rs | 4 ++-- server/src/io/fs/project.rs | 32 ++++++++++++++++++++---------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/server/src/http/mcp/diagnostics.rs b/server/src/http/mcp/diagnostics.rs index 0f858f90..d6312561 100644 --- a/server/src/http/mcp/diagnostics.rs +++ b/server/src/http/mcp/diagnostics.rs @@ -349,13 +349,14 @@ pub(super) fn tool_dump_crdt(args: &Value) -> Result { .map_err(|e| format!("Serialization error: {e}")) } -/// MCP tool: return the server version and build hash. -pub(super) fn tool_get_version() -> Result { +/// MCP tool: return the server version, build hash, and running port. +pub(super) fn tool_get_version(ctx: &AppContext) -> Result { let build_hash = std::fs::read_to_string(".huskies/build_hash").unwrap_or_else(|_| "unknown".to_string()); serde_json::to_string_pretty(&json!({ "version": env!("CARGO_PKG_VERSION"), "build_hash": build_hash.trim(), + "port": ctx.agents.port(), })) .map_err(|e| format!("Serialization error: {e}")) } diff --git a/server/src/http/mcp/mod.rs b/server/src/http/mcp/mod.rs index ab1cff5c..3fda0d77 100644 --- a/server/src/http/mcp/mod.rs +++ b/server/src/http/mcp/mod.rs @@ -897,7 +897,7 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "get_version", - "description": "Return the server version and build hash.", + "description": "Return the server version, build hash, and running port.", "inputSchema": { "type": "object", "properties": {} @@ -1330,7 +1330,7 @@ async fn handle_tools_call(id: Option, params: &Value, ctx: &AppContext) "get_pipeline_status" => story_tools::tool_get_pipeline_status(ctx), // Diagnostics "get_server_logs" => diagnostics::tool_get_server_logs(&args), - "get_version" => diagnostics::tool_get_version(), + "get_version" => diagnostics::tool_get_version(ctx), // Server lifecycle "rebuild_and_restart" => diagnostics::tool_rebuild_and_restart(ctx).await, // Permission bridge (Claude Code → frontend dialog) diff --git a/server/src/io/fs/project.rs b/server/src/io/fs/project.rs index d7ddf28a..5237c2f2 100644 --- a/server/src/io/fs/project.rs +++ b/server/src/io/fs/project.rs @@ -37,6 +37,13 @@ pub(crate) async fn ensure_project_root_with_story_kit( if !path.join(".huskies").is_dir() { scaffold_story_kit(&path, port)?; } + // Always update .mcp.json with the current port so the bot connects to + // the right endpoint even when HUSKIES_PORT changes between restarts. + let mcp_content = format!( + "{{\n \"mcpServers\": {{\n \"huskies\": {{\n \"type\": \"http\",\n \"url\": \"http://localhost:{port}/mcp\"\n }}\n }}\n}}\n" + ); + fs::write(path.join(".mcp.json"), mcp_content) + .map_err(|e| format!("Failed to write .mcp.json: {}", e))?; Ok(()) }) .await @@ -194,16 +201,15 @@ mod tests { } #[tokio::test] - async fn open_project_does_not_overwrite_existing_mcp_json() { - // scaffold must NOT overwrite .mcp.json when it already exists — QA - // test servers share the real project root, and re-writing would - // clobber the file with the wrong port. + async fn open_project_updates_mcp_json_with_current_port() { + // .mcp.json must always be updated with the actual running port so the + // bot connects to the right MCP endpoint even when HUSKIES_PORT changes. let dir = tempdir().unwrap(); let project_dir = dir.path().join("myproject"); fs::create_dir_all(&project_dir).unwrap(); - // Pre-write .mcp.json with a different port to simulate an already-configured project. + // Pre-write .mcp.json with a different port to simulate a stale file. let mcp_path = project_dir.join(".mcp.json"); - fs::write(&mcp_path, "{\"existing\": true}").unwrap(); + fs::write(&mcp_path, "{\"stale\": true}").unwrap(); let store = make_store(&dir); let state = SessionState::default(); @@ -211,15 +217,19 @@ mod tests { project_dir.to_string_lossy().to_string(), &state, &store, - 3001, + 3002, ) .await .unwrap(); - assert_eq!( - fs::read_to_string(&mcp_path).unwrap(), - "{\"existing\": true}", - "open_project must not overwrite an existing .mcp.json" + let content = fs::read_to_string(&mcp_path).unwrap(); + assert!( + content.contains("3002"), + "open_project must update .mcp.json with the actual running port" + ); + assert!( + content.contains("localhost"), + "mcp.json must reference localhost" ); }