Skip to main content
Glama
yoruuuchan

yoru-studio-mcp

by yoruuuchan

Yoru Studio

Самостоятельно размещаемая студия для работы одного творца.

Читать на упрощённом китайском.

Yoru Studio — это рабочее пространство одного человека для превращения идей в готовые творческие работы: поймать искру во входящих, перенести её в материнский проект, разбить на подпроекты (видео / фотоочерк / длинная статья / поставка материалов), спланировать раскадровки, провести полевые съёмки с офлайн-очередью, зафиксировать, что произошло на самом деле, и замкнуть цикл ретроспективой. Результаты живут в версиях под платформы, так что один и тот же монтаж можно выпустить как Douyin / Bilibili / набор изображений для Xiaohongshu без дублирования самого проекта.

Он написан для одного человека — творца — и работает на его собственном компьютере. Никакой мультитенантности, никаких командных мест, никакого SaaS-бэкенда. После установки вся система живёт на одной машине, которой вы управляете.

Что здесь есть

Чтение исходного кода — авторитетный ответ на вопрос «что это на самом деле делает?» — приведённое ниже резюме — это карта, а не территория.

  • Входящие → Материнский проект → Подпроект → Версия платформы: полный хребет творческого рабочего процесса, с быстрым путём, позволяющим хорошей идее сразу перейти в активный подпроект, когда вы знаете, куда она относится.

  • Раскадровки с представлением списком и представлением доски, перетаскиванием для изменения порядка, эталонными изображениями для каждого кадра, экспортом в XLSX и печатной версией для использования на площадке.

  • Расписание и календарь: точное время, события на весь день и размытые окна («на этой неделе», «на выходных») сосуществуют в одном календаре; просроченное вычисляется, а не запоминается, так что ничто тихо не гниёт.

  • Напоминания и внутрисайтовые уведомления, дедуплицированные на уровне базы данных, чтобы перезапуск никогда не срабатывал дважды на одно и то же предупреждение.

  • Записи о выполнении для съёмок / пересъёмок / записи экрана / писательских сессий — прикрепите запись к тому слою проекта, который действительно соответствует тому, что вы сделали.

  • Ретроспективы, лёгкие или полные; каждое поле необязательно. Структура существует, чтобы напомнить вам, а не требовать.

  • Вложения четырёх видов: загруженные изображения (с миниатюрами), указатели путей (например, NAS/2026/Aug shoots/), внешние ссылки и текстовые фрагменты. Мягко удалённые файлы лежат в корзине 30 дней.

  • Полевой режим: мобильная страница для использования на площадке. Если сеть пропадает, правки ставятся в очередь в IndexedDB и синхронизируются при восстановлении соединения.

  • Полный экспорт: JSON + пакет загрузок для выноса данных, либо из CLI, либо со страницы настроек.

  • Резервные копии: онлайн-резервное копирование SQLite по расписанию и опциональные скрипты restic для зашифрованных внешних копий с настоящим средством прогона восстановления.

  • Канал MCP для ИИ-агентов (Claude, ChatGPT, Codex, …) — см. раздел ниже.

Related MCP server: todos

Принципы дизайна

  • Один пользователь, одна учётная запись. Модель данных несёт колонку рабочего пространства, чтобы будущая многопользовательская версия не перестраивала схему, но всё в поставляемом коде предполагает ровно одного пользователя.

  • Никаких внешних сервисов. SQLite на диске, файлы на диске. Никакого Redis, никакой очереди сообщений, никакой сторонней аутентификации. Можно запустить на VPS за $5/месяц.

  • Малый след. Цель — приложение 512 МиБ / планировщик 256 МиБ / (опционально) боковой контейнер обратного прокси 128 МиБ. Виртуальной машины на 2 ГиБ достаточно.

  • Сервер не собирает фронтенд. Vite-сборка выполняется локально (или в CI) и поставляется как предварительно собранные файлы. На машинах развёртывания Node не нужен.

  • Содержание важнее церемоний. В форме ретроспективы нет обязательных полей — схема существует, чтобы напомнить вам, о чём подумать, а не чтобы блокировать сохранение.

Технологический стек

  • Бэкенд: Python 3.12, FastAPI, SQLite (с uv для управления зависимостями).

  • Фронтенд: React 19 + TypeScript, собирается с помощью Vite.

  • Развёртывание: Docker Compose (один хост). Обратное проксирование и TLS — на ваше усмотрение — подойдут Cloudflare Tunnel, Caddy, Nginx, Tailscale Funnel или просто SSH-туннели для локального использования.

  • Тестирование: pytest для бэкенда, vitest для фронтенда.

Канал MCP: подключение ИИ-агентов

Yoru Studio предоставляет сервер Model Context Protocol (MCP), чтобы агенты, говорящие на MCP — Claude Desktop, ChatGPT desktop, Codex CLI, Claude Code и другие — могли читать из вашей студии и (дополнять её) без копипасты.

Всего восемь инструментов, все ограничены записью-добавлением с идемпотентностью:

Чтение (5):

  • list_projects — список материнских проектов со счётчиками.

  • get_project — полные детали одного материнского проекта, включая его подпроекты.

  • get_sub_project — один подпроект со встроенными раскадровкой / записями о выполнении / ретроспективой.

  • get_schedule — предстоящие (14 или 30 дней), все просроченные, ближайшие размытые события.

  • get_inbox — ожидающие или отклонённые элементы входящих.

Запись (3, все только-добавление, все идемпотентные):

  • capture_inspiration — бросить искру во входящие.

  • append_storyboard_shots — атомарно добавить N кадров в раскадровку видеоподпроекта.

  • append_execution_record — зафиксировать съёмку / писательскую сессию / тест.

Каждый инструмент записи принимает idempotency_key. Повтор с тем же ключом возвращает первый результат; другая полезная нагрузка с тем же ключом — жёсткий конфликт. Ничто из того, что делает агент, не может молча перезаписать уже имеющуюся у вас работу.

Два пути аутентификации за одной конечной точкой /mcp (спецификация §5.1 в docs/spec/ в исходниках):

  • Статический Bearer-токен для личного / одноагентного использования. Вы создаёте одну длинную случайную строку, сохраняете её sha256 в окружении и передаёте токен агенту.

  • OAuth 2.0 с PKCE + динамическая регистрация клиентов для коннекторов, которые этого ожидают (коннектор ChatGPT — текущий случай, который этого требует).

Оба пути могут сосуществовать. Оба необязательны — оставьте оба не заданными, и маршрут /mcp никогда не смонтируется.

Быстрый старт

Два пути в зависимости от того, как вы хотите запускать: из исходников (для разработки или если предпочитаете управлять Python самостоятельно) или через Docker Compose (для стабильной установки на одном хосте).

Из исходников

Требуется Python 3.12 и uv, плюс Node 20+ для фронтенда.

# 1. Install Python deps and set up the venv
uv sync

# 2. Initialize / migrate the database (creates ./data/studio.sqlite3)
uv run studio init-db

# 3. Start the API server on http://127.0.0.1:8000 (local mode — no auth)
uv run studio serve

# 4. In another terminal, run the frontend dev server
cd frontend
npm install
npm run dev        # http://localhost:5173, proxies to the API

Локальный режим привязывается к loopback и пропускает аутентификацию для удобства разработчика. Чтобы попробовать поток аутентификации локально, следуйте разделу «Включение удалённого режима» ниже.

Другие команды CLI:

uv run studio db-backup            # verified online SQLite backup
uv run studio db-restore <path> --confirm-database ./data/studio.sqlite3
uv run studio export               # full JSON + uploads takeout
uv run studio schedule-tick        # run the periodic maintenance jobs once
uv run studio hash-password        # interactively hash a password for STUDIO_AUTH_PASSWORD_HASH

Запустите тесты:

uv run pytest                      # backend
cd frontend && npm test            # frontend

Docker Compose

Файл docker-compose.yml в этом репозитории определяет три сервиса: app (FastAPI + собранный SPA), scheduler (цикл с тиком в 60 секунд, выполняющий резервное копирование, напоминания, хранение) и cloudflared (эталонный боковой контейнер обратного прокси — замените его на то, что подходит вашей инфраструктуре).

Обратное проксирование / TLS намеренно вне рамок приложения: выбирайте своё. Разумные варианты включают:

  • Cloudflare Tunnel (эталонный сервис cloudflared в docker-compose.yml со скриптом подготовки в scripts/provision-cloudflare-tunnel.py).

  • Caddy или Nginx как обратный прокси на уровне хоста с завершением TLS на ваших собственных сертификатах.

  • Tailscale Funnel для приватного размещения.

  • Просто SSH-форвард -L 8000, если вам нужно только на своей машине.

Если вы используете Cloudflare Tunnel, либо отредактируйте, либо удалите сервис cloudflared и снимите STUDIO_TRUSTED_PROXY_IPS в .env.production. Если вы используете другой прокси, задайте STUDIO_TRUSTED_PROXY_IPS как IP вашего прокси, чтобы реальные IP клиентов попадали в журнал аудита.

Шаги развёртывания (когда ваш Docker-хост готов):

# 1. Build the frontend locally — the server never builds it.
cd frontend && npm ci && npm run build && cd ..

# 2. Copy the env template and fill in the required secrets.
cp deploy/env.production.example .env.production
chmod 600 .env.production
$EDITOR .env.production

# 3. Generate a scrypt-hashed password for STUDIO_AUTH_PASSWORD_HASH.
uv run studio hash-password
# Paste the "password_hash" value into .env.production, single-quoted.

# 4. Build and start.
docker compose --env-file .env.production build
docker compose --env-file .env.production up -d

В docs/deploy.md есть более подробное руководство, охватывающее эталонную компоновку, скрипты автоматизации резервного копирования в scripts/ и операционную блокировку, которую разделяют задания развёртывания и резервного копирования.

Включение удалённого режима

Удалённый режим превращает приложение из «локальной разработки без аутентификации» в «публичный URL за прокси с сессионными cookie». Задайте как минимум:

  • STUDIO_MODE=remote

  • STUDIO_SESSION_SECRET — случайная строка не короче 32 символов.

  • STUDIO_AUTH_PASSWORD_HASH — вывод uv run studio hash-password.

  • STUDIO_ALLOWED_HOSTS — точное имя (имена) хоста, на которые приложение будет отвечать (без подстановочных знаков; приложение откажется запускаться с *).

  • STUDIO_TRUSTED_PROXY_IPS — если перед приложением стоит обратный прокси, IP-адрес(а), с которых он обращается к приложению.

Приложение отказывается запускаться в удалённом режиме, если отсутствует любой из обязательных секретов или allowed_hosts пуст — это намеренно. Не существует конфигурации «тихо открытой».

Конфигурация

Большинство значений живут в переменных окружения (так производство дружелюбно к Docker). Подмножество также может жить в TOML-файле, загружаемом через --config или STUDIO_CONFIG — см. config/config.example.toml для формы.

Секреты только в окружении по дизайну: они никогда не читаются из TOML-конфига, так что включение конфиг-файла в развёртывание никогда не может их утечь.

Переменная

Назначение

По умолчанию

STUDIO_MODE

local (только loopback, без аутентификации) или remote (сессионные cookie + пароль)

local

STUDIO_BIND_HOST

Адрес, к которому привязывается сервер

127.0.0.1

STUDIO_BIND_PORT

Порт, к которому привязывается сервер

8000

STUDIO_ALLOWED_HOSTS

Список имён хостов через запятую, принимаемых в заголовке Host: (обязательно в remote-режиме)

(пусто)

STUDIO_TRUSTED_PROXY_IPS

Список IP прокси через запятую, чьим CF-Connecting-IP / X-Forwarded-For доверять

(пусто)

STUDIO_SESSION_SECRET

Случайная строка ≥32 символов для подписи сессионных cookie (обязательно в remote-режиме)

(пусто)

STUDIO_AUTH_PASSWORD_HASH

scrypt-хеш пароля для входа из studio hash-password (обязательно в remote-режиме)

(пусто)

STUDIO_DATA_DIR

Где хранится база данных SQLite

./data

STUDIO_UPLOADS_DIR

Где хранятся загруженные вложения

<data-dir>/uploads

STUDIO_BACKUPS_DIR

Куда записываются онлайн-резервные копии SQLite

./backups

STUDIO_LOGS_DIR

Куда идут журналы приложения

./logs

STUDIO_BACKUP_STATE_DIR

Необязательный путь только для чтения, куда задания резервного копирования хоста кладут capacity.json для виджета статуса в приложении

(не задан — статус показывает unknown)

STUDIO_UPLOAD_MAX_FILE_BYTES

Лимит загрузки на один файл

26214400 (25 МиБ)

STUDIO_UPLOAD_QUOTA_BYTES

Общая квота загрузки на поддерево каждого материнского проекта

2147483648 (2 ГиБ)

STUDIO_UPLOAD_MAX_IMAGE_PIXELS

Защита от бомбы декомпрессии

40000000 (40 млн пикс.)

STUDIO_RADAR_TOKEN_HASH

sha256-hex bearer-токена канала приёма; если не задан, конечная точка приёма отключена

(не задан)

STUDIO_MCP_TOKEN_HASH

sha256-hex статического bearer-токена MCP; если не задан, путь статического Bearer отключён

(не задан)

STUDIO_MCP_OAUTH_ISSUER_URL

Публичный URL, на котором размещены метаданные OAuth AS; его установка активирует путь OAuth

(не задан)

STUDIO_MCP_OAUTH_ALLOWED_REDIRECT_HOSTS

Список имён хостов через запятую, разрешённых в redirect URI DCR (loopback разрешён всегда)

chatgpt.com

STUDIO_MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS

Время жизни OAuth access-токена

3600

STUDIO_MCP_OAUTH_REFRESH_TOKEN_TTL_SECONDS

Время жизни OAuth refresh-токена

2592000 (30 дней)

STUDIO_MCP_OAUTH_CODE_TTL_SECONDS

Время жизни OAuth кода авторизации

300

Генерация хешированных токенов

Конечная точка приёма и путь статического Bearer MCP хранят sha256(token) — никогда не сам токен — поэтому утёкший .env.production не даёт ничего, что можно было бы воспроизвести.

# Generate a token and its hash. The token goes to whichever caller needs it
# (your external intake, your MCP client). The hash goes into .env.production.
TOKEN=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
printf %s "$TOKEN" | sha256sum | cut -d' ' -f1   # → STUDIO_RADAR_TOKEN_HASH / STUDIO_MCP_TOKEN_HASH
echo "$TOKEN"                                     # → give to the caller, nowhere else

Внешний приём: передайте свой собственный поток входящих во входящие

Существует HTTP-конечная точка, предназначенная для приёма элементов от внешнего источника — скрапера RSS, инструмента радара тем, запланированного задания по сбору данных, любого инструмента, который загружает контент от вашего имени. Конечная точка универсальна: принесите свой собственный апстрим, подключите его сюда, и элементы попадут во входящие, где вы их разберёте.

Конечная точка: POST /api/inbox

Аутентификация: Authorization: Bearer <token>. Сервер сравнивает sha256(token) с STUDIO_RADAR_TOKEN_HASH за постоянное время. Если эта переменная окружения не задана, конечная точка возвращает 401 на каждый вызов Bearer — приём остаётся полностью закрытым.

CSRF не требуется на этом пути: CSRF-cookie защищает от воспроизведения браузерной сессии, что не является угрозой, когда вызывающая сторона предоставляет свой собственный bearer-заголовок.

Тело запроса (JSON):

Поле

Тип

Примечания

title

строка, обязательно, ≤500 символов

Заголовок элемента входящих. Пусто / отсутствует → 400.

first_reaction

строка, необязательно

Ваш однострочный комментарий.

links

строка, необязательно

Произвольный текст — вставленные URL подойдут.

radar_topic_id

строка, необязательно, ≤500 символов

Идентификатор этой темы от вашего источника. Второй по силе ключ дедупликации.

canonical_url

строка, необязательно, ≤2000 символов

Канонический URL элемента. Третий по силе ключ дедупликации.

idempotency_key

строка, необязательно, ≤500 символов

Уникальный ключ на каждую доставку. Самый сильный ключ дедупликации.

Приоритет дедупликации: idempotency_key > radar_topic_id > canonical_url. При повторной доставке сервер возвращает уже существующую строку, а не создаёт вторую — даже если вы уже отклонили или преобразовали эту строку. Повторная доставка не должна отменять ваше решение по разбору.

Ответ:

  • 201 Created — была вставлена новая строка.

  • 200 OK — повторная доставка была сопоставлена с существующей строкой (любой статус, включая отклонённый / преобразованный). Та же форма тела.

  • 400 Bad Request — отсутствует / недействителен title.

  • 401 Unauthorized — неверный или отсутствующий bearer-токен, или приём не настроен.

Тело ответа:

{
  "item": {
    "id": 42,
    "title": "…",
    "source": "radar",
    "status": "pending",
    "created_at": "2026-08-12T12:34:56Z",
    "…": "…"
  },
  "deduplicated": false
}

Пример curl:

curl -X POST https://studio.example.com/api/inbox \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Interesting minisite on typography systems",
    "first_reaction": "worth a look for the next essay",
    "links": "https://example.com/article",
    "canonical_url": "https://example.com/article",
    "idempotency_key": "myfeed-2026-08-12-a3f9"
  }'

Поле называется «radar» во всей кодовой базе, потому что изначально оно было подключено к внешнему инструменту радара контента; сама конечная точка универсальна и работает с любым источником, умеющим говорить по HTTP.

Лицензия

Copyright (C) 2026 yoruuuchan.

Yoru Studio лицензируется по GNU Affero General Public License, версия 3, только (AGPL-3.0-only). LICENSE содержит точный текст лицензии.

Одним предложением: вы можете свободно размещать у себя, использовать и изменять код для своей собственной творческой работы; если вы запускаете модифицированную версию как сетевой сервис, с которым взаимодействуют другие люди, вы должны предложить им исходный код этой модифицированной версии. Именно это AGPL и призвана обеспечивать — пункт о «сетевом использовании» (§13) делает взаимное обязательство срабатывающим при запуске, а не только при распространении.

Ожидания

Это личный проект. Он существует, потому что одному создателю он был нужен, и он решил им поделиться.

  • Не продукт. Нет дорожной карты, на которую кто-то другой имеет право, нет SLA поддержки и нет обещания, что следующий релиз не сломает вашу настройку.

  • Поддерживается в собственном ритме автора. Проблемы и pull request'ы приветствуются, но ответы приходят, когда приходят.

  • Вы размещаете его у себя. Хостинговая версия не существует. И планов на неё нет.

  • Данные живут на вашей машине. Ничего не обращается домой. Ничего не отправляется третьим лицам. В этом и смысл самостоятельного размещения; это также причина, по которой никто не спасёт ваши данные, если вы их потеряете. Делайте резервные копии.

Если что-то из этого читается как «не для меня» — это честный сигнал: пожалуйста, выберите что-то другое, и никаких обид.

Вклад в проект

Отчёты об ошибках приветствуются. Пожалуйста, включайте достаточно деталей, чтобы ошибку можно было воспроизвести на чистой копии репозитория.

Запросы функций: этот проект намеренно ограничивает свой масштаб и добавляет функции только после того, как реальное использование выявит потребность. Запрос функции, который звучит как «вот с чем я реально столкнулся, пытаясь использовать приложение», с гораздо большей вероятностью будет принят, чем тот, который звучит как «вот что было бы неплохо иметь».

Pull request'ы: для чего-то большего, чем исправление ошибки в одном файле, пожалуйста, сначала откройте issue, чтобы проверить, что направление подходит. AGPL-3.0-only означает, что вклад должен быть совместим с этой лицензией — открывая pull request, вы соглашаетесь, что ваш вклад распространяется на тех же условиях, что и остальная часть проекта.

Атрибуция

Создано Yoru, Claude Fable 5 и GPT 5.6 Sol — нами троими.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server for task management, project knowledge, workspace trust, runner sandboxes, extension registry, and workflow prompts, enabling AI agents to manage tasks and collaborate locally.
    5,117
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    A self-hosted MCP server that gives AI agents controlled access to a machine: filesystem, shell, background processes, git, web fetching and persistent key-value memory.
    GPL 3.0

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/yoruuuchan/yoru-studio-oss'

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