MCPApp

TsgcHTMLComponent_MCPApp: テキストではなくページで応答する MCP ツールです。Web ページをレンダリングするのと同じ Delphi コンポーネントが、ChatGPT、Claude、VS Code の内部でレンダリングされます(MCP Apps)。

TsgcHTMLComponent_MCPApp

MCP App は、ホストが読むだけでなくレンダリングもする結果を返すツールです。このコンポーネントは、すでにお使いの MCP サーバーに、ツール、ページを運ぶリソース、ページ自身が呼び出すコンパニオンツールを公開し、ページは他のページと同じ sgcHTML コンポーネントで構築されます。MCP サーバー上で動作するため、sgcWebSockets の Enterprise または All-Access エディション、あるいは sgcAI パックが必要です。

コンポーネントクラス

TsgcHTMLComponent_MCPAppTsgcHTMLMCPApps コレクションが付属し、項目は TsgcHTMLMCPApp です

レンダリング内容

ホストがサンドボックス化されたフレームに表示する 1 つの HTML ドキュメント。アセットはインラインで含まれます

ファミリー

チャット & AI

言語

Delphi, C++ Builder, .NET

アプリを宣言し、3 つのイベントに応答する

コンポーネントに MCPServer として TsgcWSAPIServer_MCP を割り当て、ツール名と説明を持つアプリを追加し、OnRenderOnToolCallOnFragment に応答してから、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();

主なプロパティとメソッド

最もよく使うメンバーです。

アプリ

AppsTsgcHTMLMCPApps コレクションで、項目は TsgcHTMLMCPApp です。ToolName は必須で、これがないアプリは何も登録しません。Description はモデルがツールを呼び出すかどうかを判断するために読む内容で、InputSchema はその引数の JSON スキーマです。TitleResourceURIPageBuilderEnabledPreferredWidthPreferredHeight でアプリが完成し、最後の 2 つは、ホストがフレームを開くときに求められるサイズです。

RegisterApps が宣言するもの

アプリごとにサーバー上に 3 つのものを登録します。1 つ目はツールで、ToolName で名前が付けられ、その _meta.ui.resourceUri がページを運ぶリソースをホストに伝えます。2 つ目はコンパニオンツール <ToolName>.fragment で、ページが呼び出し、モデルは呼び出しません。3 つ目はリソース ui://sgchtml/<toolname> で、text/html;profile=mcp-app として提供されます。Delphi では、RegisterAppsLoaded から実行され、アプリを追加するコードは再度これを呼び出します。.NET では自分で呼び出します。UnregisterApps はそれらを削除します。

結果の 2 つの側面

ツールの結果には 2 種類の受け手がいます。OnToolCall では、aText はモデルが読む文で、aStructured はページが読む JSON です。どちらも省略可能で、テキストが空の場合はアプリの Title が使われます。両者が異なる場合は両方に応答してください。通常は異なります。モデルは文を必要とし、ページは数値を必要とするからです。

ページ

OnRender は、ページを通常の sgcHTML マークアップとして返します。aHTML には、アプリの PageBuilder が割り当てられている場合にそれが構築したページが入った状態で渡されるので、ハンドラーはそれを置き換えることも、そのままにすることもできます。GetAppHTML は 1 つのアプリのドキュメント全体を返し、これはリソースが返す内容であり、テストが読み取る内容でもあります。

フラグメントとブリッジ

サンドボックス化されたフレームには、hx-get に応答する HTTP サーバーがありません。すべてのドキュメントは window.sgcMCPApp を持ちます。これはページの準備ができると ui/initialize を送信し、ホストが返したテーマを適用し、ホストがフレームのサイズを決められるようにページの高さを報告し、すべての hx-gethx-post をフラグメントツールの tools/call に変換する htmx 拡張を登録します。OnFragment がこれに応答します。aTarget は要素が要求したもの、aArguments はフォームまたはクエリの JSON、aHTML は差し替えられるマークアップです。HTTP 経由で提供される同じマークアップは、通常の htmx リクエストです。

1 つのドキュメント

フレームはサンドボックス化されており、通常は独自のネットワークを持たないため、何もリンクできません。InlineAssets は既定でオンで、スタイルシート、スクリプト、ページを 1 つのファイルにまとめて運びます。アセットを提供できる同じマシン上のホストの場合にのみ、オフにしてください。

MCP サーバー

MCPServer は、アプリが宣言される TsgcAI_MCP_Server です。TsgcWSAPIServer_MCP はこれを public プロパティとして公開しているため、FApps.MCPServer := FMCP.MCPServer によって Web サーバーのエンドポイントにアプリが置かれます。コンポーネントはツールとリソースのイベントを購読し、それまで設定されていたハンドラーを連鎖させるので、すでに公開しているツールは引き続き動作します。それらのイベントを自前で処理するホストは ProcessToolsCallProcessResourcesRead を呼び出します。これらは、リクエストがアプリのものでなかった場合に False を返します。.NET では、お持ちの TsgcAI_MCP_Server を渡します。たとえば TsgcAI_MCP_Server_Stdio が所有するものです。

状態を持たない

このコンポーネントは独自の状態を一切保持しません。ツール呼び出しの意味、呼び出しを許可する相手、フラグメントリクエストが返してよい内容は、Web アプリケーションのルートと同様に、アプリケーション側で決めることです。モデルが起動できるのは登録したツールだけで、返すのも自分で構築したマークアップです。

アシスタントなしで確認する

Demos\60.HTML\01.RunTime\19.MCPApp は、ポート 5725 で動作するコンソールサーバーで、1 つのエンドポイントに 2 つのアプリ orders.boardsales.summary を公開し、リファレンスホストを同梱しています。http://localhost:5725/ を開くと、左側のパネルが実際のホストと同じ動作をします。ツールを呼び出し、リソースを読み取り、サンドボックス化されたフレームにレンダリングし、ページからの呼び出しを転送します。実際の環境で試すには、Claude、ChatGPT、VS Code を http://localhost:5725/mcp に向けてください。

提供状況

ユニットは SGC_HTMLSGC_AI_MCP の両方が定義されている環境でコンパイルされます。SGC_AI_MCP は Enterprise および All-Access エディションと sgcAI パックに含まれます。SGC_HTML は sgcHTML に含まれ、sgcHTML は sgcWebSockets とは別に販売されており、Android と iOS を除くすべてのプラットフォームで利用できます。

さらに詳しく

オンラインヘルプMCP Apps の使用ガイド: ツール、リソース、フラグメントツール、ブリッジ。
すべての sgcHTML コンポーネント80 以上のコンポーネントの全機能マトリックスを閲覧できます。
無料体験版のダウンロード30 日間の体験版には 60.HTML デモプロジェクトが付属します。
価格完全なソースコード付きの Single、Team、Site ライセンス。
最もお得な選択: All-AccesseSeGeCe の全製品にプレミアムサポートが付いて、年間 €1,059 からご利用いただけます。
All-Access の価格を見る

始める準備はできましたか?

無料体験版をダウンロードして、Delphi、C++ Builder、.NET で Web UI の構築を始めましょう。