Skip to content

Commit 553928f

Browse files
author
Ebersbach, Stephan
committed
Add code cleanup support for open documents in VS
Added RunCodeCleanupAsync to service interfaces, client, and server to enable code cleanup on open documents via DTE command. Introduced the document_cleanup server tool in DocumentTools for external access, with documentation and attributes for discoverability.
1 parent efee101 commit 553928f

6 files changed

Lines changed: 38 additions & 0 deletions

File tree

src/CodingWithCalvin.MCPServer.Server/RpcClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ public Task ShutdownAsync()
112112
public Task<bool> OpenDocumentAsync(string path) => Proxy.OpenDocumentAsync(path);
113113
public Task<bool> CloseDocumentAsync(string path, bool save) => Proxy.CloseDocumentAsync(path, save);
114114
public Task<bool> SaveDocumentAsync(string path) => Proxy.SaveDocumentAsync(path);
115+
public Task<bool> RunCodeCleanupAsync(string path) => Proxy.RunCodeCleanupAsync(path);
115116
public Task<string?> ReadDocumentAsync(string path) => Proxy.ReadDocumentAsync(path);
116117
public Task<bool> WriteDocumentAsync(string path, string content) => Proxy.WriteDocumentAsync(path, content);
117118
public Task<SelectionInfo?> GetSelectionAsync() => Proxy.GetSelectionAsync();

src/CodingWithCalvin.MCPServer.Server/Tools/DocumentTools.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ public async Task<string> SaveDocumentAsync(
7272
return success ? $"Saved: {path}" : $"Document not found or failed to save: {path}";
7373
}
7474

75+
[McpServerTool(Name = "document_cleanup", Destructive = true, Idempotent = true)]
76+
[Description("Run code cleanup on an open document in Visual Studio. The document must already be open in VS. Activates the document and executes the 'Edit.RunCodeCleanupOnFile' command.")]
77+
public async Task<string> RunCodeCleanupAsync(
78+
[Description("The full absolute path to the document. Must be open in VS. Get the path from document_list. Supports forward slashes (/) or backslashes (\\).")] string path)
79+
{
80+
var success = await _rpcClient.RunCodeCleanupAsync(path);
81+
return success ? $"Code cleanup completed: {path}" : $"Document not found or code cleanup failed: {path}";
82+
}
83+
7584
[McpServerTool(Name = "document_read", ReadOnly = true)]
7685
[Description("Read the contents of a document. If the document is open in VS, reads the current editor buffer (including unsaved changes); otherwise reads from disk.")]
7786
public async Task<string> ReadDocumentAsync(

src/CodingWithCalvin.MCPServer.Shared/RpcContracts.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public interface IVisualStudioRpc
2020
Task<bool> OpenDocumentAsync(string path);
2121
Task<bool> CloseDocumentAsync(string path, bool save);
2222
Task<bool> SaveDocumentAsync(string path);
23+
Task<bool> RunCodeCleanupAsync(string path);
2324
Task<string?> ReadDocumentAsync(string path);
2425
Task<bool> WriteDocumentAsync(string path, string content);
2526
Task<SelectionInfo?> GetSelectionAsync();

src/CodingWithCalvin.MCPServer/Services/IVisualStudioService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public interface IVisualStudioService
1616
Task<bool> OpenDocumentAsync(string path);
1717
Task<bool> CloseDocumentAsync(string path, bool save = true);
1818
Task<bool> SaveDocumentAsync(string path);
19+
Task<bool> RunCodeCleanupAsync(string path);
1920
Task<string?> ReadDocumentAsync(string path);
2021
Task<bool> WriteDocumentAsync(string path, string content);
2122
Task<SelectionInfo?> GetSelectionAsync();

src/CodingWithCalvin.MCPServer/Services/RpcServer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ public async Task RequestShutdownAsync()
170170
public Task<bool> OpenDocumentAsync(string path) => _vsService.OpenDocumentAsync(path);
171171
public Task<bool> CloseDocumentAsync(string path, bool save) => _vsService.CloseDocumentAsync(path, save);
172172
public Task<bool> SaveDocumentAsync(string path) => _vsService.SaveDocumentAsync(path);
173+
public Task<bool> RunCodeCleanupAsync(string path) => _vsService.RunCodeCleanupAsync(path);
173174
public Task<string?> ReadDocumentAsync(string path) => _vsService.ReadDocumentAsync(path);
174175
public Task<bool> WriteDocumentAsync(string path, string content) => _vsService.WriteDocumentAsync(path, content);
175176
public Task<SelectionInfo?> GetSelectionAsync() => _vsService.GetSelectionAsync();

src/CodingWithCalvin.MCPServer/Services/VisualStudioService.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,31 @@ public async Task<bool> SaveDocumentAsync(string path)
260260
return false;
261261
}
262262

263+
public async Task<bool> RunCodeCleanupAsync(string path)
264+
{
265+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
266+
var dte = await GetDteAsync();
267+
268+
foreach (Document doc in dte.Documents)
269+
{
270+
try
271+
{
272+
if (PathsEqual(doc.FullName, path))
273+
{
274+
doc.Activate();
275+
dte.ExecuteCommand("EditorContextMenus.FileHealthIndicator.RunDefaultCodeCleanup");
276+
return true;
277+
}
278+
}
279+
catch (Exception ex)
280+
{
281+
VsixTelemetry.TrackException(ex);
282+
}
283+
}
284+
285+
return false;
286+
}
287+
263288
public async Task<string?> ReadDocumentAsync(string path)
264289
{
265290
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

0 commit comments

Comments
 (0)