- accounting.outgoing_documents.preview rendert den Beleg wie der Editor und liefert Seiten als PNG-Bilder im MCP-Ergebnis - Layout je Seite in mm mit Warnungen zu übervollen Seiten, allein stehenden Überschriften, leeren Seiten und vom Überweisungs-QR-Code überdeckten Beträgen samt Vorschlag für den Seitenumbruch - rows testet geänderte Positionen samt Seitenumbrüchen, ohne zu speichern - Belegdaten für das PDF als Backend-Port von getDocumentData (Titelsummen, Überträge, Abschläge, Optional-/Alternativpositionen) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
import { McpToolResult } from "./types"
|
|
|
|
const OMIT_ARCHIVED = Symbol("omit-archived")
|
|
|
|
/** Attach images to a tool payload; they become MCP image content next to the JSON text. */
|
|
export const MCP_IMAGES = Symbol("mcp-images")
|
|
export type McpImage = { data: string, mimeType: string }
|
|
export const withImages = <T extends Record<string, unknown>>(payload: T, images: McpImage[]) =>
|
|
Object.assign(payload, { [MCP_IMAGES]: images })
|
|
|
|
function omitArchivedRecords(value: unknown): unknown | typeof OMIT_ARCHIVED {
|
|
if (Array.isArray(value)) {
|
|
return value
|
|
.map(omitArchivedRecords)
|
|
.filter((item) => item !== OMIT_ARCHIVED)
|
|
}
|
|
|
|
if (!value || typeof value !== "object") return value
|
|
|
|
const prototype = Object.getPrototypeOf(value)
|
|
if (prototype !== Object.prototype && prototype !== null) return value
|
|
|
|
const record = value as Record<string, unknown>
|
|
if (record.archived === true) return OMIT_ARCHIVED
|
|
|
|
return Object.fromEntries(
|
|
Object.entries(record)
|
|
.map(([key, item]) => [key, omitArchivedRecords(item)] as const)
|
|
.filter(([, item]) => item !== OMIT_ARCHIVED),
|
|
)
|
|
}
|
|
|
|
export function asToolResult(payload: unknown): McpToolResult {
|
|
const sanitizedPayload = omitArchivedRecords(payload)
|
|
const resultPayload = sanitizedPayload === OMIT_ARCHIVED ? {} : sanitizedPayload
|
|
const structuredContent =
|
|
resultPayload && typeof resultPayload === "object" && !Array.isArray(resultPayload)
|
|
? resultPayload as Record<string, unknown>
|
|
: { result: resultPayload }
|
|
|
|
const images: McpImage[] = (payload as any)?.[MCP_IMAGES] || []
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text",
|
|
text: JSON.stringify(resultPayload, null, 2),
|
|
},
|
|
...images.map((image) => ({ type: "image" as const, data: image.data, mimeType: image.mimeType })),
|
|
],
|
|
structuredContent,
|
|
}
|
|
}
|
|
|
|
export function asToolError(error: unknown): McpToolResult {
|
|
const message = error instanceof Error ? error.message : "Unbekannter Fehler"
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text",
|
|
text: message,
|
|
},
|
|
],
|
|
isError: true,
|
|
structuredContent: {
|
|
error: message,
|
|
},
|
|
}
|
|
}
|