Skip to main content
Glama

pilates_mcp

pilates_mcp — это локальный MCP-сервер для рекламных постеров пилатес-центра. Он создаёт редактируемые HTML/CSS-исходники постеров, хранит их в локальном архиве, ищет и повторно использует прошлые постеры, записывает отзывы о дизайне и может рендерить PNG/PDF-артефакты с помощью headless Chromium.

На этапе 1 (Phase 1) сервер намеренно не хранит имена участников, номера телефонов, расписания, данные о здоровье, платёжные данные и прочую личную информацию участников.

Структура проекта

На момент реализации репозиторий был пуст, поэтому сервер реализован как TypeScript + Node.js MCP-сервер.

src/
  server.ts        MCP stdio JSON-RPC transport and tool dispatch
  service.ts       poster workflow orchestration
  repository.ts    local poster archive search/read/write
  renderer.ts      Playwright PNG/PDF renderer
  templates.ts     HTML/CSS template layer
  feedback.ts      design feedback storage
  profile.ts       center profile storage
  themes.ts        design token presets
  types.ts         domain types
data/
  posters/YYYY/<poster-id>/
    poster.html
    poster.css
    metadata.json
    content.json
    preview.png    optional
    poster.pdf     optional
    revisions/     update backups
  feedback/
    global.json
    table.json
    standard.json
    poster-<poster-id>.json
  config/
    center-profile.json
  schedules/
    settings.json
    center-closures.json
    group/
      template.json
      group_schedule.xlsx
      revisions/
    private/
      template.json
      private_schedule.xlsx
      revisions/

Related MCP server: Networking MCP

Установка

npm install
npx playwright install chromium

Разработка

npm run build
npm test
npm run dev

PILATES_MCP_DATA_DIR может указывать на другую локальную директорию для архива. Если переменная не задана, сервер использует ./data.

Деплой на Railway

Деплой на Railway настраивается с помощью railway.json и Dockerfile.

В production-контейнере используется официальный образ Playwright, поэтому зависимости Chromium доступны для рендеринга PNG/PDF. Railway запускает npm run start:railway, который предоставляет:

  • GET /health — проверка работоспособности деплоя

  • GET /tools — сводка MCP-инструментов для проверки деплоя

  • GET /schedule — лёгкое рабочее пространство в стиле Excel для расписания

MCP-сервер stdio остаётся доступным через npm run start для MCP-клиентов, подключающихся по команде. Процесс проверки работоспособности на Railway намеренно отдельный, потому что stdio MCP не предоставляет HTTP-порт.

Для постоянного локального хранения архива на Railway смонтируйте том Railway в /data или задайте PILATES_MCP_DATA_DIR как другой постоянный путь.

Подключение MCP-клиента

Используйте собранный сервер как stdio MCP-команду:

{
  "mcpServers": {
    "pilates_mcp": {
      "command": "node",
      "args": ["G:/pilates_mcp/dist/src/server.js"],
      "env": {
        "PILATES_MCP_DATA_DIR": "G:/pilates_mcp/data"
      }
    }
  }
}

Инструменты

Инструменты для постеров:

  • get_center_profile

  • update_center_profile

  • search_posters

  • get_poster

  • create_poster

  • update_poster

  • reuse_poster_template

  • import_poster

  • render_poster

  • add_design_feedback

  • get_design_feedback

  • recommend_poster_style

Инструменты для расписания:

  • get_schedule_settings

  • update_schedule_settings

  • inspect_schedule_file

  • import_schedule_file

  • create_schedule_template

  • get_schedule

  • generate_weekly_schedule

  • set_schedule_slot

  • clear_schedule_slot

  • find_available_slots

  • validate_schedule

  • add_center_closure

  • remove_center_closure

  • get_center_closures

  • save_schedule

  • export_schedule

  • create_schedule_poster

Процесс создания постера

create_poster читает профиль центра, применяет значения по умолчанию из профиля, проверяет PosterBrief, собирает релевантные отзывы, определяет макет и тему, рендерит статический HTML/CSS, записывает метаданные/контент/исходные файлы и при необходимости рендерит PNG/PDF.

Требуемый порядок:

user request
-> center profile defaults
-> PosterBrief
-> validation
-> ask only missing questions
-> past posters and feedback
-> HTML/CSS
-> optional render
-> archive save

Обязательные решения по брифу постера проверяются до генерации:

  • eventName

  • programSeparation

  • tablePreference

  • tableStyle, если таблица требуется или указана

  • vatPolicy, если в контенте есть цены

Сервер возвращает valid: false, missing и вопросы на корейском (questions) вместо того, чтобы угадывать отсутствующие название события, политику НДС или разделение программ.

programSeparation и tableStyle — это отдельные решения. Например, для групповых/индивидуальных продуктов можно использовать programSeparation: "table" с tableStyle: "split", чтобы отображать отдельные блоки таблиц GROUP/PRIVATE. tablePreference отражает намерение пользователя; layout — это итоговый выбор рендерера.

Значения по умолчанию из профиля центра позволяют сократить повторяющиеся вопросы:

{
  "posterDefaults": {
    "programSeparation": "table",
    "tablePreference": "required",
    "tableStyle": "split",
    "vatPolicy": "excluded"
  }
}

Приоритет такой: текущий запрос и PosterBrief, затем значения по умолчанию из профиля центра, затем проверочный ответ с запросом у пользователя только недостающих значений. НДС никогда не выводится автоматически.

Примеры

Создание постера с прайс-таблицей за август

{
  "title": "8월 회원권 이벤트",
  "purpose": "event",
  "brief": {
    "eventName": "8월 회원권 이벤트",
    "programCategories": ["private", "duet"],
    "programSeparation": "table",
    "tablePreference": "required",
    "tableStyle": "comparison",
    "vatPolicy": "excluded"
  },
  "content": {
    "subtitle": "이번 달 특별 혜택",
    "badge": "8월 EVENT",
    "table": {
      "columns": ["상품", "정상가", "이벤트가"],
      "rows": [
        ["1:1 개인레슨 10회", "800,000원", "650,000원"],
        ["듀엣레슨 10회", "500,000원", "390,000원"]
      ],
      "highlightColumn": 2
    },
    "footer": "선착순 마감"
  },
  "style": "premium",
  "render": { "png": true, "pdf": true, "size": "instagram-portrait" }
}

Повторное использование шаблона постера за сентябрь прошлого года

{
  "sourcePosterId": "poster_20250901_ab12cd34",
  "title": "2026년 9월 신규회원 이벤트",
  "brief": {
    "eventName": "9월 신규회원 이벤트",
    "vatPolicy": "excluded"
  },
  "content": {
    "subtitle": "올해 가격으로 업데이트",
    "table": {
      "columns": ["상품", "정상가", "이벤트가"],
      "rows": [["1:1 개인레슨 10회", "820,000원", "670,000원"]],
      "highlightColumn": 2
    }
  }
}

Рекомендация стиля на основе записей за последний год

{
  "purpose": "event",
  "month": 9,
  "recentMonths": 12
}

Отзывы

Отзывы хранятся в JSON-файлах, а не зашиты в код. create_poster получает активные отзывы глобального уровня и уровня макета и включает их в результат как appliedFeedback.

Пример:

{
  "scope": "table",
  "text": "이벤트가는 정상가보다 확실히 강조."
}

Рендеринг

render_poster использует Playwright Chromium с отключённым JavaScript. Поддерживаемые размеры:

  • instagram-portrait: 1080 x 1350

  • instagram-square: 1080 x 1080

  • story: 1080 x 1920

  • a4-portrait: A4, книжная ориентация

HTML/CSS — это источник истины. PNG/PDF — опциональные артефакты.

Рабочее пространство расписания

На этапе 2 (Phase 2) добавляется локальное рабочее пространство расписания для групповых/индивидуальных занятий пилатесом. Это не CRM. В частных расписаниях может содержаться только displayName — для отображения в сетке и оперативного размещения.

Основная модель:

  • ScheduleSettings: неделя отображения, время открытия/закрытия, длительность слота по умолчанию, опция выходных, локаль, код страны

  • ScheduleTemplate: явное сохранение еженедельного шаблона для групповых/индивидуальных занятий

  • ScheduleSlot: нейтральный доменный слот, отдельный от ячеек Excel

  • ScheduleTemplateMapping: сопоставление XLSX-листа/заголовков/времени/дней/колонок

  • CenterClosure: даты закрытия конкретного центра, отдельные от государственных праздников

set_schedule_slot изменяет слот в памяти (dirty-состояние). Изменения не сохраняются, пока не вызван save_schedule. export_schedule записывает XLSX и перед заменой делает резервную копию существующего файла.

Существующие XLSX-файлы обрабатываются через inspect_schedule_file и import_schedule_file. Импортёр захватывает имя листа, используемый диапазон, колонки дней, колонку времени, ширины колонок, высоты строк и объединённые ячейки там, где они есть. Формулы не выполняются.

Обработка праздников основана на провайдере. На этапе 2 (Phase 2) встроен локальный провайдер с базовыми праздниками Южной Кореи; позже его можно заменить внешним провайдером без изменения доменной модели. Закрытия центров имеют приоритет над государственными праздниками, но занятые слоты не удаляются молча — возвращаются предупреждения.

Railway предоставляет лёгкое рабочее пространство в стиле Excel по адресу /schedule с закреплёнными шапками, прямым редактированием ячеек, удалением клавишами Delete/Backspace и видимым состоянием сохранения. MCP остаётся источником реальных операций с расписанием.

Примеры работы с расписанием

Сценарий A: создание нового группового расписания, когда файла ещё нет:

{
  "scheduleType": "group",
  "settings": {
    "weekDisplay": "mon-sat",
    "openingTime": "09:00",
    "closingTime": "21:00",
    "defaultSlotMinutes": 60,
    "autoHolidayMarking": true,
    "locale": "ko-KR",
    "countryCode": "KR"
  }
}

Сценарий B: импорт существующего Excel-файла и генерация расписания на следующую неделю:

{ "filePath": "fixtures/group_schedule.xlsx", "scheduleType": "group" }
{
  "scheduleType": "group",
  "weekStart": "2026-10-05",
  "applyHolidays": true,
  "applyCenterClosures": true
}

Сценарий C: операция с индивидуальным расписанием:

{
  "scheduleType": "private",
  "dayOfWeek": "monday",
  "startTime": "19:00",
  "displayName": "김OO"
}

Сценарий D: постер группового расписания:

{
  "scheduleType": "group",
  "weekStart": "2026-10-05",
  "title": "9월 그룹레슨 시간표",
  "render": { "png": true, "pdf": true, "size": "instagram-portrait" }
}

Безопасность и конфиденциальность

В архиве используются сгенерированные ID постеров, и ID проверяются перед доступом к файлу. Импорт проверяется на относительные пути, чтобы заблокировать обход через ../ и выход за пределы корня. Сгенерированный HTML постеров статичен, пользовательский текст экранируется для HTML, а удалённые скрипты не являются частью шаблона. При рендеринге JavaScript отключён.

На этапе 1 (Phase 1) исключены: управление участниками, бронирование, платежи, SMS, публикация в Instagram, интеграция со StudioMate, внешний скрейпинг дизайнов, генерация изображений через ИИ, облачные базы данных и SaaS-аутентификация.

На этапе 2 (Phase 2) в данных расписания, связанных с людьми, допускается только displayName. Не создаются поля для телефона, email, даты рождения, пола, состояния здоровья, истории болезней, платежей, членства, консультаций, посещаемости, маркетинговых предпочтений и согласий. Имена не используются для профилирования, аналитики, отзывов о постерах, маркетинга или рекомендаций.

На этапе 2 (Phase 2) по-прежнему исключены: интеграция со StudioMate, скрейпинг StudioMate, автоматизация через расширения Chrome, CRM участников, управление контактами, управление платежами, анализ посещаемости, профилирование предпочтений участников, автоматическое подтверждение бронирований, SMS, KakaoTalk, публикация в Instagram, расчёт зарплат, расчёты и сложные ERP-функции.

Точки расширения

Разделение на сервис и репозиторий оставляет место для будущего семантического поиска или другого индекса. Внешние источники дизайнов можно добавить позже за интерфейсом провайдера, например:

interface DesignReferenceProvider {
  search(query: string): Promise<DesignReference[]>;
}

На этапе 1 (Phase 1) не реализованы скрейпинг и копирование внешних шаблонов.

Install Server
F
license - not found
B
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

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/sebit-provider/pilates_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server