From d86162c72d6c33c1da16235955fec4188856e34d Mon Sep 17 00:00:00 2001 From: Hwany Date: Wed, 1 Jul 2026 21:25:44 +0900 Subject: [PATCH] fix(build): make build/clean tools non-blocking to match async contract BuildSolution, BuildProject and CleanSolution called the EnvDTE SolutionBuild APIs with WaitForBuildToFinish/WaitForCleanToFinish set to true, on the UI thread. This blocks the Visual Studio main thread until the entire build/clean completes, which contradicts the tool description ("runs asynchronously; use build_status to check progress; returns immediately after starting the build"). Two consequences: - For large solutions the RPC call never returns in time and the MCP client reports "The operation timed out.", instead of "Build started". - While the UI thread is blocked, build_status/build_cancel cannot run, so the documented polling workflow is impossible. Pass false so the build/clean is queued and the call returns immediately, letting build_status observe the InProgress -> Done transition as intended. --- .../Services/VisualStudioService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CodingWithCalvin.MCPServer/Services/VisualStudioService.cs b/src/CodingWithCalvin.MCPServer/Services/VisualStudioService.cs index 95dd653..0a642f2 100644 --- a/src/CodingWithCalvin.MCPServer/Services/VisualStudioService.cs +++ b/src/CodingWithCalvin.MCPServer/Services/VisualStudioService.cs @@ -621,7 +621,7 @@ public async Task BuildSolutionAsync() try { - dte.Solution.SolutionBuild.Build(true); + dte.Solution.SolutionBuild.Build(false); return true; } catch (Exception ex) @@ -643,7 +643,7 @@ public async Task BuildProjectAsync(string projectName) { var config = dte.Solution.SolutionBuild.ActiveConfiguration.Name; var normalizedPath = NormalizePath(projectName); - dte.Solution.SolutionBuild.BuildProject(config, normalizedPath, true); + dte.Solution.SolutionBuild.BuildProject(config, normalizedPath, false); return true; } catch (Exception ex) @@ -663,7 +663,7 @@ public async Task CleanSolutionAsync() try { - dte.Solution.SolutionBuild.Clean(true); + dte.Solution.SolutionBuild.Clean(false); return true; } catch (Exception ex)