MCPApp

TsgcHTMLComponent_MCPApp: una herramienta MCP que responde con una página en lugar de texto, de modo que los mismos componentes de Delphi que renderizan cualquier página web se renderizan dentro de ChatGPT, Claude y VS Code (MCP Apps).

TsgcHTMLComponent_MCPApp

Una MCP App es una herramienta cuyo resultado el host renderiza en lugar de limitarse a leerlo. El componente publica la herramienta, el recurso que lleva la página y una herramienta auxiliar a la que llama la propia página, en el servidor MCP que ya tienes, y la página se construye con los mismos componentes sgcHTML que cualquier otra. Requiere la edición Enterprise o All-Access de sgcWebSockets, o el pack sgcAI, porque se ejecuta en el servidor MCP.

Clase del componente

TsgcHTMLComponent_MCPApp, con la colección TsgcHTMLMCPApps de elementos TsgcHTMLMCPApp

Genera

Un documento HTML que el host muestra en un marco aislado, con sus recursos incrustados

Familia

Chat e IA

Lenguajes

Delphi, C++ Builder, .NET

Declara una app, responde a tres eventos

Dale al componente el MCPServer de un TsgcWSAPIServer_MCP, añade una app con un nombre de herramienta y una descripción, responde a OnRender, OnToolCall y OnFragment, y luego llama a RegisterApps.

uses
  Classes, SysUtils, StrUtils,
  // sgc
  sgcWebSocket_Server, sgcAI, sgcHTML_Nodes, sgcHTML_Nodes_Bootstrap,
  sgcHTML_MCPApp;

// The MCP endpoint a host connects to
FMCP := TsgcWSAPIServer_MCP.Create(nil);
FMCP.Server := FHTTPServer;
FMCP.EndpointOptions.Endpoint := '/mcp';

// The apps, declared on the MCP server the endpoint owns
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"}}}';
  PreferredWidth := 720;
  PreferredHeight := 460;
end;
FApps.RegisterApps;   // the tool, the fragment tool and the resource

// What the model reads, and what the page reads
procedure TMyLogic.DoToolCall(Sender: TObject; aApp: TsgcHTMLMCPApp;
  const aArguments: string; var aText, aStructured: string);
begin
  aText := '3 open orders, 1420.50 in total.';
  aStructured := '{"orders":3,"total":1420.5}';
end;

// The page: ordinary sgcHTML components
procedure TMyLogic.DoRender(Sender: TObject; aApp: TsgcHTMLMCPApp;
  const aArguments: string; var aHTML: string);
var
  oCard: TsgcHTMLCard;
  oButton: TsgcHTMLContainer;
begin
  oCard := TsgcHTMLCard.Create;
  try
    oCard.Body.Add(TsgcHTMLHeading.Create('Orders', 5));

    oButton := TsgcHTMLContainer.Create('button');
    oButton.CSSClass := 'btn btn-outline-secondary';
    // inside a host, the bridge turns this hx-get into a call of the fragment tool
    oButton.Attributes := 'type="button" hx-get="orders?status=open" ' +
      'hx-target="#orders" hx-swap="outerHTML"';
    oButton.AddText('Open');
    oCard.Body.Add(oButton);

    oCard.Body.AddRaw(BuildOrdersTable(''));   // your markup: the element whose id is orders
    aHTML := oCard.HTML;
  finally
    oCard.Free;
  end;
end;

// The markup a control of the page asked for
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;
// includes: sgcAI.hpp, sgcHTML_MCPApp.hpp

// The MCP endpoint a host connects to
FMCP = new TsgcWSAPIServer_MCP(NULL);
FMCP->Server = FHTTP;
FMCP->EndpointOptions->Endpoint = "/mcp";

// The apps, declared on the MCP server the endpoint owns
FApps = new TsgcHTMLComponent_MCPApp(NULL);
FApps->MCPServer = FMCP->MCPServer;
FApps->OnRender = DoRender;
FApps->OnToolCall = DoToolCall;
FApps->OnFragment = DoFragment;

TsgcHTMLMCPApp *app = FApps->Apps->Add();
app->ToolName = "orders.board";
app->Title = "Orders board";
app->Description = "Shows the orders of the company as a board that can be filtered by status.";
app->InputSchema->Text = "{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"}}}";
app->PreferredWidth = 720;
app->PreferredHeight = 460;
FApps->RegisterApps();   // the tool, the fragment tool and the resource

// What the model reads, and what the page reads
void __fastcall TMyLogic::DoToolCall(TObject *Sender, TsgcHTMLMCPApp *aApp,
  const String aArguments, String &aText, String &aStructured)
{
  aText = "3 open orders, 1420.50 in total.";
  aStructured = "{\"orders\":3,\"total\":1420.5}";
}

// The markup a control of the page asked for
void __fastcall TMyLogic::DoFragment(TObject *Sender, TsgcHTMLMCPApp *aApp,
  const String aTarget, const String aArguments, String &aHTML)
{
  // aTarget is what the element asked for, for instance orders?status=open
  if (aTarget.Pos("orders") == 1)
    aHTML = BuildOrdersTable(StatusOf(aTarget));
}

// DoRender answers the page with sgcHTML components, as in the Delphi tab.
using esegece.sgcWebSockets;

// An MCP server over stdio, for a host that starts your program as a process
var host = new TsgcAI_MCP_Server_Stdio();

var apps = new TsgcHTMLComponent_MCPApp();
apps.MCPServer = host.MCPServer;

var app = apps.Apps.Add();
app.ToolName = "orders.board";
app.Title = "Orders board";
app.Description = "Shows the orders of the company as a board that can be filtered by status.";
app.InputSchema.Add("{\"type\":\"object\",\"properties\":{\"status\":{\"type\":\"string\"}}}");
app.PreferredWidth = 720;
app.PreferredHeight = 460;

// What the model reads, and what the page reads
apps.OnToolCall += (object sender, TsgcHTMLMCPApp a, string args,
    ref string text, ref string structured) =>
{
    text = "3 open orders, 1420.50 in total.";
    structured = "{\"orders\":3,\"total\":1420.5}";
};

// The page: ordinary sgcHTML components
apps.OnRender += (object sender, TsgcHTMLMCPApp a, string args, ref string html) =>
{
    var card = new TsgcHTMLCard();
    card.Body.Add(new TsgcHTMLHeading("Orders", 5));

    var button = new TsgcHTMLContainer("button");
    button.CSSClass = "btn btn-outline-secondary";
    // inside a host, the bridge turns this hx-get into a call of the fragment tool
    button.Attributes = "type=\"button\" hx-get=\"orders?status=open\" "
        + "hx-target=\"#orders\" hx-swap=\"outerHTML\"";
    button.AddText("Open");
    card.Body.Add(button);

    card.Body.AddRaw(BuildOrdersTable(""));   // your markup: the element whose id is orders
    html = card.HTML;
};

// The markup a control of the page asked for
apps.OnFragment += (object sender, TsgcHTMLMCPApp a, string target,
    string args, ref string html) =>
{
    // target is what the element asked for, for instance orders?status=open
    if (target.StartsWith("orders"))
        html = BuildOrdersTable(StatusOf(target));
};

apps.RegisterApps();   // the tool, the fragment tool and the resource
host.Run();

Propiedades y métodos clave

Los miembros que usarás con más frecuencia.

Apps

Apps es una colección TsgcHTMLMCPApps de elementos TsgcHTMLMCPApp. ToolName es obligatorio: una app sin él no registra nada. Description es lo que lee el modelo para decidir si llama a la herramienta; InputSchema es el esquema JSON de sus argumentos. Title, ResourceURI, PageBuilder, Enabled, PreferredWidth y PreferredHeight completan una app, siendo los dos últimos el tamaño con el que se pide al host que abra el marco.

Lo que declara RegisterApps

Tres cosas por cada app en el servidor: la herramienta, con el nombre indicado en ToolName, cuyo _meta.ui.resourceUri indica al host qué recurso lleva la página; la herramienta auxiliar <ToolName>.fragment, a la que llama la página y nunca el modelo; y el recurso ui://sgchtml/<toolname>, servido como text/html;profile=mcp-app. En Delphi, RegisterApps se ejecuta desde Loaded y el código que añade una app vuelve a llamarlo; en .NET, llámalo tú mismo. UnregisterApps las elimina.

Las dos mitades de un resultado

Un resultado de herramienta tiene dos destinatarios. En OnToolCall, aText es la frase que lee el modelo y aStructured es el JSON que lee la página. Ambos son opcionales, y cuando el texto está vacío se usa el Title de la app. Responde a ambos cuando difieran, lo que suele ocurrir: el modelo quiere una frase y la página quiere números.

La página

OnRender responde con la página como marcado sgcHTML normal. aHTML llega con la página que construye el PageBuilder de la app, cuando hay uno asignado, de modo que un manejador puede reemplazarla o dejarla. GetAppHTML devuelve el documento completo de una app, que es lo que responde el recurso y lo que lee una prueba.

Fragmentos y el puente

Un marco aislado no tiene servidor HTTP que responda a un hx-get. Cada documento lleva window.sgcMCPApp: envía ui/initialize cuando la página está lista, aplica el tema con el que responde el host, informa de la altura de la página para que el host pueda dimensionar el marco, y registra una extensión de htmx que convierte cada hx-get y hx-post en un tools/call de la herramienta de fragmentos. OnFragment responde a esa llamada: aTarget es lo que el elemento pidió, aArguments el JSON del formulario o de la consulta, y aHTML el marcado que se intercambia. El mismo marcado servido por HTTP es una petición htmx normal.

Un solo documento

El marco está aislado y normalmente no tiene red propia, así que no se puede enlazar nada. InlineAssets está activado por defecto y hace que la hoja de estilos, los scripts y la página viajen en un solo archivo. Desactívalo solo para un host en la misma máquina que pueda servir los recursos.

El servidor MCP

MCPServer es el TsgcAI_MCP_Server en el que se declaran las apps. TsgcWSAPIServer_MCP lo expone como propiedad pública, de modo que FApps.MCPServer := FMCP.MCPServer coloca las apps en el endpoint de un servidor web. El componente se suscribe a los eventos de herramientas y recursos y encadena los manejadores que ya había, así que las herramientas que ya publicas siguen funcionando. Un host que gestiona esos eventos por sí mismo llama a ProcessToolsCall y ProcessResourcesRead, que responden False cuando la petición no era de una app. En .NET, pásale el TsgcAI_MCP_Server que tengas, por ejemplo el que es propiedad de TsgcAI_MCP_Server_Stdio.

Sin estado

El componente no guarda ningún estado propio. Qué significa una llamada a una herramienta, quién puede hacerla y qué puede devolver una petición de fragmento son decisiones de tu aplicación, exactamente igual que con una ruta en una aplicación web. Lo que el modelo puede desencadenar es una herramienta que tú registraste, que responde con marcado que tú construiste.

Pruébalo sin un asistente

Demos\60.HTML\01.RunTime\19.MCPApp es un servidor de consola en el puerto 5725 que publica dos apps, orders.board y sales.summary, en un mismo endpoint, e incluye un host de referencia. Abre http://localhost:5725/ y el panel izquierdo hace lo que hace un host real: llama a la herramienta, lee el recurso, lo renderiza en un marco aislado y reenvía las llamadas de la página. Apunta Claude, ChatGPT o VS Code a http://localhost:5725/mcp para probarlo de verdad.

Disponibilidad

La unidad se compila donde están definidos SGC_HTML y SGC_AI_MCP. SGC_AI_MCP viene con las ediciones Enterprise y All-Access y con el pack sgcAI. SGC_HTML viene con sgcHTML, que se vende de forma independiente de sgcWebSockets, en todas las plataformas excepto Android e iOS.

Sigue explorando

Ayuda en líneaGuía de uso de las MCP Apps: la herramienta, el recurso, la herramienta de fragmentos y el puente.
Todos los componentes de sgcHTMLExplora la matriz completa de más de 80 componentes.
Descargar prueba gratuitaLa prueba de 30 días incluye los proyectos de demostración 60.HTML.
PreciosLicencias Single, Team y Site con código fuente completo.
La mejor opción: All-AccessTodos los productos de eSeGeCe, con Premium Support incluido, desde €1,059 al año.
Ver precios de All-Access

¿Listo para empezar?

Descarga la prueba gratuita y empieza a crear interfaces web en Delphi, C++ Builder y .NET.