portfolio-mcp
Portfolio MCP
Servidor independiente del Model Context Protocol (MCP) para gestionar el blog de ingeniería respaldado por Supabase que utiliza el portafolio de Salman Butt.
El portafolio público de Next.js permanece de solo lectura. Este servicio posee la superficie privilegiada de gestión del blog y mantiene la clave secreta de Supabase fuera del despliegue del frontend.
Lo que expone
Herramientas de artículos
list_blog_postsget_blog_postcreate_blog_postupdate_blog_postpublish_blog_postunpublish_blog_postdelete_blog_post
Herramientas de imágenes
upload_blog_imagereplace_blog_imagedelete_blog_imageget_blog_image_url
El servidor no expone SQL arbitrario ni acceso sin restricciones a Supabase.
Related MCP server: Self-Hosted Supabase MCP Server
Arquitectura
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 accessRequisitos
Node.js 22+
Un proyecto de Supabase que contenga la tabla
blogsdel portafolioUna clave secreta de Supabase del lado del servidor con acceso a la tabla de blogs y al bucket de Storage
Para ChatGPT: un despliegue remoto de este servidor MCP accesible por HTTPS
Configuración
git clone https://github.com/salman0butt/portfolio-mcp.git
cd portfolio-mcp
npm ci
cp .env.example .envConfigura .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=5242880Los puntos de entrada HTTP y stdio cargan automáticamente un archivo .env local cuando está presente. Las variables de entorno inyectadas por tu plataforma de despliegue siguen funcionando normalmente.
Generar los tokens MCP
Ejecuta este comando dos veces:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Usa dos salidas diferentes:
PORTFOLIO_MCP_TOKEN— token de portador para clientes que pueden enviar cabecerasAuthorization.PORTFOLIO_MCP_URL_TOKEN— token desechable para clientes donde una cabecera estática personalizada es inconveniente.
Ambos tokens deben tener al menos 32 caracteres y deben ser diferentes.
Nunca uses la clave secreta de Supabase como token MCP. Nunca pongas SUPABASE_SECRET_KEY en una URL de conector de ChatGPT.
Autenticación de Supabase
Prefiere la clave secreta moderna del lado del servidor de Supabase:
sb_secret_...El servicio envía claves modernas sb_secret_* solo en la cabecera apikey de Supabase. Estas claves son claves API opacas y no se envían como JWTs Authorization: Bearer.
Las claves service_role basadas en JWT heredadas siguen siendo compatibles para la migración, pero los nuevos despliegues deben usar sb_secret_*.
Desarrollo
Modo HTTP remoto:
npm run dev:httpPunto final MCP:
http://localhost:3000/mcpComprobación de salud:
http://localhost:3000/healthzModo stdio local:
npm run dev:stdioEl modo stdio no usa tokens MCP HTTP porque el acceso está controlado por el proceso local que lanza el servidor.
Despliegue en producción
Compila y ejecuta directamente:
npm run build
npm startO usa Docker:
docker build -t portfolio-mcp .
docker run --rm -p 3000:3000 --env-file .env portfolio-mcpEl contenedor instala las dependencias desde package-lock.json, se ejecuta como el usuario node no root y expone una comprobación de salud Docker /healthz.
Despliega este servicio en una plataforma que admita un proceso/contenedor HTTP de Node de larga duración, como Railway, Render, Fly.io, Kubernetes o un VPS. La implementación actual no es un punto de entrada de función serverless de Vercel.
Para ChatGPT, el punto final MCP desplegado debe ser accesible por HTTPS, por ejemplo:
https://portfolio-mcp.example.com/mcpAutenticación HTTP
Los clientes que admiten cabeceras de solicitud deben usar:
Authorization: Bearer <PORTFOLIO_MCP_TOKEN>Para un cliente donde configurar una cabecera de portador estática es inconveniente, el punto final también acepta:
https://YOUR_MCP_HOST/mcp?token=YOUR_PORTFOLIO_MCP_URL_TOKENLas credenciales en la cadena de consulta pueden aparecer en los registros de infraestructura/acceso. Trata PORTFOLIO_MCP_URL_TOKEN como desechable y rótalo si se expone. Prefiere la autenticación de portador cuando el cliente MCP lo admita.
Conectar a ChatGPT
ChatGPT se conecta a servidores MCP remotos, no a un servidor que se ejecuta solo en localhost.
En el momento de esta actualización del repositorio (agosto de 2026), OpenAI documenta soporte completo de MCP personalizado, incluidas acciones de escritura/modificación para espacios de trabajo de ChatGPT Business, Enterprise y Edu en la web. La disponibilidad puede cambiar, así que consulta la documentación actual de aplicaciones/MCP personalizadas de OpenAI ChatGPT si tu interfaz difiere.
Cuando tu espacio de trabajo de ChatGPT exponga aplicaciones/conectores MCP personalizados:
Despliega este repositorio en un punto final HTTPS.
Configura todas las variables de entorno del servidor en la plataforma de despliegue.
En ChatGPT, activa el Modo Desarrollador / aplicaciones personalizadas según los permisos de tu espacio de trabajo.
Crea una aplicación MCP personalizada.
Si el formulario de ChatGPT no proporciona un campo de cabecera de portador estática personalizada, usa el punto final de token de URL:
https://YOUR_MCP_HOST/mcp?token=YOUR_PORTFOLIO_MCP_URL_TOKENSelecciona Sin autenticación en ChatGPT para ese conector. La autenticación aún la aplica este servidor mediante el token de URL.
Elige Escanear herramientas. El servidor debe exponer las herramientas de artículos e imágenes listadas anteriormente.
Añade/habilita la aplicación en un nuevo chat y prueba una acción de lectura como
list_blog_postsantes de probar una acción de escritura.ChatGPT puede solicitar confirmación para acciones de escritura/destructivas según los permisos del espacio de trabajo/aplicación y las anotaciones de herramientas.
No introduzcas SUPABASE_SECRET_KEY en ChatGPT. ChatGPT solo necesita el punto final MCP remoto (y, con esta configuración de token de URL, el token MCP de URL desechable).
Secuencia de prueba recomendada para ChatGPT
Después de que el conector escanee correctamente:
List my portfolio blog posts.Luego:
Create a draft blog post titled "MCP Connection Test". Do not publish it.Después verifícalo:
Get the MCP Connection Test draft and show me its metadata.Finalmente, elimina el borrador de prueba solo cuando tengas la intención explícita de eliminarlo.
CORS / orígenes
MCP_ALLOWED_ORIGINS acepta una lista separada por comas:
MCP_ALLOWED_ORIGINS=https://example.com,https://another-client.exampleEl servidor HTTP admite las cabeceras MCP actuales, incluidas Mcp-Protocol-Version, Mcp-Method, Mcp-Name y Mcp-Session-Id en los preflight CORS del navegador.
El valor predeterminado * maximiza la compatibilidad mientras la autenticación por token sigue siendo obligatoria. Ajusta la lista cuando conozcas los orígenes exactos del navegador que deben llamar al servicio.
Límites de solicitudes e imágenes
El límite predeterminado de solicitudes HTTP MCP es 5 MiB:
MCP_MAX_REQUEST_BYTES=5242880Esto es intencionalmente mayor que el límite de imagen decodificada de 3 MiB porque base64 añade aproximadamente un tercio de sobrecarga más el marco JSON.
Tipos de contenido de imagen aceptados:
PNG
JPEG
WebP
GIF
AVIF
Las rutas de almacenamiento se normalizan y rechazan el traversal como ../. Las cargas útiles de imagen deben contener base64 válido.
Rutas de objetos recomendadas:
senior-software-engineer/cover.webp
production-rag-systems/architecture.webp
nextjs-at-scale/performance.webpEliminar un artículo de blog no elimina automáticamente sus imágenes. Esto evita la eliminación accidental de medios que pueden compartirse o reutilizarse.
Flujo de trabajo del blog
Flujo de publicación recomendado:
Crea el artículo como borrador.
Sube imágenes de portada/diagramas si es necesario.
Actualiza el borrador con las URLs públicas de imagen devueltas.
Revisa el título, el extracto, el Markdown, la categoría, las etiquetas y la fecha de publicación.
Publica usando
publish_blog_post.Actualiza o despublica más tarde cuando sea necesario.
Solo elimina el artículo o las imágenes cuando sea explícitamente intencional.
published_at acepta una fecha o fecha-hora ISO 8601, por ejemplo:
2026-08-25
2026-08-25T12:00:00+05:00Modelo de seguridad
Las credenciales secretas de Supabase son solo del lado del servidor.
Las claves modernas
sb_secret_*se envían como claves API de Supabase, no como tokens de portador JWT.El portafolio de Next.js mantiene su modelo de acceso público de solo lectura a Supabase.
Las solicitudes HTTP MCP requieren un token de portador o token de URL.
Los tokens MCP deben ser fuertes y distintos.
La comparación de tokens usa igualdad segura en tiempo.
No se expone ningún ejecutor SQL/consulta genérico.
Se validan slugs, fechas de publicación, rutas de imagen, tipos de imagen, cargas útiles base64, tamaños de imagen y tamaños de solicitud HTTP.
Las herramientas de sobrescritura, despublicación, reemplazo y eliminación usan anotaciones MCP apropiadas al riesgo.
El apagado deja de aceptar nuevo tráfico y da a las solicitudes activas un período de drenaje limitado antes de cerrar los recursos MCP.
Los secretos nunca deben comprometerse en GitHub.
Protocolo MCP
El servidor HTTP usa el SDK de TypeScript MCP estable v2 y expone HTTP Streamable en /mcp. Se incluye un punto de entrada stdio para hosts MCP locales.
El envoltorio HTTP remoto admite tanto el tráfico MCP moderno como el fallback heredado sin estado del SDK para maximizar la compatibilidad con los clientes.
Validación
Ejecuta la misma validación que usa CI:
npm run checkEsto ejecuta:
verificación estricta de tipos de TypeScript
pruebas de regresión en tiempo de ejecución
compilación de TypeScript de producción
Las pruebas en tiempo de ejecución cubren el manejo de claves secretas de Supabase, autenticación HTTP, CORS, límites de solicitudes, carga de entorno, validación de tokens y una solicitud real de tools/list MCP a través del adaptador HTTP remoto.
GitHub Actions instala el grafo de dependencias exacto con npm ci desde el lockfile comprometido.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceManage 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.14MIT
- FlicenseNot gradedqualityDmaintenanceEnables 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.
- AlicenseAqualityFmaintenanceEnables AI tools to programmatically manage Substack content, including creating drafts, publishing posts, and posting to Substack Notes. It supports image uploads, live blogging, and document formatting compatible with Substack's ProseMirror editor.118MIT
- AlicenseNot gradedqualityDmaintenanceManages Supabase projects, databases, edge functions, secrets, and branches across organizations using the Supabase Management API with 24 tools.MIT
Related MCP Connectors
Publish and manage articles, series, comments, reactions, newsletters and blog analytics.
Manage Supabase projects end to end across database, auth, storage, realtime, and migrations. Moni…
Manage Appwrite projects, databases, auth, storage, functions, and messaging; search Appwrite docs
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/salman0butt/portfolio-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server