Het Model Context Protocol heeft een nieuwe specificatie, MCP 2026-07-28. Het is de grootste wijziging aan het protocol sinds Streamable HTTP: de sessie-handshake is verdwenen, elk request bevat wat de server nodig heeft om het te beantwoorden, en lang of interactief werk krijgt eersteklas ondersteuning. sgcWebSockets 2026.10.0 implementeert dit zowel in de MCP-server als in de MCP-client voor Delphi en C++Builder.
Het belangrijkste voor iedereen die al een Delphi MCP-server draait: er breekt niets. De server is dual-era. Clients die 2025-11-25 spreken, zoals VS Code of Claude, blijven initialize aanroepen en krijgen precies zoals voorheen een sessie, terwijl 2026-07-28-clients het nieuwe stateless model op hetzelfde endpoint gebruiken. Je hebt geen schakelaar of tweede server nodig.
Wat is er veranderd in MCP 2026-07-28
In gewone taal, dit zijn de wijzigingen die ertoe doen als je een server of een client bouwt:
- Stateless requests. Er is geen
initialize-handshake en geenMcp-Session-Id. Elk request bevat zijn protocolversie, clientinfo en clientcapabilities in_meta, zodat elke serverinstantie achter een load balancer het kan beantwoorden. - server/discover. Een client die wil weten wat een server aanbiedt, roept
server/discoveraan en krijgt de ondersteunde versies, capabilities en instructies terug. Het resultaat kan worden gecachet, en resultaten bevatten cachehints (ttlMs,cacheScope). - subscriptions/listen. Eén streaming request vervangt de oude GET-stream. De client geeft aan welke notificaties hij wil (tools, prompts en resources list changes, resource updates) en de server pusht ze op die stream.
- Multi round-trip requests (MRTR). Een tool-, prompt- of resourcehandler roept de client niet langer terug om om invoer te vragen. Hij retourneert
input_requiredmet de vragen, de client beantwoordt ze en herhaalt de aanroep met de antwoorden en een gesigneerderequestState. - Tasks-extensie. Een lange tool-aanroep kan meteen antwoorden met een task handle. De client polt hem met
tasks/get, beantwoordt vragen mettasks/updateen stopt hem mettasks/cancel. - Routing headers. HTTP-requests bevatten de headers
MCP-Protocol-Version,Mcp-MethodenMcp-Name(plusMcp-Param-*voor tool-argumenten die zijn gemarkeerd metx-mcp-header), zodat gateways kunnen routeren en filteren zonder de body te parsen. De server controleert ze tegen de body. - Clientautorisatie. De OAuth-flow voor clients is aangescherpt: protected resource metadata discovery, Client ID Metadata Documents, PKCE met de resource indicator en RFC 9207
iss-validatie.
Een dual-era MCP-server in Delphi
De component TsgcWSAPIServer_MCP detecteert de era van elk request. Een request waarvan _meta 2026-07-28 aangeeft, volgt het stateless pad, terwijl initialize en de oudere versies het sessiepad volgen dat je al kent. Je tool-, prompt- en resourcehandlers worden door beide gedeeld. De nieuwe opties vullen alleen aan wat 2026-07-28-clients lezen uit server/discover en uit de cachehints.
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;
Wanneer ServerInfo.Name is ingesteld, bevatten 2026-07-28-resultaten ook de serverinfo in _meta. Protocolfouten gebruiken de nieuwe codes: een header die niet overeenkomt met de body geeft -32020, een ontbrekende clientcapability -32021 en een niet-ondersteunde versie -32022, met de lijst van ondersteunde versies in de foutdata.
Subscriptions met subscriptions/listen
Subscriptions staan standaard aan. Een 2026-07-28-client opent één subscriptions/listen-stream, en de notificaties die je al verstuurt met SendNotificationToolsListChanged of SendNotificationResourcesUpdated bereiken die listeners net zo goed als de 2025-11-25-sessies. De server stuurt een keep-alive-comment op inactieve streams, en wanneer de server wordt gedeactiveerd, wordt elke open subscription netjes gesloten met zijn eindresultaat.
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;
Multi round-trip requests: de gebruiker om een naam vragen
Met MRTR vraagt een handler om meer invoer door aResponse.InputRequired te vullen en terug te keren. De client verzamelt de antwoorden en roept de tool opnieuw aan. In de tweede ronde worden de antwoorden gelezen met aRequest.InputResponse. Het onderstaande voorbeeld is de tool ask_name uit de serverdemo.
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;
De requestState reist gesigneerd met HMAC-SHA256 met behulp van MCPOptions.MRTR.Secret en verloopt na MCPOptions.MRTR.StateTTL seconden, zodat een client er niet mee kan knoeien. URL elicitation (AddElicitationURL), sampling (AddSampling) en roots (AddRoots) volgen hetzelfde patroon. Voordat de server input_required beantwoordt, controleert hij of de client de bijbehorende capability heeft gedeclareerd.
De Tasks-extensie: een long_job-tool
Schakel tasks in bij MCPOptions.Tasks en roep CreateTask aan vanuit de tool-handler. Wanneer de client de extensie io.modelcontextprotocol/tasks op dat request heeft gedeclareerd, antwoordt de aanroep meteen met een task-id en voltooit je code het werk op zijn eigen thread. CreateTask retourneert nil wanneer tasks zijn uitgeschakeld, het request 2025-11-25 is of de client de extensie niet heeft gedeclareerd, dus houd voor die clients een synchroon pad achter de hand.
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;
Het task-object is thread safe. OnMCPTaskCancel vuurt wanneer de client tasks/cancel aanroept, en OnMCPTaskUpdate wanneer hij een task beantwoordt die op invoer wacht. Tasks zijn gebonden aan de principal die ze heeft aangemaakt en verlopen na TTL milliseconden.
De MCP-client: ProtocolEra en Discover
De component TsgcWSAPIClient_MCP krijgt een nieuwe property MCPOptions.ProtocolEra. Laat hem op aimcpeAuto staan, dan onderzoekt de client de server met server/discover, gebruikt 2026-07-28 wanneer de server dat ondersteunt en valt terug op de initialize-handshake wanneer dat niet zo is. De onderhandelde era wordt per endpoint gecachet. Zet hem op aimcpeModern of aimcpeLegacy om er één te forceren.
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;
Op het 2026-07-28-pad schrijft de client _meta bij elk request, verstuurt hij de routing headers, inclusief Mcp-Param-* voor tools die x-mcp-header declareren, en opent hij subscriptions met SubscriptionsListen. List changes komen binnen in OnMCPListChanged en resource updates in OnMCPResourcesUpdated. Met MCPOptions.Tasks.Enabled declareert de client de Tasks-extensie en polt hij tasks zelfstandig, met OnMCPTaskCreated, OnMCPTaskStatus en OnMCPTaskCompleted die vuren.
MRTR-vragen beantwoorden met OnMCPInputRequired
Wanneer een server input_required beantwoordt, vuurt de client OnMCPInputRequired met de openstaande vragen. Beantwoord elke key en laat Accept op True staan. De client herhaalt de aanroep vervolgens met de antwoorden en de gesigneerde requestState, tot maximaal MCPOptions.MRTR.MaxRounds rondes. Zet MCPOptions.MRTR.Elicitation, Sampling of Roots om die capabilities te declareren.
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;
Hetzelfde event dekt tasks die op invoer wachten, in welk geval aMethod gelijk is aan tasks/update. Legacy-servers die nog rechtstreeks roots-, sampling- of elicitation-requests versturen, krijgen hun antwoorden via OnMCPListRoots, OnMCPSamplingCreateMessage en OnMCPElicitationCreate.
Clientautorisatie met MCPOptions.Authorization
Zet MCPOptions.Authorization.Enabled aan en een 401 of 403 van de server start de MCP-autorisatieflow: protected resource metadata discovery, registratie (een vooraf geregistreerde ClientId, een Client ID Metadata Document van ClientMetadataURL, of dynamische registratie), PKCE met de resource indicator, de browser sign-in op de loopback RedirectURL, iss-validatie en de tokenaanvraag. Het oorspronkelijke request wordt vervolgens herhaald, en tokens worden ververst voordat ze verlopen.
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;
Credentials worden per issuer bewaard. Handel OnMCPAuthorizationCredentials af om ze op te slaan en bij de volgende run te laden, zodat de gebruiker slechts één keer hoeft in te loggen.
Ook in sgcWebSockets .NET
Alles in dit artikel is ook beschikbaar in sgcWebSockets .NET, met dezelfde klasse-, property- en eventnamen: TsgcWSAPIServer_MCP en TsgcWSAPIClient_MCP stellen MCPOptions.Subscriptions, MCPOptions.MRTR, MCPOptions.Tasks, ProtocolEra, Discover en MCPOptions.Authorization beschikbaar, zodat een C#-applicatie met een Delphi MCP-server in beide era's kan praten, en omgekeerd.
Demo's en documentatie
De demo's in Demos\15.AI\03.MCP tonen elke feature. De serverdemo (01.MCP_Server) logt de era van elk request, heeft schakelaars voor tasks en subscriptions en implementeert de tools ask_name en long_job. De clientdemo (02.MCP_Client) laat je de era kiezen, Discover aanroepen, je abonneren op notificaties, MRTR-vragen beantwoorden en tasks uitvoeren.
De volledige referentie staat in de documentatie van de MCP-server en de documentatie van de MCP-client, en de pagina MCP-componenten voor Delphi geeft een overzicht van alles wat de componenten doen. Je kunt sgcWebSockets 2026.10.0 downloaden van de downloadpagina van sgcWebSockets.
Vragen, feedback of hulp bij migratie? Neem contact op, je krijgt antwoord van de mensen die de code hebben geschreven.
