Isometrisches Blueprint-Diagramm: MCP-Server als zentraler Hub, der ein bestehendes Backend mit Auth-Layer, Tools und Resources verbindet

    MCP-Server bauen: Schritt-für-Schritt-Anleitung für REST- und GraphQL-Backends

    13. Mai 20268 min LesezeitDeep Dive
    Till Freitag

    TL;DR:In 7 Schritten zum produktionsreifen MCP-Server: Backend kapseln, Tools modellieren, Resources exponieren, OAuth absichern, deployen. Code-Beispiele in TypeScript inklusive."

    Till Freitag

    Warum diese Anleitung?

    Wenn du die strategische Begründung für MCP gelesen hast, weißt du: Ohne MCP-Server bist du in 12 Monaten nicht mehr im Workflow deiner Nutzer. Die Frage ist nur noch: Wie baust du das konkret?

    Diese Anleitung zeigt dir den schnellsten Weg von „bestehendes REST/GraphQL-Backend" zu „funktionsfähiger MCP-Server, an dem Claude, Codex und ChatGPT andocken können". Du brauchst dafür keinen Greenfield – wir kapseln, was schon da ist.

    Wenn du die Grundlagen noch nicht kennst: Lies vorher kurz MCP für Einsteiger.

    Die Architektur in 30 Sekunden

    ┌──────────────┐    MCP     ┌──────────────┐    HTTP    ┌──────────────┐
    │  AI-Client   │  ────────▶ │  MCP-Server  │  ────────▶ │ Dein Backend │
    │ (Claude etc.)│            │  (Adapter)   │            │ (REST/GraphQL│
    └──────────────┘            └──────────────┘            └──────────────┘
                                       │
                                       └─ exponiert: Tools, Resources, Prompts

    Der MCP-Server ist kein Replacement deines Backends. Er ist ein dünner Adapter davor, der deine APIs in der Sprache spricht, die Agenten verstehen.

    Voraussetzungen

    • Bestehendes REST- oder GraphQL-Backend mit dokumentierten Endpoints
    • Node.js 20+ oder Python 3.11+
    • Ein Auth-Mechanismus deines Backends (API-Key, OAuth, JWT)
    • Eine Hosting-Option für Long-running HTTP (Cloudflare Workers, Railway, Fly, Render, Supabase Edge Functions)

    Schritt 1: Tools, Resources und Prompts identifizieren

    Bevor du Code schreibst, mach diese eine Liste. Sie ist 80 % der Arbeit:

    MCP-KonzeptWofür?Beispiel aus deinem Backend
    ToolAktion, die der Agent ausführen darfPOST /dealscreate_deal
    ResourceDaten, die der Agent lesen darfGET /deals/:iddeal://{id}
    PromptVordefinierte Vorlage für wiederkehrende Tasks„Erstelle Wochenreport aus Deals"

    Faustregel: Starte mit den 3 wichtigsten Workflows, nicht mit dem ganzen API-Surface. Lemlist hat mit 3 Tools 700 Kunden geholt. Dein API hat wahrscheinlich 200 Endpoints – ignoriere 197 davon im ersten Wurf.

    Schritt 2: Setup mit dem offiziellen TypeScript-SDK

    mkdir my-mcp-server && cd my-mcp-server
    npm init -y
    npm install @modelcontextprotocol/sdk zod
    npm install -D typescript tsx @types/node
    npx tsc --init

    Grundgerüst in src/index.ts:

    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
    import { z } from "zod";
    
    const server = new McpServer({
      name: "acme-crm",
      version: "0.1.0",
    });
    
    // ... Tools & Resources hier registrieren ...
    
    const transport = new StreamableHTTPServerTransport();
    await server.connect(transport);

    Schritt 3: REST-Endpoints als Tools kapseln

    Pro Tool brauchst du Name, Beschreibung, Input-Schema und Handler. Die Beschreibung ist entscheidend – sie ist der Prompt, an dem der Agent entscheidet, ob er dein Tool nutzt.

    server.tool(
      "create_deal",
      "Erstellt einen neuen Deal im CRM. Nutze dies, wenn der User von einem neuen Kunden, einer Opportunity oder einem Verkaufsabschluss spricht.",
      {
        title: z.string().describe("Klarer Deal-Titel, z. B. 'Acme Corp – Enterprise Q3'"),
        value: z.number().describe("Deal-Wert in Euro, ohne Komma"),
        contactId: z.string().describe("ID des Kontakts aus dem CRM"),
      },
      async ({ title, value, contactId }, { authInfo }) => {
        const res = await fetch(`${process.env.BACKEND_URL}/api/deals`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${authInfo?.token}`,
          },
          body: JSON.stringify({ title, value, contactId }),
        });
    
        if (!res.ok) {
          return {
            content: [{ type: "text", text: `Fehler: ${res.status} ${await res.text()}` }],
            isError: true,
          };
        }
    
        const deal = await res.json();
        return {
          content: [{ type: "text", text: `Deal angelegt: ${deal.id} (${title})` }],
        };
      },
    );

    Drei Dinge, die hier wichtig sind:

    1. Beschreibungen sind Prompts – schreib sie für den Agenten, nicht für den Menschen
    2. Fehler immer als isError: true zurückgeben, sonst halluziniert der Agent Erfolg
    3. authInfo.token kommt aus der OAuth-Session (siehe Schritt 5)

    Schritt 4: GraphQL-Backends kapseln

    Bei GraphQL hast du den Vorteil, dass du die Query genau auf das zuschneiden kannst, was der Agent braucht. Mach das. Gib niemals das ganze Schema frei.

    server.tool(
      "search_customers",
      "Sucht Kunden anhand eines Suchbegriffs. Liefert Name, Email und letzten Kontakt.",
      { query: z.string().min(2) },
      async ({ query }, { authInfo }) => {
        const gql = `
          query Search($q: String!) {
            customers(search: $q, limit: 10) {
              id name email lastContactAt
            }
          }
        `;
        const res = await fetch(`${process.env.BACKEND_URL}/graphql`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${authInfo?.token}`,
          },
          body: JSON.stringify({ query: gql, variables: { q: query } }),
        });
        const { data } = await res.json();
        return { content: [{ type: "text", text: JSON.stringify(data.customers, null, 2) }] };
      },
    );

    Anti-Pattern: Ein generisches execute_graphql-Tool, das beliebige Queries entgegennimmt. Damit verlierst du Auth-Granularität, gibst dem Agenten zu viele Optionen und fängst dir Schema-Lecks ein.

    Schritt 5: Resources – Daten zum Lesen exponieren

    Resources sind URIs, die der Client laden kann, ohne dass der Agent eine Aktion ausführt. Perfekt für kontextuelle Daten, die der Agent „immer dabei" haben soll.

    server.resource(
      "deal",
      "deal://{id}",
      async (uri, { id }) => {
        const res = await fetch(`${process.env.BACKEND_URL}/api/deals/${id}`);
        const deal = await res.json();
        return {
          contents: [{
            uri: uri.href,
            mimeType: "application/json",
            text: JSON.stringify(deal),
          }],
        };
      },
    );

    Beispiele für sinnvolle Resources:

    • customer://{id} – Kunden-Stammdaten
    • report://weekly/{date} – wöchentlicher Report
    • policy://refund – statische Policy-Dokumente, die der Agent zitieren soll

    Schritt 6: OAuth – der unsexy, aber kritische Teil

    Hier scheitern 80 % der ersten MCP-Server. Drei Optionen, sortiert nach Aufwand:

    Option A: API-Key per Header (nur für interne MCPs)

    Schnell, aber nicht multi-tenant. Für interne Server hinter SSO okay.

    const transport = new StreamableHTTPServerTransport({
      authenticate: async (req) => {
        const key = req.headers.get("x-api-key");
        if (key !== process.env.INTERNAL_KEY) throw new Error("Unauthorized");
        return { token: key };
      },
    });

    Option B: Bearer-Token-Forwarding (B2B-Setups)

    Der Client schickt sein eigenes Backend-Token mit. Du leitest es 1:1 weiter. Funktioniert, wenn deine Kunden technisch sind und API-Tokens generieren können.

    Option C: OAuth 2.1 mit Dynamic Client Registration (echter SaaS-Standard)

    Das ist, was du willst, wenn dein MCP-Server in Claude Desktop, ChatGPT und Cursor automatisch funktionieren soll. Das SDK bringt das mit:

    import { ProxyOAuthServerProvider } from "@modelcontextprotocol/sdk/server/auth/providers/proxyProvider.js";
    
    const oauth = new ProxyOAuthServerProvider({
      endpoints: {
        authorizationUrl: "https://auth.deinbackend.de/oauth/authorize",
        tokenUrl: "https://auth.deinbackend.de/oauth/token",
        revocationUrl: "https://auth.deinbackend.de/oauth/revoke",
      },
      verifyAccessToken: async (token) => {
        // gegen dein Auth-Backend prüfen
        const res = await fetch("https://auth.deinbackend.de/introspect", {
          method: "POST",
          body: new URLSearchParams({ token }),
        });
        const data = await res.json();
        if (!data.active) throw new Error("Invalid token");
        return { token, clientId: data.client_id, scopes: data.scope?.split(" ") ?? [] };
      },
      getClient: async (clientId) => {
        // aus deiner Client-DB laden
        return { client_id: clientId, redirect_uris: ["..."] };
      },
    });

    Dazu noch die Discovery-Endpoints ausliefern (/.well-known/oauth-authorization-server und /.well-known/oauth-protected-resource) – das SDK übernimmt das, wenn du den Provider registrierst.

    Wenn dein Backend noch keinen OAuth-Server hat: Das ist okay. Nutz Auth0, Clerk, WorkOS oder Supabase Auth davor. Bau das nicht selbst.

    Schritt 7: Lokal testen mit dem MCP Inspector

    Das offizielle Test-Tool – wahrscheinlich das wertvollste Stück der Toolchain:

    npx @modelcontextprotocol/inspector npx tsx src/index.ts

    Es startet eine Web-UI auf localhost:6274, in der du jedes Tool, jede Resource und den OAuth-Flow durchklicken kannst, bevor du Claude überhaupt ranlässt.

    Erst wenn das hier grün ist, schaltest du Claude Desktop oder Codex an.

    Schritt 8: Deployment

    Die Streamable-HTTP-Transport-Variante läuft überall, wo Long-running HTTP geht. Empfehlungen aus unseren Projekten:

    PlattformWann nehmen?Trade-off
    Cloudflare WorkersSaaS-Server für viele TenantsGlobale Edge, aber 30s CPU-Limit pro Request
    Supabase Edge FunctionsWenn dein Backend eh Supabase nutztAuth & DB direkt verfügbar, Deno-Runtime
    Railway / Fly / RenderKlassischer Long-running Node-ServerEinfach, kein Vendor-Lock-in
    AWS Lambda + API GatewayEnterprise mit AWS-VorgabeCold Starts, mehr Boilerplate

    Setze hinter den Server CDN + Rate Limit und log jede Tool-Invocation mit Tenant-ID. Du wirst diese Logs lieben, sobald jemand fragt „Warum hat der Agent das gemacht?".

    Schritt 9: Listing & Distribution

    Sobald der Server live ist:

    1. Eintrag in mcp.so und glama.ai/mcp/servers
    2. Eigene Docs-Seite mit „Connect to Claude"-Button (Deep-Link claude://mcp/install?...)
    3. Submit für native Marketplaces in Claude und ChatGPT
    4. Beispiele in deiner Doku, die zeigen, welcher Prompt welches Tool triggert – das ist Onboarding für Agenten und Menschen

    Häufige Fehler – und wie du sie vermeidest

    FehlerKonsequenzFix
    Zu viele Tools (>30)Agent wählt schlecht ausAuf 5–10 Kern-Tools reduzieren
    Vage BeschreibungenTool wird nie aufgerufenBeschreibung mit „Nutze dies, wenn..." starten
    Keine IdempotenzDoppelte Deals, doppelte Mailsidempotency_key Param ergänzen
    Auth-Token loggenDSGVO-GAUStrukturiertes Logging mit Token-Redaction
    Schema-DriftAgent ruft veraltete Felder aufZod-Schemas aus Backend-Types generieren

    Was als Nächstes?

    Wenn dein erster MCP-Server läuft, hast du den schwersten Teil hinter dir. Die nächsten Iterationen:

    • Skills schreiben (SKILL.md), damit Agenten deinen Server systematisch nutzen
    • Multi-Tenant-Logging mit OpenTelemetry
    • Eval-Suite mit echten Prompts, damit Schema-Änderungen Agenten-Verhalten nicht brechen

    Fazit

    Ein erster, produktionsreifer MCP-Server ist kein Monatsprojekt. Mit einem bestehenden REST- oder GraphQL-Backend, dem offiziellen SDK und einer der genannten Hosting-Optionen schaffst du das in 1–3 Tagen – mit OAuth in 1–2 Wochen.

    Der Punkt ist nicht, perfekt zu sein. Der Punkt ist, da zu sein, bevor deine Konkurrenz es ist.

    Die beste Zeit, deinen MCP-Server zu launchen, war gestern. Die zweitbeste ist heute.


    Du willst diesen Schritt nicht alleine gehen? Wir bauen MCP-Server für SaaS und interne Plattformen – mit OAuth, Multi-Tenant und sauberem Tool-Design. Lass uns reden →

    TeilenLinkedInWhatsAppE-Mail

    Verwandte Artikel

    Schwebende Fragezeichen über einem MCP-Server mit Auth-Shield und vernetzten Knoten – visuelle FAQ-Metapher
    13. Mai 20267 min

    MCP-FAQ: Die 12 häufigsten Einwände – ehrlich beantwortet

    Brauche ich überhaupt MCP, wenn ich schon eine API habe? Was kostet das? Wie sicher ist das wirklich? Wir beantworten di

    Weiterlesen
    MCP als zentraler Hub, der KI-Agenten mit CRM, ERP, Datenbanken und SaaS-Tools verbindet
    13. Mai 20265 min

    No MCP, no Party: Warum kein Unternehmen mehr an MCP vorbeikommt

    MCP ist nicht mehr nur ein Protokoll – es ist ein neuer Distributionskanal. Wer als SaaS oder Unternehmen jetzt keinen M

    Weiterlesen
    Schematische Darstellung des Model Context Protocol: KI-Gehirn verbunden mit Datenbanken, Kalender, CRM und Dokumenten
    12. März 20266 min

    MCP für Einsteiger: Alles, was du über das Model Context Protocol wissen musst

    MCP ist der offene Standard, der KI-Modelle mit deinen Tools verbindet. Was es ist, wie es funktioniert und warum kein W

    Weiterlesen
    Isometrisches Diagramm: MCP-Server als produktiver Retrieval-Layer zwischen Vector Store, Source Repositories und Agenten
    20. Mai 20264 min

    MCP-Server selber bauen: Vom Prototyp zum produktiven Retrieval-Layer

    Ein MCP-Server am Nachmittag ist einfach. Ein MCP-Server, der unter Last, mit echten Permissions und sauberem Retrieval

    Weiterlesen
    monday.com MCP-Integrationen – AI-Agents verbinden sich mit der Work-Management-Plattform
    15. April 20265 min

    monday.com MCP: Alle verfügbaren Tools und Integrationen im Überblick

    monday.com bietet mit dem Platform MCP und dem Apps MCP zwei leistungsstarke MCP-Server – plus native Integrationen für

    Weiterlesen
    Claude Managed Agents Architektur – Gehirn verbunden mit mehreren Händen für Tools und Sandboxes
    8. April 20265 min

    Claude Managed Agents: Anthropics Griff nach der Agent-Runtime

    Anthropic launcht Managed Agents in der Public Beta – eine gehostete Runtime, die das 'Gehirn' von den 'Händen' entkoppe

    Weiterlesen
    Warum wir von ChatGPT auf Claude umgestiegen sind – und was wir dabei über LLMs gelernt haben
    20. Februar 20265 min

    Warum wir von ChatGPT auf Claude umgestiegen sind – und was wir dabei über LLMs gelernt haben

    Wir haben 18 Monate mit ChatGPT gearbeitet – und sind dann auf Claude umgestiegen. Hier ist der ehrliche Vergleich aller

    Weiterlesen
    Die nächste Generation CRM: Warum monday CRM dazugehört – und das Interface der Zukunft ein Chat istDeep Dive
    15. Juli 20258 min

    Die nächste Generation CRM: Warum monday CRM dazugehört – und das Interface der Zukunft ein Chat ist

    Das CRM der Zukunft ist kein Dashboard – es ist ein Chat. Warum monday CRM zur nächsten Generation gehört und wie MCP da

    Weiterlesen
    Eine stilisierte 5 aus orangefarbenen Bändern und Zahnrädern – Visual zu Claude Sonnet 5
    30. Juni 20263 min

    Claude Sonnet 5: Agentik für die breite Masse

    Anthropic launcht Claude Sonnet 5 – ein Sonnet-Modell, das nah an Opus 4.8 herankommt, aber zu einem Bruchteil des Preis

    Weiterlesen