Workshop: Criando Agentes de IA com MCP em C#
📋 Índice
- Sobre este Workshop
- Pré-requisitos
- Configuração do Ambiente
- Módulo 1: Fundamentos do MCP
- Módulo 2: Primeiro MCP Server com Tools
- Módulo 3: Trabalhando com Prompts
- Módulo 4: Conexão Local (stdio)
- Módulo 5: Conexão Remota (HTTP)
- Módulo 6: Integração com Clientes de IA
- Troubleshooting
- Recursos Adicionais
📚 Documentação Complementar
Este README é o guia prático principal. Para aprofundamento teórico, consulte:
- 📖 Conceitos Fundamentais do MCP - Explicação detalhada de todos os conceitos MCP mapeados ao código deste projeto
- 🔗 Referências Complementares - Links oficiais, tutoriais avançados e padrões de design relacionados ao código existente
Sobre este Workshop
Este workshop ensina como criar agentes de IA usando o Model Context Protocol (MCP) em C#. O MCP é um protocolo aberto que padroniza como aplicações fornecem contexto para Large Language Models (LLMs).
O que você vai aprender
- ✅ Criar MCP Servers em C#
- ✅ Implementar Tools (ferramentas) que LLMs podem usar
- ✅ Criar Prompts reutilizáveis
- ✅ Conectar servidores localmente (stdio) e remotamente (HTTP)
- ✅ Integrar com GitHub Copilot e ferramentas de IA
- ✅ Debugar comunicação com MCP Inspector
Estrutura Real do Projeto
Este workshop contém implementações funcionais prontas para uso:
src/
├── ToolsServer/ → Servidor com ferramentas (calculadora + texto)
├── PromptsServer/ → Servidor com prompts para LLMs
│ └── PromptsServer/
├── ClienteLocal/ → Cliente stdio (conexão local)
│ └── McpClient/
├── ClienteRemoto/ → Cliente HTTP (conexão remota)
│ └── HttpMcpClient/
└── ServidorRemoto/ → Servidor HTTP
└── HttpMcpServer/Cada projeto está completo e pode ser executado independentemente!
Pré-requisitos
Software Necessário
- Visual Studio Code
- Instalar de:
- .NET 9.0 SDK (ou superior)
dotnet --version
# Deve retornar 9.0 ou superior- Instalar de:
- Node.js (v18+) - para ferramentas auxiliares
node --version
npm --version- Instalar de:
- MCP Inspector (para debug)
npm install -g @modelcontextprotocol/inspector- GitHub Copilot CLI (opcional)
npm install -g @github/copilotExtensões do VS Code Recomendadas
- C# Dev Kit
- C# (Microsoft)
- REST Client (para testar endpoints HTTP)
Conhecimentos Prévios
- C# básico a intermediário
- Conceitos de async/await
- JSON básico
- Linha de comando (PowerShell)
Configuração do Ambiente
1. Clone ou Baixe este Repositório
git clone
cd AgentesWorkShop2. Estrutura do Projeto
Agentes/
├── README.md (este arquivo)
├── src/
│ ├── ToolsServer/ # Servidor MCP com ferramentas (calculadora, texto)
│ ├── PromptsServer/ # Servidor MCP com prompts reutilizáveis
│ │ └── PromptsServer/
│ ├── ClienteLocal/ # Cliente MCP usando conexão stdio
│ │ └── McpClient/
│ ├── ClienteRemoto/ # Cliente MCP usando conexão HTTP
│ │ └── HttpMcpClient/
│ └── ServidorRemoto/ # Servidor MCP acessível via HTTP
│ └── HttpMcpServer/
├── configs/
│ ├── copilot-config.json
│ └── copilot-cli-config.json
└── docs/
└── referencias.md3. Compilar Todos os Projetos
# Compilar solução principal (todos os projetos)
cd src
dotnet build AgentesWorkShop.sln
# Ou compilar individualmente:
# ToolsServer
cd ToolsServer
dotnet build
# PromptsServer
cd ..\PromptsServer\PromptsServer
dotnet build
# ClienteLocal
cd ..\..\ClienteLocal\McpClient
dotnet build
# ServidorRemoto
cd ..\..\ServidorRemoto\HttpMcpServer
dotnet build
# ClienteRemoto
cd ..\..\ClienteRemoto\HttpMcpClient
dotnet build4. Informações Importantes
Versões Utilizadas:
- .NET: 9.0
- ModelContextProtocol: 0.4.0-preview.1
- ModelContextProtocol.AspNetCore: 0.4.0-preview.1
- Microsoft.Extensions.Hosting: 9.0.9
Principais Mudanças em Relação à Versão Inicial:
- ✅ Uso correto de
McpClient.CreateAsync()com opções configuráveis - ✅ Implementação de
ServerInfoeServerInstructionspara melhor contexto - ✅ Configuração de logging para stderr (separado do protocolo)
- ✅ Uso de
MapMcp()simplificado para servidores HTTP - ✅ Suporte a
HttpClientTransportcom auto-detecção de modo - ✅ Tratamento robusto de conteúdo (TextContentBlock vs JsonContentBlock)
- ✅ Configurações de timeout e capabilities no cliente
- ✅ Atributo
[McpServerTool(Name = "...")]para nomes explícitos
Módulo 1: Fundamentos do MCP
O que é MCP?
O Model Context Protocol permite que LLMs acessem ferramentas e dados de forma padronizada. Pense nele como uma "API universal" para LLMs.
Componentes principais:
- Server: Expõe ferramentas (tools) e prompts
- Client: Conecta-se ao servidor e usa suas capacidades
- Transport: Canal de comunicação (stdio ou HTTP)
🎯 Arquitetura do Protocolo no Projeto
O MCP é baseado em JSON-RPC 2.0 (Especificação) e define três componentes principais implementados neste workshop:
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ McpClient │ ◄─────► │ Transport │ ◄─────► │ MCP Server │
│ (Host/Cliente) │ │ (stdio ou HTTP) │ │ (Tools/Prompts) │
└─────────────────┘ └─────────────────┘ └──────────────────┘Implementações no Projeto
Clientes:
McpClient- Cliente stdio localHttpMcpClient- Cliente HTTP remoto
Servidores:
ToolsServer- Servidor stdio com toolsPromptsServer- Servidor stdio com prompts e tools auxiliaresHttpMcpServer- Servidor HTTP remoto
Transports:
- stdio: Comunicação através de stdin/stdout (local)
- HTTP/SSE: Comunicação através de HTTP com Server-Sent Events (remoto)
📚 Conceitos Fundamentais Implementados
1. Tools (Ferramentas)
Funções executáveis que o LLM pode chamar. São stateless e idempotentes quando possível.
Exemplo do ToolsServer:
[McpServerTool(Name = "add"), Description("Soma dois números")]
public static double Add(
[Description("Primeiro número")] double a,
[Description("Segundo número")] double b)
{
return a + b;
}Fluxo de Execução (implementado em McpClient):
// 1. Cliente solicita lista de tools
var tools = await client.ListToolsAsync(cancellationToken: cts.Token);
// 2. Servidor responde com metadados (nome, descrição, parâmetros)
foreach (var tool in tools)
{
Console.WriteLine($" • {tool.Name}: {tool.Description}");
}
// 3. Cliente chama tool específica
var addResult = await client.CallToolAsync(
"add",
new Dictionary { ["a"] = 10, ["b"] = 5 },
cancellationToken: cts.Token);
// 4. Servidor executa e retorna resultadoCategorias de Tools no Projeto:
a) Operações Matemáticas (CalculatorTools):
add,subtract,multiply,divide- Validação: divisão por zero
b) Manipulação de Texto (TextTools):
toUpperCase,toLowerCase,reverseTextcountWords,countCharacters- Validação: entrada não nula/vazia
c) Informações do Sistema (RemoteTools):
GetSystemInfo: informações de máquina, SO, CPUGenerateUuid: geração de identificadores únicosCalculateHash: hash SHA256 de textoGetCurrentTime: data/hora em múltiplos formatosGetProcessInfo: estatísticas do processo
⚠️ Pontos de Atenção da Implementação:
- Use o atributo
Nameexplicitamente para controlar o nome da tool - Sempre adicione
Descriptionpara parâmetros e métodos (ajuda o LLM a entender) - Ferramentas devem ser
statice marcadas com[McpServerTool] - A classe deve ser marcada com
[McpServerToolType] - Valide entradas (exemplo:
ArgumentException.ThrowIfNullOrEmpty)
2. Prompts (Templates)
Templates reutilizáveis para interações com LLM. Permitem parametrização e consistência.
Exemplo do PromptsServer:
[McpServerPrompt(Name = "code_review"), Description("Cria um prompt de revisão de código")]
public static ChatMessage CodeReview(
[Description("Código para revisar")] string code,
[Description("Linguagem de programação")] string language = "C#")
{
return new ChatMessage(ChatRole.User,
$"Revise o seguinte código {language} e forneça sugestões de melhoria:\n\n{code}");
}Quando usar Prompts vs Tools:
| Aspecto | Prompts | Tools |
|---|---|---|
| Propósito | Guiar conversação, análises | Executar ações, buscar dados |
| Retorno | ChatMessage | Dados estruturados |
| Estado | Stateless | Stateless (idealmente) |
| Exemplo no Projeto | code_review, summarize_text | add, GetSystemInfo |
Categorias de Prompts no Projeto:
a) Desenvolvimento (DeveloperPrompts):
code_review: revisão de códigoexplain_code: explicação didáticadocument_function: geração de documentação XMLrefactor_code: refatoração com objetivo específico
b) Escrita (WritingPrompts):
summarize_text: resumo com limite de palavrasimprove_writing: melhoria de redaçãotranslate_text: tradução para idioma alvocheck_grammar: correção gramatical
c) Tools Auxiliares (PromptHelpers):
list_available_prompts: lista todos os promptsget_prompt_info: informações detalhadas de um promptvalidate_prompt_args: valida argumentos JSON
⚠️ Pontos de Atenção da Implementação:
- Use
ChatMessagedo namespaceMicrosoft.Extensions.AI - Prompts devem retornar
ChatMessagecom role apropriado (ChatRole.User) - A classe deve ser marcada com
[McpServerPromptType] - Use parâmetros opcionais com valores padrão úteis
3. Resources (Recursos)
Dados ou arquivos que o servidor disponibiliza. Podem ser estáticos ou dinâmicos.
Tipos suportados pelo protocolo:
file://- Arquivos locaishttp://- Recursos web- Custom URIs - Esquemas personalizados
📝 Nota: Resources não foram implementados neste workshop básico, mas são parte da Especificação MCP.
🔄 Ciclo de Vida de uma Sessão MCP
Implementado em todos os clientes (McpClient, HttpMcpClient):
1. Initialize → Cliente e servidor trocam capabilities
(McpClient.CreateAsync)
2. Initialized → Sessão estabelecida
(Informações do servidor disponíveis)
3. Request/Response → Troca de mensagens
• ListToolsAsync() - listar tools
• CallToolAsync() - chamar tool
• GetPromptAsync() - obter prompt
4. Notifications → Mudanças de estado (opcional)
5. Shutdown → Encerramento gracioso
(await using - IAsyncDisposable)Exemplo de Inicialização (McpClient/Program.cs):
var clientOptions = new McpClientOptions
{
ClientInfo = new Implementation
{
Name = "McpClient Demo",
Version = "1.0.0"
},
InitializationTimeout = TimeSpan.FromSeconds(30),
Capabilities = new ClientCapabilities()
};
await using var client = await McpClient.CreateAsync(
clientTransport,
clientOptions,
loggerFactory,
cts.Token);
// Sessão estabelecida - informações disponíveis
Console.WriteLine($"Servidor: {client.ServerInfo.Name} v{client.ServerInfo.Version}");
Console.WriteLine($"Protocolo: {client.NegotiatedProtocolVersion}");📊 ServerInfo e ServerInstructions
Conceito importante: Fornecer contexto rico para o LLM entender as capacidades do servidor.
Implementação em ToolsServer:
builder.Services
.AddMcpServer(options =>
{
options.ServerInfo = new()
{
Name = "ToolsServer",
Version = "1.0.0"
};
options.ServerInstructions = "Servidor MCP com ferramentas de calculadora e manipulação de texto.";
})Implementação em HttpMcpServer:
options.ServerInstructions = """
Este é um servidor MCP HTTP remoto que fornece ferramentas de informações do sistema.
Ferramentas disponíveis:
- GetSystemInfo: Retorna informações detalhadas do sistema...
- GenerateUuid: Gera um UUID único
- CalculateHash: Calcula hash SHA256
...
""";Benefício: LLMs usam essas informações para decidir quando e como usar as tools disponíveis.
🔗 Referências da Especificação
| Conceito | Implementado em | Link Oficial |
|---|---|---|
| Core Protocol | Todos os servidores/clientes | Especificação Core |
| Tools | ToolsServer, HttpMcpServer, PromptsServer | Especificação Tools |
| Prompts | PromptsServer | Especificação Prompts |
| Transport stdio | ToolsServer, PromptsServer, McpClient | Especificação Transports |
| Transport HTTP | HttpMcpServer, HttpMcpClient | Especificação HTTP/SSE |
Módulo 2: Primeiro MCP Server com Tools
Objetivo
Criar um servidor MCP simples que expõe ferramentas úteis usando transporte stdio.
Localização
Estrutura do Projeto
O projeto utiliza:
- .NET 9.0 como framework
- ModelContextProtocol 0.4.0-preview.1 - pacote principal do SDK
- Microsoft.Extensions.Hosting 9.0.9 - para hospedagem e dependency injection
Configuração do Servidor
Pontos-chave da implementação:
- Configuração de Logging:
builder.Logging.AddConsole(options =>
{
options.LogToStandardErrorThreshold = LogLevel.Trace;
});⚠️ Importante: O MCP usa stdout para comunicação do protocolo, então logs devem ir para stderr.
- Configuração do Servidor MCP:
builder.Services
.AddMcpServer(options =>
{
options.ServerInfo = new()
{
Name = "ToolsServer",
Version = "1.0.0"
};
options.ServerInstructions = "Servidor MCP com ferramentas de calculadora e manipulação de texto.";
})
.WithStdioServerTransport()
.WithToolsFromAssembly();⚠️ Importante: ServerInfo e ServerInstructions ajudam LLMs a entender as capacidades do servidor.
Implementação das Tools
O servidor implementa duas categorias de ferramentas:
1. CalculatorTools - Operações matemáticas
Pontos-chave:
[McpServerToolType]
public static class CalculatorTools
{
[McpServerTool(Name = "add"), Description("Soma dois números")]
public static double Add(
[Description("Primeiro número")] double a,
[Description("Segundo número")] double b)
{
return a + b;
}
[McpServerTool(Name = "divide"), Description("Divide dois números")]
public static double Divide(
[Description("Numerador (dividendo)")] double a,
[Description("Denominador (divisor)")] double b)
{
if (b == 0)
throw new ArgumentException("Não é possível dividir por zero");
return a / b;
}
}⚠️ Pontos de Atenção:
- Nomes explícitos com
Name = "..."(camelCase) - Validação de entrada (divisão por zero)
- Descrições claras para parâmetros
2. TextTools - Manipulação de texto
Pontos-chave:
[McpServerToolType]
public static class TextTools
{
[McpServerTool(Name = "toUpperCase"), Description("Converte texto para maiúsculas")]
public static string ToUpperCase(
[Description("Texto a converter")] string text)
{
ArgumentException.ThrowIfNullOrEmpty(text, nameof(text));
return text.ToUpper();
}
[McpServerTool(Name = "countWords"), Description("Conta o número de palavras no texto")]
public static int CountWords(
[Description("Texto para contar palavras")] string text)
{
if (string.IsNullOrWhiteSpace(text))
return 0;
return text.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
}
}⚠️ Pontos de Atenção:
- Validação robusta de entrada
- Tratamento de casos especiais (texto vazio, null)
- Retorno de tipos simples (string, int, double)
Executar o Servidor
cd src\ToolsServer
dotnet run💡 Dica: O servidor aguardará conexões via stdin/stdout e não exibirá output visível até que um cliente se conecte.
Referência Completa
Veja a implementação completa em src/ToolsServer/Program.cs
🏗️ Padrões de Design Utilizados no Projeto
Padrão 1: Validação de Entrada em Tools
Onde: ToolsServer/Program.cs, HttpMcpServer/Program.cs
Problema: Entradas inválidas podem causar exceções ou comportamento inesperado.
Solução implementada:
// Validação em TextTools
[McpServerTool(Name = "toUpperCase")]
public static string ToUpperCase([Description("Texto a converter")] string text)
{
ArgumentException.ThrowIfNullOrEmpty(text, nameof(text)); // ✅ Validação
return text.ToUpper();
}
// Validação em CalculatorTools
[McpServerTool(Name = "divide")]
public static double Divide(double a, double b)
{
if (b == 0) // ✅ Validação de regra de negócio
throw new ArgumentException("Não é possível dividir por zero");
return a / b;
}
// Validação em RemoteTools
[McpServerTool]
public static string CalculateHash(string input)
{
if (string.IsNullOrEmpty(input)) // ✅ Validação explícita
throw new ArgumentException("A entrada não pode ser nula ou vazia", nameof(input));
using var sha256 = System.Security.Cryptography.SHA256.Create();
// ... implementação
}Benefícios:
- Mensagens de erro claras para o LLM
- Evita comportamento indefinido
- Facilita debug
Padrão 2: Extração Robusta de Conteúdo
Onde: McpClient/Program.cs, HttpMcpClient/Program.cs
Problema: Tools podem retornar diferentes tipos de conteúdo (text, json).
Solução implementada em McpClient:
static string ExtractTextContent(CallToolResult result)
{
// ✅ Verificação de null
if (result?.Content == null || !result.Content.Any())
return "N/A";
// ✅ Procurar por conteúdo do tipo texto
var textContent = result.Content.FirstOrDefault(c => c.Type == "text");
if (textContent != null)
{
// ✅ Serialização segura para acessar propriedades
var json = JsonSerializer.SerializeToElement(textContent);
if (json.TryGetProperty("text", out var textProp))
{
return textProp.GetString() ?? "N/A";
}
}
return "N/A"; // ✅ Fallback
}Solução implementada em HttpMcpClient:
static string GetContentString(CallToolResult result)
{
// ✅ Tentar TextContentBlock primeiro
if (result.Content.FirstOrDefault(c => c.Type == "text") is TextContentBlock textBlock)
{
return textBlock.Text ?? "N/A";
}
// ✅ Tentar JSON block - handle como JsonElement
if (result.Content.FirstOrDefault(c => c.Type == "json") is var jsonBlock && jsonBlock != null)
{
try
{
var jsonProp = jsonBlock.GetType().GetProperty("Json");
if (jsonProp?.GetValue(jsonBlock) is JsonElement jsonElement)
{
return JsonSerializer.Serialize(jsonElement, new JsonSerializerOptions { WriteIndented = true });
}
}
catch { /* Fallback */ }
}
return "N/A"; // ✅ Fallback
}Benefícios:
- Trata múltiplos tipos de retorno
- Nunca falha (sempre retorna algo)
- Código robusto e resiliente
Padrão 3: Logging para stderr
Onde: Todos os servidores (ToolsServer, PromptsServer, HttpMcpServer)
Problema: MCP usa stdout para comunicação do protocolo.
Solução implementada:
// ✅ Configurar logs para stderr
builder.Logging.AddConsole(options =>
{
options.LogToStandardErrorThreshold = LogLevel.Trace;
});Por que é importante:
- stdout: reservado para mensagens JSON-RPC do protocolo MCP
- stderr: usado para logs, debug, diagnóstico
- Separação evita corrupção da comunicação
Referência: Especificação stdio Transport
Padrão 4: Tratamento de Erros Hierárquico
Onde: McpClient/Program.cs
Problema: Diferentes tipos de erro requerem tratamentos diferentes.
Solução implementada:
try
{
// ... código do cliente ...
}
catch (OperationCanceledException)
{
Console.WriteLine("\n❌ Operação cancelada pelo usuário.");
}
catch (TimeoutException ex)
{
Console.WriteLine($"\n❌ Timeout durante conexão: {ex.Message}");
}
catch (McpException ex) // ✅ Exceção específica do protocolo
{
Console.WriteLine($"\n❌ Erro do protocolo MCP: {ex.Message}");
}
catch (Exception ex) // ✅ Catch-all como último recurso
{
Console.WriteLine($"\n❌ Erro inesperado: {ex.GetType().Name}");
Console.WriteLine($" Mensagem: {ex.Message}");
}Hierarquia:
- Mais específico (
OperationCanceledException) - Médio (
TimeoutException,McpException) - Genérico (
Exception)
Benefícios:
- Mensagens de erro apropriadas ao contexto
- Facilita troubleshooting
- UX melhor para o usuário
Padrão 5: Tool Discovery Pattern
Onde: PromptsServer/Program.cs - [PromptHelpers]
Problema: LLMs precisam descobrir quais prompts estão disponíveis e como usá-los.
Solução implementada:
[McpServerToolType]
public static class PromptHelpers
{
// ✅ Tool para listar todos os prompts disponíveis
[McpServerTool(Name = "list_available_prompts")]
public static string ListAvailablePrompts()
{
return @"Prompts Disponíveis:
📝 DESENVOLVIMENTO:
• code_review - Revisa código e fornece sugestões
• explain_code - Explica o funcionamento do código
...";
}
// ✅ Tool para obter informações detalhadas
[McpServerTool(Name = "get_prompt_info")]
public static string GetPromptInfo(string promptName)
{
return promptName.ToLower() switch
{
"code_review" => "Revisa código em qualquer linguagem...",
_ => $"Prompt '{promptName}' não encontrado."
};
}
// ✅ Tool para validar argumentos antes de usar
[McpServerTool(Name = "validate_prompt_args")]
public static string ValidatePromptArgs(string promptName, string argsJson)
{
// ... validação
}
}Benefícios:
- LLM pode descobrir capacidades dinamicamente
- Validação antes de executar
- Documentação self-service
Padrão relacionado: API Discovery Pattern
Padrão 6: Dependency Injection com Generic Host
Onde: ToolsServer/Program.cs, PromptsServer/Program.cs
Problema: Configurar e inicializar servidor MCP de forma estruturada.
Solução implementada:
var builder = Host.CreateApplicationBuilder(args);
// ✅ Configurar serviços via DI
builder.Services
.AddMcpServer(options =>
{
options.ServerInfo = new() { Name = "ToolsServer", Version = "1.0.0" };
options.ServerInstructions = "...";
})
.WithStdioServerTransport()
.WithToolsFromAssembly(); // ✅ Descoberta automática via reflexão
await builder.Build().RunAsync();Benefícios:
- Configuração centralizada
- Testabilidade (pode injetar mocks)
- Descoberta automática de tools/prompts via reflexão
- Ciclo de vida gerenciado
Referência: Generic Host - Microsoft Docs
Padrão 7: Configuration-Based Endpoints
Onde: HttpMcpClient/Program.cs, appsettings.json
Problema: Endpoints hardcoded dificultam deploy em diferentes ambientes.
Solução implementada:
appsettings.json:
{
"McpServer": {
"Endpoint": "http://localhost:5000"
}
}Program.cs:
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();
// ✅ Ler de configuração com fallback
var endpoint = configuration["McpServer:Endpoint"] ?? "http://localhost:5000";Benefícios:
- Fácil mudança entre ambientes (dev, staging, prod)
- Não requer recompilação
- Suporta reload dinâmico
Padrão relacionado: Configuration Pattern
Padrão 8: Resource Disposal com await using
Onde: Todos os clientes (McpClient, HttpMcpClient)
Problema: Conexões e recursos precisam ser liberados corretamente.
Solução implementada:
await using var transport = new HttpClientTransport(transportOptions);
await using var client = await McpClient.CreateAsync(transport);
// ✅ Ao sair do escopo, Dispose/DisposeAsync é chamado automaticamenteBenefícios:
- Garantia de cleanup mesmo com exceções
- Prevenção de resource leaks
- Código mais limpo (sem try-finally explícito)
Referência: IAsyncDisposable Pattern
Padrão 9: CORS Configuration para APIs Públicas
Onde: HttpMcpServer/Program.cs
Problema: Browsers bloqueiam requisições cross-origin por padrão.
Solução implementada:
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Mcp-Session-Id"); // ✅ Expor header importante
});
});
var app = builder.Build();
app.UseCors(); // ✅ Ativar middleware CORS⚠️ Nota de Segurança: AllowAnyOrigin() é adequado para desenvolvimento. Em produção, especifique origens permitidas:
policy.WithOrigins("https://app.exemplo.com", "https://admin.exemplo.com")Referência: CORS - MDN
Padrão 10: Health Check e Info Endpoints
Onde: HttpMcpServer/Program.cs
Problema: Monitoramento e observabilidade de servidores remotos.
Solução implementada:
// ✅ Health check para load balancers e monitoramento
app.MapGet("/health", () => Results.Ok(new
{
status = "saudavel",
service = "Servidor MCP HTTP",
version = "1.0.0",
timestamp = DateTime.UtcNow
}));
// ✅ Endpoint de informações para descoberta
app.MapGet("/info", () => Results.Ok(new
{
name = "HttpMcpServer",
version = "1.0.0",
transport = "HTTP (Streamable HTTP)",
endpoints = new { mcp = "/", health = "/health", info = "/info" }
}));Benefícios:
- Integração com Kubernetes/Docker health checks
- Facilita troubleshooting
- API self-documenting
Referência: Health Checks in ASP.NET Core
Exercício Prático
- Adicione uma nova tool
IsPalindromeque verifica se um texto é palíndromo - Adicione uma tool
Powerque calcula potenciação (base^expoente) - Teste suas tools com o MCP Inspector
Módulo 3: Trabalhando com Prompts
Objetivo
Criar prompts reutilizáveis que LLMs podem usar, combinados com tools auxiliares.
Localização
src/PromptsServer/PromptsServer/
Estrutura do Projeto
O projeto utiliza:
- ModelContextProtocol 0.4.0-preview.1 - para servidor e client
- Microsoft.Extensions.AI - para abstrações de chat (ChatMessage, ChatRole)
Configuração do Servidor
Pontos-chave:
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithPromptsFromAssembly()
.WithToolsFromAssembly();⚠️ Importante: Este servidor expõe tanto prompts quanto tools auxiliares.
Implementação dos Prompts
1. DeveloperPrompts - Prompts para desenvolvimento
Exemplo de implementação:
[McpServerPromptType]
public static class DeveloperPrompts
{
[McpServerPrompt(Name = "code_review"), Description("Cria um prompt para revisão de código")]
public static ChatMessage CodeReview(
[Description("Código para revisar")] string code,
[Description("Linguagem de programação")] string language = "C#")
{
return new ChatMessage(ChatRole.User,
$"Revise o seguinte código {language} e forneça sugestões de melhoria:\n\n{code}");
}
[McpServerPrompt(Name = "refactor_code"), Description("Cria um prompt para refatoração de código")]
public static ChatMessage RefactorCode(
[Description("Código para refatorar")] string code,
[Description("Objetivo da refatoração")] string goal = "melhorar legibilidade")
{
return new ChatMessage(ChatRole.User,
$"Refatore este código com foco em {goal}:\n\n{code}");
}
}⚠️ Pontos de Atenção:
- Use
ChatMessagecomChatRole.Userpara prompts - Parâmetros opcionais têm valores padrão úteis
- Mantenha prompts focados e claros
2. WritingPrompts - Prompts para redação
Exemplo de implementação:
[McpServerPromptType]
public static class WritingPrompts
{
[McpServerPrompt(Name = "summarize_text"), Description("Cria um prompt para resumir texto")]
public static ChatMessage Summarize(
[Description("Texto para resumir")] string content,
[Description("Número máximo de palavras")] int maxWords = 100)
{
return new ChatMessage(ChatRole.User,
$"Resuma o seguinte texto em no máximo {maxWords} palavras:\n\n{content}");
}
[McpServerPrompt(Name = "translate_text"), Description("Cria um prompt para tradução de texto")]
public static ChatMessage TranslateText(
[Description("Texto para traduzir")] string text,
[Description("Idioma de destino")] string targetLanguage = "inglês")
{
return new ChatMessage(ChatRole.User,
$"Traduza o seguinte texto para {targetLanguage}, mantendo o tom e contexto:\n\n{text}");
}
}Tools Auxiliares
O servidor também expõe tools para ajudar a descobrir e validar prompts:
Pontos-chave:
[McpServerToolType]
public static class PromptHelpers
{
[McpServerTool(Name = "list_available_prompts"), Description("Lista todos os prompts disponíveis no servidor")]
public static string ListAvailablePrompts()
{
return @"Prompts Disponíveis:
📝 DESENVOLVIMENTO:
• code_review - Revisa código e fornece sugestões
• explain_code - Explica o funcionamento do código
...";
}
[McpServerTool(Name = "get_prompt_info"), Description("Obtém informações detalhadas sobre um prompt específico")]
public static string GetPromptInfo(
[Description("Nome do prompt")] string promptName)
{
return promptName.ToLower() switch
{
"code_review" => "Revisa código em qualquer linguagem...",
_ => $"Prompt '{promptName}' não encontrado."
};
}
}⚠️ Pontos de Atenção:
- Tools auxiliares facilitam descoberta de prompts
- Use switch expressions para mapeamentos limpos
- Forneça mensagens úteis para casos de erro
Executar o Servidor
cd src\PromptsServer\PromptsServer
dotnet runConfiguração para Claude Desktop
O projeto inclui um arquivo de exemplo claude_desktop_config.json mostrando como configurar o servidor para uso com Claude Desktop.
Referência Completa
Veja a implementação completa em src/PromptsServer/PromptsServer/Program.cs
Exercício Prático
- Crie um prompt
GenerateTestsque gera testes unitários - Adicione uma tool
validate_prompt_argsque valida argumentos JSON - Teste seus prompts com o cliente exemplo em
ClientExample.txt
Módulo 4: Conexão Local (stdio)
Objetivo
Criar um cliente que se conecta ao servidor MCP usando transporte stdio (standard input/output) para uso local.
Localização
O que é stdio?
stdio (standard input/output) permite que o servidor e cliente se comuniquem através de streams de entrada/saída padrão. É ideal para:
- ✅ Desenvolvimento local
- ✅ Ferramentas CLI
- ✅ Integração com editores (VS Code, etc.)
- ✅ Debug e testes rápidos
Configuração do Cliente
Pontos-chave da implementação:
- Configuração de Logging:
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddConsole()
.SetMinimumLevel(LogLevel.Warning);
});- Criação do Transport:
var clientTransport = new StdioClientTransport(new StdioClientTransportOptions
{
Name = "ToolsServerClient",
Command = "dotnet",
Arguments = ["run", "--project", "../../ToolsServer"],
});- Criação do Cliente com Opções:
var clientOptions = new McpClientOptions
{
ClientInfo = new Implementation
{
Name = "McpClient Demo",
Version = "1.0.0"
},
InitializationTimeout = TimeSpan.FromSeconds(30),
Capabilities = new ClientCapabilities()
};
await using var client = await McpClient.CreateAsync(
clientTransport,
clientOptions,
loggerFactory,
cts.Token);⚠️ Pontos de Atenção:
- Use
await usingpara garantir disposal correto - Configure timeout adequado para inicialização
- Forneça informações do cliente para logging
Usando o Cliente
1. Listar Tools:
var tools = await client.ListToolsAsync(cancellationToken: cts.Token);
foreach (var tool in tools)
{
Console.WriteLine($" • {tool.Name}: {tool.Description}");
}2. Chamar Tools:
var addResult = await client.CallToolAsync(
"add",
new Dictionary { ["a"] = 10, ["b"] = 5 },
cancellationToken: cts.Token);3. Extrair Conteúdo de Forma Robusta:
static string ExtractTextContent(CallToolResult result)
{
if (result?.Content == null || !result.Content.Any())
return "N/A";
var textContent = result.Content.FirstOrDefault(c => c.Type == "text");
if (textContent != null)
{
var json = JsonSerializer.SerializeToElement(textContent);
if (json.TryGetProperty("text", out var textProp))
{
return textProp.GetString() ?? "N/A";
}
}
return "N/A";
}⚠️ Pontos de Atenção:
- Sempre verifique se
Contentnão é null - Use serialização JSON para acessar propriedades de forma segura
- Forneça valores padrão para casos de erro
Tratamento de Erros
O cliente implementa tratamento robusto de exceções:
try
{
// ... código do cliente ...
}
catch (OperationCanceledException)
{
Console.WriteLine("\n❌ Operação cancelada pelo usuário.");
}
catch (TimeoutException ex)
{
Console.WriteLine($"\n❌ Timeout durante conexão: {ex.Message}");
}
catch (McpException ex)
{
Console.WriteLine($"\n❌ Erro do protocolo MCP: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"\n❌ Erro inesperado: {ex.GetType().Name}");
Console.WriteLine($" Mensagem: {ex.Message}");
}Executar o Cliente
cd src\ClienteLocal\McpClient
dotnet runSaída esperada:
=== Cliente MCP - Demonstração ===
✅ Conectado ao servidor MCP com sucesso
Servidor: ToolsServer v1.0.0
Protocolo: 2024-11-05
📋 Ferramentas disponíveis:
• add: Soma dois números
• subtract: Subtrai dois números
...
🧮 Exemplo 1: Ferramentas de Calculadora
➕ Adição: 10 + 5 = 15
➖ Subtração: 20 - 8 = 12
...Configuração para GitHub Copilot
Para usar o servidor com GitHub Copilot, edite as configurações do VS Code:
{
"github.copilot.advanced": {
"mcp": {
"enabled": true,
"servers": {
"csharp-tools": {
"command": "dotnet",
"args": ["run", "--project", "D:\\Agentes\\src\\ToolsServer"],
"transport": "stdio"
}
}
}
}
}⚠️ Importante: Use caminhos absolutos corretos para seu sistema.
Testando com MCP Inspector
cd src\ToolsServer
npx @modelcontextprotocol/inspector dotnet runIsso abrirá uma interface web onde você pode:
- 📋 Ver todas as tools disponíveis
- 🧪 Testar cada tool interativamente
- 📊 Ver logs de comunicação
- 🔍 Debugar problemas
Referência Completa
Veja a implementação completa em src/ClienteLocal/McpClient/Program.cs
Exercício Prático
- Modifique o cliente para se conectar ao PromptsServer
- Adicione retry logic para chamadas de tools
- Implemente cache de resultados para tools determinísticas
Módulo 5: Conexão Remota (HTTP)
Objetivo
Criar e conectar a um servidor MCP acessível via HTTP com Server-Sent Events (SSE), permitindo acesso remoto através de uma API web.
Localizações
- Servidor:
src/ServidorRemoto/HttpMcpServer/ - Cliente:
src/ClienteRemoto/HttpMcpClient/
O que é HTTP/SSE?
HTTP com SSE (Server-Sent Events) ou Streamable HTTP permite comunicação bidirecional através de HTTP. É ideal para:
- ✅ Acesso remoto a servidores MCP
- ✅ Serviços web e APIs públicas
- ✅ Integração com aplicações web
- ✅ Deploy em nuvem (Azure, AWS, etc.)
- ✅ Compartilhamento de ferramentas entre equipes
- ✅ Escalabilidade e load balancing
Quando usar HTTP vs stdio?
| Característica | stdio (Módulo 4) | HTTP/SSE (Módulo 5) |
|---|---|---|
| Uso | Local, mesmo processo | Remoto, através da rede |
| Cenário | Desenvolvimento, CLI | Produção, web apps |
| Segurança | Isolado | Requer autenticação |
| Escalabilidade | 1 cliente | Múltiplos clientes |
| Latência | Muito baixa | Depende da rede |
Implementação do Servidor HTTP
Pacotes necessários:
- ModelContextProtocol.AspNetCore 0.4.0-preview.1 - para suporte HTTP
Pontos-chave da configuração:
- Logging para stderr:
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options =>
{
options.LogToStandardErrorThreshold = LogLevel.Information;
});- Configuração do servidor MCP:
builder.Services
.AddMcpServer(options =>
{
options.ServerInfo = new Implementation
{
Name = "HttpMcpServer",
Version = "1.0.0"
};
options.ServerInstructions = """
Este é um servidor MCP HTTP remoto que fornece ferramentas de informações do sistema.
Ferramentas disponíveis:
- GetSystemInfo: Retorna informações do sistema
- GenerateUuid: Gera um UUID único
- CalculateHash: Calcula hash SHA256
...
""";
})
.WithHttpTransport(httpOptions =>
{
httpOptions.IdleTimeout = TimeSpan.FromHours(2);
httpOptions.MaxIdleSessionCount = 10_000;
// httpOptions.Stateless = true; // Para ambientes com load balancing
})
.WithToolsFromAssembly();⚠️ Pontos de Atenção:
ServerInstructionsfornece contexto rico para LLMs- Configure
IdleTimeoutapropriadamente - Use
Stateless = truepara ambientes distribuídos
- Configuração CORS:
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Mcp-Session-Id");
});
});- Mapeamento de endpoints:
var app = builder.Build();
app.UseCors();
app.MapMcp(); // Mapeia MCP na raiz "/"
// Endpoints auxiliares
app.MapGet("/health", () => Results.Ok(new { status = "saudavel", ... }));
app.MapGet("/info", () => Results.Ok(new { name = "HttpMcpServer", ... }));
app.Run();Implementação das Tools Remotas
Exemplo de tools otimizadas para uso remoto:
[McpServerToolType]
public static class RemoteTools
{
[McpServerTool]
[Description("Obtém informações detalhadas do sistema...")]
public static object GetSystemInfo()
{
return new
{
MachineName = Environment.MachineName,
OSVersion = Environment.OSVersion.ToString(),
ProcessorCount = Environment.ProcessorCount,
CurrentTime = DateTime.Now,
CurrentTimeUtc = DateTime.UtcNow,
Uptime = TimeSpan.FromMilliseconds(Environment.TickCount64),
// ... mais informações
};
}
[McpServerTool]
[Description("Gera um identificador único (UUID/GUID)")]
public static string GenerateUuid()
{
return Guid.NewGuid().ToString();
}
[McpServerTool]
[Description("Calcula hash SHA256 de um texto")]
public static string CalculateHash(
[Description("Texto de entrada")] string input)
{
if (string.IsNullOrEmpty(input))
throw new ArgumentException("A entrada não pode ser nula ou vazia");
using var sha256 = System.Security.Cryptography.SHA256.Create();
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(input);
byte[] hash = sha256.ComputeHash(bytes);
return Convert.ToHexString(hash);
}
}⚠️ Pontos de Atenção:
- Valide sempre entradas de usuários
- Retorne objetos estruturados para JSON
- Forneça informações detalhadas nas descrições
Executar o Servidor
cd src\ServidorRemoto\HttpMcpServer
dotnet runURLs disponíveis:
- MCP Endpoint:
http://localhost:5000/ - Health Check:
http://localhost:5000/health - Server Info:
http://localhost:5000/info
Implementação do Cliente HTTP
Pontos-chave:
- Configuração via appsettings:
{
"McpServer": {
"Endpoint": "http://localhost:5000"
}
}- Criação do transport HTTP:
var transportOptions = new HttpClientTransportOptions
{
Endpoint = new Uri(endpoint),
TransportMode = HttpTransportMode.AutoDetect,
Name = "HttpMcpClient"
};
await using var transport = new HttpClientTransport(transportOptions);
await using var client = await McpClient.CreateAsync(transport);⚠️ Pontos de Atenção:
AutoDetectescolhe automaticamente entre StreamableHttp e SSE- Use
await usingpara disposal correto
- Tratamento de diferentes tipos de conteúdo:
static string GetContentString(CallToolResult result)
{
// Tentar TextContentBlock
if (result.Content.FirstOrDefault(c => c.Type == "text") is TextContentBlock textBlock)
{
return textBlock.Text ?? "N/A";
}
// Tentar JSON
if (result.Content.FirstOrDefault(c => c.Type == "json") is var jsonBlock && jsonBlock != null)
{
var jsonProp = jsonBlock.GetType().GetProperty("Json");
if (jsonProp?.GetValue(jsonBlock) is JsonElement jsonElement)
{
return JsonSerializer.Serialize(jsonElement, new JsonSerializerOptions { WriteIndented = true });
}
}
return "N/A";
}⚠️ Pontos de Atenção:
- Ferramentas podem retornar text ou JSON
- Use
JsonElementpara conteúdo JSON - Sempre forneça fallback
Executar o Cliente
Terminal 1 (Servidor):
cd src\ServidorRemoto\HttpMcpServer
dotnet runTerminal 2 (Cliente):
cd src\ClienteRemoto\HttpMcpClient
dotnet runTestando com cURL
# Health check
curl http://localhost:5000/health
# Server info
curl http://localhost:5000/infoConfigurações de Produção
1. HTTPS:
// appsettings.json
{
"Kestrel": {
"Endpoints": {
"Https": {
"Url": "https://localhost:5001"
}
}
}
}2. Rate Limiting e Timeouts:
{
"Kestrel": {
"Limits": {
"MaxConcurrentConnections": 100,
"MaxConcurrentUpgradedConnections": 100,
"MaxRequestBodySize": 10485760,
"KeepAliveTimeout": "00:02:00",
"RequestHeadersTimeout": "00:00:30"
}
}
}Referências Completas
- Servidor:
src/ServidorRemoto/HttpMcpServer/Program.cs - Cliente:
src/ClienteRemoto/HttpMcpClient/Program.cs - Configurações:
appsettings.json
Exercício Prático
- Adicione autenticação por API Key ao servidor
- Implemente retry logic no cliente com backoff exponencial
- Configure o servidor para HTTPS com certificado
- Adicione métricas de uso (número de chamadas, latência)
Módulo 6: Integração com Clientes de IA
GitHub Copilot (VS Code)
Configurar Settings
Abra VS Code Settings (JSON) pressionando Ctrl+Shift+P e digitando "Preferences: Open User Settings (JSON)":
{
"github.copilot.advanced": {
"mcp": {
"enabled": true,
"servers": {
"csharp-tools": {
"command": "dotnet",
"args": ["run", "--project", "D:\\Agentes\\src\\ToolsServer"],
"transport": "stdio",
"env": {
"DOTNET_ENVIRONMENT": "Production"
}
},
"csharp-prompts": {
"command": "dotnet",
"args": ["run", "--project", "D:\\Agentes\\src\\PromptsServer\\PromptsServer"],
"transport": "stdio"
}
}
}
}
}⚠️ Importante:
- Use caminhos absolutos corretos para seu sistema
- Configure variáveis de ambiente se necessário
- Teste cada servidor individualmente antes
Usar no Chat
- Abra o GitHub Copilot Chat (
Ctrl+Shift+I) - Digite comandos como:
- @mcp/csharp-tools add 15 e 25 - @mcp/csharp-tools countWords "Olá mundo MCP" - @mcp/csharp-prompts get code_review para revisar meu código
- O Copilot usará suas tools automaticamente!
GitHub Copilot CLI
Configuração
Crie ou edite ~/.config/github-copilot/config.yml:
mcp:
servers:
csharp-tools:
command: dotnet
args: ["run", "--project", "D:\\Agentes\\src\\ToolsServer"]
transport: stdioUsar na Linha de Comando
# Usar ferramentas
gh copilot suggest "calculate 15 plus 25"
# O Copilot detectará automaticamente suas tools disponíveisClaude Desktop
Configuração
Edite o arquivo de configuração do Claude Desktop:
Windows: %APPDATA%\Claude\claude_desktop_config.json macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"csharp-tools": {
"command": "dotnet",
"args": [
"run",
"--project",
"D:\\Agentes\\src\\ToolsServer"
],
"env": {
"DOTNET_ENVIRONMENT": "Production"
}
},
"csharp-prompts": {
"command": "dotnet",
"args": [
"run",
"--project",
"D:\\Agentes\\src\\PromptsServer\\PromptsServer"
]
}
}
}Usar no Claude
- Reinicie o Claude Desktop
- Os servidores MCP aparecerão como ferramentas disponíveis
- Claude usará as tools automaticamente quando relevante
MCP Inspector
O que é?
Ferramenta oficial para debugar servidores MCP. Permite:
- 🔍 Inspecionar tools e prompts
- 🧪 Testar ferramentas interativamente
- 📊 Ver comunicação em tempo real
- 🐛 Debugar problemas de protocolo
- 📝 Ver logs detalhados
Instalação
npm install -g @modelcontextprotocol/inspectorUsar com Servidor stdio
# Navegar até o diretório do servidor
cd src\ToolsServer
# Iniciar com Inspector
npx @modelcontextprotocol/inspector dotnet runIsso abrirá uma interface web em http://localhost:5173 onde você pode:
- Ver todas as tools:
- Nomes, descrições e parâmetros - Tipos de retorno
- Testar tools:
- Fornecer argumentos - Ver resultados em tempo real
- Ver logs de comunicação:
- Mensagens JSON-RPC - Erros e avisos
Usar com Servidor HTTP
# Iniciar o servidor HTTP normalmente
cd src\ServidorRemoto\HttpMcpServer
dotnet run
# Em outro terminal, conectar o Inspector
npx @modelcontextprotocol/inspector http://localhost:5000Dicas de Debug
Problemas comuns identificados pelo Inspector:
- Tool não aparece:
- Verifique atributos [McpServerTool] e [McpServerToolType] - Confirme que .WithToolsFromAssembly() está configurado
- Erro ao chamar tool:
- Veja a mensagem de erro no Inspector - Verifique tipos de parâmetros - Confirme validações de entrada
- Timeout de conexão:
- Verifique se o servidor está rodando - Confirme que não há conflitos de porta - Veja logs em stderr
Testando Integração Completa
Fluxo de teste recomendado:
- Testar servidor isolado com Inspector:
cd src\ToolsServer
npx @modelcontextprotocol/inspector dotnet run- Testar com cliente stdio:
cd src\ClienteLocal\McpClient
dotnet run- Configurar no GitHub Copilot:
- Adicionar nas configurações do VS Code - Testar com comandos simples no chat
- Monitorar comportamento:
- Observar quais tools o LLM escolhe usar - Ver como interpreta descrições - Ajustar descrições se necessário
Arquivo de Configuração Exemplo
Veja exemplos completos em:
configs/copilot-config.jsonconfigs/copilot-cli-config.jsonsrc/PromptsServer/PromptsServer/claude_desktop_config.json
Exercício Prático
- Configure todos os três servidores (Tools, Prompts, HTTP) no GitHub Copilot
- Teste interações complexas que usam múltiplas tools
- Use o MCP Inspector para debugar uma tool com erro
- Configure e teste com Claude Desktop
Troubleshooting
Problema: Servidor não responde
Sintomas:
- Cliente trava ao conectar
- Timeout de conexão
- Sem output no console
Soluções:
- Verificar se o servidor está rodando:
# Listar processos dotnet
Get-Process dotnet- Verificar logs em stderr:
# Redirecionar stderr para arquivo
dotnet run 2> error.log- Testar com MCP Inspector primeiro:
cd src\ToolsServer
npx @modelcontextprotocol/inspector dotnet run- Verificar caminhos de projeto:
- Use caminhos absolutos em configs - Confirme que .csproj existe no caminho
Problema: Tools não aparecem no cliente
Sintomas:
ListToolsAsync()retorna lista vazia- LLM não vê as ferramentas
Soluções:
- Verificar atributos:
// ✅ Correto
[McpServerToolType]
public static class MyTools
{
[McpServerTool(Name = "myTool")]
[Description("...")]
public static string MyTool() { ... }
}
// ❌ Incorreto - faltam atributos
public static class MyTools
{
public static string MyTool() { ... }
}- Confirmar registro no servidor:
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly(); // ← Importante!- Recompilar projeto:
dotnet clean
dotnet build- Verificar com Inspector:
- Deve mostrar todas as tools - Se aparecer no Inspector mas não no cliente, o problema é na comunicação
Problema: Erro ao chamar tool
Sintomas:
- Exceção ao chamar
CallToolAsync - Erro "Tool not found"
- Timeout na chamada
Soluções:
- Verificar nome da tool:
// Nome definido no servidor
[McpServerTool(Name = "add")]
// Deve corresponder ao usado no cliente
await client.CallToolAsync("add", ...);- Verificar tipos de argumentos:
// Servidor espera double
public static double Add(double a, double b)
// Cliente deve enviar double, não string
await client.CallToolAsync("add", new Dictionary
{
["a"] = 10.0, // ✅ double
["b"] = 5.0 // ✅ double
});- Ver detalhes do erro:
try
{
await client.CallToolAsync(...);
}
catch (McpException ex)
{
Console.WriteLine($"Erro MCP: {ex.Message}");
Console.WriteLine($"Detalhes: {ex.InnerException?.Message}");
}- Testar com Inspector:
- Fornece interface para testar argumentos - Mostra erro exato do servidor
Problema: Erro de conexão HTTP
Sintomas:
- Cliente HTTP não conecta
- "Connection refused"
- Timeout na requisição
Soluções:
- Verificar se servidor está rodando:
# Testar health check
curl http://localhost:5000/health- Verificar porta disponível:
# Ver o que está usando a porta
netstat -ano | findstr :5000- Confirmar URL correta:
// appsettings.json ou código
"Endpoint": "http://localhost:5000" // Sem /mcp no final!- Verificar firewall:
- Windows pode bloquear a porta - Adicionar exceção se necessário
- Testar com curl primeiro:
# Health check deve responder
curl http://localhost:5000/health
# Info do servidor
curl http://localhost:5000/infoProblema: Conteúdo null ou "N/A"
Sintomas:
- Tool executa mas retorna "N/A"
- Content é null no resultado
Soluções:
- Verificar tipo de retorno:
// ✅ Tipos suportados
public static string MyTool() // text
public static int MyTool() // number
public static object MyTool() // json
// ❌ Tipos não suportados diretamente
public static MyCustomClass MyTool()- Usar extraction robusta:
static string ExtractTextContent(CallToolResult result)
{
if (result?.Content == null || !result.Content.Any())
return "N/A";
// Tentar como texto
var textContent = result.Content.FirstOrDefault(c => c.Type == "text");
if (textContent != null)
{
var json = JsonSerializer.SerializeToElement(textContent);
if (json.TryGetProperty("text", out var textProp))
{
return textProp.GetString() ?? "N/A";
}
}
return "N/A";
}- Verificar logs do servidor:
- Ver se tool está sendo executada - Confirmar que não há exceções
Problema: MCP Inspector não abre
Sintomas:
- Comando não inicia interface web
- Erro "inspector not found"
Soluções:
- Reinstalar Inspector:
npm uninstall -g @modelcontextprotocol/inspector
npm install -g @modelcontextprotocol/inspector- Verificar instalação:
npx @modelcontextprotocol/inspector --version- Limpar cache do npm:
npm cache clean --force- Usar npx diretamente:
# Sem instalar globalmente
npx @modelcontextprotocol/inspector dotnet runProblema: GitHub Copilot não vê o servidor
Sintomas:
- Servidor configurado mas Copilot não usa tools
- Sem erro, mas tools não aparecem
Soluções:
- Verificar sintaxe do JSON:
{
"github.copilot.advanced": {
"mcp": {
"enabled": true, // ← Não esquecer
"servers": { ... }
}
}
}- Usar caminhos absolutos:
{
"args": ["run", "--project", "D:\\Agentes\\src\\ToolsServer"]
// ↑ Caminho completo
}- Reiniciar VS Code:
- Fechar completamente - Reabrir - Aguardar carregamento completo
- Verificar logs do VS Code:
- Ver console de desenvolvedor (Help > Toggle Developer Tools) - Procurar por erros relacionados a MCP
- Testar servidor isoladamente:
- Confirmar que funciona com Inspector - Confirmar que funciona com cliente C# - Só depois integrar com Copilot
Logs de Debug
Habilitar logs detalhados no servidor:
builder.Logging.AddConsole(options =>
{
options.LogToStandardErrorThreshold = LogLevel.Trace; // ← Debug máximo
});Habilitar logs detalhados no cliente:
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddConsole()
.SetMinimumLevel(LogLevel.Debug); // ← Debug máximo
});Capturar logs em arquivo:
# Windows PowerShell
dotnet run 2> logs.txt
# Ou redirecionar ambos stdout e stderr
dotnet run > output.txt 2>&1Checklist Geral de Debug
Quando algo não funciona, siga esta ordem:
- [ ] 1. Servidor compila sem erros?
- [ ] 2. Servidor inicia sem exceções?
- [ ] 3. Tools aparecem no MCP Inspector?
- [ ] 4. Tools funcionam no Inspector?
- [ ] 5. Cliente consegue listar tools?
- [ ] 6. Cliente consegue chamar tools?
- [ ] 7. Configuração de cliente IA está correta?
- [ ] 8. Cliente IA está reiniciado?
- [ ] 9. Logs mostram algo anormal?
- [ ] 10. Versões de pacotes estão corretas?
Recursos Adicionais
Documentação Oficial
- 📚 MCP Specification - Especificação completa do protocolo
- 📖 C# SDK Documentation - API Reference completa
- 🔧 - Código-fonte e issues
- 🌐 MCP Website - Site oficial com overview
Pacotes NuGet
Versões usadas neste workshop:
- ModelContextProtocol 0.4.0-preview.1
- Pacote principal com servidor e cliente stdio -
- ModelContextProtocol.AspNetCore 0.4.0-preview.1
- Extensões para servidores HTTP com ASP.NET Core -
- ModelContextProtocol.Core 0.4.0-preview.1
- APIs de baixo nível do cliente e servidor -
- Microsoft.Extensions.Hosting 9.0.9
- Hospedagem e dependency injection -
- Microsoft.Extensions.AI.Abstractions
- Abstrações para integração com LLMs (ChatMessage, ChatRole) -
Frameworks e Tecnologias
- .NET: 9.0
- C# Language: 13.0 (latest)
- MCP Protocol: Specification 2024-11-05
Exemplos e Tutoriais
- MCP Samples (C#) - Exemplos oficiais do SDK
- Awesome MCP Servers - Lista curada de servidores MCP
- MCP Community Servers - Servidores em várias linguagens
Referências Complementares
Para uma lista completa de recursos, tutoriais avançados e casos de uso, consulte:
Este arquivo contém:
- Tutoriais aprofundados
- Padrões e best practices
- Casos de uso reais
- Exemplos de projetos avançados
- Roadmap do MCP
- Lista de ferramentas úteis
Comunidade e Suporte
| Canal | Descrição | Link |
|---|---|---|
| Discord MCP | Comunidade oficial | https://discord.gg/modelcontextprotocol |
| GitHub Discussions | Discussões técnicas | https://github.com/modelcontextprotocol/csharp-sdk/discussions |
| Stack Overflow | Q&A técnico | Tag: model-context-protocol |
Ferramentas Úteis
| Ferramenta | Propósito | Link |
|---|---|---|
| MCP Inspector | Debug de servidores | npm install -g @modelcontextprotocol/inspector |
| Postman | Testar endpoints HTTP | https://www.postman.com/ |
| Insomnia | Cliente REST | https://insomnia.rest/ |
| REST Client | Extensão VS Code | Marketplace |
Leitura Complementar
- Understanding LLM Agents
- https://www.anthropic.com/index/claude-agent - Como LLMs usam ferramentas efetivamente
- Tool Use Best Practices
- https://docs.anthropic.com/claude/docs/tool-use - Padrões para criar tools úteis
- Prompt Engineering Guide
- https://www.promptingguide.ai/ - Como escrever prompts efetivos
- Async/Await in C#
- https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/ - Programação assíncrona
Projetos de Exemplo Avançados
Ideias para próximos projetos:
- File System Server
- Tools para ler/escrever arquivos - Buscar arquivos por padrão - Listar diretórios
- Database Query Server
- Executar queries SQL seguras - Ver schemas de tabelas - Exports de dados
- API Gateway Server
- Integrar múltiplas APIs externas - Weather, stocks, news, etc. - Cache e rate limiting
- Development Tools Server
- Formatar código - Lint e análise estática - Gerar testes unitários
Próximos Passos
Depois de completar este workshop, você pode:
- ✅ Explorar os exemplos oficiais
- Ver casos de uso mais complexos - Aprender padrões avançados
- ✅ Criar seu próprio servidor MCP
- Integrar com suas ferramentas - Expor APIs internas como tools
- ✅ Contribuir com a comunidade
- Compartilhar seus servidores - Abrir issues e PRs - Ajudar outros desenvolvedores
- ✅ Deploy em produção
- Configurar HTTPS e autenticação - Deploy na nuvem (Azure, AWS) - Monitorar uso e performance
- ✅ Integrar com projetos existentes
- Adicionar MCP a aplicações .NET - Expor funcionalidades via tools - Criar interfaces conversacionais
Como Contribuir
Para este Workshop
- 🐛 Encontrou um bug? Abra uma issue
- 💡 Tem uma sugestão? Crie uma discussion
- 🔧 Quer contribuir? Envie um pull request
- 📝 Melhorou algo? Compartilhe sua experiência
Para o SDK C#
- Fork do repositório oficial
- Crie branch feature:
git checkout -b feature/minha-feature - Commit mudanças:
git commit -am 'Adiciona feature X' - Push branch:
git push origin feature/minha-feature - Abra Pull Request
Atualizações Futuras
Este workshop será atualizado conforme:
- Novas versões do SDK C#
- Novos recursos do protocolo MCP
- Feedback da comunidade
- Melhores práticas emergentes
Última atualização: Janeiro 2025
Versão do workshop: 2.0.0 (atualizada para SDK 0.4.0-preview.1)
Feedback e Contribuições
Este é um projeto educacional em constante evolução. Seu feedback é essencial!
Como ajudar:
- ⭐ Dê uma estrela no repositório se achou útil
- 🐛 Reporte bugs ou problemas
- 💡 Sugira melhorias
- 📝 Compartilhe sua experiência
- 🔧 Contribua com código
- 📖 Melhore a documentação
Contato:
- GitHub Issues: Para bugs e features
- GitHub Discussions: Para perguntas e ideias
- Discord MCP: Para discussões em tempo real
Licença
Este workshop é disponibilizado sob licença MIT. Veja o arquivo LICENSE para mais detalhes.
Você é livre para:
- ✅ Usar comercialmente
- ✅ Modificar
- ✅ Distribuir
- ✅ Uso privado
Desde que:
- 📋 Inclua a licença e copyright
- 📋 Forneça atribuição
Agradecimentos
Este workshop não seria possível sem:
- Anthropic - Pela criação do Model Context Protocol
- Microsoft - Pelo desenvolvimento do SDK C#
- Comunidade .NET - Pelas ferramentas e frameworks
- Contribuidores - Por feedback e melhorias
- Você - Por dedicar tempo para aprender!
Conclusão
🎉 Parabéns por completar o workshop!
Você agora sabe como:
- ✅ Criar servidores MCP em C#
- ✅ Implementar tools e prompts
- ✅ Conectar clientes localmente e remotamente
- ✅ Integrar com GitHub Copilot e outras ferramentas
- ✅ Debugar problemas com MCP Inspector
- ✅ Seguir melhores práticas de segurança
- ✅ Deploy servidores
