MCPApp

TsgcHTMLComponent_MCPApp: narzędzie MCP, które zamiast tekstu odpowiada stroną, dzięki czemu te same komponenty Delphi, które renderują każdą stronę webową, renderują się wewnątrz ChatGPT, Claude i VS Code (MCP Apps).

TsgcHTMLComponent_MCPApp

MCP App to narzędzie, którego wynik host renderuje, zamiast go tylko odczytywać. Komponent publikuje narzędzie, zasób niosący stronę oraz narzędzie towarzyszące, które wywołuje sama strona, na serwerze MCP, który już masz, a strona jest zbudowana z tych samych komponentów sgcHTML co każda inna. Wymaga edycji Enterprise lub All-Access sgcWebSockets albo pakietu sgcAI, ponieważ działa na serwerze MCP.

Klasa komponentu

TsgcHTMLComponent_MCPApp, z kolekcją TsgcHTMLMCPApps złożoną z elementów TsgcHTMLMCPApp

Renderuje

Jeden dokument HTML, który host pokazuje w ramce w piaskownicy, ze wszystkimi zasobami wbudowanymi

Rodzina

Czat i AI

Języki

Delphi, C++ Builder, .NET

Zadeklaruj aplikację, obsłuż trzy zdarzenia

Przekaż komponentowi MCPServer z TsgcWSAPIServer_MCP, dodaj aplikację z nazwą narzędzia i opisem, obsłuż OnRender, OnToolCall i OnFragment, a następnie wywołaj 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();

Kluczowe właściwości i metody

Składniki, po które sięgasz najczęściej.

Aplikacje

Apps to kolekcja TsgcHTMLMCPApps zawierająca elementy TsgcHTMLMCPApp. ToolName jest wymagane: aplikacja bez niego niczego nie rejestruje. Description jest tym, co czyta model, aby zdecydować, czy wywołać narzędzie, a InputSchema to schemat JSON jego argumentów. Title, ResourceURI, PageBuilder, Enabled, PreferredWidth i PreferredHeight uzupełniają aplikację, przy czym ostatnie dwa to rozmiar, w jakim host jest proszony o otwarcie ramki.

Co deklaruje RegisterApps

Na serwerze trzy rzeczy dla każdej aplikacji: narzędzie, nazwane przez ToolName, którego _meta.ui.resourceUri mówi hostowi, który zasób niesie stronę; narzędzie towarzyszące <ToolName>.fragment, które wywołuje strona, a model nigdy; oraz zasób ui://sgchtml/<toolname>, serwowany jako text/html;profile=mcp-app. W Delphi RegisterApps uruchamia się z Loaded, a kod, który dodaje aplikację, wywołuje je ponownie; w .NET wywołaj je samodzielnie. UnregisterApps je usuwa.

Dwie połowy wyniku

Wynik narzędzia ma dwóch odbiorców. W OnToolCall aText to zdanie, które czyta model, a aStructured to JSON, który czyta strona. Oba są opcjonalne, a gdy tekst jest pusty, używany jest Title aplikacji. Wypełnij oba, gdy się różnią, co zwykle ma miejsce: model chce zdania, a strona liczb.

Strona

OnRender zwraca stronę jako zwykłe znaczniki sgcHTML. aHTML przychodzi zawierając stronę, którą buduje PageBuilder aplikacji, jeśli jest przypisany, więc procedura obsługi może ją zastąpić lub zostawić. GetAppHTML zwraca cały dokument jednej aplikacji, czyli to, co odpowiada zasób i co czyta test.

Fragmenty i most

Ramka w piaskownicy nie ma serwera HTTP, który mógłby odpowiedzieć na hx-get. Każdy dokument zawiera window.sgcMCPApp: wysyła ui/initialize, gdy strona jest gotowa, stosuje motyw, który zwraca host, zgłasza wysokość strony, aby host mógł dobrać rozmiar ramki, i rejestruje rozszerzenie htmx, które zamienia każde hx-get i hx-post na tools/call narzędzia fragmentów. OnFragment na nie odpowiada: aTarget to to, o co poprosił element, aArguments to JSON formularza lub zapytania, a aHTML to znaczniki wstawiane do strony. Te same znaczniki serwowane przez HTTP to zwykłe żądanie htmx.

Jeden dokument

Ramka jest w piaskownicy i zwykle nie ma własnej sieci, więc nic nie może być podlinkowane. InlineAssets jest domyślnie włączone i sprawia, że arkusz stylów, skrypty i strona podróżują w jednym pliku. Wyłącz je tylko dla hosta na tej samej maszynie, który może serwować zasoby.

Serwer MCP

MCPServer to TsgcAI_MCP_Server, na którym deklarowane są aplikacje. TsgcWSAPIServer_MCP udostępnia go jako właściwość publiczną, więc FApps.MCPServer := FMCP.MCPServer umieszcza aplikacje na punkcie końcowym serwera webowego. Komponent subskrybuje zdarzenia narzędzi i zasobów i łączy w łańcuch procedury obsługi, które już tam były, więc narzędzia, które już publikujesz, nadal działają. Aplikacja hostująca, która sama obsługuje te zdarzenia, wywołuje ProcessToolsCall i ProcessResourcesRead, które zwracają False, gdy żądanie nie dotyczyło aplikacji. W .NET przekaż mu posiadany TsgcAI_MCP_Server, na przykład ten, którego właścicielem jest TsgcAI_MCP_Server_Stdio.

Brak stanu

Komponent nie przechowuje żadnego własnego stanu. To, co oznacza wywołanie narzędzia, kto może je wywołać i co może zwrócić żądanie fragmentu, to decyzje Twojej aplikacji, dokładnie tak jak w przypadku trasy w aplikacji webowej. Model może uruchomić tylko narzędzie zarejestrowane przez Ciebie, które odpowiada znacznikami zbudowanymi przez Ciebie.

Zobacz to bez asystenta

Demos\60.HTML\01.RunTime\19.MCPApp to serwer konsolowy na porcie 5725, który publikuje dwie aplikacje, orders.board i sales.summary, na jednym punkcie końcowym i dostarcza referencyjnego hosta. Otwórz http://localhost:5725/, a lewy panel robi to, co prawdziwy host: wywołuje narzędzie, odczytuje zasób, renderuje go w ramce w piaskownicy i przekazuje wywołania strony. Skieruj Claude, ChatGPT lub VS Code na http://localhost:5725/mcp, aby wypróbować prawdziwy scenariusz.

Dostępność

Jednostka kompiluje się tam, gdzie zdefiniowane są zarówno SGC_HTML, jak i SGC_AI_MCP. SGC_AI_MCP jest częścią edycji Enterprise i All-Access oraz pakietu sgcAI. SGC_HTML jest częścią sgcHTML, sprzedawanego niezależnie od sgcWebSockets, na każdej platformie z wyjątkiem Androida i iOS.

Poznawaj dalej

Pomoc onlinePrzewodnik użytkowania MCP Apps: narzędzie, zasób, narzędzie fragmentów i most.
Wszystkie komponenty sgcHTMLPrzejrzyj pełną matrycę funkcji 80+ komponentów.
Pobierz bezpłatną wersję próbną30-dniowa wersja próbna zawiera projekty demonstracyjne 60.HTML.
CennikLicencje Single, Team i Site z pełnym kodem źródłowym.
Najkorzystniejsza oferta: All-AccessWszystkie produkty eSeGeCe, ze wsparciem Premium w cenie, już od €1,059 rocznie.
Zobacz cennik All-Access

Gotowy, aby zacząć?

Pobierz bezpłatną wersję próbną i zacznij budować interfejsy webowe w Delphi, C++ Builder i .NET.