Zum Inhalt springen
thconsulting
Menü öffnen
Tech-Deep-Dive
für CTOs / Senior Devs

MCP-Server self-hosted.
Multi-Tenant. Field-Whitelist. Audit-Spur.

Architektur-Patterns und Capabilities. Multi-Tenant via tenant_id, Field-Whitelist auf DB-Spalten-Ebene für DSGVO, Approval-State-Machine, Heartbeats als DB-Polling, anbieter-agnostisches LLM-Routing. Open-Core mit MCP-Schicht als MIT-Lizenz in Vorbereitung.

Capability-Stack

Neun Schichten, was sie können.

Konkrete Tool-Wahl behalte ich für mich, was zählt sind die Eigenschaften: Type-Safety End-to-End, anbieter-agnostischer LLM-Layer, Field-Whitelist als Default-Pflicht statt opt-in-Feature.

MCP-Runtime
Offizielles MCP-Protokoll
stdio + HTTP/SSE · OpenAI-/Google-kompatibel
HTTP-Layer
Schlanker Edge-Compatible Server
Bundle < 200 kB · ~10k req/s pro Core
DB-Layer
Type-safe End-to-End
Schema → Query → Response, ein Typecheck
Persistence
Relationale DB mit JSONB
Flexible Tool-Configs · gute Concurrency
LLM-Layer
Provider-agnostisch via Adapter
Claude Default · OpenAI / Ollama optional
Auth
Magic-Link + Bearer-Token + OAuth-Konnektoren
Tool-Registry pro Tenant · Session HttpOnly + SameSite
Validation
Schema-validierte Tool-Inputs
Type-safe Schemas für Beacon, Tools, Config
Deploy
Container-Cluster, Auto-TLS, Zero-Downtime
CI < 2 min · EU-Hosting · Rolling-Update
Observability
Append-only Audit-Log + JSON-Logs
GoBD/DSGVO-konform · optional Hash-Chain
MCP-Server-Anatomie

Drei Layer im offiziellen Protokoll.

Jeder MCP-Server hat drei klare Schichten. Das Modell ruft Werkzeuge auf, liest Daten, nutzt vordefinierte Prompts, alles deterministisch, alles mit Berechtigungen, alles loggbar.

01

Tool-Layer

Konkrete Werkzeuge die das Modell aufrufen darf, listInvoices, createBooking, queryProducts. Jedes Werkzeug deterministisch, mit JSON-Schema, Rückgabe-Typ und Berechtigungs-Check pro Aufruf.

02

Resource-Layer

Daten die das Modell lesen darf. Dokumente, DB-Snapshots, API-Responses. Der Server entscheidet was rausgeht, nicht das Modell. Field-Whitelist auf Spalten-Ebene per Default.

03

Prompt-Layer

Wiederverwendbare Prompts mit Parametern, die im UI angeboten werden. „Kontierung-Vorschlag erstellen", „Kunden-Brief verfassen", „Report Q4". Strukturiert, versioniert, testbar.

Tools

Sieben Standard-Tools je MCP-Server.

Default-Tool-Set für jeden MCP-Server. Custom-Tools je Mandanten-Use-Case oben drauf, werden via ToolDefinitionBuilder aus DG-Schema generiert (Auto-Tool-Generation aus Datenmodell).

list_records (scope, filter?) → Record[]

Liest Records aus DG-Scope mit Field-Whitelist. ScopeDataLoader prüft tenant_id und Berechtigung pro Spalte.

create_record (scope, data) → Record

Schreibt mit Validation (Schema aus DG-Definition). Audit-Log-Entry wird automatisch erzeugt.

update_record (scope, id, patch) → Record

Patch nur auf whitelisted Felder. revisionNote in audit_log.data.

invoke_connector (connector, action, params) → Result

Generischer Konnektor-Aufruf. Credentials aus connectors.credentialsEncrypted (AES-256-GCM mit per-Tenant-Salt).

request_approval (question, context, amount?) → ApprovalId

Pausiert Run, schreibt Approval-Entry. Worker pollt status, setzt Run fort bei approved.

handoff_to_agent (targetEmployee, context) → RunId

Live-Konversations-Routing zwischen Agents (OpenAI-Swarm-Pattern). Bernd reicht komplexen Case an Max weiter.

schedule_heartbeat (schedule, contextTemplate) → HeartbeatId

Cron-Trigger für 24/7-Agent-Aktivität. Default Polling alle 60 Sek.

Architektur-Pattern

Sechs Pattern, in jedem Build umgesetzt.

Pattern-Library aus produktiven MCP-Builds. Adaptiert wo sinnvoll von Paperclip (MIT-Lizenz) und OpenAI Swarm (handoff_to_agent).

PATTERN 01

Multi-Tenant via tenant_id

tenant_id Foreign-Key auf jeder Business-Tabelle. ScopeDataLoader filtert auf Service-Layer (kein DB Row-Level-Security, zu fragil bei Schema-Migrations). Pattern bewährt in analytics.thconsulting.dev und EDUSyn-Akademie. tenant_users-Junction für N:N (User kann mehrere Tenants administrieren).

PATTERN 02

Field-Whitelist auf Spalten-Ebene

Pro Scope (= DB-View) eine strErlaubteFelder-Konfiguration. Tools lesen nur was whitelisted ist, schreiben nur was whitelisted ist. Wenn DSGVO-Auskunft kommt: SELECT field, value FROM audit_log WHERE tenant_id=X AND containsPii=true → fertig.

PATTERN 03

Approval-Lifecycle als State-Machine

pending → approved | rejected | revision_requested | expired. expiresAt für Soft-Expiry (default 48h). Worker re-prüft pending Approvals, setzt Run fort oder marked als expired. State-Diff im audit_log nachvollziehbar.

PATTERN 04

Heartbeats als DB-Polling

heartbeats-Tabelle mit nextRunAt-Index. Worker-Process pollt jede Minute SELECT * FROM heartbeats WHERE next_run_at <= NOW() AND is_active = true. Triggert runs, setzt nextRunAt = NOW() + INTERVAL. Reicht bis ~10K aktive Heartbeats, danach Migration auf Queue-Backend.

PATTERN 05

Konnektor-Credentials verschlüsselt

AES-256-GCM mit Master-Key (env) plus per-Tenant-Salt. Verschlüsselte Credentials in connectors.credentialsEncrypted (text). Decrypt nur in Service-Layer für aktive Tool-Calls, niemals im API-Response. Master-Key-Rotation als geplantes Feature.

PATTERN 06

Anbieter-agnostisches LLM-Routing

LLMProvider-Interface mit Implementierungen für Claude, OpenAI, Ollama. Pro Tenant konfigurierbar. Datenschutz-paranoide Kunden bekommen Ollama-Endpoint mit lokalem Llama 3.3, kein Daten-Egress. costMicroEur pro Run für Cost-Pass-Through.

Deploy

Container-Cluster mit Auto-TLS.

Default-Deploy-Pattern. Pipeline: git push → CI → Container-Registry → SSH-Stack-Deploy → Auto-TLS via Reverse-Proxy. Migrations als one-shot-Service.

# docker-compose.yaml (Auszug, generalisiert)
services:
  mcp-server:
    image: registry.kunde.de/mcp-server:${VERSION}
    networks: [proxy-net, internal]
    environment:
      DATABASE_URL: ${DATABASE_URL}
      MASTER_ENCRYPTION_KEY: ${MASTER_ENCRYPTION_KEY}
      LLM_API_KEY: ${LLM_API_KEY}
    deploy:
      labels:
        - proxy.enable=true
        - proxy.host=mcp.kunde.de
        - proxy.tls.cert=letsencrypt
        - proxy.port=3000
      restart_policy:
        condition: any
        delay: 10s

  mcp-worker:
    image: registry.kunde.de/mcp-worker:${VERSION}
    networks: [internal]
    environment:
      DATABASE_URL: ${DATABASE_URL}
      WORKER_POLL_INTERVAL_MS: 60000
    command: # Worker-Process (Heartbeat-Polling)
    deploy:
      replicas: 1
      restart_policy:
        condition: any

networks:
  proxy-net: { external: true }
  internal: { driver: overlay }
FAQ

Tech-Fragen.

Welcher MCP-Transport, stdio oder HTTP?
Beides je nach Use-Case. stdio für Desktop-Clients (Claude Desktop, Claude Code, Cursor), kein Server-Setup, lokaler Subprocess-Spawn. HTTP/SSE für Multi-User und Web-Integrationen, wir hosten den Server unter mcp.<kunde>.de mit Bearer-Token-Auth. Default in unseren Builds: HTTP/SSE für Production, stdio nur für Dev-Umgebung. Offizielles MCP-Protokoll in beiden Fällen, gleicher Tool-Handler-Code.
Wie funktioniert Multi-Tenant-Isolation?
tenant_id durchgängig auf jeder Tabelle, ScopeDataLoader holt nur Daten mit passendem tenant_id (kein RLS auf DB-Ebene, sondern Service-Layer-Pflicht, robuster bei Schema-Migrations). Field-Whitelist auf DB-Spalten-Ebene begrenzt was der Agent überhaupt sehen kann (strErlaubteFelder pro Scope). Audit-Log loggt jeden Daten-Touch mit actorType plus tenantId. DSGVO-Auskünfte werden daraus generiert.
Wie wird der Server deployed?
Container-Cluster auf EU-Hosting (eigener Server pro Mandant ab L-Plan). Reverse-Proxy mit Auto-TLS via Let's Encrypt. Stack-Deploy-Pipeline via signiertem Container-Image, Migrations als one-shot-Service. Pattern aus EDUSyn-Akademie und analytics.thconsulting.dev, beide produktiv seit 2026.
Welche Konnektoren sind Standard?
Phase-1-Konnektoren: DATEV (ASCII-Export + Buchungssätze), Microsoft 365 (Graph API + OAuth), HubSpot (REST + OAuth), Stripe, eigene REST-API mit OAuth/Bearer/Basic. Phase 2: Lexoffice, sevDesk, WhatsApp Business, Slack, Twilio. Pro Konnektor: Auth-Flow, Tool-Definitionen, Field-Whitelist, Schema-Mapping, Rate-Limit-Handling, Error-Handling. Custom-Konnektoren als Setup-Fee einmalig, ab 2 Mandanten Standard-Bibliothek.
Wie funktioniert das Approval-System?
Approval-Tabelle mit Status pending|approved|rejected|revision_requested|expired. Agent eskaliert wenn ein definierter Schwellwert überschritten wird, Run pausiert, User bekommt Notification (Slack/Mail/Push), entscheidet via Admin-Konsole oder MCP-Tool, Run setzt fort. Audit-Log dokumentiert decidedByUserId plus decisionNote. Pattern adaptiert von Paperclip (MIT-Lizenz).
Gibt es Heartbeats / Cron-Trigger?
Ja, eigene heartbeats-Tabelle mit Schedule plus nextRunAt. Worker-Process pollt fällige Heartbeats jede Minute, triggert runs mit contextTemplate. Schedule-Format: every-15-min, daily-08:00, mon-fri-09:00. Für 24/7-Mitarbeiter (Anna prüft alle 15 Min DATEV, Bernd checkt alle 5 Min neue Site-Anfragen). DB-basiertes Polling reicht bis ~10K aktive Heartbeats, danach Queue-Backend als Upgrade-Pfad.
Welcher LLM-Provider. Anthropic, OpenAI, Ollama?
Provider-agnostisch via LLMProvider-Abstraktion. Default Claude Sonnet 4.7 für Reasoning und Long-Form. OpenAI (GPT-4o, o1) als Alternative für Web-Search-Tasks. Ollama-Endpoint für Datenschutz-paranoide Mandanten, lokales Llama 3.3 oder Qwen 2.5 auf eigenem Server, kein Daten-Egress. Provider-Wahl pro Tenant konfigurierbar, Cost-Pass-Through transparent.
Open-Source oder proprietär?
Open-Core. MCP-Server-Schicht als OSS in thorlyio/mcp-server (MIT-Lizenz, geplant Q3 2026). Backbone proprietär: DG-Scope-Engine, Whitelist-Validierung, GoBD-Audit-Trail, Multi-Tenant-Plattform. Apps (Anna/Bernd/Lisa-Templates) proprietär. Pattern wie Supabase oder PostHog. OSS gewinnt Mind-Share, proprietäres Backend ist Burggraben.
Wie passt MCP zu Webanwendung?
Saubere Trennung. Webanwendung ist Foundation: typsicherer DB-Layer, schlanker HTTP-Layer, Magic-Link plus 2FA, RBAC, Admin-UI. MCP-Server ist Layer obendrauf: nutzt die gleichen Tabellen via ScopeDataLoader, exposiert Tools für AI-Clients. Webanwendung läuft auch ohne MCP, MCP läuft nicht ohne Foundation. Empfehlung: Webanwendung zuerst bauen, MCP als Phase-2-Erweiterung.
Was kostet ein MCP-Build?
Drei Tier-Stufen. S: MCP-Server mit 3-5 Tools, einem Konnektor, ohne Multi-Tenant. M: Multi-Tenant, 5-8 Konnektoren, Approval-System, Heartbeats. L: plus Custom-Konnektoren, eigenes LLM-Provider-Routing, On-Premise-Option mit Ollama. Plus laufender Care-Plan (Updates, Monitoring, Konnektor-Pflege). Konkrete Konditionen klären wir im Erstgespräch nach Scope-Klärung.

Tech-Sparring oder Code-Walkthrough?

30 Min Erstgespräch, kostenlos. Patterns besprechen, Use-Case prüfen, Architektur-Entscheidungen klären. Wenn passt, Code-Walkthrough an einer Reference-Implementierung.

Erstgespräch buchen