Code ausführen (Tool js_execute, integrierter MCP-Server „JS“)¶
Der integrierte MCP-Server JS erweitert Assistenten um zwei zentrale Fähigkeiten:
- Automationen ausführen: wiederkehrende Abläufe zuverlässig nach Ereignissen oder Zeitplänen anstoßen.
- Code-Tool: kleine TypeScript/JavaScript-Skripte sicher in einer isolierten Umgebung ausführen, um Daten zu verarbeiten oder Aktionen zu orchestrieren.
Diese Seite erklärt, was du damit als Endnutzer tun kannst, und welche Funktionen dir im Code-Tool zur Verfügung stehen.
Wann ist der JS-Server sinnvoll?¶
Nutze ihn, wenn du:
- Daten aus Dateien/Ergebnissen transformieren willst (z. B. Liste bereinigen, Felder normieren, JSON erzeugen).
- Tools kombinieren willst (z. B. erst suchen, dann Ergebnisse filtern, dann als Datei speichern).
- aus einem Trigger heraus Folgeschritte durchführen willst (z. B. „Wenn X passiert, lege Einträge an, schreibe eine Zusammenfassung, speichere Artefakte“).
Wenn du nur eine normale Frage beantwortet haben willst, ist der JS-Server meist nicht nötig.
Gerade für effiziente Automationen ist der Server wichtig, weil du mit Code erst die billigen Schritte erledigen kannst: prüfen, filtern, deduplizieren, Felder normalisieren, Relevanz entscheiden. Ein LLM-Aufruf sollte erst danach kommen, wenn wirklich ein inhaltlicher KI-Schritt nötig ist.
Beziehung zu Automation Actions¶
Der Name ist etwas irreführend: Das Code-Tool läuft über den integrierten MCP-Server JS ist nicht nur für klassische Trigger-Automationen relevant, sondern auch selbst eine Quelle für Tools, die als Aktion in Automationen auftauchen können.
Das heißt praktisch:
- In einer Automation kann als Aktion ein Tool aus dem Server JS gewählt werden.
- Dazu gehören vor allem Such-, Patch- und Code-Ausführungswerkzeuge.
- Daneben können auch viele andere integrierte MCP-Server als Aktion dienen, zum Beispiel
chat/send_message,event/event_dispatch,email/email_sendodertask_management/task_create.
Mehr dazu:
Das Tool js_execute (JS/TS in der Sandbox ausführen)¶
js_execute führt TypeScript/JavaScript in einer Sandbox aus:
- keine Shell-Befehle, kein direkter Systemzugriff
- Virtuelles Dateisystem (
fs) undmcp/helpnur im Chat- und Playground-Profil (siehe Zwei Modi) - MCP im klassischen Automations-Hintergrund z. B. über
import { callMcpTool } from "clye.ai"(oder übertools.*, je nach Setup) - Hilfsfunktionen für Events, Wissens-/Chunk-Operationen und (profilabhängig)
fetch; Datum/JSON wie gewohnt über Standard-JavaScript (new Date(),JSON.*) bzw. über die inhelp()gelisteten Projekt-APIs
Zwei Modi: Chat vs. Automation (wichtig)¶
Je nachdem, wo du Code ausführst, gelten unterschiedliche Regeln:
- Im Chat (interaktiver Lauf, z. B. Tool „JS/TS im Chat ausführen“)
fs,mcpundhelpstehen als Globals zur Verfügung (virtuelles Dateisystem).- Dateien liegen im Chat-Kontext (Uploads + Workspace).
- HTTP/
fetchist bewusst deaktiviert (damit kein unkontrollierter Netzwerkzugriff aus der Sandbox passiert). - Bei
addChunks: die Varianteurl: { fetch: "…" }(Host lädt eine URL nach) ist im gleichen Profil ebenfalls deaktiviert. Normale URL-Strings,data:-URLs sowie Blob/ArrayBuffer/Uint8Array funktionieren weiterhin. - Im Space-JS-Playground
- Wie Chat:
fs,mcp,help; kein freiesfetch;addChunksohne{ fetch: … }. - In einer klassischen Automation (Hintergrundlauf ohne Chat-Kontext)
fs,mcpundhelpgibt es hier nicht als Globals (kein Chat-Dateisystem in diesem Profil).fetchist möglich, wenn eure Umgebung das zulässt.addChunksdarfurl: { fetch: "…", … }nutzen (Host lädt die URL und legt die Datei ab).- Typisch nutzt du
tools.*, Events (lastEvent/getEvents), Chunk-Helfer,import … from "clye.ai",consoleund das Objektautomation(siehe unten).
Dateisystem (fs)¶
Im Chat- und Playground-Profil steht dir das Objekt fs zur Verfügung. Im klassischen Automation-Hintergrund (ohne Chat-Kontext) ist fs kein Global — nutze dort tools.*, Events, Chunks und clye.ai, oder führe Dateizugriffe über andere Tools aus.
Chat-Kontext (typische Ordner)¶
Im Chat arbeitest du in einem Root wie:
/chats/<chatId>/assets(Uploads, nur lesen)/chats/<chatId>/workspace(dein Arbeitsbereich, schreiben erlaubt)/chats/<chatId>/workspace/out(Outputs)/chats/<chatId>/workspace/tmp(temporär)/chats/<chatId>/.tool-results(Tool-Artefakte)
Wichtig: Das aktuelle Arbeitsverzeichnis startet bereits in .../workspace.
Nutze deshalb bevorzugt relative Pfade wie out/result.json statt workspace/out/result.json.
Verfügbare fs-Funktionen¶
fs.pwd()– aktuelles Verzeichnisawait fs.cd(path)– Verzeichnis wechselnawait fs.ls(dir?, { glob?, limit?, offset?, withStat? })– Dateien/Ordner listen (liefert u. a.entries; das Ergebnis ist auch iterierbar)await fs.readdir(dir?)– nur Dateinamen (einfache Liste, intern überlsmit Limit)await fs.stat(path)– Metadaten zu einer Datei oder einem Ordner (type,size,mtime,isFile()/isDirectory())await fs.exists(path)await fs.mkdir(path, { recursive? })await fs.rm(path, { recursive? })await fs.readText(path, { maxBytes? })await fs.writeText(path, content)await fs.readJson(path)await fs.writeJson(path, value, { pretty? })await fs.mv(src, dst, { overwrite? })await fs.cp(src, dst, { recursive?, overwrite? })
API im Editor durchsuchen (help)¶
Nur im Chat- und Playground-Profil (wenn fs/mcp als Globals gesetzt sind):
await help()– Überblick und Beispiele zu den Runtime-APIsawait help("addChunks")– gezielt Signaturen und Kurzbeschreibungen (u. a.fs,mcp, Chunk-Funktionen, Event-Typen)
MCP-Tools nutzen (mcp)¶
Im Chat- und Playground-Profil: Wenn in eurem Space MCP-Server verbunden sind, kannst du sie über das Global mcp verwenden:
await mcp.tools()listet verfügbare Tools (Name + Beschreibung).await mcp.call("serverName/toolName", { ...args })ruft ein Tool auf. Erlaubt ist auch die SchreibweiseserverName:toolName(Doppelpunkt statt Slash).
So kannst du z. B. „Suche → Filter → Export“ automatisieren, ohne alles manuell zu klicken.
Events abfragen (lastEvent, getEvents)¶
Für Automationen ist es oft wichtig, Ereignisse nachzuschlagen:
await lastEvent({ type?, objectId?, causedBy? })– gibt das letzte passende Event zurück (odernull)await getEvents({ type?, objectId?, causedBy?, limit?, cursor?, direction? })– paginierte Listelimit: optional, Standard 50, maximal 500cursor: Sequenznummer (string) des letzten Events der vorherigen Seite (wienextCursorin der Antwort)direction:"desc"(Standard, neueste zuerst) oder"asc"
Das ist praktisch, um z. B. „Was ist zuletzt passiert?“ in einer Automation zu prüfen.
Wissen/Chunks bearbeiten (addChunks, deleteChunk, deleteChunks)¶
Du kannst Inhalte als Chunks in den Space schreiben oder entfernen. Die Logik entspricht grob dem Schreibpfad des RAG-Patch-Tools: bestehende Chunks mit derselben id werden überschrieben bzw. neu indexiert.
await addChunks(chunks)¶
Parameter: Array von Objekten (ChunkInput):
| Feld | Bedeutung |
|---|---|
id |
Eindeutige ID des Chunks (wird intern in eine UUID übernommen). |
text |
Textinhalt für die Indexierung. Wenn weggelassen, wird kein neuer Text geschrieben, sondern ein Re-Index des bestehenden Chunks ausgelöst (z. B. nach Aktualisierung der url). |
url |
Optional: Referenz oder Binärdaten. Unterstützt u. a.: normale URL-Strings (https://…, interne Pfade wie /f/…), data:-URLs (werden automatisch hochgeladen und durch dauerhafte /f/…-Links ersetzt), Blob / ArrayBuffer / Uint8Array (Upload), Response-ähnliche Objekte (Bytes werden übernommen), sowie { fetch: string, init?: RequestInit, filename?: string, mime?: string } — nur im Automation-Profil (Host lädt die URL; im Chat/Playground deaktiviert). |
metadata |
Optionale Schlüssel/Werte (z. B. Dateiname/MIME-Hinweise bei Binärimport). |
addedAutomatically |
Ob der Chunk als automatisch angelegt gilt (Standard: true). |
Rückgabe: { chunkIds: string[] } — UUIDs der angelegten bzw. verarbeiteten Chunks.
await deleteChunk(chunkId) / await deleteChunks(chunkIds)¶
Löscht einen bzw. mehrere Chunks dauerhaft. Rückgabe jeweils mit deletedCount.
Typische Nutzung:
- Ergebnisse als neue Wissenskarte/Chunk ablegen
- veraltete automatische Chunks aufräumen
- Inhalte nach erneuter Verarbeitung re-indexieren (
textweglassen oderurl/textaktualisieren)
Tools direkt aufrufen (tools.NAME)¶
Im Code gibt es ein tools-Objekt. Jedes verfügbare Tool kann wie eine Funktion aufgerufen werden, z. B.:
Welche Tool-Namen bei euch verfügbar sind, hängt von eurem Setup (Assistent/Space) ab.
Datum, Zeit und JSON¶
In der Sandbox steht dir normales JavaScript zur Verfügung — typischerweise new Date(), JSON.stringify / JSON.parse und die üblichen eingebauten Objekte der QuickJS-/Node-Kompatibilitätsschicht.
Zusätzlich pflegt der Bot in den TypeScript-Deklarationen (Autocomplete im Code-Editor) und in await help("…") (nur Chat/Playground) weitere Namen wie now, addDays, formatDate, parseJson, coalesce, usw. Welche davon zur Laufzeit wirklich als globale Funktion gebunden sind, kann vom Ausführungspfad und der Bot-Version abhängen — für portable Skripte sind die Standard-APIs die zuverlässigste Wahl.
Automation-Kontext (automation)¶
Im Sandbox-Code existiert die Konstante automation mit u. a.:
id— ID der Automation (z. B. für Abfragen früherer Läufe derselben Automation)spaceId— SpaceuserId/actorId— auslösender Nutzer bzw. Actor (falls gesetzt)
Modul clye.ai (Import)¶
Neben den Globals kannst du aus "clye.ai" importieren (QuickJS-Bundling im Bot):
dispatchEvent(event)— Event im Space auslösen (type, optionalobjectId,data,metadata,causedBy,timestamp,idfür Idempotenz)callMcpTool(serverName, toolName, input)— MCP-Tool aufrufengetMcpResource(serverName, uri)— MCP-Ressource lesen (text/blob/Metadaten)lastEvent/getEvents— dieselben Event-Helfer wie global (wenn du sie explizit aus dem Modul beziehen willst)
Effizient bauen: erst Code, dann LLM¶
Ein wichtiger Grundsatz für produktive Automationen ist: Regeln und Code zuerst, LLM nur wenn nötig.
Das bedeutet typischerweise:
- zuerst prüfen, ob sich überhaupt etwas geändert hat
- zuerst filtern, ob ein Treffer fachlich relevant ist
- zuerst einfache Entscheidungen mit Code treffen
- erst danach
chat/send_messageoder einen anderen LLM-basierten Schritt aufrufen
Beispiel:
- Ein Postfach wird regelmäßig geprüft.
- Code erkennt zuerst, ob es neue E-Mails gibt und ob darunter überhaupt interessante Nachrichten sind.
- Nur diese relevanten Nachrichten werden anschließend an einen Assistenten zur Zusammenfassung oder Antwortvorbereitung gegeben.
So bleibt die Automation effizient, ohne auf Qualität zu verzichten.
dispatchEvent (fortgeschritten)¶
In manchen Setups kann ein Skript auch Events auslösen — per import { dispatchEvent } from "clye.ai" (siehe Abschnitt Modul clye.ai (Import) weiter oben).
Wenn ihr das nutzt, macht das am besten nur in klar definierten Automationen.
Ein sehr gutes Muster ist dabei:
- Code erkennt zuerst eine Änderung oder einen fachlich relevanten Fall.
- Danach wird ein eigenes Event dispatcht.
- Eine andere Automation reagiert auf dieses Event.
Beispiel:
- Ein Code-Schritt erkennt drei geänderte Dateien.
- Er dispatcht drei getrennte Events.
- Weitere Automationen können diese Änderungen unabhängig voneinander verarbeiten.
Das macht Abläufe meist einfacher, retrybarer und besser erweiterbar als eine einzige große Automation mit vielen direkten Folgeschritten.
Beispiele¶
Beispiel: Cross-Assistant-Dateizugriff (Ordner aus einem anderen Space listen und indexieren)¶
Manchmal liegt ein Dateisystem-Zugriff (z. B. über einen Filesystem-Connector) in einem anderen Assistenten/Space. Wenn du trotzdem gezielt einzelne Ordner in deinem aktuellen Assistenten indexieren möchtest, kannst du MCP-Tools raumübergreifend aufrufen.
Begriffe¶
- Base-Assistent: Assistent/Space, der Zugriff auf das Dateisystem hat.
- Specific-Assistent: Assistent/Space, der nur einen Teil davon (z. B. bestimmte Ordner) nutzen bzw. indexieren soll.
Voraussetzungen¶
- Öffne im Specific-Assistenten: Einstellungen → Berechtigungen.
- Lade den Base-Assistenten ein (damit der Specific-Assistent dessen MCP-Server/Tools verwenden darf).
Optional (Best Practice): Wenn im Base-Assistenten bisher „alles“ indexiert wird, kannst du in dessen Indexierungs-Automationen die Inhalte, die künftig „spezifisch“ verarbeitet werden sollen, ausklammern (z. B. Ordner exkludieren), damit nichts doppelt läuft.
MCP-Server-ID ermitteln¶
Die Server-ID findest du im Specific-Assistenten unter Einstellungen → MCP-Server:
- MCP-Server auswählen
- Auf das Zahnrad klicken
- Den Wert bei Server-Id kopieren
Tool-Aufruf im Automation-Code¶
Im Automation-Code rufst du das Tool über callMcpTool auf und gibst dabei zusätzlich die spaceId des Base-Assistenten an.
Parameter:
serverName: Name/ID des MCP-Servers (wie in den Einstellungen angezeigt)toolName: Name des Tools auf diesem MCP-Server (z. B.list_directory)input: Parameter-Objekt für das ToolbaseSpaceId:spaceIddes Base-Assistenten (z. B. aus der URL des Base-Spaces)
const res = await process.env.callMcpTool(
"Filesystem Connector",
"list_directory",
{
include_hidden: false,
path: "Vertrieb",
recursive: true,
},
"123abc456-7899-56ec-bcdb-ef11801750b1"
);
Mit dem Ergebnis kannst du anschließend wie gewohnt Events dispatchen und diese in einer zweiten Automation indexieren lassen.
Empfehlung: Idempotenz beim Dispatch & Indexing¶
Wenn du pro Datei (oder pro gefundenem Objekt) ein Event auslöst und danach indexierst, achte darauf, dass du:
- eine eindeutige
objectIdfür das Event verwendest, damit Wiederholungen nicht zu Fehlern/Dubletten führen - beim Indexieren eine eindeutige
uriverwendest
Praktisches Muster: einen Prefix voranstellen, z. B. "company-" + uri.
Beispiel: Upload lesen und Ergebnis als JSON speichern (Chat)¶
export default async function () {
const input = await fs.readText("assets/input.txt");
const lines = input.split("\n").map((l) => l.trim()).filter(Boolean);
await fs.writeJson("out/result.json", { count: lines.length, lines });
return { ok: true };
}
Beispiel: Tools kombinieren (Suche → Ergebnis speichern, Chat)¶
export default async function () {
const result = await tools.rag_search({ query: "Vertrag", filter: undefined });
await fs.writeJson("out/rag-result.json", result, { pretty: true });
return { saved: true, items: result?.chunks?.length ?? 0 };
}
Kurz gesagt¶
Der integrierte MCP-Server JS ist der richtige Baustein, wenn ihr über reine Chat-Antworten hinaus wollt: wiederholbar, nachvollziehbar, mit Outputs, und mit der Möglichkeit, Tools und Datenverarbeitung in einem sicheren Code-Lauf zu kombinieren.