Een Model Context Protocol (MCP) Server bouwen in Delphi

· Componenten

Wat is het Model Context Protocol?

Het Model Context Protocol (MCP) is Anthropic’s open standaard voor het blootstellen van tools, data en prompt-templates aan AI-modellen. Zie het als USB voor AI: elke MCP-server kan worden ingeplugd in elke MCP-client (Claude Desktop, Cursor, Continue, je eigen Delphi-app, OpenAI’s clients), en het model ontdekt direct welke tools beschikbaar zijn en hoe ze aan te roepen.

Voor MCP betekende elke AI-integratie het bedraden van tool-definities, JSON-schema’s en call-dispatchers in elke individuele app. MCP brengt dat samen in een enkel protocol: schrijf de server een keer, elk model kan hem gebruiken. Voor Delphi-shops die al een stapel business-API’s hebben — ERP-queries, CRM-lookups, file-generatoren, billing-functies — is MCP de goedkoopste route om die API’s AI-toegankelijk te maken.

Deze tutorial doorloopt het bouwen van een MCP-server in Delphi met de TsgcAI_MCP_Server-component, het blootstellen van een werkende get_weather-tool, en het verbinden met Claude Desktop via zowel stdio- als HTTP-transporten.

Een stukje geschiedenis plaatst MCP in context. Anthropic publiceerde de spec eind 2024 als antwoord op de wildgroei van incompatibele tool-calling-formaten — OpenAI’s function-calling JSON, Google’s Gemini grounding tools, elke leveranciers eigen schema. Tegen de tijd dat je dit leest, wordt MCP-ondersteuning geleverd in Claude Desktop, Cursor, Continue, Zed en de meeste moderne AI-IDE’s; OpenAI kondigde compatibiliteit aan begin 2026. Met andere woorden: een MCP-server bouwen vandaag is een eenmalige investering die uitbetaalt over elke client die je klanten kunnen gebruiken, vandaag en morgen.

MCP-bouwstenen

Een MCP-server kan drie soorten capabilities blootstellen:

Tools

Aanroepbare functies met typed inputs. Het model beslist wanneer ze in te roepen. Voorbeeld: get_weather(city), create_invoice(customer, lines).
Resources

Read-only data die het model kan ophalen. Elke resource heeft een URI. Voorbeeld: file:///docs/handbook.md, db://customers/12345.
Prompts

Herbruikbare prompt-templates die de gebruiker (niet het model) selecteert. Voorbeeld: een “Vertaal naar formeel Spaans”- of “Vat vergadernotities samen”-template.

Het protocol gebruikt JSON-RPC 2.0 over een van twee transporten: stdio (de server is een childproces; berichten lopen via stdin/stdout) of HTTP met Server-Sent Events voor de server-naar-client-stream. Stdio is de standaard voor desktop-integraties zoals Claude Desktop; HTTP is de juiste keuze wanneer de server op een andere machine draait of meerdere clients bedient.

De component verbergt beide transporten achter een enkele API. Je schrijft je tool-handler een keer, dan kies je het transport bij opstart. Dezelfde code draait als Claude Desktop-helper, een netwerk-bereikbare HTTP-service, of beide tegelijkertijd binnen een proces. We hebben shops die 30+ MCP-servers op een box draaien, gemultiplexed over verschillende poorten en een of twee stdio-binaries, allemaal dezelfde Delphi-codebase serverend.

Project-setup

Voeg sgcAI_MCP_Server toe aan je uses-clausule, plaats een TsgcAI_MCP_Server op het formulier (of maak hem in code voor een console-app), hang de events aan en start hem. De component doet de JSON-RPC-framing, message-routing en capability-advertisement voor je.

uses
  sgcAI_MCP_Server, sgcAI_MCP_Classes;

procedure TForm1.FormCreate(Sender: TObject);
begin
  oMCP := TsgcAI_MCP_Server.Create(Self);
  oMCP.ServerInfo.Name    := 'weather-mcp';
  oMCP.ServerInfo.Version := '1.0.0';

  // Wire handlers
  oMCP.OnListTools := DoListTools;
  oMCP.OnCallTool  := DoCallTool;

  // Stdio transport for Claude Desktop integration
  oMCP.Transport := mtStdio;
  oMCP.Active    := True;
end;

Een tool implementeren: get_weather

Een tool heeft twee handlers nodig. OnListTools vertelt de client welke tools bestaan en welke argumenten ze accepteren. OnCallTool voert de aanroep daadwerkelijk uit. Beide handlers zijn gewone Delphi-events — geen handmatige JSON-constructie.

procedure TForm1.DoListTools(Sender: TObject;
  const aTools: TsgcAI_MCP_Tools);
var
  oTool: TsgcAI_MCP_Tool;
begin
  oTool := aTools.Add;
  oTool.Name        := 'get_weather';
  oTool.Description := 'Return the current weather for a city.';
  oTool.InputSchema :=
    '{"type":"object",' +
     '"properties":{' +
       '"city":{"type":"string","description":"City name, e.g. Madrid"},' +
       '"units":{"type":"string","enum":["metric","imperial"],"default":"metric"}' +
     '},' +
     '"required":["city"]}';
end;

procedure TForm1.DoCallTool(Sender: TObject;
  const aRequest : TsgcAI_MCP_ToolCall;
  const aResult  : TsgcAI_MCP_ToolResult);
var
  vCity, vUnits, vReport: string;
begin
  if aRequest.Name = 'get_weather' then
  begin
    vCity  := aRequest.Arguments.S['city'];
    vUnits := aRequest.Arguments.S['units'];
    if vUnits = '' then vUnits := 'metric';

    // Call your own weather backend
    vReport := MyWeatherService.Fetch(vCity, vUnits);
    aResult.AddText(vReport);
  end
  else
    aResult.Error('Unknown tool: ' + aRequest.Name);
end;

Dat is de volledige implementatie. De component zorgt voor input-validatie tegen het schema, error-formattering en de onderliggende JSON-RPC-envelop. Jij richt je op de businesslogica.

Enkele principes voor het ontwerpen van goede tools, de harde weg geleerd:

Resources blootstellen

Tools zijn voor acties; resources zijn voor data die het model kan lezen. Een resource-handler geeft de content terug voor een gegeven URI. Een documentatieserver zou elk Markdown-bestand onder docs/ als resource kunnen blootstellen.

oMCP.OnListResources := DoListResources;
oMCP.OnReadResource  := DoReadResource;

procedure TForm1.DoListResources(Sender: TObject;
  const aResources: TsgcAI_MCP_Resources);
var
  vFiles: TStringDynArray;
  i     : Integer;
  oRes  : TsgcAI_MCP_Resource;
begin
  vFiles := TDirectory.GetFiles('C:\docs', '*.md');
  for i := 0 to High(vFiles) do
  begin
    oRes := aResources.Add;
    oRes.URI         := 'file:///' + StringReplace(vFiles[i], '\', '/', [rfReplaceAll]);
    oRes.Name        := ExtractFileName(vFiles[i]);
    oRes.MimeType    := 'text/markdown';
    oRes.Description := 'Documentation page';
  end;
end;

procedure TForm1.DoReadResource(Sender: TObject;
  const aURI: string; const aResult: TsgcAI_MCP_ResourceResult);
var
  vPath: string;
begin
  vPath := StringReplace(Copy(aURI, 9, MaxInt), '/', '\', [rfReplaceAll]);
  if FileExists(vPath) then
    aResult.AddText(TFile.ReadAllText(vPath))
  else
    aResult.Error('Resource not found');
end;

Stdio vs HTTP-transport

Kies het transport op basis van waar de server draait en wie hem gebruikt.

Transport Gebruik Voordelen Nadelen
Stdio Lokale desktop-tools (Claude Desktop, Cursor) Geen configuratie, geen poorten, OS regelt proces-lifecycle Een client per proces, geen externe toegang
HTTP / SSE Gedeelde bedrijfsservers, webclients, multi-tenant Veel clients, netwerk-bereikbaar, TLS, auth Vereist hosting, poortbeheer, auth-ontwerp

Transport wisselen is een regel:

// Stdio (default for desktop)
oMCP.Transport := mtStdio;

// HTTP listener on port 8080
oMCP.Transport       := mtHTTP;
oMCP.HTTPOptions.Host := '0.0.0.0';
oMCP.HTTPOptions.Port := 8080;
oMCP.HTTPOptions.TLS.Enabled  := True;
oMCP.HTTPOptions.TLS.CertFile := 'cert.pem';
oMCP.HTTPOptions.TLS.KeyFile  := 'key.pem';
oMCP.Active := True;

Verbinden vanuit Claude Desktop

Voor stdio bewerk je claude_desktop_config.json en voeg je een entry toe die naar je gecompileerde .exe wijst. Claude Desktop spawnt het proces op afroep.

{
  "mcpServers": {
    "weather": {
      "command": "C:\\Tools\\weather-mcp.exe",
      "args": []
    }
  }
}

Herstart Claude Desktop en je ziet een klein tools-icoon in het prompt-gebied. Vraag “Wat is het weer in Tokio?” en Claude zal je Delphi-tool aanroepen.

Voor HTTP wijs je elke MCP-capable client naar https://your-host:8080/mcp. Dezelfde Delphi-server bedient probleemloos een Claude Desktop-instance, een Cursor-sessie en een custom Delphi MCP-client tegelijkertijd.

Prompts: de onderbenutte derde capability

Tools en resources krijgen alle aandacht; prompts zijn het stille werkpaard. Een MCP-prompt is een herbruikbaar template — “vat deze vergadering samen”, “extraheer actiepunten”, “vertaal naar formeel Spaans” — dat de gebruiker vanuit een UI-menu in zijn MCP-client invoegt. Het model voert die prompt vervolgens uit tegen de context die de gebruiker levert.

Voor interne tooling is dit goud. Je supportteam krijgt een gecureerde lijst bedrijfsgezegende prompts binnen Claude Desktop. Je salesteam krijgt een “stel een follow-up e-mail op”-prompt die je tone of voice al kent. Geen van hen hoeft prompt engineering te leren — ze kiezen gewoon het template.

oMCP.OnListPrompts := DoListPrompts;
oMCP.OnGetPrompt   := DoGetPrompt;

procedure TForm1.DoListPrompts(Sender: TObject;
  const aPrompts: TsgcAI_MCP_Prompts);
var
  oPrompt: TsgcAI_MCP_Prompt;
begin
  oPrompt := aPrompts.Add;
  oPrompt.Name        := 'summarise_meeting';
  oPrompt.Description := 'Turn a meeting transcript into bullet decisions and actions.';
  oPrompt.AddArgument('transcript', 'Plain-text transcript', True);
end;

procedure TForm1.DoGetPrompt(Sender: TObject;
  const aRequest: TsgcAI_MCP_PromptRequest;
  const aResult : TsgcAI_MCP_PromptResult);
begin
  if aRequest.Name = 'summarise_meeting' then
    aResult.AddMessage('user',
      'You are a meeting note taker. Read the transcript and produce: ' +
      '(1) a 3-sentence summary, (2) decisions taken, (3) action items ' +
      'with owners and due dates.' + sLineBreak + sLineBreak +
      aRequest.Arguments.S['transcript']);
end;

Productie-overwegingen

Een paar dingen om voor te budgetteren voordat je een MCP-server in productie brengt:

Debug-tips

MCP draait onzichtbaar binnen de AI-client, wat debuggen lastig maakt de eerste keer dat er iets misgaat. Drie gewoonten besparen je uren:

Afronding

MCP verandert een interne Delphi-API in iets dat elke moderne AI-client kan gebruiken, zonder per-client-bedrading. De TsgcAI_MCP_Server-component handelt de JSON-RPC-framing, transport en capability-advertisement af, en laat jou de daadwerkelijke tool-body schrijven. Begin met een read-only tool, kijk hoe het model hem gebruikt, breid dan uit naar writes, resources en prompts.

Onze grootste les uit het intern uitrollen van MCP: de waarde is niet “Claude kan nu onze API’s gebruiken”. De waarde is “iedereen in het bedrijf kan onze API’s gebruiken via natuurlijke taal, zonder de API te leren”. Dat verandert wie wat kan doen, en daar komt de werkelijke productiviteitswinst vandaan.

Wil je de bijbehorende client? Zie TsgcAI_MCP_Client voor het bouwen van Delphi-apps die elke MCP-server consumeren. En als de AI-componenten nieuw voor je zijn, loopt de Aan de slag-hub je in vijf minuten door de installatie.