Este documento apresenta uma análise aprofundada do Windows MCP.Net, um servidor de automação de desktop para Windows desenvolvido em .NET 10.0. O projeto visa fornecer capacidades robustas de interação com o ambiente de desktop do Windows para assistentes de IA, utilizando o protocolo padronizado MCP (Model Context Protocol).
O sistema permite que assistentes de IA controlem diretamente o sistema Windows, possibilitando a automação de tarefas complexas no desktop.
Arquitetura do Sistema
O Windows MCP.Net adota uma arquitetura em camadas clássica, composta por:
- Camada de Protocolo MCP: Responsável pela comunicação via protocolo MCP.
- Camada de Ferramentas: Encapsula as funcionalidades em ferramentas padronizadas.
- Camada de Serviços: Implementa a lógica de negócio para as operações do desktop.
- Camada de Interface: Define contratos claros para os serviços.
- Camada de API do Windows: Interface direta com as APIs nativas do sistema Windows.
A estrutura de camadas é representada visualmente:
┌─────────────────────────────────────┐
│ Camada de Protocolo MCP │
├─────────────────────────────────────┤
│ Camada de Ferramentas │
├─────────────────────────────────────┤
│ Camada de Serviços │
├─────────────────────────────────────┤
│ Camada de Interface │
├─────────────────────────────────────┤
│ Camada de API do Windows │
└─────────────────────────────────────┘
Componentes Principais
1. Camada de Interface
Define contratos de serviço claros para desacoplamento:
// Interface do Serviço de Desktop
public interface IDesktopService
{
Task<string> GetDesktopStateAsync(bool useVision = false);
Task<(string Response, int Status)> ClickAsync(int x, int y, string button = "left", int clickCount = 1);
Task<(string Response, int Status)> TypeAsync(int x, int y, string text, bool clear = false, bool pressEnter = false);
// ... outros métodos
}
// Interface do Serviço de Sistema de Arquivos
public interface IFileSystemService
{
Task<(string Response, int Status)> CreateFileAsync(string path, string content);
Task<(string Content, int Status)> ReadFileAsync(string path);
Task<(string Response, int Status)> WriteFileAsync(string path, string content, bool append = false);
// ... outros métodos
}
// Interface do Serviço de Controle do Sistema
public interface ISystemControlService
{
Task<string> SetVolumeAsync(bool increase);
Task<string> SetVolumePercentAsync(int percent);
Task<string> SetBrightnessAsync(bool increase);
// ... outros métodos
}
2. Camada de Serviços
Implementa a lógica de negócio:
public class DesktopService : IDesktopService
{
private readonly ILogger<DesktopService> _logger;
// Declarações de API do Windows
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);
// Implementação da lógica de operação do desktop
public async Task<(string Response, int Status)> ClickAsync(int x, int y, string button = "left", int clickCount = 1)
{
try
{
SetCursorPos(x, y);
await Task.Delay(50); // Pequeno atraso para garantir o movimento do cursor
uint mouseDown, mouseUp;
switch (button.ToLower())
{
case "left":
mouseDown = 0x02; // MOUSEEVENTF_LEFTDOWN
mouseUp = 0x04; // MOUSEEVENTF_LEFTUP
break;
case "right":
mouseDown = 0x08; // MOUSEEVENTF_RIGHTDOWN
mouseUp = 0x10; // MOUSEEVENTF_RIGHTUP
break;
default:
return ("Tipo de botão inválido", 1);
}
for (int i = 0; i < clickCount; i++)
{
mouse_event(mouseDown, 0, 0, 0, 0);
mouse_event(mouseUp, 0, 0, 0, 0);
if (i < clickCount - 1) await Task.Delay(100);
}
return ($"Clique realizado com sucesso em ({x}, {y}) com botão {button} {clickCount} vez(es)", 0);
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao clicar em ({X}, {Y})", x, y);
return ($"Erro: {ex.Message}", 1);
}
}
// ... implementação de outros métodos
}
3. Camada de Ferramentas
Encapsula os serviços em ferramentas MCP:
[McpServerToolType]
public class ClickTool
{
private readonly IDesktopService _desktopService;
private readonly ILogger<ClickTool> _logger;
public ClickTool(IDesktopService desktopService, ILogger<ClickTool> logger)
{
_desktopService = desktopService;
_logger = logger;
}
[McpServerTool, Description("Clique em coordenadas específicas na tela")]
public async Task<string> ClickAsync(
[Description("Coordenada X")] int x,
[Description("Coordenada Y")] int y,
[Description("Botão do mouse: left, right, ou middle")] string button = "left",
[Description("Número de cliques: 1=simples, 2=duplo, 3=triplo")] int clickCount = 1)
{
_logger.LogInformation("Clicando em ({X}, {Y}) com botão {Button}, {ClickCount} vezes", x, y, button, clickCount);
var (response, status) = await _desktopService.ClickAsync(x, y, button, clickCount);
var result = new
{
success = status == 0,
message = response,
coordinates = new { x, y },
button,
clickCount
};
return JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true });
}
}
Módulos de Funcionalidade Principais
1. Módulo de Operações de Desktop
Oferece interações ricas com o desktop:
- Operações de Mouse: Clique, arraste, movimentação e rolagem.
- Operações de Teclado: Digitação de texto inteligente, pressionamento de teclas individuais e atalhos.
- Gerenciamento de Aplicações: Lançamento, alternância e redimensionamento de janelas.
2. Módulo de Sistema de Arquivos
Funcionalidades completas de manipulação de arquivos e diretórios:
// Exemplo de operação de arquivo
[McpServerTool, Description("Escreve conteúdo em um arquivo")]
public async Task<string> WriteFileAsync(
[Description("Caminho do arquivo para escrita")] string path,
[Description("Conteúdo a ser escrito")] string content,
[Description("Anexar ao conteúdo existente (true) ou sobrescrever (false)")] bool append = false)
{
try
{
_logger.LogInformation("Escrevendo no arquivo: {Path}, Anexar: {Append}", path, append);
var (response, status) = await _fileSystemService.WriteFileAsync(path, content, append);
var result = new
{
success = status == 0,
message = response,
path,
contentLength = content?.Length ?? 0,
append
};
return JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true });
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro em WriteFileAsync");
var errorResult = new
{
success = false,
message = $"Erro ao escrever no arquivo: {ex.Message}",
path,
append
};
return JsonSerializer.Serialize(errorResult, new JsonSerializerOptions { WriteIndented = true });
}
}
3. Módulo de Controle do Sistema
Controle de nível de sistema operacional:
- Controle de Volume: Ajuste de volume para um percentual específico.
- Controle de Brilho: Definição do brilho da tela.
- Controle de Resolução: Alteração da resolução da tela.
[McpServerTool, Description("Define o volume do sistema para uma porcentagem específica")]
public async Task<string> SetVolumePercentAsync(
[Description("Porcentagem de volume (0-100)")] int percent)
{
_logger.LogInformation("Definindo volume para {Percent}%", percent);
return await _systemControlService.SetVolumePercentAsync(percent);
}
4. Módulo de Reconhecimento OCR
Funcionalidades de reconhecimento óptico de caracteres:
- Extração de texto da tela (total ou por região).
- Localização de texto na tela.
- Obtenção de coordenadas de texto.
Análise de Implementação de Código
Injeção de Dependência e Registro de Serviços
Utiliza o contêiner de injeção de dependência do .NET para desacoplamento:
// Registro de serviços em Program.cs
var builder = Host.CreateApplicationBuilder(args);
// Configura o log para stderr (stdout é para mensagens do protocolo MCP)
builder.Logging.AddConsole(o => o.LogToStandardErrorThreshold = LogLevel.Trace);
// Registra serviços e ferramentas MCP
builder.Services
.AddSingleton<IDesktopService, DesktopService>()
.AddSingleton<IFileSystemService, FileSystemService>()
.AddSingleton<IOcrService, OcrService>()
.AddSingleton<ISystemControlService, SystemControlService>()
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly(Assembly.GetExecutingAssembly());
Tratamento de Erros e Logging
Adota um padrão unificado para tratamento de exceções:
try
{
// Lógica de negócio
var result = await SomeOperation();
return ("Mensagem de sucesso", 0);
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro na operação com parâmetros {Param1}, {Param2}", param1, param2);
return ($"Erro: {ex.Message}", 1);
}
Integração com APIs do Windows
Faz uso extensivo das APIs do Windows para funcionalidades de baixo nível:
// Declarações de API do Windows
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);
// Constantes
private const uint MOUSEEVENTF_LEFTDOWN = 0x02;
private const uint MOUSEEVENTF_LEFTUP = 0x04;
private const uint MOUSEEVENTF_RIGHTDOWN = 0x08;
private const uint MOUSEEVENTF_RIGHTUP = 0x10;
Cenários de Uso e Casos de Teste
1. Tarefas de Escritório Automatizadas
{
"tool": "launch_app",
"params": {
"name": "notepad"
}
}
{
"tool": "type",
"params": {
"x": 400,
"y": 300,
"text": "Este é um relatório gerado automaticamente\n\nData: 15 de Janeiro de 2024\nConteúdo: Sistema operando normalmente",
"clear": true
}
}
{
"tool": "key",
"params": {
"key": "ctrl+s"
}
}
2. Processamento em Lote de Aruqivos
{
"tool": "list_directory",
"params": {
"path": "C:\\Documents",
"includeFiles": true,
"recursive": false
}
}
{
"tool": "search_files_by_extension",
"params": {
"directory": "C:\\Documents",
"extension": ".txt",
"recursive": true
}
}
{
"tool": "copy_file",
"params": {
"source": "C:\\Documents\\report.txt",
"destination": "C:\\Backup\\report_backup.txt",
"overwrite": true
}
}
3. Monitoramento e Controle do Sistema
{
"tool": "get_desktop_state",
"params": {
"useVision": false
}
}
{
"tool": "set_volume_percent",
"params": {
"percent": 50
}
}
{
"tool": "set_brightness_percent",
"params": {
"percent": 80
}
}
Otimização de Desempenho e Melhores Práticas
1. Padrão de Programação Assíncrona
O uso extensivo de async/await melhora a concorrência:
public async Task<string> ProcessLargeFileAsync(string filePath)
{
// Operações de I/O assíncronas
var content = await File.ReadAllTextAsync(filePath);
// Processamento assíncrono
var processedContent = await ProcessContentAsync(content);
// Escrita assíncrona
await File.WriteAllTextAsync(filePath + ".processed", processedContent);
return "Processamento concluído";
}
2. Gerenciamento de Recursos
Implementação do padrão IDisposable para liberar recursos:
public class DesktopService : IDesktopService, IDisposable
{
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Liberar recursos gerenciados
}
// Liberar recursos não gerenciados
_disposed = true;
}
}
}
3. Estratégia de Cache
Uso de ConcurrentDictionary para cache de informações de jenela:
private readonly ConcurrentDictionary<string, WindowInfo> _windowCache = new();
public async Task<WindowInfo> GetWindowInfoAsync(string windowTitle)
{
return _windowCache.GetOrAdd(windowTitle, title =>
{
// Operação custosa para obter informações da janela
return GetWindowInfoFromSystem(title);
});
}
Guia de Desenvolvimento de Extensões
1. Adição de Novas Ferramentas
- Adicionar método à interface de serviço correspondente.
- Implementar a lógica específica na classe de serviço.
- Criar uma nova classe de ferramenta decorada com
\[McpServerToolType\]. - Expor o método de serviço através de um método público na clase de ferramenta, decorado com
\[McpServerTool\].
// Exemplo de adição de nova ferramenta
[McpServerToolType]
public class NewOperationTool
{
private readonly IDesktopService _desktopService;
// ... construtor e logger
[McpServerTool, Description("Descrição da nova operação")]
public async Task<string> ExecuteAsync(
[Description("Descrição do parâmetro")] string parameter)
{
_logger.LogInformation("Executando nova operação com parâmetro: {Parameter}", parameter);
var (response, status) = await _desktopService.NewOperationAsync(parameter);
// ... serialização do resultado
return "Resultado serializado";
}
}
2. Escrita de Testes Unitários
Utilizar frameworks de teste como xUnit para validar as ferramentas:
public class NewOperationToolTest
{
// ... setup do service provider e dependências
[Fact]
public async Task ExecuteAsync_ValidParameter_ReturnsSuccess()
{
// Arrange
var parameter = "test";
// Act
var result = await _tool.ExecuteAsync(parameter);
// Assert
Assert.NotNull(result);
var jsonResult = JsonSerializer.Deserialize<JsonElement>(result);
Assert.True(jsonResult.GetProperty("success").GetBoolean());
}
}
3. Gerenciamento de Configurações
Utilizar appsettings.json e IOptions para gerenciar configurações:
// appsettings.json
{
"WindowsMcp": {
"DefaultTimeout": 5000,
"MaxRetries": 3,
"EnableCaching": true
}
}
// Classe de opções
public class WindowsMcpOptions
{
public int DefaultTimeout { get; set; } = 5000;
public int MaxRetries { get; set; } = 3;
public bool EnableCaching { get; set; } = true;
}
// Registro em Program.cs
builder.Services.Configure<WindowsMcpOptions>(builder.Configuration.GetSection("WindowsMcp"));
Resumo e Perspectivas
O Windows MCP.Net representa um avanço significativo em automação de desktop com .NET. Seus pontos fortes incluem o uso de tecnologias modernas, arquitetura modular, conjunto completo de funcionalidades, conformidade com o protocolo MCP e alta qualidade de código.
As inovações destacam a integração pioneira do protocolo MCP, o design modular de ferramentas e o uso de programação assíncrona.
As direções futuras incluem a integração aprimorada com IA, suporte multiplataforma, integração com serviços em nuvem, fortalecimento da segurança e otimizações de desempenho.
Para os desenvolvedores, este projeto serve como um estudo de caso valioso em arquitetura .NET moderna, integração de APIs do Windows e desenvolvimento de automação de desktop.