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:
- O MCP Agent envia comandos contextualizados ou dados estruturados
- O Servidor gRPC valida, autentica e roteia as mensagens
- A camada de domínio aplica regras de negócio e retorna resultados
- 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
Top comments (0)