.. _mcp: MCP-Schnittstelle (Model Context Protocol) ========================================== Ab Version 1.12.0 stellt der DKS einen MCP-Server bereit. Damit kann die Korrektur ohne zusätzliche Adapter direkt aus MCP-fähigen KI-Clients und Automatisierungsplattformen verwendet werden -- etwa Cursor, Claude Desktop, ChatGPT, n8n, Dify oder Langdock. Überblick --------- * **Protokoll**: Model Context Protocol, Revision ``2025-06-18`` (die ältere Revision ``2025-03-26`` wird beim Handshake weiterhin akzeptiert) * **Transport**: Streamable HTTP, stateless JSON-RPC 2.0 * **Endpunkt**: ``POST /mcp`` * **Authentifizierung**: API-Token (Bearer), Rolle ``API`` -- identisch zur REST-API * **Aktivierung**: standardmäßig aktiviert; zweistufig über die Umgebungsvariable ``MCP_DISABLED`` (harter Kill-Schalter) plus einen Schalter in der Admin-Oberfläche Es werden keine SSE-Streams erzeugt und keine Sitzungen geführt -- jeder Aufruf ist atomar und kommt als einzelne JSON-RPC-Antwort zurück. In der Admin-Oberfläche unter *Text-Assistent -> MCP-Server* werden Status, Endpunkt, Authentifizierung sowie die verfügbaren Werkzeuge (live aus ``tools/list``) und Einbindungsbeispiele für die gängigen Clients angezeigt. Aktivierung ----------- Der Endpunkt ist standardmäßig **aktiviert**. Um ihn hart zu deaktivieren, wird die Umgebungsvariable ``MCP_DISABLED`` gesetzt:: MCP_DISABLED=true Solange die Variable nicht gesetzt oder ``false`` ist, ist MCP verfügbar. Ist ``MCP_DISABLED=true`` gesetzt, beantwortet der Server jeden Request an ``/mcp`` mit einem leeren HTTP 404; Clients können nicht erkennen, dass die Schnittstelle existiert. Eine Änderung dieser Variable wird erst nach einem Neustart des Servers wirksam. Laufzeit-Schalter (Admin-Oberfläche) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Solange MCP nicht per ``MCP_DISABLED=true`` hart abgeschaltet ist, lässt sich die Schnittstelle zusätzlich zur Laufzeit über die Admin-Oberfläche unter *Text-Assistent -> MCP-Server* an- und ausschalten -- ohne Neustart. Die Umgebungsvariable bleibt dabei der harte Master-Schalter (z. B. um MCP in bestimmten Deployments vollständig zu sperren). Wirksame Logik: * ``MCP_DISABLED=true`` -> MCP immer aus (Admin-Schalter ohne Wirkung). * ``MCP_DISABLED`` nicht gesetzt/``false`` und Admin-Schalter *an* (Default) -> MCP an. * ``MCP_DISABLED`` nicht gesetzt/``false`` und Admin-Schalter *aus* -> MCP aus. Authentifizierung ----------------- Jede Anfrage an ``/mcp`` muss authentifiziert sein -- identisch zur REST-API. Bevorzugt wird ein API-Token im ``Authorization``-Header:: Authorization: Bearer Alternativ wird HTTP-Basic-Authentifizierung (Benutzername/Passwort) akzeptiert. In jedem Fall ist die Rolle ``API`` erforderlich. API-Tokens werden in der Admin-Oberfläche unter *API-Tokens* erstellt und verwaltet (siehe :doc:`UserAccounts`). Empfohlen wird ein eigener Token pro Client (z. B. ``Langdock Workspace RP``), damit Aktivität nachvollziehbar bleibt und ein einzelner Client jederzeit revoziert werden kann. Verfügbare Tools ---------------- Der Server meldet die Werkzeuge über ``tools/list``. Jedes Tool liefert dort neben ``name``, ``description`` und ``inputSchema`` zusätzlich: * ``title`` -- menschenlesbarer Anzeigename * ``outputSchema`` -- JSON-Schema des strukturierten Ergebnisses; die lesenden Tools sind damit voll selbstbeschreibend * ``annotations`` -- Verhaltenshinweise (``readOnlyHint``, ``destructiveHint``, ``idempotentHint``, ``openWorldHint``), an denen Clients ihre Sicherheits-UI und Auto-Freigabe ausrichten Alle lesenden Tools sind ``readOnlyHint=true``; ``propose_word`` schreibt (``readOnlyHint=false``), ist aber idempotent. Jeder ``tools/call`` liefert ein ``content``-Array (Text mit dem JSON als Zeichenkette) und -- bei strukturierten Werkzeugen -- dasselbe Ergebnis als strukturiertes JSON im Feld ``structuredContent``. Bei Fehlern ist ``isError=true`` gesetzt. ``check_text`` -- Text prüfen ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Prüft einen Text auf Rechtschreibung, Grammatik und Stil mit dem Duden-Korrektor. Liefert pro Fundstelle Position, Snippet, Typ, Fehlertext und Korrekturvorschläge. Parameter: * ``text`` (string, Pflicht) -- Der zu prüfende Text. Plain Text per Default; mit ``markupMode=xml`` für ausgezeichneten Text. * ``language`` (string, Default ``de-DE``) -- Sprache des Textes (BCP-47). Mögliche Werte liefert ``list_languages``. * ``level`` (integer, Default ``3``) -- Prüfstufe: 0 = keine, 1 = schnelle Rechtschreibung, 2 = Rechtschreibung+Grammatik, 3 = zusätzlich Stil (nur DE). * ``orthographyStandard`` (string) -- überschreibt den im Profil hinterlegten Rechtschreibstandard. Werte: ``duden``, ``conservative``, ``progressive``, ``extended``, ``press``. * ``propertySets`` (string[]) -- Namen der anzuwendenden Korrekturprofile (siehe ``list_property_sets``). * ``dictionaries`` (string[]) -- Namen zusätzlicher Custom-Wörterbücher (siehe ``list_dictionaries``). * ``markupMode`` (string, Default ``text``) -- ``text`` oder ``xml``. * ``correctionProposals`` (boolean, Default ``true``) -- Korrekturvorschläge liefern. * ``hyphenation`` (boolean, Default ``false``) -- zusätzlich Silbentrennpositionen liefern. * ``glossary`` (boolean, Default ``false``) -- Glossartreffer mitliefern (nur wenn Glossarwörterbücher angegeben sind). * ``singleWordMode`` (boolean, Default ``false``) -- Eingabe als einzelnes Wort behandeln (z. B. für Wortlisten). Rückgabe (``structuredContent``): * ``errorCount`` (integer) -- Anzahl der Fundstellen. * ``errors`` (object[]) -- eine Fundstelle je Problem, mit ``offset``, ``length``, ``snippet``, ``type``, ``errorCode``, ``message``, ``longMessage``, ``examples`` (je ``false``/``correct``), ``group``, ``category`` und ``suggestions`` (string[]). * ``hyphenationPositions`` (object[]) -- nur wenn ``hyphenation=true``, sonst leer. * ``glossaryMessages`` (object) -- nur wenn ``glossary=true``, sonst ein leeres Objekt. .. code-block:: json { "errorCount": 1, "errors": [ { "offset": 12, "length": 8, "snippet": "Endwurff", "type": "orth", "errorCode": 4711, "message": "Mögliche Falschschreibung", "longMessage": "Das Wort wurde nicht im Wörterbuch gefunden ...", "examples": [ { "false": "Endwurff", "correct": "Entwurf" } ], "group": "Rechtschreibung", "category": "Schreibung", "suggestions": ["Entwurf", "Entwürfe"] } ], "hyphenationPositions": [], "glossaryMessages": {} } ``list_dictionaries`` -- Wörterbücher auflisten ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Listet die im DKS verfügbaren Wörterbücher. Hilfreich, bevor ein Agent ``check_text`` oder ``propose_word`` mit einem bestimmten Wörterbuch aufruft. Keine Parameter. Rückgabe (``structuredContent``): * ``count`` (integer) * ``dictionaries`` (object[]) -- je ``name``, ``description``, ``language``, ``isGlossary``, ``isSystem``, ``isReadOnly``. ``list_property_sets`` -- Korrekturprofile auflisten ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Listet alle Korrekturprofile (Property Sets) inklusive Sprache und Prüfstufe, damit ein Agent ein gültiges Profil für ``check_text.propertySets`` wählen kann. Keine Parameter. Rückgabe (``structuredContent``): * ``count`` (integer) * ``propertySets`` (object[]) -- je ``id``, ``name``, ``description``, ``language``, ``checklevel``, ``orthstd``, ``enforce`` und ``dictionaries`` (string[]). ``list_languages`` -- Sprachen auflisten ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Listet die im DKS verfügbaren Sprachen, damit ein Agent einen gültigen Wert für ``check_text.language`` wählen kann. Keine Parameter. Rückgabe (``structuredContent``): * ``count`` (integer) * ``languages`` (object[]) -- je ``code`` (BCP-47) und ``source`` (``dpf`` = eingebaut oder ``hunspell``). ``propose_word`` -- Wort vorschlagen ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Trägt ein Wort in ein beschreibbares Wörterbuch ein. Per Default wird das Wort als korrekt akzeptiert (``accept``); mit ``correction`` wird es stattdessen als Falschschreibung markiert und ein Korrekturvorschlag hinterlegt (``reject``). Idempotent: ein bereits existierender Eintrag für dasselbe Wort und Wörterbuch wird in-place aktualisiert statt dupliziert. Parameter: * ``word`` (string, Pflicht, max. 76 Zeichen) -- das vorzuschlagende Wort. * ``dictionary`` (string, Default ``Proposals``) -- Zielwörterbuch. ``Proposals`` ist das System-Wörterbuch für Nutzervorschläge; weitere Optionen siehe ``list_dictionaries``. * ``comment`` (string, optional, max. 256 Zeichen) -- Begründung / Kontext, der mit dem Eintrag gespeichert wird. * ``correction`` (string, optional, max. 256 Zeichen) -- wird dieses Feld gesetzt, wird das Wort als Falschschreibung markiert (``reject=true``) und ``correction`` als Vorschlagswort gespeichert. Mehrere Vorschläge per Semikolon trennen. Ohne ``correction`` wird das Wort akzeptiert (``accept=true``). Rückgabe (``structuredContent``): * ``status`` (string) -- ``created`` oder ``updated``. * ``mode`` (string) -- ``accept`` oder ``reject``. * ``word`` (string) * ``dictionary`` (string) * ``entryId`` (integer) * ``accept`` (boolean) * ``reject`` (boolean) * ``proposal`` (string) -- hinterlegter Korrekturvorschlag (nur bei ``reject``). * ``comment`` (string) -- gespeicherte Begründung, falls vorhanden. .. code-block:: json { "status": "created", "mode": "reject", "word": "Endwurff", "dictionary": "Proposals", "entryId": 1, "accept": false, "reject": true, "proposal": "Entwurf", "comment": "Tippfehler aus dem MCP-Smoketest" } Beispiel-Aufrufe (curl) ----------------------- Typischer Ablauf: ``initialize``, dann ``tools/list``, dann ``tools/call``. ```` durch ein gültiges API-Token und ```` durch den Hostnamen ersetzen. Initialisierung:: curl -s -X POST https:///mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize", "params":{"protocolVersion":"2025-06-18","capabilities":{}, "clientInfo":{"name":"demo","version":"1"}}}' Tool-Liste abrufen:: curl -s -X POST https:///mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' Text prüfen:: curl -s -X POST https:///mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call", "params":{"name":"check_text", "arguments":{"text":"Das ist ein Testt.", "language":"de-DE","level":3}}}' Einbindung in KI-Clients ------------------------ Der DKS-MCP-Server lässt sich in gängige KI-Clients und Automatisierungsplattformen einbinden. Ersetzen Sie überall ```` durch ein gültiges API-Token (Rolle ``API``) und ```` durch den Hostnamen Ihrer Instanz. .. note:: Der Endpunkt muss vom Client erreichbar sein. Lokale Desktop-Clients (Cursor, Claude Desktop) genügen im selben Netz. Cloud-Dienste (ChatGPT, Langdock, Dify-Cloud) benötigen einen öffentlich über HTTPS erreichbaren Endpunkt. Cursor ~~~~~~ Cursor unterstützt Remote-MCP über Streamable HTTP direkt. Tragen Sie den Server in ``~/.cursor/mcp.json`` (global) oder ``.cursor/mcp.json`` (projektbezogen) ein: .. code-block:: json { "mcpServers": { "dks": { "url": "https:///mcp", "headers": { "Authorization": "Bearer " } } } } Danach Cursor neu laden ("Reload Window"). Tipp: Statt Klartext kann das Token als Umgebungsvariable referenziert werden, z. B. ``"Bearer ${env:DKS_TOKEN}"``. Claude Desktop ~~~~~~~~~~~~~~ Claude Desktop spricht in seiner Konfiguration nur stdio; für Remote-HTTP wird die Bridge ``mcp-remote`` genutzt. Konfigurationsdatei: macOS ``~/Library/Application Support/Claude/claude_desktop_config.json``, Windows ``%APPDATA%\Claude\claude_desktop_config.json``. .. code-block:: json { "mcpServers": { "dks": { "command": "npx", "args": [ "-y", "mcp-remote", "https:///mcp", "--transport", "http-only", "--allow-http", "--header", "Authorization:${DKS_AUTH}" ], "env": { "DKS_AUTH": "Bearer " } } } } ``--allow-http`` ist nur bei unverschlüsseltem ``http://`` nötig (bei HTTPS weglassen). Das Bearer-Token wird wegen eines Whitespace-Bugs über die env-Variable gesetzt. Anschließend Claude Desktop neu starten. ChatGPT ~~~~~~~ ChatGPT bindet eigene MCP-Server über den "Developer Mode" (Entwicklermodus) als Connector/App ein -- nur im Web (Desktop-Browser), nicht in der Mobile-App. Voraussetzung ist ein bezahlter Plan; Plus/Pro können nur lesende Connectors nutzen, schreibende Tools brauchen Business/Enterprise/Education (dort muss ein Admin den Developer Mode erst freigeben). 1. Einstellungen -> "Apps & Connectors" -> "Erweiterte Einstellungen" -> "Developer Mode" einschalten. 2. Danach erscheint die Schaltfläche "Erstellen" (Create): Connector anlegen mit Name, Beschreibung und der Endpunkt-URL ``https:///mcp``. 3. Im Chat über das "+"-/Tools-Menü "Developer Mode" wählen und den Connector aktivieren. .. warning:: ChatGPT erreicht nur öffentlich über HTTPS erreichbare Endpunkte und unterstützt im Connector-Formular nur "OAuth", "Keine Authentifizierung" oder "Mixed" -- kein statisches Bearer-Token. Für den DKS-Server (Bearer-Auth) ist daher ein vorgelagerter HTTPS-Reverse-Proxy nötig, der OAuth bereitstellt oder das Token serverseitig injiziert. n8n ~~~ In n8n verbindet der Node "MCP Client Tool" externe MCP-Server (aktuelle n8n-Version mit HTTP-Streamable-Unterstützung vorausgesetzt; alternativ der Community-Node ``n8n-nodes-mcp``). 1. Node "MCP Client Tool" zum Workflow hinzufügen. 2. Connection Type auf "HTTP Streamable" setzen und als URL ``https:///mcp`` eintragen. 3. Als Authentication "Bearer Auth" wählen und ein Bearer-Token-Credential mit dem API-Token anlegen. 4. Operation wählen (z. B. "List Tools" oder "Call Tool") und den Node mit dem Agenten verbinden. Dify ~~~~ In Dify werden MCP-Server unter *Tools* eingebunden (nur HTTP-Transport). 1. *Tools -> MCP -> "Add MCP Server (HTTP)"* öffnen. 2. Als Server-URL ``https:///mcp`` eintragen sowie Name und eine feste Server-ID vergeben. 3. Im Headers-Feld den Authorization-Header hinterlegen:: Authorization: Bearer Das Headers-Feld gibt es erst in neueren Dify-Versionen; ältere unterstützen nur OAuth. Dify muss den Endpunkt erreichen können (bei Self-Hosting ggf. den SSRF-Proxy anpassen). Langdock ~~~~~~~~ In Langdock wird der Server als Integration hinzugefügt. 1. *Workspace-Einstellungen -> Integrations -> "Add Integration"* -> Typ "MCP" wählen. 2. Als URL ``https:///mcp`` eintragen und als Authentifizierung "API Key" wählen. 3. Header-Typ "Authorization: Bearer" setzen, das API-Token eintragen und mit "Test connection" prüfen. Langdock läuft in der Cloud -- der DKS-Endpunkt muss daher öffentlich über HTTPS erreichbar sein. Liegt der DKS hinter einer Firewall mit IP-Whitelist, sollte die statische IP der Langdock-Plattform freigeschaltet werden (siehe `Langdock Docs: Static IP Configuration `_). Korrekturen automatisch anwenden (Prompt-Vorlage) ------------------------------------------------- Der häufigste Anwendungsfall ist: einen Text von ``check_text`` prüfen lassen und die gefundenen Korrekturen anschließend automatisch in den Text übernehmen. ``check_text`` liefert dazu die Befunde (Fundstellen samt Vorschlägen, Regeltext und Beispielen), aber es *ändert den Text nicht* -- das Anwenden übernimmt ein Sprachmodell (LLM). Bewährtes Muster (ein Durchlauf pro Text): 1. ``check_text`` aufrufen und aus der Antwort das ``errors``-Array aus ``structuredContent`` entnehmen. 2. Die Befunde zusammen mit dem Originaltext an ein LLM geben -- mit der Prompt-Vorlage unten und ``temperature = 0`` für deterministische Ausgabe. 3. Die LLM-Antwort ist der korrigierte Text. Die Vorlage nutzt bewusst *alle* Felder eines Befunds: liegen ``suggestions`` vor, wählt das Modell den passendsten Vorschlag; ist die Liste leer, leitet es die Korrektur aus ``longMessage`` und den ``examples`` (Paare aus ``false`` und ``correct``) ab. Dadurch werden auch Fehler behoben, für die DKS keinen fertigen Vorschlag hat. Variante A -- Plain Text ~~~~~~~~~~~~~~~~~~~~~~~~~ Für einfache Texte ohne Auszeichnung (z. B. Titel, Überschriften, Fließtext). System-Prompt: .. code-block:: text Du erhältst einen Text und eine Liste von DKS-Korrekturbefunden. Jeder Befund enthält -- soweit verfügbar -- die Felder: - snippet : die markierte Textstelle - type : "orth" | "gram" | "style" | ... - errorCode : numerischer DKS-Regel-Code - message : Kurztext der Regel - longMessage : ausführliche Beschreibung der Regel - examples : Liste von { "false": ..., "correct": ... } Beispielen derselben Regel -- die wichtigste Hilfe, wenn suggestions leer ist. - suggestions : ggf. von DKS vorgeschlagene Korrekturen Wende AUSSCHLIESSLICH die Befunde an. Pro Befund gilt: a) suggestions gefüllt -> wähle den grammatikalisch und semantisch passendsten Vorschlag (Numerus, Genus, Kasus, Artikel, Verbkongruenz). b) suggestions leer -> orientiere dich an longMessage und examples. Übertrage das Muster aus den Beispielen ANALOG auf den vorliegenden Text (gleiche Regel, anderer konkreter Wortlaut). Bist du dir trotz Regelinfo und Beispielen nicht sicher, lass den Befund unverändert. Antworte ausschließlich mit dem korrigierten Text, ohne Anführungszeichen, ohne Markdown, ohne Kommentar. Als Benutzernachricht die Befunde und den Originaltext übergeben, z. B.:: === DKS-Befunde (JSON) === === Originaltext === Variante B -- HTML/Markup erhalten ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Wenn der Text Auszeichnung enthält (HTML, z. B. aus einem CMS) und diese zeichengenau erhalten bleiben muss. Wichtig: Vor der Prüfung den *sichtbaren* Text aus dem Markup extrahieren und an ``check_text`` geben; die Korrekturen werden anschließend auf das *originale* Markup angewandt. System-Prompt: .. code-block:: text Du bist ein deterministischer HTML-Korrekturassistent. Wende AUSSCHLIESSLICH die unten gelisteten Befunde des Duden-Korrektor- Servers (DKS) auf den gegebenen HTML-Inhalt an. Jeder Befund enthält -- soweit verfügbar -- die Felder snippet, type, errorCode, message, longMessage, examples ({ "false": ..., "correct": ... }), group/category und suggestions. Strikte Regeln: 1. Ändere KEINE HTML-Tags, -Attribute, -Klassennamen, -IDs, -URLs oder HTML-Entities. Die Tag-Struktur des Outputs muss zeichengenau mit der des Inputs übereinstimmen; nur reine Text-Knoten dürfen sich ändern. 2. Pro Befund -- abhängig von "suggestions": a) GEFÜLLT: Wähle den Vorschlag, der grammatikalisch und semantisch am besten in den umgebenden Satz passt (Numerus, Genus, Kasus, Artikel, Verbkongruenz, Satzbedeutung). longMessage und examples liefern den Regel-Hintergrund. Beispiel: bei "ein Haii" mit ["Haie","Hai"] wählst du "Hai", weil "ein" Singular verlangt. b) LEER: Bestimme die Korrektur SELBST anhand von longMessage und examples. Übertrage das in den Beispielen gezeigte Muster ANALOG auf den vorliegenden Text (gleiche Regel, anderer konkreter Wortlaut). Beispiele: - type "orth", examples ["Entgeld"->"Entgelt", "watren"->"warten"]: "Resteraunt" wird zu "Restaurant". - type "gram", example "Wir vertrauen Herr Schmidt"->"Wir vertrauen Herrn Schmidt": "bestellten ... ein komplizierter Cocktail" wird zu "... einen komplizierten Cocktail" (Akkusativ nach "bestellen"). - type "style" ohne Vorschlag: meist nicht zwingend ändern -- nur bei einem trivialen, eindeutigen Fix aus den examples. 3. Ermöglichen weder suggestions noch examples eine eindeutige Korrektur, lass den Befund unverändert und ignoriere ihn still. 4. Korrigiere im sichtbaren Text nur die "snippet"-Strings (bei type "gram" ggf. die umrissene Wortgruppe) -- berücksichtige umliegende Satzzeichen. Erscheint ein Snippet mehrfach und der Kontext erlaubt keine eindeutige Unterscheidung, korrigiere alle Vorkommen. 5. Ist ein Snippet im sichtbaren Text nicht auffindbar, ignoriere den Befund still. 6. Füge KEINEN neuen Text, KEINE Erklärungen, KEINE Kommentare und KEINE Markdown-Codeblöcke hinzu. 7. Antworte ausschließlich mit dem korrigierten HTML, beginnend exakt mit dem ersten Zeichen des Originals. Als Benutzernachricht die Befunde und die HTML-Quelle übergeben, z. B.:: === DKS-Befunde (JSON-Array) === === HTML-Quelle === Referenz-Workflow für Dify ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ein vollständiger Beispiel-Workflow, der genau diese Prompts verwendet, steht als Dify-DSL bereit: ausgelöst durch das Veröffentlichen eines WordPress-Artikels prüft er Titel und Inhalt per MCP (``check_text``) und schreibt die Korrekturen als Entwurf (Autosave) samt Editor-Kommentar zurück. Der Workflow ist ein optionales Beispiel und **nicht Teil der DKS-Installation**. Zum Verwenden den folgenden Inhalt als ``.yml`` speichern und in Dify unter *Studio -> Import DSL* importieren (:download:`direkter Download `). Über die Schaltfläche oben rechts im Codeblock lässt sich der gesamte Inhalt in die Zwischenablage kopieren. .. literalinclude:: examples/workflow_dks_spellcheck.yml :language: yaml