yoru-studio-mcp
Yoru Studio
一个为单一创作者提供的自托管执行工作室。
阅读此文档的简体中文版本。
Yoru Studio 是一个人的工作空间,用于将想法转化为完成的创意作品:在收件箱中捕捉灵感,将其拉入母项目,拆分为子项目(视频 / 图片散文 / 长文 / 资产交付),规划故事板,使用离线安全队列进行外景拍摄,记录实际发生的情况,然后通过回顾来闭环。交付物位于平台版本之下,因此同一剪辑可以作为抖音 / 哔哩哔哩 / 小红书图片集发布,而无需复制项目本身。
它是为一个人——创作者——在自己的机器上运行而编写的。没有多租户的故事,没有团队席位,没有 SaaS 后端。当你安装它时,整个系统都位于你控制的一台机器上。
这里有什么
阅读源代码是回答“它实际上做什么?”的权威方式——下面的摘要是一张地图,而不是领土本身。
收件箱 → 母项目 → 子项目 → 平台版本:创意工作流的完整主干,并带有快速通道,当你知道一个好想法属于哪里时,可以直接跳入活跃的子项目。
故事板:支持列表视图和看板视图,拖拽排序,每个镜头的参考图片,XLSX 导出,以及用于现场的可打印版本。
日程与日历:精确时间、全天日期和模糊时间窗口(“本周”、“周末”)共存于一个日历中;逾期是计算出来的,而不是记住的,所以不会悄悄腐烂。
提醒和站内通知,在数据库层去重,因此重启永远不会重复触发同一条提醒。
执行记录:用于拍摄 / 重拍 / 屏幕录制 / 写作会话——将记录附加到与你实际所做匹配的任何项目层。
回顾,轻量或完整;每个字段都是可选的。结构的存在是为了提醒你,而不是要求你。
附件有四种形式:上传的图片(带缩略图)、路径指针(例如
NAS/2026/Aug shoots/)、外部链接和文本片段。软删除的文件在回收站中保留 30 天。现场模式:为现场使用而设计的移动优先页面。如果网络断开,编辑内容会在 IndexedDB 中排队,并在连接恢复时同步。
完整导出:JSON + 上传文件捆绑包,用于数据迁移,可从 CLI 或设置页面进行。
备份:按计划进行在线 SQLite 备份,以及可选的 restic 脚本,用于加密的异地副本,并带有真正的恢复演练运行器。
MCP 通道,用于 AI 代理(Claude、ChatGPT、Codex 等)——请参阅下面的章节。
Related MCP server: todos
设计立场
单用户,单账户。 数据模型带有一个工作区列,因此未来的多用户版本不必重建模式,但已发布代码中的所有内容都假设只有一个用户。
不需要外部服务。 磁盘上的 SQLite,磁盘上的文件。没有 Redis,没有消息队列,没有第三方认证。你可以在每月 5 美元的 VPS 上运行它。
占用空间小。 目标是应用 512 MiB / 调度器 256 MiB /(可选)反向代理边车 128 MiB。2 GiB 的虚拟机就足够了。
服务器不构建前端。 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 通道:连接 AI 代理
Yoru Studio 暴露了一个模型上下文协议(MCP)服务器,因此支持 MCP 的代理——Claude Desktop、ChatGPT 桌面版、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 端点后面有两条认证路径(源代码中 docs/spec/ 的规范 §5.1):
静态 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本地模式绑定到回环地址并跳过认证,以方便开发。要在本地尝试认证流程,请按照下面的“启用远程模式”部分操作。
其他 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 # frontendDocker Compose
此仓库中的 docker-compose.yml 定义了三个服务:app(FastAPI + 构建好的 SPA)、scheduler(一个 60 秒滴答循环,运行备份、提醒、保留)和 cloudflared(一个参考反向代理边车——可以替换为适合你基础设施的任何东西)。
反向代理 / TLS 故意不在应用范围内:由你自行选择。合理的选择包括:
Cloudflare Tunnel(
docker-compose.yml中的参考cloudflared服务,以及scripts/provision-cloudflare-tunnel.py中的配置脚本)。Caddy 或 Nginx 作为主机级反向代理,使用你自己的证书终止 TLS。
Tailscale Funnel 用于私有优先托管。
仅使用 SSH 转发
-L 8000,如果你只想在自己的机器上使用。
如果你使用 Cloudflare Tunnel,请编辑或删除 cloudflared 服务,并在 .env.production 中取消设置 STUDIO_TRUSTED_PROXY_IPS。如果你使用其他代理,请将 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 -ddocs/deploy.md 有更长的演练,涵盖参考布局、scripts/ 下的备份自动化脚本,以及部署和备份作业共享的操作锁。
启用远程模式
远程模式将应用从“无认证的本地开发”转变为“代理后面的公共 URL,带有会话 cookie”。至少设置以下内容:
STUDIO_MODE=remoteSTUDIO_SESSION_SECRET— 一个随机字符串,至少 32 个字符。STUDIO_AUTH_PASSWORD_HASH—uv run studio hash-password的输出。STUDIO_ALLOWED_HOSTS— 应用将响应的确切主机名(不允许通配符;应用会拒绝使用*启动)。STUDIO_TRUSTED_PROXY_IPS— 如果前面有反向代理,则为其用于与应用通信的 IP。
如果任何必需的密钥缺失或 allowed_hosts 为空,应用会拒绝在远程模式下启动——这是故意的。没有“静默开放”的配置。
配置
大多数值位于环境变量中(生产环境这样对 Docker 友好)。一部分也可以位于由 --config 或 STUDIO_CONFIG 加载的 TOML 文件中——有关格式,请参阅 config/config.example.toml。
密钥在设计上仅限环境变量:它们永远不会从 TOML 配置中读取,因此将配置文件与部署捆绑在一起永远不会泄露它们。
变量 | 用途 | 默认值 |
|
|
|
| 服务器绑定的地址 |
|
| 服务器绑定的端口 |
|
| 在 | (空) |
| 逗号分隔的代理 IP 列表,这些代理的 | (空) |
| 用于签名会话 Cookie 的随机字符串,长度 ≥32 字符(远程模式必需) | (空) |
| 来自 | (空) |
| SQLite 数据库所在位置 |
|
| 上传附件所在位置 |
|
| SQLite 在线备份写入位置 |
|
| 应用日志存放位置 |
|
| 可选的只读路径,主机的备份任务会在其中放置 | (未设置——状态显示 |
| 单文件上传上限 |
|
| 每个母项目子树的上传总配额 |
|
| 解压炸弹防护 |
|
| 摄取通道 bearer 令牌的 | (未设置) |
| MCP 静态 Bearer 令牌的 | (未设置) |
| 托管 OAuth AS 元数据的公共 URL;设置后会启用 OAuth 路径 | (未设置) |
| DCR 重定向 URI 中允许的主机名逗号分隔列表(始终允许回环地址) |
|
| OAuth 访问令牌有效期 |
|
| OAuth 刷新令牌有效期 |
|
| OAuth 授权码有效期 |
|
生成哈希令牌
摄取端点和 MCP 静态 Bearer 路径都存储 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 进行比较。如果该环境变量未设置,端点会对每次 Bearer 调用返回 401——摄取通道始终保持完全关闭。
此路径不需要 CSRF:CSRF cookie 用于防御浏览器会话重放,而当调用方自带 bearer 头时,这并不构成威胁。
请求体(JSON):
字段 | 类型 | 说明 |
| string,必填,≤500 字符 | 收件箱条目标题。空白 / 缺失 → |
| string,可选 | 你的一句话热评。 |
| string,可选 | 自由文本——粘贴 URL 即可。 |
| string,可选,≤500 字符 | 你的供给器对该主题的标识符。第二强的去重键。 |
| string,可选,≤2000 字符 | 条目的规范 URL。第三强的去重键。 |
| string,可选,≤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 通用公共许可证,仅第 3 版(AGPL-3.0-only)授权。LICENSE 包含逐字许可证文本。
一句话概括:你可以自由地自行托管、使用和修改代码,用于你自己的创作;如果你将修改后的版本作为网络服务运行供他人交互,你必须向他们提供该修改版本的源代码。这正是 AGPL 的设计目标——“网络使用”条款(§13)使互惠义务在运行该服务时即触发,而不仅仅是在分发时触发。
期望
这是一个个人项目。它之所以存在,是因为一位创作者需要它,并决定将其分享出来。
不是产品。 没有哪条路线图是别人有权要求的,没有支持 SLA,也不保证下一个版本不会破坏你的现有环境。
按作者自己的节奏维护。 欢迎提交 issue 和 pull request,但回复时间不定。
由你自己托管。 不存在托管版本,也没有相关计划。
数据保存在你的机器上。 没有任何东西会回传,也不会向第三方发送任何内容。这正是自我托管的意义所在;也是如果你丢失数据,没有人会来救你的原因。请做好备份。
如果其中任何一条让你觉得“不适合我”,那这就是真实的信号——请选择其他方案,彼此无需介怀。
贡献
欢迎提交错误报告。请提供足够的细节,使错误能够在干净检出(clean checkout)上重现。
功能请求:这个项目刻意保持小范围,只有在实际使用暴露出需求后才会添加功能。一个读起来像“这是我在使用应用时实际遇到的问题”的功能请求,远比读起来像“这是一个锦上添花的功能”的请求更有可能被采纳。
Pull request:对于任何超过单文件错误修复规模的改动,请先开一个 issue,确认方向是否合适。AGPL-3.0-only 意味着贡献必须与该许可证兼容——通过提交 pull request,你即同意你的贡献与项目其余部分遵循相同的条款。
致谢
由 Yoru、Claude Fable 5 和 GPT 5.6 Sol 共同构建——我们三人。
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Remote MCP server for AI.TV creators — delegate account operations to your AI agent over MCP.
Hosted MCP server for AI agents to post to LinkedIn profiles and X and upload to YouTube.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Related MCP Servers
- AlicenseBqualityDmaintenanceProduction-grade MCP server that gives AI agents safe access to your local dev environment: filesystem, databases, processes, and OpenAPI specs.1565 npm4MIT
- AlicenseNot gradedqualityBmaintenanceMCP 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 npmApache 2.0
- AlicenseNot gradedqualityCmaintenanceA 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
- FlicenseAqualityCmaintenanceA local-first MCP server that handles daily work tasks through your AI assistant: converts meeting notes into todos, manages todo lifecycle, tracks work hours, generates daily/weekly reports, organizes files via move-only operations, and diagnoses dev environments, all guarded by a human-maintained preview/apply safety model.25-