🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2

Integração Completa com gRPC

Nesta segunda parte da série “Minha Primeira Comunicação com MCP e .NET”, exploramos como realizar uma integração completa com gRPC, permitindo que o MCP (Model Context Protocol) comunique-se com aplicações .NET…


This content originally appeared on DEV Community and was authored by Danilo O. Pinheiro, dopme.io

Integração Completa com gRPC

Nesta segunda parte da série "Minha Primeira Comunicação com MCP e .NET", exploramos como realizar uma integração completa com gRPC, permitindo que o MCP (Model Context Protocol) comunique-se com aplicações .NET de maneira eficiente, tipada e de alta performance.

🚀 Introdução

O MCP (Model Context Protocol) surge como uma camada de interoperabilidade entre modelos de linguagem, agentes e aplicações corporativas. No ecossistema .NET, a integração com gRPC é uma escolha natural, combinando tipagem forte, baixa latência e eficiência binária via Protocol Buffers — características ideais para comunicação entre processos e serviços distribuídos.

Este artigo demonstra, de forma arquitetural e prática, como criar uma ponte robusta entre MCP e aplicações .NET via gRPC, garantindo integração segura e escalável para sistemas modernos.

⚙️ O que é gRPC e por que usá-lo?

O gRPC (Google Remote Procedure Call) é um framework de comunicação que utiliza Protocol Buffers (protobuf) como formato de serialização binária. Ele substitui o tradicional REST em cenários que exigem alta performance, streaming bidirecional e comunicação eficiente entre microsserviços.

Benefícios principais:

  • 🚀 Performance superior: comunicação até 7x mais rápida que JSON/REST
  • 🔒 Contrato tipado: validação em tempo de compilação entre cliente e servidor
  • ⚙️ Streaming nativo: suporte a comunicação unidirecional e bidirecional
  • 🌐 Multiplataforma: compatibilidade com C#, Python, Go, Java, Node.js e mais
  • 📦 Payload compacto: serialização binária reduz tráfego de rede

🧠 Arquitetura da Integração MCP + gRPC + .NET

A integração segue uma arquitetura de orquestração bidirecional onde o MCP atua como cliente inteligente:

┌─────────────┐         ┌──────────────────┐         ┌─────────────────┐
│             │         │                  │         │                 │
│  MCP Agent  │ ◄────► │  gRPC Server     │ ◄────► │  Domain Layer   │
│  (Cliente)  │         │  (.NET 8)        │         │  Business Logic │
│             │         │                  │         │                 │
└─────────────┘         └──────────────────┘         └─────────────────┘
     ▲                           ▲                           ▲
     │                           │                           │
  Contexto                   Validação                   Persistência
  Semântico                  & Roteamento                 & Regras

Fluxo de comunicação:

  1. O MCP Agent envia comandos contextualizados ou dados estruturados
  2. O Servidor gRPC valida, autentica e roteia as mensagens
  3. A camada de domínio aplica regras de negócio e retorna resultados
  4. Respostas retornam via stream ou chamadas unitárias

🏗️ Implementação Passo a Passo

1️⃣ Criar o Projeto Base

dotnet new grpc -n MCPPipeline.GrpcServer
cd MCPPipeline.GrpcServer

O template gera automaticamente:

  • Estrutura de Protos/ para definição de contratos
  • Pasta Services/ para implementações
  • Configuração Kestrel otimizada para HTTP/2

2️⃣ Definir o Contrato Protobuf

Crie o arquivo Protos/mcp.proto:

syntax = "proto3";

option csharp_namespace = "MCPPipeline.Grpc";

package mcp;

// Serviço principal de comunicação MCP
service MCPService {
  // Comando único com resposta direta
  rpc SendCommand (MCPRequest) returns (MCPResponse);

  // Streaming bidirecional para múltiplas operações
  rpc StreamUpdates (stream MCPRequest) returns (stream MCPResponse);

  // Health check para monitoramento
  rpc HealthCheck (HealthRequest) returns (HealthResponse);
}

message MCPRequest {
  string command = 1;           // Comando a ser executado
  string payload = 2;           // Dados contextuais (JSON)
  map<string, string> metadata = 3;  // Metadados adicionais
  int64 timestamp = 4;          // Timestamp da requisição
}

message MCPResponse {
  string result = 1;            // Resultado da operação
  string status = 2;            // Status: OK, ERROR, PROCESSING
  string error_message = 3;     // Mensagem de erro (se houver)
  int64 processing_time_ms = 4; // Tempo de processamento
}

message HealthRequest {}

message HealthResponse {
  string status = 1;
  string version = 2;
}

Configure o .csproj para incluir o arquivo proto:

<ItemGroup>
  <Protobuf Include="Protos\mcp.proto" GrpcServices="Server" />
</ItemGroup>

3️⃣ Implementar o Serviço gRPC

using Grpc.Core;
using MCPPipeline.Grpc;
using System.Diagnostics;

namespace MCPPipeline.GrpcServer.Services;

public class MCPServiceImpl : MCPService.MCPServiceBase
{
    private readonly ILogger<MCPServiceImpl> _logger;
    private readonly IMCPCommandHandler _commandHandler;

    public MCPServiceImpl(
        ILogger<MCPServiceImpl> logger,
        IMCPCommandHandler commandHandler)
    {
        _logger = logger;
        _commandHandler = commandHandler;
    }

    public override async Task<MCPResponse> SendCommand(
        MCPRequest request, 
        ServerCallContext context)
    {
        var sw = Stopwatch.StartNew();

        try
        {
            _logger.LogInformation(
                "Comando recebido: {Command} | Payload: {Payload}", 
                request.Command, 
                request.Payload);

            // Processar comando via handler de domínio
            var result = await _commandHandler.ExecuteAsync(
                request.Command, 
                request.Payload,
                context.CancellationToken);

            sw.Stop();

            return new MCPResponse
            {
                Result = result,
                Status = "OK",
                ProcessingTimeMs = sw.ElapsedMilliseconds
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Erro ao processar comando: {Command}", request.Command);

            return new MCPResponse
            {
                Status = "ERROR",
                ErrorMessage = ex.Message,
                ProcessingTimeMs = sw.ElapsedMilliseconds
            };
        }
    }

    public override async Task StreamUpdates(
        IAsyncStreamReader<MCPRequest> requestStream,
        IServerStreamWriter<MCPResponse> responseStream,
        ServerCallContext context)
    {
        await foreach (var request in requestStream.ReadAllAsync(context.CancellationToken))
        {
            _logger.LogInformation("Stream recebido: {Command}", request.Command);

            var response = new MCPResponse
            {
                Result = $"Processando → {request.Command}",
                Status = "PROCESSING"
            };

            await responseStream.WriteAsync(response);
        }
    }

    public override Task<HealthResponse> HealthCheck(
        HealthRequest request, 
        ServerCallContext context)
    {
        return Task.FromResult(new HealthResponse
        {
            Status = "Healthy",
            Version = "1.0.0"
        });
    }
}

4️⃣ Implementar o Command Handler (Domain Layer)

public interface IMCPCommandHandler
{
    Task<string> ExecuteAsync(string command, string payload, CancellationToken ct);
}

public class MCPCommandHandler : IMCPCommandHandler
{
    private readonly ILogger<MCPCommandHandler> _logger;

    public MCPCommandHandler(ILogger<MCPCommandHandler> logger)
    {
        _logger = logger;
    }

    public async Task<string> ExecuteAsync(
        string command, 
        string payload, 
        CancellationToken ct)
    {
        return command switch
        {
            "GetStatus" => await GetSystemStatusAsync(ct),
            "ProcessData" => await ProcessDataAsync(payload, ct),
            "AnalyzeContext" => await AnalyzeContextAsync(payload, ct),
            _ => throw new InvalidOperationException($"Comando desconhecido: {command}")
        };
    }

    private async Task<string> GetSystemStatusAsync(CancellationToken ct)
    {
        await Task.Delay(10, ct); // Simula processamento
        return "Sistema operacional | Uptime: 99.9%";
    }

    private async Task<string> ProcessDataAsync(string payload, CancellationToken ct)
    {
        _logger.LogInformation("Processando dados: {Payload}", payload);
        await Task.Delay(50, ct);
        return $"Dados processados com sucesso: {payload.Length} caracteres";
    }

    private async Task<string> AnalyzeContextAsync(string payload, CancellationToken ct)
    {
        await Task.Delay(100, ct);
        return $"Análise contextual concluída | Tokens: {payload.Split(' ').Length}";
    }
}

5️⃣ Configurar o Servidor no Program.cs

using MCPPipeline.GrpcServer.Services;

var builder = WebApplication.CreateBuilder(args);

// Adicionar serviços gRPC
builder.Services.AddGrpc(options =>
{
    options.EnableDetailedErrors = true;
    options.MaxReceiveMessageSize = 4 * 1024 * 1024; // 4MB
});

// Registrar handlers de domínio
builder.Services.AddScoped<IMCPCommandHandler, MCPCommandHandler>();

var app = builder.Build();

// Mapear serviços gRPC
app.MapGrpcService<MCPServiceImpl>();

// Endpoint HTTP para verificação
app.MapGet("/", () => Results.Ok(new 
{ 
    Service = "MCP gRPC Server", 
    Status = "Running",
    Version = "1.0.0"
}));

app.Run();

Configuração do appsettings.json:

{
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http2"
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Grpc": "Debug"
    }
  }
}

6️⃣ Criar Cliente MCP (Simulação)

using Grpc.Net.Client;
using MCPPipeline.Grpc;

// Configurar canal gRPC
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new MCPService.MCPServiceClient(channel);

// Exemplo 1: Comando único
var response = await client.SendCommandAsync(new MCPRequest
{
    Command = "GetStatus",
    Payload = "Kernel v2.0",
    Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
});

Console.WriteLine($"✅ Resposta: {response.Result}");
Console.WriteLine($"⏱️  Tempo: {response.ProcessingTimeMs}ms");

// Exemplo 2: Streaming bidirecional
using var streamingCall = client.StreamUpdates();

// Enviar múltiplos comandos
await streamingCall.RequestStream.WriteAsync(new MCPRequest 
{ 
    Command = "ProcessData", 
    Payload = "Sample data batch 1" 
});

await streamingCall.RequestStream.WriteAsync(new MCPRequest 
{ 
    Command = "AnalyzeContext", 
    Payload = "Context information" 
});

await streamingCall.RequestStream.CompleteAsync();

// Receber respostas
await foreach (var streamResponse in streamingCall.ResponseStream.ReadAllAsync())
{
    Console.WriteLine($"📥 Stream: {streamResponse.Result}");
}

🔗 Integração com MCP Kernel

Para integrar com o Semantic Kernel ou outro framework MCP:

public class MCPGrpcPlugin
{
    private readonly MCPService.MCPServiceClient _grpcClient;

    public MCPGrpcPlugin(MCPService.MCPServiceClient grpcClient)
    {
        _grpcClient = grpcClient;
    }

    [KernelFunction, Description("Executa comando no servidor MCP via gRPC")]
    public async Task<string> ExecuteCommandAsync(
        [Description("Comando a executar")] string command,
        [Description("Dados contextuais")] string payload)
    {
        var response = await _grpcClient.SendCommandAsync(new MCPRequest
        {
            Command = command,
            Payload = payload,
            Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
        });

        return response.Status == "OK" 
            ? response.Result 
            : $"Erro: {response.ErrorMessage}";
    }
}

Registro no Kernel:

var kernel = Kernel.CreateBuilder()
    .AddOpenAIChatCompletion("gpt-4", apiKey)
    .Build();

var grpcChannel = GrpcChannel.ForAddress("https://localhost:5001");
var grpcClient = new MCPService.MCPServiceClient(grpcChannel);

kernel.Plugins.AddFromObject(new MCPGrpcPlugin(grpcClient), "MCPCommands");

🔒 Boas Práticas e Segurança

Autenticação e Segurança

// Adicionar autenticação JWT
builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true
        };
    });

builder.Services.AddAuthorization();

Observabilidade

// OpenTelemetry para tracing distribuído
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddGrpcClientInstrumentation()
        .AddOtlpExporter());

Resiliência

// Polly para retry e circuit breaker
services.AddGrpcClient<MCPService.MCPServiceClient>(o =>
{
    o.Address = new Uri("https://localhost:5001");
})
.AddPolicyHandler(Policy
    .HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
    .WaitAndRetryAsync(3, retryAttempt => 
        TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))));

📊 Quando Usar gRPC com MCP

Microsserviços internos com alta frequência de comunicação

Streaming de dados em tempo real (logs, métricas, eventos)

Pipelines de IA que exigem baixa latência (<10ms)

Comunicação entre agentes distribuídos em Kubernetes

APIs internas onde tipagem forte previne erros em produção

Evite usar quando:

  • Precisar de suporte em navegadores web (sem HTTP/2 full)
  • Integração com sistemas legados sem suporte a Protobuf
  • APIs públicas onde REST/JSON é mais apropriado

🎯 Conclusão

A integração entre MCP e gRPC no .NET cria uma base sólida para sistemas inteligentes e distribuídos, unindo a velocidade e confiabilidade do gRPC com a inteligência contextual do Model Context Protocol. Essa combinação é ideal para pipelines de IA corporativos onde precisão, performance e interoperabilidade são essenciais.

Próximos passos:

  • Implementar autenticação mTLS para produção
  • Adicionar cache distribuído (Redis) para respostas frequentes
  • Configurar balanceamento de carga com health checks gRPC
  • Instrumentar com OpenTelemetry para observabilidade completa

Na Parte 3 desta série, exploraremos observabilidade e tracing distribuído entre MCP e .NET usando OpenTelemetry e Datadog.

🤝 Conecte-se Comigo

Se você trabalha com .NET moderno e quer dominar arquitetura, C#, observabilidade, DevOps ou interoperabilidade:

💼 LinkedIn
✍️ Medium

📬 contato@dopme.io

📬 devsfree@devsfree.com.br

📚 Referências:

² Porque eis que teus inimigos fazem tumulto, e os que te odeiam levantaram a cabeça. ³ Tomaram astuto conselho contra o teu povo, e consultaram contra os teus escondidos. Salmos 83:2,3


This content originally appeared on DEV Community and was authored by Danilo O. Pinheiro, dopme.io


Print Share Comment Cite Upload Translate Updates
APA

Danilo O. Pinheiro, dopme.io | Sciencx (2025-10-19T18:16:11+00:00) 🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2. Retrieved from https://www.scien.cx/2025/10/19/%f0%9f%a7%a9-minha-primeira-comunicacao-com-mcp-e-net-parte-2/

MLA
" » 🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2." Danilo O. Pinheiro, dopme.io | Sciencx - Sunday October 19, 2025, https://www.scien.cx/2025/10/19/%f0%9f%a7%a9-minha-primeira-comunicacao-com-mcp-e-net-parte-2/
HARVARD
Danilo O. Pinheiro, dopme.io | Sciencx Sunday October 19, 2025 » 🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2., viewed ,<https://www.scien.cx/2025/10/19/%f0%9f%a7%a9-minha-primeira-comunicacao-com-mcp-e-net-parte-2/>
VANCOUVER
Danilo O. Pinheiro, dopme.io | Sciencx - » 🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/10/19/%f0%9f%a7%a9-minha-primeira-comunicacao-com-mcp-e-net-parte-2/
CHICAGO
" » 🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2." Danilo O. Pinheiro, dopme.io | Sciencx - Accessed . https://www.scien.cx/2025/10/19/%f0%9f%a7%a9-minha-primeira-comunicacao-com-mcp-e-net-parte-2/
IEEE
" » 🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2." Danilo O. Pinheiro, dopme.io | Sciencx [Online]. Available: https://www.scien.cx/2025/10/19/%f0%9f%a7%a9-minha-primeira-comunicacao-com-mcp-e-net-parte-2/. [Accessed: ]
rf:citation
» 🧩 Minha Primeira Comunicação com MCP e .NET – Parte 2 | Danilo O. Pinheiro, dopme.io | Sciencx | https://www.scien.cx/2025/10/19/%f0%9f%a7%a9-minha-primeira-comunicacao-com-mcp-e-net-parte-2/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.