Lançada a versão 1.0 do SDK oficial do MCP para C# e .NET
O SDK do MCP para C# chegou à versão 1.0 e entrega suporte completo à especificação MCP 2025-11-25, com melhorias em autorização, metadados, chamada de ferramentas, elicitação e tarefas de longa duração. Neste artigo, você vai entender cada novidade dessa versão, com exemplos de código e considerações práticas para levar o recurso a produção.
O que é o Model Context Protocol
O Model Context Protocol (MCP) se consolidou como o padrão aberto para a comunicação entre aplicações de IA e fontes de contexto externas. Em outras palavras, ele define como clientes e servidores trocam contexto com modelos de linguagem.
Um servidor MCP expõe ferramentas (tools), recursos (resources) e prompts. Por sua vez, clientes como agentes de IA, IDEs e aplicações consomem essas capacidades.
O protocolo padroniza a comunicação, então você constrói o servidor uma vez e qualquer cliente compatível consegue usá-lo. Se o conceito ainda for novo para você, vale ler antes o artigo o que é MCP, que explica os fundamentos.
O SDK do MCP para C# é a implementação oficial do protocolo para a plataforma .NET. Além disso, Microsoft, Anthropic e a organização do protocolo mantêm o projeto em conjunto, no repositório modelcontextprotocol/csharp-sdk.
O que chega no SDK do MCP 1.0
A Microsoft anunciou a versão 1.0 em março de 2026, em um post de Mike Kistler no blog oficial do .NET. Na prática, o SDK do MCP passa a suportar a especificação 2025-11-25 de ponta a ponta.
As novidades se dividem em oito frentes principais:
- Descoberta aprimorada de servidores de autorização.
- Ícones para ferramentas, recursos e prompts.
- Consentimento de escopo incremental.
- Elicitação em modo URL.
- Chamada de ferramentas dentro de requisições de sampling.
- Client ID Metadata Documents (CIMD).
- Requisições de longa duração com polling.
- Tasks, ainda em caráter experimental.
Descoberta de servidores de autorização no SDK do MCP
A especificação 2025-11-25 amplia as formas de um servidor expor o Protected Resource Metadata (PRM) Document. A versão anterior exigia o link no parâmetro resource_metadata do cabeçalho WWW-Authenticate.
Agora existem três caminhos possíveis:
- Uma URL no parâmetro
resource_metadatado cabeçalhoWWW-Authenticate, como antes. - Uma URL well-known derivada do caminho do endpoint MCP, por exemplo
https://example.com/.well-known/oauth-protected-resource/public/mcp. - A URL well-known raiz, por exemplo
https://example.com/.well-known/oauth-protected-resource.
Os clientes verificam essas localizações nessa ordem. No servidor, o método de extensão AddMcp no AuthenticationBuilder simplifica a configuração do documento:
.AddMcp(options =>
{
options.ResourceMetadata = new()
{
ResourceDocumentation = new Uri("https://docs.example.com/api/weather"),
AuthorizationServers = { new Uri(inMemoryOAuthServerUrl) },
ScopesSupported = ["mcp:tools"],
};
});
Com essa configuração, o SDK do MCP hospeda o PRM Document na URL well-known e inclui o link no cabeçalho WWW-Authenticate. Do lado do cliente, o SDK cuida de toda a sequência de descoberta sem código extra.
Ícones para ferramentas, recursos e prompts
A especificação também introduz metadados de ícones em ferramentas, recursos e prompts. Assim, as respostas às requisições tools/list, resources/list e prompts/list passam a carregar essas informações.
A forma mais simples de adicionar um ícone a uma ferramenta usa o parâmetro IconSource no atributo McpServerToolAttribute:
[McpServerTool(Title = "This is a title", IconSource = "https://example.com/tool-icon.svg")]
public static string ToolWithIcon(string message) => message;
Para cenários mais completos, você configura os ícones de forma programática via McpServerToolCreateOptions.Icons. Por exemplo, dá para combinar vários ícones, tipos MIME, dicas de tamanho e preferências de tema:
.WithTools([
McpServerTool.Create(
typeof(EchoTool).GetMethod(nameof(EchoTool.Echo))!,
options: new McpServerToolCreateOptions
{
Icons = [
new Icon
{
Source = "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Loudspeaker/Flat/loudspeaker_flat.svg",
MimeType = "image/svg+xml",
Sizes = ["any"],
Theme = "light"
},
new Icon
{
Source = "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Loudspeaker/3D/loudspeaker_3d.png",
MimeType = "image/png",
Sizes = ["256x256"],
Theme = "dark"
}
]
}
)
])
A classe Implementation também ganhou as propriedades Icons e WebsiteUrl. Com isso, servidores e clientes descrevem a própria identidade com mais riqueza:
.AddMcpServer(options =>
{
options.ServerInfo = new Implementation
{
Name = "Everything Server",
Version = "1.0.0",
Title = "MCP Everything Server",
WebsiteUrl = "https://github.com/modelcontextprotocol/csharp-sdk",
Icons = [
new Icon
{
Source = "https://raw.githubusercontent.com/microsoft/fluentui-emoji/main/assets/Gear/Flat/gear_flat.svg",
MimeType = "image/svg+xml",
Sizes = ["any"],
Theme = "light"
}
]
};
})
Consentimento de escopo incremental
O consentimento de escopo incremental aplica o Princípio do Menor Privilégio à autorização MCP. Ou seja, o cliente pede apenas o acesso mínimo necessário para cada operação.
O MCP usa OAuth 2.0 para autorização, e os escopos definem o nível de acesso do cliente. Antes, os clientes pediam todos os escopos de uma vez, porque não sabiam quais escopos cada operação exigiria.
Com o modelo incremental, o cliente começa com escopos mínimos e solicita escopos adicionais conforme a necessidade. O mecanismo funciona em dois fluxos:
- Escopos iniciais: em uma requisição sem autenticação, o servidor responde
401 Unauthorizedcom um cabeçalhoWWW-Authenticateque agora traz o parâmetroscopes. - Escopos adicionais: quando o token não tem o escopo certo, o servidor responde
403 Forbiddencomerror="insufficient_scope"e o parâmetroscopes.
No segundo caso, o cliente obtém um novo token com os escopos ampliados e tenta de novo. Se você quiser revisar como tokens e claims funcionam, o artigo o que é JWT ajuda bastante.
Como o SDK do MCP trata os escopos no cliente
O SDK do MCP trata o consentimento incremental automaticamente no cliente. Portanto, você não precisa escrever nenhuma linha extra para reagir às respostas 401 e 403.
Verificações de autorização no servidor
No servidor, a configuração envolve quatro etapas. Primeiro, você adiciona os serviços de autenticação com o esquema MCP.
Em seguida, habilita a autenticação JWT Bearer com a validação correta de tokens. Depois, especifica os metadados do esquema e, por fim, faz as verificações de autorização em middleware.
Esse último ponto merece atenção, porque o handler HTTP do MCP pode enviar os cabeçalhos de resposta antes de invocar a ferramenta. Assim, uma verificação dentro do método da ferramenta chega tarde demais para alterar o código de status.
Para extrair os escopos do token, lembre que o ASP.NET Core converte os escopos do JWT em claims no HttpContext.User:
var user = context.User;
var userScopes = user?.Claims
.Where(c => c.Type == "scope" || c.Type == "scp")
.SelectMany(c => c.Value.Split(' '))
.Distinct()
.ToList();
Elicitação em modo URL
A elicitação em modo URL permite uma interação segura e fora de banda entre o servidor e o usuário final. Nesse fluxo, os dados não passam pelo host nem pelo cliente MCP.
O recurso vale muito para coletar dados sensíveis, como chaves de API, autorizações de terceiros e informações de pagamento. Afinal, trafegar esses dados pelo cliente criaria um risco de segurança.
A ideia segue padrões web como o OAuth. O cliente obtém o consentimento do usuário e abre no navegador uma URL segura do servidor, onde a interação sensível acontece.
No cliente, você declara o suporte configurando a propriedade Url nas capacidades de elicitação:
McpClientOptions options = new()
{
Capabilities = new ClientCapabilities
{
Elicitation = new ElicitationCapability
{
Url = new UrlElicitationCapability()
}
}
};
O cliente também precisa fornecer um ElicitationHandler. Como existe um único handler para os modos de formulário e URL, ele deve verificar a propriedade Mode dos parâmetros para saber qual modo chegou.
No servidor, você define um endpoint para a URL de elicitação. Uma boa abordagem usa uma Razor Page com proteção contra CSRF via anti-forgery tokens, recurso nativo do ASP.NET Core.
Além disso, um servidor MCP com transporte HTTP atende vários usuários ao mesmo tempo. Por isso, ele precisa associar cada requisição de elicitação à sessão MCP correta com um parâmetro de identificação.
Chamada de ferramentas no sampling com o SDK do MCP
Um dos acréscimos mais poderosos da especificação permite que servidores incluam ferramentas nas requisições de sampling. Dessa forma, o modelo pode invocar essas ferramentas para produzir a resposta.
No entanto, essas ferramentas diferem das ferramentas MCP comuns. Elas não precisam seguir o formato tradicional, e o servidor implementa a própria lógica para tratar as invocações.
O fluxo funciona assim: quando o modelo pede uma ferramenta durante o sampling, esse pedido é a resposta à requisição. Então o servidor executa a ferramenta e envia uma nova requisição com o pedido e o resultado.
Esse ciclo se repete até o modelo produzir uma resposta final sem novas invocações.
No cliente, você declara o suporte nas capacidades e fornece um SamplingHandler. Escrever esse handler do zero seria trabalhoso, mas o pacote Microsoft.Extensions.AI resolve a maior parte:
IChatClient chatClient =
new OpenAIClient(new ApiKeyCredential(token), new OpenAIClientOptions { Endpoint = new Uri(baseUrl) })
.GetChatClient(modelId)
.AsIChatClient();
var samplingHandler = chatClient.CreateSamplingHandler();
O método CreateSamplingHandler traduz entre o formato do protocolo e o formato do modelo. Já no servidor, o SDK do MCP oferece McpServer.AsSamplingChatClient(), e o UseFunctionInvocation adiciona a chamada de ferramentas:
IChatClient chatClient =
ChatClientBuilderChatClientExtensions.AsBuilder(_mcpServer.AsSamplingChatClient())
.UseFunctionInvocation()
.Build();
Você define as ferramentas como objetos AIFunction e as passa em ChatOptions. A partir daí, o IChatClient cuida do envio das requisições, da execução das ferramentas e da tradução entre formatos.
Essa integração mostra como o SDK se apoia nas abstrações do .NET para IA, tema que aparece também no artigo sobre o novo .NET AI stack.
Client ID Metadata Documents (CIMD)
A especificação introduz os Client ID Metadata Documents (CIMDs) como alternativa ao Dynamic Client Registration (DCR). Agora, o CIMD é o método preferido para registrar clientes no MCP.
O conceito é direto: o cliente informa uma URL como seu client_id nas requisições de autorização. Essa URL aponta para um documento JSON com metadados, identificadores e URIs de redirecionamento do cliente.
No SDK do MCP, os clientes informam a URL do CIMD via ClientOAuthOptions:
await using var transport = new HttpClientTransport(new()
{
Endpoint = new(McpServerUrl),
OAuth = new ClientOAuthOptions()
{
RedirectUri = new Uri("http://localhost:1179/callback"),
AuthorizationRedirectDelegate = HandleAuthorizationUrlAsync,
ClientMetadataDocumentUri = new Uri(ClientMetadataDocumentUrl)
},
}, HttpClient, LoggerFactory);
A URL do CIMD precisa usar HTTPS e ter um caminho não vazio. Além disso, ela não pode conter segmentos de ponto nem fragmento.
O documento deve incluir pelo menos client_id, client_name e redirect_uris. O SDK tenta o CIMD primeiro e, se o servidor não suportar, recorre ao DCR quando essa opção estiver habilitada.
Requisições de longa duração com polling
Na camada de dados, o MCP é um protocolo baseado em mensagens, sem limite de tempo próprio. Sobre HTTP, porém, timeouts fazem parte da realidade.
A abordagem anterior permitia desconectar e reconectar quando o servidor enviava um Event ID nos eventos SSE. Contudo, poucos servidores implementavam esse recurso.
A nova abordagem é mais clara. O servidor que abre um stream SSE começa com um evento vazio que traz um Event ID e, opcionalmente, um campo Retry-After.
Depois desse evento inicial, o servidor pode fechar o stream a qualquer momento. Então o cliente se reconecta usando o Event ID e continua recebendo as atualizações.
Para habilitar esse comportamento, o servidor fornece uma implementação de ISseEventStreamStore. O SDK do MCP inclui o DistributedCacheEventStreamStore, que funciona com qualquer IDistributedCache:
builder.Services.AddDistributedMemoryCache();
builder.Services
.AddMcpServer()
.WithHttpTransport()
.WithDistributedCacheEventStreamStore()
.WithTools<RandomNumberTools>();
Quando um handler quer encerrar a conexão SSE e liberar o cliente para fazer polling, ele chama EnablePollingAsync no McpRequestContext:
await context.EnablePollingAsync(retryInterval: TimeSpan.FromSeconds(retryIntervalInSeconds));
Também vale pensar na retenção, porque esses stores podem crescer sem limite na memória. O DistributedCacheEventStreamStore aceita expiração por tempo via DistributedCacheEventStreamStoreOptions.
Além disso, a recomendação é apagar streams de sessões encerradas. Também convém guardar apenas eventos relevantes, como resultados finais, e descartar notificações intermediárias de progresso.
Tasks experimentais no SDK do MCP
A especificação introduz as tasks como um novo primitivo. Elas oferecem rastreamento durável de estado e recuperação adiada de resultados para requisições MCP.
Enquanto a retomada de streams atua no transporte, as tasks atuam na camada de dados. Assim, o servidor guarda o resultado de forma durável dentro de uma janela de retenção que ele mesmo define.
As tasks complementam as requisições existentes em vez de substituí-las. Por exemplo, o cliente inclui um campo task em uma chamada tools/call para pedir rastreamento durável.
Nesse caso, o servidor devolve um CreateTaskResult no lugar da resposta normal. Esse objeto traz um ID único, o status working, timestamps, um TTL e, opcionalmente, um intervalo de polling sugerido.
O ciclo de vida segue estes estados:
| Status | Descrição |
|---|---|
working |
A task está em processamento |
input_required |
A task aguarda entrada adicional, como uma elicitação |
completed |
A task terminou com sucesso e o resultado está disponível |
failed |
A task encontrou um erro |
cancelled |
O cliente cancelou a task |
Os estados completed, failed e cancelled são terminais. Ou seja, depois de chegar a um deles, a task não muda mais de estado.
Esse recurso ajuda em vários cenários, como resiliência a falhas de rede e rastreamento explícito de status. Também facilita a integração com pipelines de CI/CD e processamento em lote.
Configuração do task store no servidor
Para habilitar as tasks, você configura um task store na inicialização do servidor:
var taskStore = new InMemoryMcpTaskStore();
builder.Services.AddMcpServer(options =>
{
options.TaskStore = taskStore;
})
.WithHttpTransport()
.WithTools<MyTools>();
O InMemoryMcpTaskStore serve como implementação de referência para desenvolvimento e para um único servidor. Em produção com várias instâncias, implemente IMcpTaskStore sobre um armazenamento persistente, como banco de dados ou Redis.
As ferramentas anunciam suporte a tasks automaticamente quando retornam Task, ValueTask, Task<T> ou ValueTask<T>. Mesmo assim, você pode controlar esse suporte com o enum ToolTaskSupport:
[McpServerTool(TaskSupport = ToolTaskSupport.Required)]
[Description("Processes a batch of data records. Always runs as a task.")]
public static async Task<string> ProcessData(
[Description("Number of records to process")] int recordCount,
CancellationToken cancellationToken)
{
// simula um processamento demorado
await Task.Delay(TimeSpan.FromSeconds(8), cancellationToken);
return $"Processed {recordCount} records successfully.";
}
Consumo de tasks no cliente
Para executar uma ferramenta como task no SDK do MCP, o cliente inclui a propriedade Task nos parâmetros da requisição. Depois, ele acompanha o status com PollTaskUntilCompleteAsync e busca o resultado com GetTaskResultAsync.
O SDK do MCP também oferece ListTasksAsync para listar tasks e CancelTaskAsync para cancelar tasks em execução.
Os clientes podem registrar um handler para receber notificações de mudança de status. Contudo, o polling deve ser sempre o mecanismo principal, pois as notificações são opcionais.
Como começar a usar o SDK do MCP
O SDK do MCP é distribuído em pacotes NuGet com responsabilidades diferentes. Assim, você escolhe apenas o que o projeto precisa:
- O pacote
ModelContextProtocol.Coretraz dependências mínimas, para quem precisa só do cliente ou das APIs de servidor de baixo nível. - Já o
ModelContextProtocolé o pacote principal, com extensões de hosting e injeção de dependência. - Por fim, o
ModelContextProtocol.AspNetCoreadiciona suporte a servidores MCP sobre HTTP.
Para um servidor local via stdio, o pacote principal costuma bastar:
dotnet add package ModelContextProtocol
A documentação do Microsoft Learn traz um guia para criar um servidor MCP mínimo em C# e publicá-lo no NuGet. Além disso, o repositório de demos reúne exemplos da maioria dos recursos deste artigo.
Considerações para adoção do SDK do MCP
A versão 1.0 representa uma mudança relevante para equipes que constroem integrações de IA no .NET. Por isso, alguns pontos merecem atenção na migração ou na adoção do SDK do MCP.
Compatibilidade com a especificação: o SDK mira a especificação 2025-11-25. Portanto, projetos que dependem de versões anteriores devem avaliar o impacto, sobretudo em autorização e transporte HTTP.
Tasks em produção: o InMemoryMcpTaskStore não atende ambientes com várias instâncias. Nesse caso, implemente IMcpTaskStore com um store distribuído, e a interface simples facilita integrações com Redis ou PostgreSQL.
Autorização em middleware: mover as verificações para o middleware exige atenção. Afinal, o middleware pode precisar desserializar a requisição para saber quais escopos exigir, um custo que futuras versões do protocolo prometem reduzir.
Tasks como recurso experimental: a especificação marca as tasks como experimentais. Logo, a API pode mudar em versões futuras do protocolo.
Para entender onde o MCP se encaixa, o comparativo agents ou MCP ajuda a separar os papéis de cada abordagem.
Conclusão
O lançamento da versão 1.0 do SDK do MCP consolida o .NET como opção de primeira classe para servidores e clientes MCP. A especificação 2025-11-25 responde a desafios reais de produção.
Entre eles estão a autorização granular com escopos incrementais, a identidade de cliente via CIMD e a coleta segura de dados com elicitação por URL. Além disso, o polling e as tasks dão suporte a fluxos de longa duração.
A integração com Microsoft.Extensions.AI merece destaque, porque reduz a complexidade do sampling com ferramentas. Com ela, o SDK do MCP esconde a tradução entre o protocolo e os diferentes provedores de LLM.
FAQ
Qual versão da especificação o SDK do MCP 1.0 suporta?
O SDK suporta a especificação MCP 2025-11-25. Projetos baseados em versões anteriores devem revisar principalmente autorização e transporte HTTP.
Preciso escrever código para o consentimento de escopo incremental no cliente?
Não. O cliente do SDK trata as respostas 401 e 403 com o parâmetro scopes automaticamente.
Por que a verificação de autorização deve ficar no middleware?
O handler HTTP do MCP pode enviar os cabeçalhos antes de chamar a ferramenta. Assim, uma verificação dentro da ferramenta não consegue mais alterar o código de status.
O InMemoryMcpTaskStore serve para produção?
Ele serve para desenvolvimento e para um único servidor. Com várias instâncias, implemente IMcpTaskStore sobre um armazenamento persistente.
O CIMD substitui o Dynamic Client Registration?
O CIMD é o método preferido, mas o SDK ainda recorre ao DCR quando o servidor de autorização não suporta CIMD e a opção estiver habilitada.
As tasks já são estáveis?
Não. A especificação marca as tasks como experimentais, então a API pode mudar.