Inkscape
Ein Modell steuert Inkscape 1.4 über den Hub, um auf zwei Ebenen eine Visitenkarte zu gestalten. Inkscape ist hier die einzige Anwendung, bei der nichts zu starten ist: Der Hub führt für jedes Skript einen Python-Prozess aus. Die Seite nennt den Text, das Skript, die Antworten des Hubs und die Aufnahme.

Auf dieser Seite
Inkscape aktivieren
Es gibt weder eine Brücke noch ein Fenster. Der Hub sucht /usr/bin/python3, /usr/bin/inkscape und die Inkscape-Erweiterungen in /usr/share/inkscape/extensions. Die gesamte Vorbereitung ist ein Eintrag in ~/.config/libremodular-mcp/config.toml, nach libremodular-mcp init:
[apps.inkscape]
enabled = true
Auf einem frischen Debian 13 braucht import inkex außerdem python3-tinycss2, das das Paket inkscape nicht nachzieht: sudo apt install inkscape python3-tinycss2.
get_state für hub listete Inkscape als verbunden im Modus cli auf, mit der Version, die Inkscape meldete:
{
"app": "hub",
"app_version": "0.1.0",
"bridge_version": null,
"captured_at": "2026-10-21T12:47:13.608Z",
"connected": true,
"content_origin": "hub",
"screenshot": null,
"state": {
"modules": [
{
"app_version": "1.4",
"bridge_version": null,
"connected": true,
"mode": "cli",
"name": "inkscape"
}
]
},
"warnings": []
}Dem Modell gegebener Text
Vor dem Schreiben rief das Modell get_state für inkscape auf. Der state war leer, und eine Warnung lautete no document yet: the working document is created by the first script.
Geschriebenes Skript
Ein Modell, Claude Sonnet 5.5, schrieb dieses Skript nach dem Leitfaden und nach diesem Zustand. Es ist kein Skript aus den Tests des Projekts. Zwei Dinge stammen aus dem Leitfaden: Das Skript entfernt zuerst die Kindelemente der Wurzel, weil das Dokument von einem Skript zum nächsten erhalten bleibt, und es setzt cx, cy und r des Kreises einzeln, weil die beiden Argumente von inkex.Circle.new, wie der Leitfaden warnt, keinen Mittelpunkt ergeben.
import json
import os
import inkex
document = inkex.load_svg(os.environ["LMM_DOCUMENT"])
svg = document.getroot()
for child in list(svg):
svg.remove(child)
svg.set("width", "148mm")
svg.set("height", "105mm")
svg.set("viewBox", "0 0 148 105")
background = svg.add(inkex.Layer.new("Background"))
panel = inkex.Rectangle.new(0, 0, 148, 105)
panel.style = {"fill": "#1c385c"}
background.add(panel)
disc = inkex.Circle()
disc.set("cx", "20")
disc.set("cy", "20")
disc.set("r", "9")
disc.style = {"fill": "#c25438"}
background.add(disc)
rule = inkex.Rectangle.new(20, 62, 108, 0.8)
rule.style = {"fill": "#f2b344"}
background.add(rule)
texts = svg.add(inkex.Layer.new("Text"))
for content, y, size, colour, weight in [("Alice Martin", 56, 12, "#ffffff", "bold"), ("Sound engineer", 76, 6, "#cfd4da", "normal")]:
line = inkex.TextElement()
line.text = content
line.set("x", "20")
line.set("y", str(y))
line.style = {"fill": colour, "font-size": f"{size}px", "font-family": "sans-serif", "font-weight": weight}
texts.add(line)
document.write(os.environ["LMM_DOCUMENT"])
print("LMM_RESULT: " + json.dumps({"layers": [layer.label for layer in svg.descendants().filter(inkex.Layer)], "elements": len(list(svg.descendants()))}))Antwort des Hubs
{
"app": "inkscape",
"duration_ms": 151,
"error": null,
"result": {
"elements": 8,
"layers": [
"Background",
"Text"
]
},
"status": "ok",
"stderr": "",
"stdout": "",
"truncated": false
}Das Skript lief in 151 ms: Ein Python-Prozess wurde gestartet und beendet. Das Skript gab sein result in der letzten Zeile aus, nach LMM_RESULT: , so gibt ein Inkscape-Skript einen Wert zurück. get_state beschrieb danach das Arbeitsdokument und gab eine Aufnahme zurück:
{
"app": "inkscape",
"app_version": "1.4",
"bridge_version": null,
"captured_at": "2026-10-21T12:47:14.185Z",
"connected": true,
"content_origin": "document",
"screenshot": "$XDG_RUNTIME_DIR/libremodular-mcp/captures/inkscape-20261021T124713832Z.png",
"state": {
"element_count": 8,
"height": "105mm",
"layers": [
{
"id": null,
"label": "Background"
},
{
"id": null,
"label": "Text"
}
],
"width": "148mm"
},
"warnings": []
}Erzeugtes Bild
Die Aufnahme ist das Arbeitsdokument, von inkscape selbst exportiert, 559 × 397 Pixel für eine Karte von 148 × 105 mm. Der Text ist in der Schrift sans-serif dieses Rechners gezeichnet, ein anderer Rechner zeichnet ihn in seiner eigenen. Das Pixel oben links in der Aufnahme ist #1C385C und das im Kreis #C25438.
