Servidor de Automação de Desktop Windows MCP.Net com .NET: Análise Detalhada

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

  1. Adicionar método à interface de serviço correspondente.
  2. Implementar a lógica específica na classe de serviço.
  3. Criar uma nova classe de ferramenta decorada com \[McpServerToolType\].
  4. 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.

Tags: dotnet Windows automation MCP desktop

Publicado em 8-3 20:22