O Model Context Protocol tem uma nova especificação, MCP 2026-07-28. É a maior mudança no protocolo desde o Streamable HTTP: o handshake de sessão desapareceu, cada requisição carrega o que o servidor precisa para respondê-la, e trabalhos longos ou interativos passam a ter suporte de primeira classe. O sgcWebSockets 2026.10.0 implementa isso tanto no servidor MCP quanto no cliente MCP para Delphi e C++Builder.
A parte importante para quem já está executando um servidor MCP em Delphi: nada quebra. O servidor é de duas eras. Clientes que falam 2025-11-25, como o VS Code ou o Claude, continuam chamando initialize e recebem uma sessão exatamente como antes, enquanto os clientes 2026-07-28 usam o novo modelo sem estado no mesmo endpoint. Você não precisa de uma chave de alternância nem de um segundo servidor.
O que mudou no MCP 2026-07-28
Em termos simples, estas são as mudanças que importam ao construir um servidor ou um cliente:
- Requisições sem estado. Não há handshake de
initializenemMcp-Session-Id. Cada requisição carrega sua versão de protocolo, informações do cliente e capacidades do cliente dentro de_meta, para que qualquer instância de servidor atrás de um load balancer possa respondê-la. - server/discover. Um cliente que quer saber o que um servidor oferece chama
server/discovere recebe de volta as versões suportadas, as capacidades e as instruções. O resultado pode ser armazenado em cache, e os resultados trazem dicas de cache (ttlMs,cacheScope). - subscriptions/listen. Uma única requisição de streaming substitui o antigo stream GET. O cliente informa quais notificações quer (mudanças nas listas de tools, prompts e resources, atualizações de resources) e o servidor as envia por esse stream.
- Requisições multi round-trip (MRTR). Um handler de tool, prompt ou resource não chama mais o cliente de volta para pedir informações. Ele retorna
input_requiredcom as perguntas, o cliente responde e repete a chamada com as respostas e umrequestStateassinado. - Extensão Tasks. Uma chamada de tool demorada pode responder imediatamente com um identificador de task. O cliente faz polling com
tasks/get, responde perguntas comtasks/updatee a interrompe comtasks/cancel. - Cabeçalhos de roteamento. As requisições HTTP carregam os cabeçalhos
MCP-Protocol-Version,Mcp-MethodeMcp-Name(além deMcp-Param-*para argumentos de tool marcados comx-mcp-header), para que os gateways possam rotear e filtrar sem analisar o corpo. O servidor os verifica em relação ao corpo. - Autorização do cliente. O fluxo OAuth para clientes foi reforçado: descoberta de metadados de recursos protegidos, Client ID Metadata Documents, PKCE com o indicador de recurso e validação de
isssegundo a RFC 9207.
Um servidor MCP de duas eras em Delphi
O componente TsgcWSAPIServer_MCP detecta a era de cada requisição. Uma requisição cujo _meta indica 2026-07-28 segue pelo caminho sem estado, enquanto initialize e as versões mais antigas seguem pelo caminho de sessão que você já conhece. Seus handlers de tool, prompt e resource são compartilhados por ambos. As novas opções apenas preenchem o que os clientes 2026-07-28 leem em server/discover e nas dicas de cache.
procedure TMainForm.FormCreate(Sender: TObject);
begin
MCPServer.MCPOptions.ServerInfo.Name := 'tickets-mcp';
// returned by server/discover to 2026-07-28 clients
MCPServer.MCPOptions.Instructions := 'Use search_tickets before opening a ticket.';
// cache hints returned with 2026-07-28 results (ttlMs, cacheScope)
MCPServer.MCPOptions.Cache.TTLMs := 60000;
MCPServer.MCPOptions.Cache.Scope := aimcpcsPublic;
MCPServer.Active := True;
end;
Quando ServerInfo.Name é definido, os resultados 2026-07-28 também carregam as informações do servidor em _meta. Os erros de protocolo usam os novos códigos: um cabeçalho que não corresponde ao corpo responde -32020, uma capacidade de cliente ausente -32021 e uma versão não suportada -32022, com a lista de versões suportadas nos dados do erro.
Subscriptions com subscriptions/listen
As subscriptions vêm habilitadas por padrão. Um cliente 2026-07-28 abre um stream de subscriptions/listen, e as notificações que você já envia com SendNotificationToolsListChanged ou SendNotificationResourcesUpdated chegam a esses ouvintes assim como às sessões 2025-11-25. O servidor envia um comentário de keep-alive em streams ociosos, e quando o servidor é desativado cada subscription aberta é fechada de forma graciosa com seu resultado final.
procedure TMainForm.FormCreate(Sender: TObject);
begin
MCPServer.MCPOptions.Subscriptions.Enabled := True;
MCPServer.MCPOptions.Subscriptions.KeepAliveInterval := 15000; // 0 disables it
end;
procedure TMainForm.ToolsChanged;
begin
// delivered to legacy sessions and to every subscriptions/listen stream
MCPServer.SendNotificationToolsListChanged;
end;
Requisições multi round-trip: pedindo o nome do usuário
Com o MRTR, um handler pede mais informações preenchendo aResponse.InputRequired e retornando. O cliente coleta as respostas e chama a tool novamente. Na segunda rodada, as respostas são lidas com aRequest.InputResponse. O exemplo abaixo é a tool ask_name do demo de servidor.
procedure TMainForm.MCPServerMCPRequestTool(Sender: TObject;
const aSession: TsgcAI_MCP_Session;
const aRequest: TsgcAI_MCP_Request_ToolsCall;
const aResponse: TsgcAI_MCP_Response_ToolsCall);
begin
if aRequest.Params.Name = 'ask_name' then
begin
if not aRequest.HasInputResponse('name') then
begin
// first round: ask the client for the user's name
aResponse.InputRequired.AddElicitation('name', 'What is your name?',
'{"type":"object","properties":{"name":{"type":"string"}},' +
'"required":["name"]}');
Exit;
end;
// second round: the answer arrives as raw JSON
aResponse.Result.Content.AddText('Hello, ' + aRequest.InputResponse('name'));
end;
end;
O requestState viaja assinado com HMAC-SHA256 usando MCPOptions.MRTR.Secret e expira após MCPOptions.MRTR.StateTTL segundos, para que um cliente não possa adulterá-lo. A elicitation de URL (AddElicitationURL), o sampling (AddSampling) e os roots (AddRoots) seguem o mesmo padrão. Antes de responder input_required, o servidor verifica se o cliente declarou a capacidade correspondente.
A extensão Tasks: uma tool long_job
Habilite tasks em MCPOptions.Tasks e chame CreateTask a partir do handler da tool. Quando o cliente declarou a extensão io.modelcontextprotocol/tasks naquela requisição, a chamada responde imediatamente com um id de task e seu código termina o trabalho em sua própria thread. CreateTask retorna nil quando tasks estão desabilitadas, a requisição é 2025-11-25 ou o cliente não declarou a extensão, então mantenha um caminho síncrono para esses clientes.
procedure TMainForm.FormCreate(Sender: TObject);
begin
MCPServer.MCPOptions.Tasks.Enabled := True;
MCPServer.MCPOptions.Tasks.TTL := 3600000;
MCPServer.MCPOptions.Tasks.PollInterval := 1000;
end;
procedure TMainForm.MCPServerMCPRequestTool(Sender: TObject;
const aSession: TsgcAI_MCP_Session;
const aRequest: TsgcAI_MCP_Request_ToolsCall;
const aResponse: TsgcAI_MCP_Response_ToolsCall);
var
oTask: TsgcAI_MCP_Task;
begin
if aRequest.Params.Name = 'long_job' then
begin
oTask := MCPServer.CreateTask(aSession, aResponse);
if Assigned(oTask) then
TLongJobThread.Create(oTask) // runs the job, see below
else
aResponse.Result.Content.AddText(RunLongJob);
end;
end;
procedure TLongJobThread.Execute;
var
i: Integer;
oResponse: TsgcAI_MCP_Response_ToolsCall;
begin
for i := 1 to 3 do
begin
if FTask.IsCancelled then
Break;
DoStep(i);
FTask.SetStatusMessage(Format('long_job step %d of 3', [i]));
end;
if FTask.IsCancelled then
FTask.Fail(CS_AI_MCP_INTERNAL_ERROR, 'Cancelled by the client')
else
begin
oResponse := TsgcAI_MCP_Response_ToolsCall.Create;
try
oResponse.Result.Content.AddText('long_job finished after 3 steps');
FTask.Complete(oResponse);
finally
oResponse.Free;
end;
end;
end;
O objeto task é thread safe. OnMCPTaskCancel dispara quando o cliente chama tasks/cancel, e OnMCPTaskUpdate quando ele responde uma task que aguarda informações. As tasks ficam vinculadas ao principal que as criou e expiram após TTL milissegundos.
O cliente MCP: ProtocolEra e Discover
O componente TsgcWSAPIClient_MCP ganha uma nova propriedade MCPOptions.ProtocolEra. Deixe-a como aimcpeAuto e o cliente sonda o servidor com server/discover, usa 2026-07-28 quando o servidor suporta e recorre ao handshake de initialize quando não suporta. A era negociada fica em cache por endpoint. Defina-a como aimcpeModern ou aimcpeLegacy para forçar uma delas.
procedure TMainForm.Connect;
begin
MCPClient.MCPOptions.ProtocolEra := aimcpeAuto;
if MCPClient.Initialize then
begin
MemoLog.Lines.Add('protocol: ' + MCPClient.NegotiatedProtocolVersion);
if MCPClient.NegotiatedEra = aimcpeModern then
MCPClient.Discover; // result in OnMCPDiscover and ServerDiscover
MCPClient.ListTools;
end;
end;
No caminho 2026-07-28, o cliente grava _meta em cada requisição, envia os cabeçalhos de roteamento, incluindo Mcp-Param-* para tools que declaram x-mcp-header, e abre subscriptions com SubscriptionsListen. As mudanças de lista chegam em OnMCPListChanged e as atualizações de resource em OnMCPResourcesUpdated. Com MCPOptions.Tasks.Enabled, o cliente declara a extensão Tasks e faz o polling das tasks por conta própria, disparando OnMCPTaskCreated, OnMCPTaskStatus e OnMCPTaskCompleted.
Respondendo perguntas do MRTR com OnMCPInputRequired
Quando um servidor responde input_required, o cliente dispara OnMCPInputRequired com as perguntas pendentes. Responda cada chave e deixe Accept como True. O cliente então repete a chamada com as respostas e o requestState assinado, até MCPOptions.MRTR.MaxRounds rodadas. Defina MCPOptions.MRTR.Elicitation, Sampling ou Roots para declarar essas capacidades.
procedure TMainForm.MCPClientMCPInputRequired(Sender: TObject;
const aMethod: string;
const aInputRequests: TsgcAI_MCP_Client_InputRequests;
var Accept: Boolean);
var
i: Integer;
begin
for i := 0 to aInputRequests.Count - 1 do
if aInputRequests.Methods[i] = 'elicitation/create' then
aInputRequests.SetElicitationAccept(aInputRequests.Keys[i],
'{"name":"Sergio"}');
Accept := True;
end;
O mesmo evento cobre tasks aguardando informações, caso em que aMethod é tasks/update. Servidores legados que ainda enviam requisições de roots, sampling ou elicitation diretamente recebem suas respostas em OnMCPListRoots, OnMCPSamplingCreateMessage e OnMCPElicitationCreate.
Autorização do cliente com MCPOptions.Authorization
Defina MCPOptions.Authorization.Enabled e um 401 ou 403 do servidor inicia o fluxo de autorização do MCP: descoberta de metadados de recursos protegidos, registro (um ClientId pré-registrado, um Client ID Metadata Document a partir de ClientMetadataURL, ou registro dinâmico), PKCE com o indicador de recurso, o login pelo navegador no RedirectURL de loopback, validação de iss e a requisição do token. A requisição original é então repetida, e os tokens são renovados antes de expirar.
procedure TMainForm.FormCreate(Sender: TObject);
begin
MCPClient.MCPOptions.Authorization.Enabled := True;
MCPClient.MCPOptions.Authorization.ClientMetadataURL :=
'https://app.example.com/oauth/client.json';
MCPClient.MCPOptions.Authorization.AllowDynamicRegistration := True;
MCPClient.MCPOptions.Authorization.RedirectURL := 'http://127.0.0.1:33418/callback';
MCPClient.OnMCPAuthorizationURL := MCPClientAuthorizationURL;
end;
procedure TMainForm.MCPClientAuthorizationURL(Sender: TObject;
const aURL: string; var Handled: Boolean);
begin
MemoLog.Lines.Add('Sign in at ' + aURL);
Handled := False; // False: the default browser is opened
end;
As credenciais são mantidas por emissor. Trate OnMCPAuthorizationCredentials para armazená-las e carregá-las na próxima execução, para que o usuário faça login apenas uma vez.
Também no sgcWebSockets .NET
Tudo o que está neste artigo também está disponível no sgcWebSockets .NET, com os mesmos nomes de classe, propriedade e evento: TsgcWSAPIServer_MCP e TsgcWSAPIClient_MCP expõem MCPOptions.Subscriptions, MCPOptions.MRTR, MCPOptions.Tasks, ProtocolEra, Discover e MCPOptions.Authorization, para que uma aplicação C# possa conversar com um servidor MCP em Delphi em qualquer uma das eras, e vice-versa.
Demos e documentação
Os demos em Demos\15.AI\03.MCP mostram todos os recursos. O demo de servidor (01.MCP_Server) registra a era de cada requisição, tem opções para tasks e subscriptions e implementa as tools ask_name e long_job. O demo de cliente (02.MCP_Client) permite escolher a era, chamar Discover, assinar notificações, responder perguntas do MRTR e executar tasks.
A referência completa está na documentação do servidor MCP e na documentação do cliente MCP, e a página Componentes MCP para Delphi traz uma visão geral de tudo o que os componentes fazem. Você pode baixar o sgcWebSockets 2026.10.0 na página de download do sgcWebSockets.
Dúvidas, feedback ou ajuda com a migração? Entre em contato, você receberá uma resposta de quem escreveu o código.
