Skip to main content
Glama

Portfolio MCP

Eigenständiger Model Context Protocol (MCP)-Server zur Verwaltung des Supabase-gestützten Engineering-Blogs, der für das Portfolio von Salman Butt verwendet wird.

Das öffentliche Next.js-Portfolio bleibt schreibgeschützt. Dieser Dienst besitzt die privilegierte Blog-Verwaltungsoberfläche und hält den Supabase-Geheimschlüssel außerhalb des Frontend-Deployments.

Was er bereitstellt

Artikel-Tools

  • list_blog_posts

  • get_blog_post

  • create_blog_post

  • update_blog_post

  • publish_blog_post

  • unpublish_blog_post

  • delete_blog_post

Bild-Tools

  • upload_blog_image

  • replace_blog_image

  • delete_blog_image

  • get_blog_image_url

Der Server legt keine beliebigen SQL- oder uneingeschränkten Supabase-Zugriffe offen.

Related MCP server: Self-Hosted Supabase MCP Server

Architektur

ChatGPT / remote MCP host / local MCP client
             |
             | Streamable HTTP or stdio
             v
      portfolio-mcp service
             |
             +--> MCP token authentication (HTTP)
             |
             +--> MCP SDK v2 tool layer
             |
             +--> Supabase REST: public.blogs
             |
             +--> Supabase Storage: blog-images

Public visitors
      |
      v
Next.js portfolio --> Supabase anon read-only access

Anforderungen

  • Node.js 22+

  • Ein Supabase-Projekt mit der Portfolio-blogs-Tabelle

  • Ein serverseitiger Supabase-Geheimschlüssel mit Zugriff auf die Blog-Tabelle und den Storage-Bucket

  • Für ChatGPT: ein über HTTPS erreichbares Remote-Deployment dieses MCP-Servers

Einrichtung

git clone https://github.com/salman0butt/portfolio-mcp.git
cd portfolio-mcp
npm ci
cp .env.example .env

Konfigurieren Sie .env:

SUPABASE_URL=https://YOUR_PROJECT.supabase.co
SUPABASE_SECRET_KEY=sb_secret_REPLACE_ME
SUPABASE_BLOG_BUCKET=blog-images

PORTFOLIO_MCP_TOKEN=replace-with-long-random-bearer-token
PORTFOLIO_MCP_URL_TOKEN=replace-with-different-long-random-url-token

PORT=3000
HOST=0.0.0.0
MCP_ALLOWED_ORIGINS=*
MCP_MAX_REQUEST_BYTES=5242880

Die HTTP- und Stdio-Einstiegspunkte laden automatisch eine lokale .env-Datei, falls vorhanden. Von Ihrer Deployment-Plattform injizierte Umgebungsvariablen funktionieren weiterhin normal.

MCP-Tokens generieren

Führen Sie diesen Befehl zweimal aus:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Verwenden Sie zwei verschiedene Ausgaben:

  • PORTFOLIO_MCP_TOKEN — Bearer-Token für Clients, die Authorization-Header senden können.

  • PORTFOLIO_MCP_URL_TOKEN — Wegwerf-Token für Clients, bei denen ein statischer benutzerdefinierter Header unpraktisch ist.

Beide Tokens müssen mindestens 32 Zeichen lang und unterschiedlich sein.

Verwenden Sie den Supabase-Geheimschlüssel niemals als MCP-Token. Setzen Sie SUPABASE_SECRET_KEY niemals in eine ChatGPT-Connector-URL.

Supabase-Authentifizierung

Bevorzugen Sie den modernen serverseitigen Supabase-Geheimschlüssel:

sb_secret_...

Der Dienst sendet moderne sb_secret_*-Schlüssel nur im Supabase-apikey-Header. Diese Schlüssel sind undurchsichtige API-Schlüssel und werden nicht als Authorization: Bearer-JWTs gesendet.

Legacy-JWT-basierte service_role-Schlüssel bleiben aus Kompatibilitätsgründen für Migrationen unterstützt, aber neue Deployments sollten sb_secret_* verwenden.

Entwicklung

Remote-HTTP-Modus:

npm run dev:http

MCP-Endpunkt:

http://localhost:3000/mcp

Health-Check:

http://localhost:3000/healthz

Lokaler Stdio-Modus:

npm run dev:stdio

Der Stdio-Modus verwendet keine HTTP-MCP-Tokens, da der Zugriff durch den lokalen Prozess gesteuert wird, der den Server startet.

Produktions-Deployment

Direkt bauen und ausführen:

npm run build
npm start

Oder Docker verwenden:

docker build -t portfolio-mcp .
docker run --rm -p 3000:3000 --env-file .env portfolio-mcp

Der Container installiert Abhängigkeiten aus package-lock.json, läuft als nicht-Root-Benutzer node und stellt einen /healthz-Docker-Health-Check bereit.

Stellen Sie diesen Dienst auf einer Plattform bereit, die einen langlaufenden Node-HTTP-Prozess/-Container unterstützt, z. B. Railway, Render, Fly.io, Kubernetes oder einem VPS. Die aktuelle Implementierung ist kein Vercel-Serverless-Function-Einstiegspunkt.

Für ChatGPT muss der bereitgestellte MCP-Endpunkt über HTTPS erreichbar sein, zum Beispiel:

https://portfolio-mcp.example.com/mcp

HTTP-Authentifizierung

Clients, die Request-Header unterstützen, sollten Folgendes verwenden:

Authorization: Bearer <PORTFOLIO_MCP_TOKEN>

Für einen Client, bei dem die Konfiguration eines statischen Bearer-Headers unpraktisch ist, akzeptiert der Endpunkt auch:

https://YOUR_MCP_HOST/mcp?token=YOUR_PORTFOLIO_MCP_URL_TOKEN

Query-String-Anmeldeinformationen können in Infrastruktur-/Zugriffsprotokollen erscheinen. Behandeln Sie PORTFOLIO_MCP_URL_TOKEN als Wegwerf-Token und rotieren Sie es, falls es offengelegt wird. Bevorzugen Sie die Bearer-Authentifizierung, wenn der MCP-Client sie unterstützt.

Mit ChatGPT verbinden

ChatGPT verbindet sich mit Remote-MCP-Servern, nicht mit einem Server, der nur auf localhost läuft.

Zum Zeitpunkt dieses Repository-Updates (August 2026) dokumentiert OpenAI volle benutzerdefinierte MCP-Unterstützung, einschließlich Schreib-/Änderungsaktionen für ChatGPT Business-, Enterprise- und Edu-Workspaces im Web. Die Verfügbarkeit kann sich ändern. Überprüfen Sie daher die aktuelle OpenAI-ChatGPT-Dokumentation zu benutzerdefinierten Apps/MCP, falls Ihre Benutzeroberfläche abweicht.

Wenn Ihr ChatGPT-Workspace benutzerdefinierte MCP-Apps/Connectors bereitstellt:

  1. Stellen Sie dieses Repository auf einem HTTPS-Endpunkt bereit.

  2. Konfigurieren Sie alle Server-Umgebungsvariablen auf der Deployment-Plattform.

  3. Aktivieren Sie in ChatGPT den Entwicklermodus / benutzerdefinierte Apps gemäß Ihren Workspace-Berechtigungen.

  4. Erstellen Sie eine benutzerdefinierte MCP-App.

  5. Wenn das ChatGPT-Formular kein statisches benutzerdefiniertes Bearer-Header-Feld bereitstellt, verwenden Sie den URL-Token-Endpunkt:

    https://YOUR_MCP_HOST/mcp?token=YOUR_PORTFOLIO_MCP_URL_TOKEN
  6. Wählen Sie in ChatGPT für diesen Connector No Auth aus. Die Authentifizierung wird weiterhin von diesem Server über das URL-Token erzwungen.

  7. Wählen Sie Scan Tools. Der Server sollte die oben aufgeführten Artikel- und Bild-Tools bereitstellen.

  8. Fügen Sie die App in einem neuen Chat hinzu/aktivieren Sie sie und testen Sie eine Leseaktion wie list_blog_posts, bevor Sie eine Schreibaktion testen.

  9. ChatGPT kann basierend auf Workspace-/App-Berechtigungen und den Tool-Annotationen eine Bestätigung für Schreib-/destruktive Aktionen anfordern.

Geben Sie SUPABASE_SECRET_KEY nicht in ChatGPT ein. ChatGPT benötigt nur den Remote-MCP-Endpunkt (und, mit diesem URL-Token-Setup, das Wegwerf-MCP-URL-Token).

Empfohlene ChatGPT-Testsequenz

Nachdem der Connector erfolgreich gescannt hat:

List my portfolio blog posts.

Dann:

Create a draft blog post titled "MCP Connection Test". Do not publish it.

Dann verifizieren Sie es:

Get the MCP Connection Test draft and show me its metadata.

Löschen Sie den Testentwurf schließlich nur, wenn Sie ihn ausdrücklich entfernen möchten.

CORS / Ursprünge

MCP_ALLOWED_ORIGINS akzeptiert eine kommagetrennte Liste:

MCP_ALLOWED_ORIGINS=https://example.com,https://another-client.example

Der HTTP-Server unterstützt aktuelle MCP-Request-Header, einschließlich Mcp-Protocol-Version, Mcp-Method, Mcp-Name und Mcp-Session-Id, in Browser-CORS-Preflights.

Der Standardwert * maximiert die Kompatibilität, während die Token-Authentifizierung weiterhin obligatorisch ist. Engen Sie die Liste ein, wenn Sie die genauen Browser-Ursprünge kennen, die den Dienst aufrufen müssen.

Anfrage- und Bildlimits

Die Standard-Obergrenze für HTTP-MCP-Anfragen beträgt 5 MiB:

MCP_MAX_REQUEST_BYTES=5242880

Dies ist absichtlich größer als das 3-MiB-Limit für decodierte Bilder, da base64 etwa ein Drittel Overhead plus JSON-Framing hinzufügt.

Akzeptierte Bild-Content-Typen:

  • PNG

  • JPEG

  • WebP

  • GIF

  • AVIF

Speicherpfade werden normalisiert und lehnen Traversal wie ../ ab. Bild-Payloads müssen gültiges base64 enthalten.

Empfohlene Objektpfade:

senior-software-engineer/cover.webp
production-rag-systems/architecture.webp
nextjs-at-scale/performance.webp

Das Löschen eines Blog-Artikels löscht nicht automatisch dessen Bilder. Dies vermeidet versehentliches Löschen von Medien, die möglicherweise geteilt oder wiederverwendet werden.

Blog-Workflow

Empfohlener Veröffentlichungsablauf:

  1. Erstellen Sie den Artikel als Entwurf.

  2. Laden Sie bei Bedarf Titel-/Diagrammbilder hoch.

  3. Aktualisieren Sie den Entwurf mit den zurückgegebenen öffentlichen Bild-URLs.

  4. Überprüfen Sie Titel, Auszug, Markdown, Kategorie, Tags und Veröffentlichungsdatum.

  5. Veröffentlichen Sie mit publish_blog_post.

  6. Aktualisieren Sie später oder nehmen Sie die Veröffentlichung zurück, wenn nötig.

  7. Löschen Sie den Artikel oder die Bilder nur, wenn es ausdrücklich beabsichtigt ist.

published_at akzeptiert ein ISO-8601-Datum oder -Datetime, zum Beispiel:

2026-08-25
2026-08-25T12:00:00+05:00

Sicherheitsmodell

  • Supabase-Geheimanmeldeinformationen sind nur serverseitig.

  • Moderne sb_secret_*-Schlüssel werden als Supabase-API-Schlüssel gesendet, nicht als JWT-Bearer-Tokens.

  • Das Next.js-Portfolio behält sein öffentliches, schreibgeschütztes Supabase-Zugriffsmodell.

  • HTTP-MCP-Anfragen erfordern ein Bearer-Token oder URL-Token.

  • MCP-Tokens müssen stark und unterschiedlich sein.

  • Der Token-Vergleich verwendet timing-sichere Gleichheit.

  • Es wird kein generischer SQL-/Query-Executor offengelegt.

  • Slugs, Veröffentlichungsdaten, Bildpfade, Bildtypen, base64-Payloads, Bildgrößen und HTTP-Anfragegrößen werden validiert.

  • Überschreib-, Unpublish-, Ersetz- und Lösch-Tools verwenden risikogerechte MCP-Annotationen.

  • Beim Herunterfahren wird kein neuer Datenverkehr mehr akzeptiert und aktiven Anfragen wird eine begrenzte Drain-Periode gewährt, bevor MCP-Ressourcen geschlossen werden.

  • Geheimnisse dürfen niemals in GitHub committet werden.

MCP-Protokoll

Der HTTP-Server verwendet das stabile MCP TypeScript SDK v2 und stellt Streamable HTTP unter /mcp bereit. Ein Stdio-Einstiegspunkt ist für lokale MCP-Hosts enthalten.

Der Remote-HTTP-Wrapper unterstützt sowohl modernen MCP-Datenverkehr als auch den zustandslosen Legacy-Fallback des SDK, um die Client-Kompatibilität zu maximieren.

Validierung

Führen Sie dieselbe Validierung aus, die von CI verwendet wird:

npm run check

Dies führt aus:

  • strikte TypeScript-Typüberprüfung

  • Laufzeit-Regressionstests

  • Produktions-TypeScript-Build

Laufzeittests decken die Supabase-Geheimschlüsselbehandlung, HTTP-Authentifizierung, CORS, Anfragelimits, Umgebungsladen, Token-Validierung und eine echte MCP-tools/list-Anfrage über den Remote-HTTP-Adapter ab.

GitHub Actions installiert den exakten Abhängigkeitsgraphen mit npm ci aus der committeten Lockfile.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Manage your Ghost blog content directly from Claude, Cursor, or any MCP-compatible client, allowing you to create, edit, search, and delete posts with support for tag management and analytics.
    11 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables developers to interact with self-hosted Supabase instances, providing database introspection, migration management, auth user operations, storage management, and TypeScript type generation directly from MCP-compatible development environments.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables validation and fixing of Dev.to markdown articles locally, and creation of unpublished drafts via the Forem API.
    -