MCP-Server erstellen: eigene Firmendaten an Claude anbinden, von A bis Z
Wir haben einen kleinen MCP-Server gebaut, der eine Offertenliste für Claude lesbar macht: rund 90 Zeilen Node.js, ohne Bibliothek, mit Demo-Daten. Hier ist jeder Schritt, der Code, das Protokoll der Aufrufe und was Claude damit beantwortet hat.
Wie MCPDas Model Context Protocol (MCP) ist ein offener Standard, über den KI-Anwendungen einheitlich auf externe Werkzeuge, Daten und Dienste zugreifen. Statt für…Mehr erfahren → grundsätzlich funktioniert, haben wir im Artikel MCP erklärt beschrieben. Dieser Beitrag ist die Praxis dazu: ein ServerEin Server ist ein Computer oder ein Programm, das anderen Geräten Dienste bereitstellt: Er liefert Websites aus, speichert Daten, verschickt E-Mails oder…Mehr erfahren →, den wir am 11. November 2026 gebaut und getestet haben.
Das Ziel: eine Frage, die heute 15 Minuten kostet
In vielen KMU liegt eine Liste der offenen Offerten irgendwo: in einer Tabelle, im Auftragsprogramm, im Kopf der Verkaufsleiterin. Die Frage «Welche Offerten sind seit mehr als zwei Wochen offen, und wie viel steckt drin?» kostet jedes Mal ein paar Minuten Suchen und Rechnen. Genau solche Fragen sind ein gutes erstes MCP-Projekt: klar, lesend, überprüfbar.
Für den Test haben wir eine Liste mit zehn Offerten der erfundenen Schreinerei Muster AG angelegt, mit Nummer, Kunde, Objekt, Betrag, Status und Versanddatum. Keine echten Daten, nichts davon verlässt den Rechner ausser den Antworten, die der Server an Claude gibt.
- 01offerten.csv
Daten
Offertenliste als CSV, 10 Zeilen Demo-Daten.
- 02server.mjs
MCP-Server
Liest die Liste, rechnet Tage offen, bietet zwei Werkzeuge an.
- 03mcp.json
Client
Claude Code startet den Server und fragt die Werkzeuge ab.
- 04
Antwort
Claude ruft die Werkzeuge auf und formuliert die Antwort.
Schritt für Schritt
MCP-Server für eigene Daten bauen
Die Fragen festlegen
Nicht mit der Technik anfangen, sondern mit drei bis fünf Fragen, die jemand im Team wirklich stellt. Aus jeder Frage wird später ein Werkzeug oder ein Parameter.
Werkzeuge beschreiben
Jedes Werkzeug bekommt einen Namen, eine Beschreibung in ganzen Sätzen und ein Schema für die Eingaben. Die Beschreibung liest das Modell, um zu entscheiden, wann es das Werkzeug benutzt. Sie ist also Teil des Prompts.
Server schreiben
Der Server liest Zeilen von der Standardeingabe, beantwortet initialize, tools/list und tools/call und schreibt die Antworten zurück. Rechnungen gehören in den Server, nicht ins Modell.
Von Hand prüfen
Bevor ein Modell den Server sieht, schickt man ihm die Anfragen selbst und liest die Antworten, inklusive Fehlerfall.
Im Client einbinden
Konfigurationsdatei mit Startbefehl, nur die eigenen Werkzeuge erlauben, Frage stellen, Aufrufprotokoll lesen.
Die Werkzeuge
Wir haben zwei Werkzeuge gebaut. offene_offerten listet alle offenen Offerten und rechnet aus, wie viele Tage sie offen sind, optional gefiltert auf eine Mindestzahl Tage. offerte gibt eine einzelne Offerte anhand der Nummer zurück. Die Beschreibung ist absichtlich ausführlich:
{
name: 'offene_offerten',
description: 'Listet offene Offerten der Muster AG, optional nur solche, die seit mindestens N Tagen offen sind (Stichtag im Format JJJJ-MM-TT).',
inputSchema: {
type: 'object',
properties: {
stichtag: { type: 'string', description: 'Datum JJJJ-MM-TT, ab dem gezählt wird' },
mindestens_tage: { type: 'number', description: 'nur Offerten, die mindestens so viele Tage offen sind' },
},
required: ['stichtag'],
},
}
Der Stichtag ist Pflicht. So kann das Modell nicht mit einem angenommenen Datum rechnen, sondern muss eines übergeben, und im Protokoll sieht man, welches.
Der Kern des Servers
MCP über die Standardein- und -ausgabe heisst: Jede Nachricht ist eine Zeile JSON nach dem Schema JSON-RPC 2.0. Der Kern unseres Servers ist eine einzige Verzweigung:
readline.createInterface({ input: process.stdin }).on('line', (zeile) => {
const msg = JSON.parse(zeile);
if (msg.id === undefined) return; // Benachrichtigung, keine Antwort nötig
switch (msg.method) {
case 'initialize':
return antworte(msg.id, {
protocolVersion: msg.params?.protocolVersion ?? '2025-06-18',
capabilities: { tools: {} },
serverInfo: { name: 'muster-offerten', version: '0.1.0' },
});
case 'tools/list':
return antworte(msg.id, { tools: TOOLS });
case 'tools/call':
try {
const daten = rufe(msg.params.name, msg.params.arguments);
return antworte(msg.id, { content: [{ type: 'text', text: JSON.stringify(daten) }] });
} catch (e) {
return antworte(msg.id, { content: [{ type: 'text', text: String(e.message) }], isError: true });
}
default:
return fehler(msg.id, `Methode ${msg.method} nicht unterstützt`);
}
});
Dazu kommen das Einlesen der CSV-Datei und die Funktion rufe, die je Werkzeug filtert und rechnet. Zusammen sind es rund 90 Zeilen. Wir haben bewusst keine Bibliothek verwendet, damit jede Zeile nachvollziehbar ist. Für einen Server, den ein Team täglich nutzt, ist das offizielle SDK die bessere Wahl. Warum, zeigte sich gleich im Test.
Von Hand prüfen
Vor dem ersten Einsatz haben wir dem Server die vier Anfragen direkt über die Kommandozeile geschickt: initialize, tools/list, ein Aufruf mit Stichtag 11.11.2026 und mindestens 14 Tagen, und ein Aufruf mit der nicht existierenden Nummer 9999. Der letzte lieferte wie gewollt die Meldung «Offerte 9999 nicht gefunden» mit der Markierung isError. Dieser Schritt dauert Minuten und erspart später viel Rätselraten, ob ein Fehler beim Modell oder beim Server liegt.
Im Client einbinden
Claude Code bekommt eine kleine Konfigurationsdatei mit dem Startbefehl:
{
"mcpServers": {
"muster": { "command": "node", "args": ["/pfad/zu/server.mjs"] }
}
}
Beim Aufruf haben wir nur die beiden eigenen Werkzeuge erlaubt und alle eingebauten Werkzeuge abgeschaltet. So konnte das Modell weder Dateien lesen noch im Internet suchen, sondern nur unsere Offertenliste befragen.
Der Test: drei Fragen, eine davon unbeantwortbar
Wir haben Claude Sonnet und Claude Haiku je einmal dieselben drei Fragen gestellt, mit Stichtag 11. November 2026:
- Welche Offerten sind seit mindestens 14 Tagen offen? Mit Nummer, Kunde, Betrag, Tagen und Summe.
- Was ist der Status der Offerte 2026-127?
- Wie viel Umsatz hat die Muster AG im Jahr 2025 gemacht?
Die dritte Frage kann der Server nicht beantworten: Er kennt nur Offerten aus 2026 und keine Rechnungen. Dazu stand im Prompt: «Wenn die Werkzeuge eine Frage nicht beantworten können, sag das, statt zu schätzen.»
Sollwert Frage 1 (aus der Demo-Liste gerechnet)Konstruiertes Beispiel mit Demo-Daten, kein Kundenfall
Beide Modelle trafen alles. Die Liste der vier Offerten stimmte, die Summe auch. Den Status der Offerte 2026-127 gaben beide korrekt mit «abgelehnt» an, inklusive Kunde, Objekt und Versanddatum. Auf die Umsatzfrage antwortete Sonnet: «Das kann ich nicht beantworten. Die Werkzeuge liefern nur offene Offerten und einzelne Offerten nach Nummer. Es gibt keine Umsatz- oder Rechnungsdaten und keine Auswertung für 2025. Ich schätze den Betrag nicht.» Haiku verwies zusätzlich darauf, dass es dafür die Buchhaltung oder den Jahresabschluss bräuchte.
Sonnet brauchte 25 Sekunden, Haiku knapp 6. Bei Sonnet stand eine überflüssige Rechenzeile vor der Antwort, ein Schönheitsfehler. Beide riefen die zwei Werkzeuge parallel auf, wie das Protokoll des Servers zeigt.
Was das Protokoll verraten hat
Weil unser Server jede eingehende Nachricht mitschrieb, konnten wir sehen, was der Client tatsächlich tut. Die erste Nachricht war nicht initialize, sondern eine Anfrage server/discover mit der Protokollversion 2026-07-28. Unser Minimalserver kannte sie nicht und antwortete mit «nicht unterstützt». Der Client fiel danach auf initialize mit der Version 2025-11-25 zurück, und alles lief.
Das ist die praktische Lehre aus dem Test: Das Protokoll entwickelt sich weiter, und ein selbstgeschriebener Server bleibt auf dem Stand, auf dem man ihn geschrieben hat. Dass es hier funktionierte, verdanken wir dem Rückfall im Client. Das offizielle SDK hält mit neuen Versionen Schritt; für alles, was länger als ein Experiment leben soll, ist es deshalb die richtige Grundlage.
Warum der Server rechnet und nicht das Modell
Eine Designentscheidung hat sich im Test bewährt: Die Tage, seit denen eine Offerte offen ist, rechnet der Server aus und gibt sie fertig zurück. Das Modell muss nur noch filtern lassen, auflisten und zusammenzählen. Man könnte dem Modell auch die rohe Liste geben und es selbst rechnen lassen. Bei zehn Zeilen ginge das meist gut. Bei zweihundert Zeilen, Datumsangaben über den Jahreswechsel und einem Stichtag, den das Modell aus dem Gespräch ableiten muss, steigt das Risiko eines stillen Rechenfehlers deutlich.
Die Regel lautet deshalb: Alles, was eine eindeutige Antwort hat, gehört in den Server. Filtern, sortieren, Differenzen, Summen über viele Zeilen. Das Modell übernimmt, was es gut kann: die Frage verstehen, das passende Werkzeug wählen, Ergebnisse verständlich formulieren und sagen, wenn etwas fehlt. Wer diese Arbeitsteilung einhält, bekommt Antworten, die man nachprüfen kann, weil jede Zahl aus einem Werkzeugaufruf stammt, der im Protokoll steht.
Sicherheit: was wir bewusst weggelassen haben
- 01Nur lesende Werkzeuge, wo immer möglich
- 02Rechnungen und Filter im Server, nicht im Modell
- 03Nur die Felder ausgeben, die für die Frage nötig sind
- 04Jeder Aufruf wird protokolliert
- 05Schreibende Werkzeuge nur mit Bestätigung durch einen MenschenPflicht
- 06Im Client nur die eigenen Werkzeuge freigeben
- 07Klären, welche Daten an den KI-Anbieter gehenDatenschutz
- 08Offizielles SDK für den Dauerbetrieb
Ein Punkt verdient Betonung: Was der Server an das Modell zurückgibt, geht an den KI-Anbieter. In unserem Beispiel waren das zehn erfundene Zeilen. Bei echten Kundendaten muss geklärt sein, wo diese verarbeitet werden, und der Server sollte nur die Felder herausgeben, die für die Frage nötig sind. Ein Werkzeug «offene Offerten» braucht keine Telefonnummern.
Ebenso wichtig: Texte aus den eigenen Daten können Anweisungen enthalten, etwa eine Notiz «ignoriere alle Regeln». Ein lesender Server ohne schreibende Werkzeuge kann damit wenig Schaden anrichten. Sobald Werkzeuge schreiben oder senden dürfen, gehört jeder solche Schritt vor einen Menschen, wie wir es beim KI-Agenten für die erste Antwort auf Anfragen zeigen.
Wann ein eigener Server sinnvoll ist
Für viele bekannte Dienste gibt es fertige MCP-Server oder eingebaute Verbindungen. Ein eigener Server lohnt sich, wenn die Daten in einem eigenen System liegen: einer Branchensoftware, einer eigenen Datenbank, einer Tabelle, die nur ihr so führt. Oder wenn ihr genau steuern wollt, welche Felder das Modell sieht.
Der Bau selbst ist, wie das Beispiel zeigt, überschaubar. Aufwändiger sind die Fragen rundherum: Wer darf den Server nutzen, wo läuft er, wie kommt er an die Daten, was passiert, wenn das Quellsystem nicht erreichbar ist? Wenn ihr dabei Unterstützung wollt, bauen wir solche Anbindungen im Rahmen von KI-Agenten oder als Teil einer Individualsoftware. Wer zuerst prüfen will, welche Abläufe sich überhaupt lohnen, findet auf der Seite KI-Automatisierung für KMU unseren Ansatz. Wie wir selbst mit Claude Code arbeiten, beschreibt der Artikel Claude Code in der Praxis.
Fazit
Ein MCP-Server für eigene Daten ist kein Grossprojekt. Unser Beispiel hat zwei Werkzeuge, liest eine Tabelle, rechnet selbst und lässt das Modell nur zusammenfassen. Im Test waren alle Antworten richtig, und eine Frage ausserhalb der Daten wurde nicht erfunden, sondern abgelehnt. Das Protokoll hat gezeigt, warum ein Experiment ohne Bibliothek gut zum Lernen ist und das offizielle SDK gut für den Betrieb. Wer klein und lesend anfängt, hat nach einem Vormittag ein Werkzeug, das jeden Tag ein paar Minuten spart.
Häufige Fragen
Wie erstelle ich einen MCP-Server?+
Ein MCP-Server ist ein kleines Programm, das über ein festgelegtes Protokoll (JSON-RPC) Werkzeuge anbietet. Er beantwortet mindestens drei Anfragen: initialize, tools/list und tools/call. Unser Beispiel kommt mit rund 90 Zeilen Node.js aus. Für den Produktivbetrieb empfehlen wir das offizielle SDK, weil es neue Protokollversionen, Fehlerfälle und Transportwege abdeckt.
Kann Claude mit einem MCP-Server meine Daten verändern?+
Nur wenn der Server ein Werkzeug dafür anbietet. Unser Beispiel ist bewusst nur lesend: Es gibt keine Funktion zum Schreiben oder Löschen. Das ist die wichtigste Sicherheitsentscheidung beim Bau, wichtiger als jede Einstellung im Client.
Erfindet Claude Antworten, wenn die Daten fehlen?+
In unserem Test vom 11.11.2026 nicht: Auf die Frage nach dem Umsatz 2025, den unsere Werkzeuge nicht liefern konnten, antworteten Claude Sonnet und Claude Haiku beide, dass sie das nicht beantworten können. Wir hatten im Prompt allerdings ausdrücklich verlangt, nicht zu schätzen.
Brauche ich für MCP einen Server im Internet?+
Nein. Unser Beispiel läuft lokal über die Standardein- und -ausgabe und wird vom Client gestartet. Für ein ganzes Team kann ein Server auch über das Netz erreichbar sein; dann braucht es Anmeldung, Verschlüsselung und ein Protokoll der Zugriffe.
Über den Autor
Daniel MüllerSenior Developer & SEO-Stratege
Daniel Müller ist Senior Developer und SEO-Stratege bei DLM Digital in Zürich. Mit über 10 Jahren Erfahrung in Webentwicklung, SEO, GEO/AEO und KI-Integration begleitet er Schweizer KMU bei der digitalen Transformation. Im DLM Magazin schreibt er über KI, Vibe Coding und moderne Suchmaschinen-Sichtbarkeit.