MCP Fusion/Protocol and runtime/Wire-Format

Wire-Format

Frag die KI über Vinkius

Die exakten Bytes, die ein Presenter sendet: die geordneten Textblöcke, das ui_passthrough-XML, die Domain-Regeln, die Aktionsvorschläge, die _select-Guillotine, die Embeds und TOON.

Ein Tool-Aufruf mit einem Presenter gibt kein JSON.stringify zurück, sondern eine geordnete Folge von Textblöcken, jeder mit einer stabilen Form, die der Agent (und jede Client-UI) parsen kann. Diese Seite ist die Spezifikation dieses Formats.

Die Block-Sequenz

ResponseBuilder.build() gibt bis zu sechs Blöcke aus, immer in dieser Reihenfolge:

#BlockForm
1datader maskierte, serialisierte Payload als JSON-Text
2UI blocksein <ui_passthrough> pro Block
3embedsRohblöcke aus Kind-Presenters
4directives<llm_directives>-Liste
5rules<domain_rules>-Liste
6suggestions<action_suggestions>-Liste

Ein UI-Block sieht auf dem Wire so aus:

xml
<ui_passthrough type="echarts" title="Revenue by month" width="full" priority="1">
  echarts-fenced-content: the chart config as formatted JSON
</ui_passthrough>

Die Attribute type, title, width (full, half, third) und priority sagen einem Client-Renderer, was der Fence-Inhalt ist. ui.table und ui.list sind Markdown; ui.json ist fenced JSON; ui.codeBlock behält seinen Language-Tag. Es gibt keinen nativen Table-Blocktyp: das Fence ist der Vertrag, und fence() ist die einzige Stelle, die sich ändert, falls MCP UI-Blöcke standardisiert.

Die Regeln- und Vorschlagsblöcke sind schlichte Bullet-Listen:

xml
<domain_rules>
- amount_cents is in CENTS. Divide by 100.
</domain_rules>
<action_suggestions>
- billing.remind: Send a payment reminder
</action_suggestions>

structuredContent ist ein separates System

Das Feld structuredContent von MCP 2.0 wird von Presenters nicht erzeugt. Um es auszugeben, verwenden Sie successStructured(data), das den JSON-Textblock für MCP 1.0-Clients plus das maschinenlesbare Feld structuredContent sendet, und deklarieren Sie die Form auf dem Wire mit .withOutputSchema(schema). Presenters gehören der Text für Menschen und LLMs; successStructured gehört der Kanal für geparste Objekte. Verwechseln Sie die beiden nicht.

_select: die Feld-Guillotine

.enableSelect() fügt jeder Action des Tools einen Array-Parameter _select hinzu, dessen Enum die Vereinigung der Root-Schema-Keys über alle Actions ist. Wenn der Agent _select übergibt, wird der data-Block auf diese Keys gefiltert. Alles andere (UI-Blöcke, Regeln, Vorschläge) läuft weiter auf dem vollständigen Objekt, sodass ein Client, der die Antwort für einen Menschen rendert, das ganze Bild sieht, während der Model-Kontext nur enthält, was angefordert wurde. Das ist der günstigste Token-Gewinn bei breiten Modellen, und er ist pro Builder opt-in.

embed: relationale Komposition

.embed('lines', InvoiceLinesPresenter) liest data.lines über einen Kind-Presenter und fügt dessen Blöcke und Regeln der Eltern-Antwort hinzu. Der Parent besitzt eine Entität; ein Graph von Entitäten ist ein Baum von Presenters, jeder mit eigenem Schema, eigener Schwärzung und eigenen Limits.

TOON: Beschreibungen mit der Hälfte der Tokens

.toonDescription() und toonSuccess(data) verwenden für einheitliche Sammlungen das TOON-Format mit Pipe-Trennung: wiederholte Keys kollabieren in eine Kopfzeile, und das Array wird zu einer Tabelle von Werten. Bei einer Liste von zehntausend identisch geformten Einträgen halbiert sich die Token-Zahl etwa. Das Format wird aus dem Action-Schema erzeugt, sodass der Agent action|desc|required als Ebene eins und die Daten als Ebene zwei sieht.

Die Seitentür der Tests

Jede Presenter-Antwort trägt ein nicht-aufzählbares Symbol mit { data, systemRules, uiBlocks }. @mcpfusion/testing liest den strukturierten View darüber, statt das XML zurückzuparsen, und genau deshalb sind result.data, result.systemRules und result.uiBlocks in Testing exakt. JSON.stringify sieht das Symbol nie.

Implizite Wrapping-Regeln

Der Rückgabewert eines Handlers wird nach einer Regel interpretiert: gebrandete ToolResponse-Objekte passieren ihn unverändert, alles andere wird als success(data) verpackt. Ein null oder undefined wird zu dem Text OK. Deshalb bauen Sie nie von Hand { content: [...] }-Formate, und deshalb erfordert das Hinzufügen eines Presenters nie Änderungen am Handler.

Nächste Schritte