Kapitel 21: Benutzerabfragen & Elicitation – Human-in-the-Loop
In den vorherigen Kapiteln haben wir gesehen, wie Server Daten liefern und wie sie selbst ein Modell nutzen. Manchmal braucht ein Server aber etwas, das weder in den Tool-Argumenten steht noch von einem Modell kommen darf: eine Entscheidung des Menschen. Soll das Deployment wirklich nach Produktion? Welches von drei passenden Kundenkonten ist gemeint? Darf der Server sich mit Ihrem GitHub-Konto verbinden?
Dafür gibt es Elicitation (englisch für „Hervorlocken“, sinngemäß: Rückfrage). Der Server bittet den Client, dem Nutzer eine Frage zu stellen – als Formular oder als Link auf eine Webseite – und arbeitet mit der Antwort weiter.
Stand der Spezifikation
2026-07-28: Elicitation selbst ist unverändert Teil des Kerns. Geändert hat sich, wie die Frage beim Client ankommt: Der Server schicktelicitation/createnicht mehr als eigene Anfrage an den Client, sondern gibt die Frage als Antwort auf den laufenden Aufruf zurück; der Client wiederholt den Aufruf dann mit der Antwort (Multi Round-Trip Requests, SEP-2322). Damit entfallen der Fehlercode-32042, das FeldelicitationIdund die Benachrichtigungnotifications/elicitation/complete. Die Unterschiede zur Vorversion fasst Abschnitt 9 zusammen.
1. Warum nicht einfach das Modell fragen lassen?
Ohne Elicitation bleibt einem Server nur ein Umweg: Er antwortet mit einem Text wie „Bitte frag den Nutzer, ob er wirklich nach Produktion deployen will“ und hofft, dass das Modell die Frage weitergibt und die Antwort korrekt zurückbringt. Das ist aus drei Gründen schwach:
- Unzuverlässig: Das Modell kann die Frage umformulieren, vergessen oder selbst beantworten.
- Unstrukturiert: Die Antwort kommt als Freitext zurück; ob „ja, mach mal“ eine Zustimmung ist, muss der Server raten.
- Nicht nachweisbar: Ob wirklich der Mensch zugestimmt hat, lässt sich nicht unterscheiden.
Elicitation löst das: Der Server beschreibt genau, was er wissen will, der Client zeigt die Frage dem Nutzer direkt (mit Eingabefeldern, Auswahllisten, Checkboxen), und die Antwort kommt strukturiert und eindeutig zurück – ohne Umweg über das Modell.
2. Wie eine Rückfrage abläuft
Stellen Sie sich einen Behördenschalter vor. Sie geben einen Antrag ab. Der Sachbearbeiter sagt nicht „Moment, ich rufe Sie heute Nachmittag zurück“ – er gibt Ihnen den Antrag mit einem Zettel zurück: „Bitte noch Feld 7 ausfüllen und unterschreiben, dann wieder abgeben.“ Sie füllen aus und reichen denselben Antrag noch einmal ein, diesmal vollständig.
Genau so arbeitet MCP seit 2026-07-28:

- Der Client ruft ein Tool auf – ganz normal.
- Der Server merkt, dass ihm etwas fehlt, und antwortet mit
resultType: "input_required". Darin stehen die Fragen (inputRequests) und optional einrequestState– sein „Merkzettel“ für später. Damit ist dieser Aufruf abgeschlossen; der Server wartet auf nichts. - Der Client zeigt dem Nutzer die Frage und sammelt die Antwort ein.
- Der Client ruft dasselbe Tool mit denselben Argumenten erneut auf und legt die Antworten (
inputResponses, unter denselben Schlüsseln) sowie den unverändertenrequestStatebei. - Jetzt hat der Server alles und liefert das Ergebnis – oder stellt, falls nötig, die nächste Frage.
Wie das auf der Leitung aussieht:
// ② Antwort des Servers auf den ersten Aufruf
{
"jsonrpc": "2.0", "id": 1,
"result": {
"resultType": "input_required",
"inputRequests": {
"target": {
"method": "elicitation/create",
"params": {
"mode": "form",
"message": "auth-service in Version 2.4.1 ausrollen – wohin?",
"requestedSchema": {
"type": "object",
"properties": {
"environment": { "type": "string", "title": "Zielumgebung",
"oneOf": [ { "const": "staging", "title": "Staging" },
{ "const": "production", "title": "Produktion" } ],
"default": "staging" },
"confirm": { "type": "boolean", "title": "Ich habe die Änderungen geprüft" }
},
"required": ["environment", "confirm"]
}
}
}
},
"requestState": "eyJzZXJ2aWNlIjoiYXV0aC1zZXJ2aWNlIiwidmVyc2lvbiI6IjIuNC4xIi…"
}
}
// ④ Wiederholter Aufruf des Clients – neue id, gleiche Argumente, plus Antwort
{
"jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": {
"name": "deploy",
"arguments": { "service": "auth-service" },
"inputResponses": {
"target": { "action": "accept", "content": { "environment": "production", "confirm": true } }
},
"requestState": "eyJzZXJ2aWNlIjoiYXV0aC1zZXJ2aWNlIiwidmVyc2lvbiI6IjIuNC4xIi…"
}
}Warum so umständlich?
Auf den ersten Blick wirkt der „Zurückrufen“-Weg der Vorversion natürlicher: Der Server hielt den Aufruf offen, schickte selbst eine Anfrage an den Client und wartete. Das hatte aber einen Preis: Der Server musste sich den halb fertigen Aufruf merken, die Verbindung musste die ganze Zeit offen bleiben, und hinter einem Load Balancer musste die Antwort exakt bei der Instanz landen, die gerade wartete.
Mit dem neuen Weg ist jeder Aufruf in sich vollständig. Der wiederholte Aufruf enthält alles, was der Server braucht: die Original-Argumente, die Antworten und den Merkzettel. Jede beliebige Server-Instanz kann ihn bearbeiten – auch eine, die die erste Runde nie gesehen hat. Das ist die Grundlage für zustandslose, beliebig skalierbare MCP-Server.
Der Merkzettel `requestState`
Oft braucht der Server gar keinen Merkzettel – die Argumente kommen ja mit dem zweiten Aufruf zurück. Nützlich wird requestState, wenn der Server in Runde 1 etwas festgestellt hat, das in Runde 2 noch gelten muss. Im Beispiel: Der Nutzer bestätigt „Version 2.4.1 ausrollen“. Erscheint in der Zwischenzeit Version 2.4.2, darf der Server nicht einfach die neueste Version ausrollen – bestätigt wurde 2.4.1. Also schreibt der Server die Version in den requestState.
Wichtig: Der requestState wandert durch den Client. Für den Server ist er deshalb eine Eingabe, der er nicht trauen darf. Sobald er Entscheidungen beeinflusst, muss der Server ihn gegen Veränderung schützen (HMAC oder AEAD) und beim Zurückkommen prüfen: Ist die Signatur gültig? Gehört er zu genau dieser Anfrage und diesem Nutzer? Ist er noch nicht abgelaufen? Der Client darf den Inhalt weder lesen noch verändern – er gibt ihn nur exakt zurück.
Wo Rückfragen erlaubt sind
Ein Server darf mit input_required antworten auf tools/call, prompts/get und resources/read – sonst nirgends. Und er darf nur Fragen stellen, die der Client unterstützt: Der Client deklariert das bei jeder Anfrage in _meta:
"_meta": {
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": { "form": {}, "url": {} }
}
}Ein leeres "elicitation": {} bedeutet: nur Formulare. Fehlt elicitation ganz, darf der Server keine Rückfrage stellen und muss ohne auskommen.
3. Formular-Modus (`form`)
Im Formular-Modus beschreibt der Server die gewünschten Eingaben mit einem vereinfachten JSON-Schema. Der Client baut daraus ein Formular.
Damit jeder Client das darstellen kann, ist das Schema bewusst schlicht: ein flaches Objekt mit einfachen Feldern – keine verschachtelten Objekte, keine Listen von Objekten.
| Feldtyp | Schema | typische Darstellung |
|---|---|---|
| Text | "type": "string", optional minLength, maxLength, format (email, uri, date, date-time) |
Eingabefeld |
| Zahl | "type": "number" oder "integer", optional minimum, maximum |
Zahlenfeld |
| Ja/Nein | "type": "boolean" |
Checkbox |
| Auswahl (eine) | "type": "string" mit enum – oder oneOf mit const + title für lesbare Beschriftungen |
Dropdown, Radiobuttons |
| Auswahl (mehrere) | "type": "array" mit items.enum bzw. items.anyOf, optional minItems, maxItems |
Checkbox-Liste |
Jedes Feld kann title, description und einen default haben; Clients sollen Vorgabewerte vorausfüllen.
Niemals Passwörter oder Schlüssel per Formular. Was im Formular eingegeben wird, sieht der Client – und damit unter Umständen das Modell, Logs und Zwischenstationen. Die Spezifikation verbietet deshalb ausdrücklich, im Formular-Modus nach Passwörtern, API-Schlüsseln, Zugangstokens oder Zahlungsdaten zu fragen. Dafür gibt es den URL-Modus. Name, E-Mail-Adresse oder Benutzername sind dagegen erlaubt – der Nutzer sieht die Frage und kann ablehnen.
4. URL-Modus (`url`)
Manche Eingaben dürfen den Client gar nicht erst berühren: das Passwort für ein Drittsystem, eine Kreditkartennummer, die Freigabe in einem OAuth-Dialog. Im URL-Modus schickt der Server deshalb nur einen Link. Der Nutzer erledigt die eigentliche Eingabe im Browser, direkt auf einer Seite des Servers oder des Drittanbieters.
{
"method": "elicitation/create",
"params": {
"mode": "url",
"message": "Bitte verbinden Sie Ihr GitHub-Konto, damit ich Issues anlegen kann.",
"url": "https://mcp.example.com/connect/github"
}
}Der Ablauf, typischerweise für eine Verbindung zu einem Drittdienst:
- Ein Tool braucht Zugriff auf GitHub, der Server hat für diesen Nutzer aber noch kein Token. Er antwortet mit einer URL-Rückfrage und einem
requestState. - Der Client zeigt dem Nutzer die vollständige URL und fragt um Erlaubnis, sie zu öffnen.
- Der Nutzer stimmt zu; der Client öffnet den Link im Browser und wiederholt den Tool-Aufruf mit
"action": "accept". - Im Browser meldet sich der Nutzer bei GitHub an und erteilt die Freigabe. Der Server erhält das Token und speichert es für diesen Nutzer.
- Beim wiederholten Aufruf prüft der Server anhand von
requestStatebzw. seines Token-Speichers, ob die Verbindung steht. Wenn ja, führt er das Tool aus; wenn nein, stellt er die Rückfrage erneut.
Zwei Dinge sind leicht misszuverstehen:
acceptheißt nur „Nutzer hat den Link geöffnet“, nicht „Vorgang erledigt“. Was im Browser passiert, erfährt der Client nicht. Ob es geklappt hat, weiß nur der Server.- Der URL-Modus ist nicht für die Anmeldung am MCP-Server selbst da. Die regelt die MCP-Autorisierung (Kapitel 17). Der URL-Modus ist für Zugänge, die der Server gegenüber Dritten braucht. Diese Zugangsdaten gibt der Server nie an den Client weiter.
Sicherheitsregeln im URL-Modus
Ein Link, den jemand anderes erzeugt hat, ist ein klassisches Einfallstor. Die Spezifikation stellt deshalb klare Regeln auf:
| Server | Client |
|---|---|
| keine persönlichen Daten oder Zugangsdaten in die URL schreiben | URL nie automatisch öffnen oder vorab laden |
| keine „vorab angemeldeten“ Links, die allein schon Zugriff gewähren | vor dem Öffnen die vollständige URL zeigen und um Zustimmung bitten |
| HTTPS verwenden (außer in der Entwicklung) | die Domain hervorheben, vor verdächtigen Adressen (z. B. Punycode) warnen |
| prüfen, dass derselbe Nutzer den Link öffnet, der die Rückfrage ausgelöst hat | den Link so öffnen, dass weder Client noch Modell die Eingaben mitlesen können |
Die letzte Server-Regel verhindert einen konkreten Angriff: Alice löst eine Verbindungs-Rückfrage aus, schickt den Link aber an Bob. Bob meldet sich arglos bei GitHub an – und Bobs Token landet in Alice' Konto. Deshalb zeigt der Link auf eine eigene Seite des Servers (/connect/github), die zuerst prüft, ob der angemeldete Browser-Nutzer derselbe ist wie der MCP-Nutzer, und erst dann zu GitHub weiterleitet.
5. Die drei möglichen Antworten
Jede Rückfrage endet mit genau einer von drei Antworten:
action |
Bedeutung | content |
sinnvolle Reaktion des Servers |
|---|---|---|---|
accept |
Nutzer hat bestätigt bzw. abgeschickt | Formular: die Eingaben; URL: leer | weiterarbeiten |
decline |
Nutzer hat ausdrücklich abgelehnt („Nein“) | leer | abbrechen, ggf. Alternative anbieten |
cancel |
Nutzer hat den Dialog geschlossen, ohne zu entscheiden | leer | abbrechen, später erneut fragen |
decline und cancel sind keine Fehler. Der Nutzer hat eine legitime Entscheidung getroffen; das Tool sollte ein normales Ergebnis liefern („Deployment nicht gestartet“), kein isError und erst recht keinen JSON-RPC-Fehler. Und: Ein Server darf sich nie darauf verlassen, dass eine Rückfrage beantwortet wird – der Client kann den Aufruf auch einfach nicht wiederholen.
6. Implementierung in Go
Das offizielle go-sdk unterstützt den neuen Ablauf ab v1.8.0. Ein Tool-Handler gibt in Runde 1 ein CallToolResult mit InputRequests (und optional RequestState) zurück; in Runde 2 findet er die Antworten in req.Params.InputResponses und den Merkzettel in req.Params.RequestState. Das folgende Beispiel ist das deploy-Tool aus Abschnitt 2 – vollständig und lauffähig.
package main
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// Geheimer Schlüssel nur des Servers – damit kann der Client requestState nicht fälschen.
var stateKey = []byte(os.Getenv("DEPLOY_STATE_KEY"))
type DeployIn struct {
Service string `json:"service" jsonschema:"Name des Dienstes"`
}
// deployState wandert zwischen Runde 1 und 2 durch den Client.
type deployState struct {
Service string `json:"service"`
Version string `json:"version"` // die Version, die der Nutzer bestätigt
Expires time.Time `json:"exp"`
}
func latestVersion(service string) string { return "2.4.1" } // Platzhalter: Build-System fragen
func deploy(ctx context.Context, req *mcp.CallToolRequest, in DeployIn) (*mcp.CallToolResult, any, error) {
answer, answered := req.Params.InputResponses["target"].(*mcp.ElicitResult)
// Runde 1: Es gibt noch keine Antwort – Rückfrage stellen und Zustand mitgeben.
if !answered {
version := latestVersion(in.Service)
state, err := sign(deployState{Service: in.Service, Version: version, Expires: time.Now().Add(10 * time.Minute)})
if err != nil {
return nil, nil, err
}
return &mcp.CallToolResult{
InputRequests: mcp.InputRequestMap{"target": &mcp.ElicitParams{
Mode: "form",
Message: fmt.Sprintf("%s in Version %s ausrollen – wohin?", in.Service, version),
RequestedSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"environment": map[string]any{
"type": "string", "title": "Zielumgebung",
"oneOf": []map[string]any{
{"const": "staging", "title": "Staging"},
{"const": "production", "title": "Produktion"},
},
"default": "staging",
},
"confirm": map[string]any{"type": "boolean", "title": "Ich habe die Änderungen geprüft"},
},
"required": []string{"environment", "confirm"},
},
}},
RequestState: state,
}, nil, nil
}
// Runde 2: Die Antwort ist da. Abgelehnt oder weggeklickt ist kein Fehler.
if answer.Action != "accept" {
return text("Deployment nicht gestartet (" + answer.Action + ")."), nil, nil
}
var st deployState
if err := verify(req.Params.RequestState, &st); err != nil {
return nil, nil, err
}
if st.Service != in.Service || time.Now().After(st.Expires) {
return nil, nil, errors.New("requestState passt nicht zu dieser Anfrage oder ist abgelaufen")
}
if confirm, _ := answer.Content["confirm"].(bool); !confirm {
return text("Ohne Bestätigung kein Deployment."), nil, nil
}
env, _ := answer.Content["environment"].(string)
return text(fmt.Sprintf("%s %s wird nach %s ausgerollt.", st.Service, st.Version, env)), nil, nil
}
// sign verpackt den Zustand als "payload.signatur" (HMAC-SHA256). Lesbar, aber nicht fälschbar.
func sign(v any) (string, error) {
b, err := json.Marshal(v)
if err != nil {
return "", err
}
m := hmac.New(sha256.New, stateKey)
m.Write(b)
return base64.RawURLEncoding.EncodeToString(b) + "." + base64.RawURLEncoding.EncodeToString(m.Sum(nil)), nil
}
func verify(s string, v any) error {
payload, mac, ok := strings.Cut(s, ".")
if !ok {
return errors.New("requestState fehlt")
}
b, err1 := base64.RawURLEncoding.DecodeString(payload)
sig, err2 := base64.RawURLEncoding.DecodeString(mac)
if err1 != nil || err2 != nil {
return errors.New("requestState beschädigt")
}
m := hmac.New(sha256.New, stateKey)
m.Write(b)
if !hmac.Equal(sig, m.Sum(nil)) {
return errors.New("requestState wurde verändert")
}
return json.Unmarshal(b, v)
}
func text(s string) *mcp.CallToolResult {
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: s}}}
}
func main() {
if len(stateKey) < 32 {
log.Fatal("DEPLOY_STATE_KEY muss mindestens 32 Zeichen lang sein")
}
s := mcp.NewServer(&mcp.Implementation{Name: "deployer", Version: "1.0.0"}, nil)
mcp.AddTool(s, &mcp.Tool{
Name: "deploy",
Description: "Rollt einen Dienst aus. Fragt den Nutzer nach Zielumgebung und Bestätigung.",
}, deploy)
if err := s.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
log.Fatal(err)
}
}Ein paar Punkte, die man leicht übersieht:
- Der Handler läuft zweimal. Alles vor der Rückfrage geschieht in beiden Runden – teure oder folgenreiche Schritte gehören deshalb hinter die Rückfrage.
- Ein HMAC macht den Zustand fälschungssicher, nicht geheim. Der Client kann die Version im
requestStatelesen. Soll er das nicht, verschlüsseln Sie mit AEAD (z. B. AES-GCM). - Bei entfernten Servern gehört der Nutzer in den Zustand. Hier läuft der Server lokal über stdio. Ein Server mit Anmeldung schreibt zusätzlich die Nutzerkennung (etwa den
sub-Claim) in denrequestStateund prüft sie in Runde 2 – sonst könnte ein anderer Nutzer einen fremden Zustand wiederverwenden. - Ältere Clients: Spricht der Client noch eine Protokollversion vor
2026-07-28, übersetzt das go-sdk dieInputRequestsautomatisch in eine klassischeelicitation/create-Anfrage an den Client und ruft den Handler danach mit der Antwort erneut auf. Der Handler muss dafür nichts tun.
7. Rückfragen in lang laufenden Tasks
Läuft ein Tool als Task (Kapitel 19), funktioniert die Rückfrage im Prinzip gleich, nur über andere Methoden: Der Task wechselt auf den Status input_required, die Frage steht in inputRequests der tasks/get-Antwort, und der Client antwortet mit tasks/update. Der Unterschied: Der Task wird nicht neu gestartet, sondern wartet auf die Antwort und läuft danach weiter. Ein requestState ist dort nicht nötig, weil der Task seinen Zustand selbst hält.
Faustregel: Braucht der Server die Antwort, bevor er überhaupt anfängt, stellt er die Frage über den normalen Rückfrage-Weg. Taucht die Frage mitten in einer langen Arbeit auf, gehört sie in den Task.
8. Elicitation testen mit `mcp-tester`
Der mcp-tester (Kapitel 14) spielt den Client: Er erkennt input_required, beantwortet die Frage mit einer vorher festgelegten Antwort und wiederholt den Aufruf automatisch.
Auf der Kommandozeile gibt man die Antwort mit --elicit mit (accept, decline, cancel oder accept:{…} mit Inhalt; mehrfach angebbar für mehrere Fragen). Unbeantwortete Fragen lehnt der Tester ab. Das ist die Ausgabe des Beispiels aus Abschnitt 6:
$ mcp-tester call deploy -c ./deployer --args '{"service":"auth-service"}' \
--elicit 'accept:{"environment":"production","confirm":true}'
[ELICIT] auth-service in Version 2.4.1 ausrollen – wohin? → accept {"confirm":true,"environment":"production"}
Content 0 (Text):
auth-service 2.4.1 wird nach production ausgerollt.
$ mcp-tester call deploy -c ./deployer --args '{"service":"auth-service"}' --elicit decline
[ELICIT] auth-service in Version 2.4.1 ausrollen – wohin? → decline
Content 0 (Text):
Deployment nicht gestartet (decline).In Testskripten legt elicit_response die Antworten vor dem Aufruf fest; assert_elicited prüft, was gefragt wurde:
elicit_response accept '{"environment": "staging", "confirm": true}'
call_tool deploy service:"auth-service"
assert_elicited "Version 2.4.1"
assert_contains "nach staging ausgerollt"
elicit_response decline
call_tool deploy service:"auth-service"
assert_contains "nicht gestartet"Gespeichert als deploy.mcp, läuft das Skript mit mcp-tester test -s deploy.mcp -c ./deployer; alle sieben Schritte bestehen. So lassen sich alle drei Antworten – und auch die Frage selbst – automatisiert in der CI prüfen (Kapitel 15).
9. Migration von `2025-11-25`
2025-11-25 |
2026-07-28 |
|---|---|
Server schickt elicitation/create als eigene Anfrage an den Client und wartet |
Server antwortet mit resultType: "input_required" + inputRequests; Client wiederholt den Aufruf mit inputResponses |
Capability elicitation einmalig beim Verbindungsaufbau |
Capability in _meta jeder Anfrage |
Fehler -32042 (URL elicitation required), wenn ein Tool erst nach einem Login laufen kann |
entfallen – stattdessen eine URL-Rückfrage im input_required-Ergebnis |
elicitationId und notifications/elicitation/complete für den Abschluss einer URL-Rückfrage |
entfallen – der Server erkennt den Abschluss beim wiederholten Aufruf (über requestState oder eigenen Speicher) |
| Zustand zwischen Frage und Antwort lebt im wartenden Server | Zustand reist als requestState mit oder liegt in einem Speicher, den jede Instanz erreicht |
10. Häufige Fehler
| Fehler | Folge | Lösung |
|---|---|---|
| Passwort oder API-Schlüssel per Formular abfragen | Geheimnis landet im Client, evtl. im Modellkontext und in Logs | URL-Modus verwenden |
decline/cancel als Fehler behandeln |
Modell hält die bewusste Entscheidung des Nutzers für einen Defekt und versucht es erneut | normales Ergebnis mit klarer Aussage zurückgeben |
requestState ungeprüft übernehmen |
Client kann Version, Ziel oder Nutzer manipulieren | HMAC/AEAD, Ablaufzeit, Bindung an Anfrage und Nutzer |
| Folgenreiche Aktion vor der Rückfrage | wird in Runde 1 und Runde 2 ausgeführt | erst fragen, dann handeln |
| Rückfrage an einen Client ohne passende Capability | Client kann die Frage nicht darstellen | Capability in _meta prüfen; ohne url keine URL-Rückfrage |
| URL-Rückfrage ohne Nutzerprüfung auf der Zielseite | fremder Nutzer verbindet sein Konto mit dem falschen MCP-Nutzer | Zielseite prüft, ob Browser-Nutzer und MCP-Nutzer identisch sind |
Fazit
Elicitation schließt die Lücke zwischen Server, KI und Mensch: Der Server fragt gezielt, der Mensch antwortet eindeutig, und das Modell muss nichts weitertragen. Mit 2026-07-28 ist die Rückfrage ein ganz normaler zweiter Aufruf geworden – etwas mehr Hin und Her auf der Leitung, dafür ohne offene Verbindungen und mit Servern, die keinen Zustand mehr festhalten müssen.
← Kapitel 20: Agentische Server & Sampling | Inhaltsverzeichnis | Nächstes Kapitel: Programmiersprachen →
Copyright Michael Lechner – 2026-10-09 (Neufassung nach Spezifikation 2026-07-28: Multi Round-Trip Requests, URL-Modus, getestetes Go-Beispiel)