MCPApp

TsgcHTMLComponent_MCPApp: 텍스트 대신 페이지로 응답하는 MCP 도구로, 일반 웹 페이지를 렌더링하는 것과 같은 Delphi 컴포넌트가 ChatGPT, Claude, VS Code(MCP Apps) 안에서 렌더링됩니다.

TsgcHTMLComponent_MCPApp

MCP App은 호스트가 단순히 읽는 데 그치지 않고 결과를 렌더링하는 도구입니다. 이 컴포넌트는 도구, 페이지를 담은 리소스, 페이지가 직접 호출하는 보조 도구를 이미 사용 중인 MCP 서버에 게시하며, 페이지는 다른 페이지와 마찬가지로 동일한 sgcHTML 컴포넌트로 구성됩니다. MCP 서버에서 실행되므로 sgcWebSockets의 Enterprise 또는 All-Access 에디션, 또는 sgcAI 팩이 필요합니다.

컴포넌트 클래스

TsgcHTMLComponent_MCPApp, TsgcHTMLMCPApps 컬렉션(TsgcHTMLMCPApp 항목) 포함

렌더링

호스트가 샌드박스 프레임에 표시하는, 자산이 인라인으로 포함된 하나의 HTML 문서

패밀리

채팅 및 AI

언어

Delphi, C++ Builder, .NET

앱을 선언하고 세 가지 이벤트에 응답하기

컴포넌트의 MCPServerTsgcWSAPIServer_MCP를 지정하고, 도구 이름과 설명이 있는 앱을 추가한 다음 OnRender, OnToolCall, OnFragment에 응답하고 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();

주요 속성 및 메서드

가장 자주 사용하게 되는 멤버.

Apps

AppsTsgcHTMLMCPApps 컬렉션이며 TsgcHTMLMCPApp 항목을 담습니다. ToolName은 필수입니다. 이 값이 없는 앱은 아무것도 등록하지 않습니다. Description은 모델이 도구를 호출할지 판단하기 위해 읽는 내용이고, InputSchema는 인수의 JSON 스키마입니다. Title, ResourceURI, PageBuilder, Enabled, PreferredWidth, PreferredHeight가 앱을 완성하며, 마지막 두 개는 호스트가 프레임을 열 때 요청받는 크기입니다.

RegisterApps가 선언하는 내용

앱마다 서버에 세 가지가 등록됩니다. 하나는 ToolName으로 이름 붙인 도구로, 그 _meta.ui.resourceUri가 어느 리소스가 페이지를 담고 있는지 호스트에 알려 줍니다. 다른 하나는 보조 도구 <ToolName>.fragment로, 페이지가 호출하며 모델은 호출하지 않습니다. 마지막은 리소스 ui://sgchtml/<toolname>로, text/html;profile=mcp-app로 제공됩니다. Delphi에서는 RegisterAppsLoaded에서 실행되며 앱을 추가하는 코드는 이를 다시 호출합니다. .NET에서는 직접 호출하십시오. UnregisterApps는 이들을 제거합니다.

결과의 두 부분

도구 결과에는 두 종류의 독자가 있습니다. OnToolCall에서 aText는 모델이 읽는 문장이고 aStructured는 페이지가 읽는 JSON입니다. 둘 다 선택 사항이며, 텍스트가 비어 있으면 앱의 Title이 사용됩니다. 둘이 서로 다를 때는 둘 다 작성하십시오. 대개 서로 다릅니다. 모델에는 문장이 필요하고 페이지에는 숫자가 필요하기 때문입니다.

페이지

OnRender는 페이지를 일반 sgcHTML 마크업으로 응답합니다. aHTML에는 앱의 PageBuilder가 할당되어 있다면 그것이 만든 페이지가 담겨 도착하므로, 핸들러는 이를 교체하거나 그대로 둘 수 있습니다. GetAppHTML은 한 앱의 문서 전체를 반환하며, 이것이 리소스가 응답하는 내용이자 테스트가 읽는 내용입니다.

프래그먼트와 브리지

샌드박스 프레임에는 hx-get에 응답할 HTTP 서버가 없습니다. 모든 문서는 window.sgcMCPApp을 갖습니다. 이것은 페이지가 준비되면 ui/initialize를 보내고, 호스트가 응답한 테마를 적용하며, 호스트가 프레임 크기를 정할 수 있도록 페이지 높이를 보고하고, hx-gethx-post를 모두 프래그먼트 도구의 tools/call로 바꾸는 htmx 확장을 등록합니다. OnFragment가 이에 응답합니다. aTarget은 요소가 요청한 것, aArguments는 폼 또는 쿼리의 JSON, aHTML은 교체되어 들어가는 마크업입니다. HTTP로 제공되는 동일한 마크업은 일반 htmx 요청입니다.

하나의 문서

프레임은 샌드박스 안에 있고 보통 자체 네트워크가 없으므로 아무것도 링크할 수 없습니다. InlineAssets는 기본적으로 켜져 있으며, 스타일시트, 스크립트, 페이지가 하나의 파일로 함께 전달되게 합니다. 같은 컴퓨터에서 자산을 제공할 수 있는 호스트에서만 끄십시오.

MCP 서버

MCPServer는 앱이 선언되는 TsgcAI_MCP_Server입니다. TsgcWSAPIServer_MCP가 이를 공개 속성으로 노출하므로, FApps.MCPServer := FMCP.MCPServer로 웹 서버의 엔드포인트에 앱을 올릴 수 있습니다. 컴포넌트는 도구와 리소스 이벤트를 구독하고 기존에 있던 핸들러를 이어서 호출하므로, 이미 게시한 도구는 계속 동작합니다. 이 이벤트를 직접 처리하는 호스트는 ProcessToolsCallProcessResourcesRead를 호출하며, 이들은 요청이 앱의 것이 아니면 False를 반환합니다. .NET에서는 이미 가지고 있는 TsgcAI_MCP_Server를 지정하십시오. 예를 들어 TsgcAI_MCP_Server_Stdio가 소유한 것을 사용할 수 있습니다.

상태 없음

컴포넌트는 자체 상태를 전혀 갖지 않습니다. 도구 호출이 무엇을 의미하는지, 누가 호출할 수 있는지, 프래그먼트 요청이 무엇을 반환할 수 있는지는 웹 애플리케이션의 라우트와 마찬가지로 애플리케이션이 결정할 사항입니다. 모델이 실행할 수 있는 것은 사용자가 등록한 도구이며, 그 도구는 사용자가 만든 마크업으로 응답합니다.

어시스턴트 없이 확인하기

Demos\60.HTML\01.RunTime\19.MCPApp은 하나의 엔드포인트에 orders.boardsales.summary 두 개의 앱을 게시하고 참조 호스트를 함께 제공하는, 포트 5725의 콘솔 서버입니다. http://localhost:5725/를 열면 왼쪽 패널이 실제 호스트와 같은 일을 합니다. 도구를 호출하고, 리소스를 읽고, 샌드박스 프레임에 렌더링하고, 페이지의 호출을 전달합니다. 실제 환경에서 사용하려면 Claude, ChatGPT 또는 VS Code가 http://localhost:5725/mcp를 가리키도록 설정하십시오.

사용 가능 여부

이 유닛은 SGC_HTMLSGC_AI_MCP가 모두 정의된 곳에서 컴파일됩니다. SGC_AI_MCP는 Enterprise 및 All-Access 에디션과 sgcAI 팩에 포함됩니다. SGC_HTML은 sgcWebSockets와 별도로 판매되는 sgcHTML에 포함되며, Android와 iOS를 제외한 모든 플랫폼에서 사용할 수 있습니다.

계속 살펴보기

온라인 도움말MCP Apps 사용 가이드: 도구, 리소스, 프래그먼트 도구, 브리지.
모든 sgcHTML 컴포넌트80개 이상의 컴포넌트 전체 기능 매트릭스를 둘러보십시오.
무료 체험판 다운로드30일 체험판에는 60.HTML 데모 프로젝트가 포함됩니다.
가격전체 소스 코드가 포함된 Single, Team 및 Site 라이선스.
최고의 가성비: All-Access모든 eSeGeCe 제품과 프리미엄 지원이 포함되어 연 €1,059부터 이용할 수 있어요.
All-Access 가격 보기

시작할 준비가 되셨습니까?

무료 체험판을 다운로드하고 Delphi, C++ Builder 및 .NET에서 웹 UI를 구축하기 시작하십시오.