portfolio-mcp
Портфолио MCP
Автономный сервер Model Context Protocol (MCP) для управления блогом на базе Supabase, используемым в портфолио Салмана Батта.
Публичное Next.js-портфолио остаётся доступным только для чтения. Этот сервис владеет привилегированной поверхностью управления блогом и хранит секретный ключ Supabase вне фронтенд-развёртывания.
Что он предоставляет
Инструменты для статей
list_blog_postsget_blog_postcreate_blog_postupdate_blog_postpublish_blog_postunpublish_blog_postdelete_blog_post
Инструменты для изображений
upload_blog_imagereplace_blog_imagedelete_blog_imageget_blog_image_url
Сервер не предоставляет произвольный SQL или неограниченный доступ к Supabase.
Related MCP server: Self-Hosted Supabase MCP Server
Архитектура
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Требования
Node.js 22+
Проект Supabase, содержащий таблицу
blogsпортфолиоСерверный секретный ключ Supabase с доступом к таблице блога и корзине Storage
Для ChatGPT: доступное по HTTPS удалённое развёртывание этого MCP-сервера
Настройка
git clone https://github.com/salman0butt/portfolio-mcp.git
cd portfolio-mcp
npm ci
cp .env.example .envНастройте .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Точки входа HTTP и stdio автоматически загружают локальный файл .env, если он присутствует. Переменные окружения, внедряемые вашей платформой развёртывания, продолжают работать как обычно.
Сгенерируйте MCP-токены
Выполните эту команду дважды:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Используйте два разных вывода:
PORTFOLIO_MCP_TOKEN— bearer-токен для клиентов, которые могут отправлять заголовкиAuthorization.PORTFOLIO_MCP_URL_TOKEN— одноразовый токен для клиентов, где настройка статического пользовательского заголовка неудобна.
Оба токена должны быть не менее 32 символов и должны различаться.
Никогда не используйте секретный ключ Supabase в качестве MCP-токена. Никогда не помещайте SUPABASE_SECRET_KEY в URL коннектора ChatGPT.
Аутентификация Supabase
Предпочитайте современный серверный секретный ключ Supabase:
sb_secret_...Сервис отправляет современные ключи sb_secret_* только в заголовке apikey Supabase. Эти ключи являются непрозрачными ключами API и не отправляются как JWT в Authorization: Bearer.
Устаревшие ключи service_role на основе JWT остаются поддерживаемыми для совместимости при миграции, но новые развёртывания должны использовать sb_secret_*.
Разработка
Удалённый режим HTTP:
npm run dev:httpКонечная точка MCP:
http://localhost:3000/mcpПроверка работоспособности:
http://localhost:3000/healthzЛокальный режим stdio:
npm run dev:stdioРежим stdio не использует HTTP MCP-токены, поскольку доступ контролируется локальным процессом, запускающим сервер.
Производственное развёртывание
Соберите и запустите напрямую:
npm run build
npm startИли используйте Docker:
docker build -t portfolio-mcp .
docker run --rm -p 3000:3000 --env-file .env portfolio-mcpКонтейнер устанавливает зависимости из package-lock.json, работает от непривилегированного пользователя node и предоставляет Docker health check /healthz.
Разверните этот сервис на платформе, поддерживающей долго работающий Node HTTP-процесс/контейнер, например Railway, Render, Fly.io, Kubernetes или VPS. Текущая реализация не является точкой входа для serverless-функций Vercel.
Для ChatGPT развёрнутая конечная точка MCP должна быть доступна по HTTPS, например:
https://portfolio-mcp.example.com/mcpHTTP-аутентификация
Клиенты, поддерживающие заголовки запросов, должны использовать:
Authorization: Bearer <PORTFOLIO_MCP_TOKEN>Для клиента, где настройка статического bearer-заголовка неудобна, конечная точка также принимает:
https://YOUR_MCP_HOST/mcp?token=YOUR_PORTFOLIO_MCP_URL_TOKENУчётные данные в строке запроса могут появляться в журналах инфраструктуры/доступа. Относитесь к PORTFOLIO_MCP_URL_TOKEN как к одноразовому и ротируйте его при раскрытии. Предпочитайте bearer-аутентификацию, когда MCP-клиент её поддерживает.
Подключение к ChatGPT
ChatGPT подключается к удалённым MCP-серверам, а не к серверу, работающему только на localhost.
На момент обновления этого репозитория (август 2026) OpenAI документирует полную поддержку пользовательских MCP, включая действия записи/изменения для рабочих пространств ChatGPT Business, Enterprise и Edu в вебе. Доступность может меняться, поэтому проверяйте текущую документацию OpenAI по пользовательским приложениям/MCP, если ваш интерфейс отличается.
Когда ваше рабочее пространство ChatGPT предоставляет пользовательские MCP-приложения/коннекторы:
Разверните этот репозиторий на HTTPS-конечной точке.
Настройте все переменные окружения сервера на платформе развёртывания.
В ChatGPT включите режим разработчика / пользовательские приложения в соответствии с правами вашего рабочего пространства.
Создайте пользовательское MCP-приложение.
Если форма ChatGPT не предоставляет статическое поле для пользовательского bearer-заголовка, используйте конечную точку с URL-токеном:
https://YOUR_MCP_HOST/mcp?token=YOUR_PORTFOLIO_MCP_URL_TOKENВыберите No Auth в ChatGPT для этого коннектора. Аутентификация по-прежнему обеспечивается этим сервером через URL-токен.
Выберите Scan Tools. Сервер должен предоставить перечисленные выше инструменты для статей и изображений.
Добавьте/включите приложение в новом чате и протестируйте действие чтения, например
list_blog_posts, перед тестированием действия записи.ChatGPT может запрашивать подтверждение для действий записи/уничтожения в зависимости от прав рабочего пространства/приложения и аннотаций инструментов.
Не вводите SUPABASE_SECRET_KEY в ChatGPT. ChatGPT нуждается только в удалённой конечной точке MCP (и, при такой настройке с URL-токеном, в одноразовом MCP URL-токене).
Рекомендуемая последовательность тестирования ChatGPT
После успешного сканирования коннектора:
List my portfolio blog posts.Затем:
Create a draft blog post titled "MCP Connection Test". Do not publish it.Потом проверьте это:
Get the MCP Connection Test draft and show me its metadata.Наконец, удалите тестовый черновик только тогда, когда вы явно намерены его удалить.
CORS / источники
MCP_ALLOWED_ORIGINS принимает список, разделённый запятыми:
MCP_ALLOWED_ORIGINS=https://example.com,https://another-client.exampleHTTP-сервер поддерживает современные заголовки MCP-запросов, включая Mcp-Protocol-Version, Mcp-Method, Mcp-Name и Mcp-Session-Id в CORS-предварительных запросах браузера.
Значение по умолчанию * максимизирует совместимость, при этом токен-аутентификация остаётся обязательной. Ужесточите список, когда вы знаете точные источники браузера, которые должны вызывать сервис.
Лимиты запросов и изображений
Максимальный размер HTTP MCP-запроса по умолчанию — 5 МиБ:
MCP_MAX_REQUEST_BYTES=5242880Это намеренно больше, чем лимит декодированного изображения в 3 МиБ, потому что base64 добавляет примерно одну треть накладных расходов плюс JSON-обрамление.
Принимаемые типы содержимого изображений:
PNG
JPEG
WebP
GIF
AVIF
Пути хранения нормализуются и отклоняют обход каталогов, например ../. Полезные нагрузки изображений должны содержать корректный base64.
Рекомендуемые пути объектов:
senior-software-engineer/cover.webp
production-rag-systems/architecture.webp
nextjs-at-scale/performance.webpУдаление статьи блога не удаляет автоматически её изображения. Это предотвращает случайное удаление медиафайлов, которые могут быть общими или повторно используемыми.
Рабочий процесс блога
Рекомендуемый поток публикации:
Создайте статью как черновик.
Загрузите обложку/диаграммы, если необходимо.
Обновите черновик, указав возвращённые публичные URL изображений.
Проверьте заголовок, выдержку, Markdown, категорию, теги и дату публикации.
Опубликуйте с помощью
publish_blog_post.Обновляйте или снимайте с публикации позже при необходимости.
Удаляйте статью или изображения только тогда, когда это явно задумано.
published_at принимает дату или дату-время в формате ISO 8601, например:
2026-08-25
2026-08-25T12:00:00+05:00Модель безопасности
Секретные учётные данные Supabase хранятся только на стороне сервера.
Современные ключи
sb_secret_*отправляются как ключи API Supabase, а не как JWT bearer-токены.Next.js-портфолио сохраняет свою публичную модель доступа к Supabase только для чтения.
HTTP MCP-запросы требуют bearer-токен или URL-токен.
MCP-токены должны быть надёжными и различаться.
Сравнение токенов использует устойчивое к времени равенство.
Не предоставляется общий исполнитель SQL/запросов.
Проверяются слаги, даты публикации, пути изображений, типы изображений, полезные нагрузки base64, размеры изображений и размеры HTTP-запросов.
Инструменты перезаписи, снятия с публикации, замены и удаления используют аннотации MCP, соответствующие уровню риска.
Завершение работы прекращает приём нового трафика и даёт активным запросам ограниченный период дренажа перед закрытием ресурсов MCP.
Секреты никогда не должны попадать в GitHub.
Протокол MCP
HTTP-сервер использует стабильный MCP TypeScript SDK v2 и предоставляет Streamable HTTP на /mcp. Включена точка входа stdio для локальных MCP-хостов.
Удалённая HTTP-обёртка поддерживает как современный MCP-трафик, так и устаревший без сохранения состояния fallback SDK для максимальной совместимости с клиентами.
Проверка
Запустите ту же проверку, что используется в CI:
npm run checkЭто выполняет:
строгую проверку типов TypeScript
регрессионные тесты времени выполнения
производственную сборку TypeScript
Тесты времени выполнения охватывают обработку секретных ключей Supabase, HTTP-аутентификацию, CORS, лимиты запросов, загрузку окружения, проверку токенов и реальный запрос tools/list MCP через удалённый HTTP-адаптер.
GitHub Actions устанавливает точный граф зависимостей с помощью npm ci из зафиксированного lockfile.
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