Run Your Delphi App Inside ChatGPT and Claude

· Components
Run Your Delphi App Inside ChatGPT and Claude

An M C P server lets an assistant call your code. What it has never let you do is show anything: the assistant asks, your tool answers with text, and the user reads a paragraph. sgcWebSockets 2026.10 adds MCP Apps to sgcHTML, so a tool can answer with a page instead. The assistant renders it, the user clicks around in it, and the clicks come back to your Delphi application.

The page is built from the same sgcHTML components every other page uses. No JavaScript framework, no separate front end, no second code base.

A Tool That Answers With a Page

An MCP App is three things: a tool the model can call, a resource that carries the page, and the events that decide what both mean. TsgcHTMLComponent_MCPApp declares all of it on an MCP server you already have.

uses
  sgcAI, sgcHTML_MCPApp;

FMCP := TsgcWSAPIServer_MCP.Create(nil);
FMCP.Server := FHTTPServer;
FMCP.EndpointOptions.Endpoint := '/mcp';

FApps := TsgcHTMLComponent_MCPApp.Create(nil);
FApps.MCPServer := FMCP.MCPServer;
FApps.OnRender := DoRender;
FApps.OnToolCall := DoToolCall;
FApps.OnFragment := DoFragment;

with FApps.Apps.Add do
begin
  ToolName := 'orders.board';
  Title := 'Orders board';
  Description := 'Shows the orders of the company as a board ' +
    'that can be filtered by status.';
  InputSchema.Text := '{"type":"object","properties":{"status":' +
    '{"type":"string","description":"open, shipped or closed"}}}';
end;

FApps.RegisterApps;

That is the whole registration. The component declares the tool with the metadata that tells the host it carries a user interface, declares the resource the host reads to get the page, and declares a companion tool the page itself uses.

What the Model Reads, What the User Sees

A tool result has two halves, and they are not the same audience. OnToolCall writes both: a sentence for the model to reason with, and the structured content the page reads.

procedure TMyLogic.DoToolCall(Sender: TObject; aApp: TsgcHTMLMCPApp;
  const aArguments: string; var aText, aStructured: string);
begin
  aText := Format('%d open orders, %s in total.', [vCount, vTotal]);
  aStructured := '{"orders":' + IntToStr(vCount) + '}';
end;

OnRender answers the page. It is ordinary sgcHTML: a card, a table, a few buttons. Nothing about it is specific to the assistant.

Buttons That Work Where There Is No Server

This is the part that usually breaks. The page runs inside a sandboxed iframe with no network of its own, so an hx-get has nothing to reach. sgcHTML solves it with a bridge that registers an htmx extension: every hx-get and hx-post of the page becomes a call of the companion tool, and the markup that comes back is swapped in exactly as htmx would have swapped an HTTP response.

procedure TMyLogic.DoFragment(Sender: TObject; aApp: TsgcHTMLMCPApp;
  const aTarget, aArguments: string; var aHTML: string);
begin
  { aTarget is what the element asked for, for instance orders?status=open }
  if StartsText('orders', aTarget) then
    aHTML := BuildOrdersTable(StatusOf(aTarget));
end;

The same markup served over HTTP is an ordinary htmx request. You write the page once and it works in both places.

One Document, Nothing Linked

Because the frame has no network, the document carries everything: the page, the stylesheet, the script and the bridge, in a single file. The new InlineAssets option of the page template does that, and it is on by default for MCP Apps. A typical app document is around 360 KB, and it needs nothing else to render.

The host is also told what size to open the frame at, through PreferredWidth and PreferredHeight, and the page reports its own height as the content changes.

You Can See It Without Installing an Assistant

The new demo 19.MCPApp is a console server on port 5725 that publishes two apps, and it ships a reference host of its own. Open http://localhost:5725/ and the left panel stands in for the model: it calls the tool, reads the resource, renders it in a sandboxed frame, answers the handshake, resizes the frame when the page asks and forwards what the page calls. The log under it shows every message going both ways.

When you want the real thing, point Claude, ChatGPT or VS Code at http://localhost:5725/mcp. The tools and the resources are already declared there.

What It Is Not

The component keeps no state. Who may call a tool, what a record means and what a fragment request is allowed to return are your application's decisions, exactly as they are for a route in a web application. And the page cannot smuggle anything in: what the model can trigger is a tool you registered, answering with markup you built.

Upgrading

MCP Apps are part of sgcHTML and need SGC_AI_MCP, which is the Enterprise and All-Access editions and the sgcAI pack. Nothing changes for an existing MCP server: the component attaches to the one you already have and leaves the tools you already publish alone.

Watch It

There is a short video of this on the eSeGeCe channel.

Questions, feedback or migration help? Get in touch — you will get a reply from the people who wrote the code.