yoru-studio-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@yoru-studio-mcpWhat's on my schedule this week?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Yoru Studio
A self-hosted execution studio for a single creator.
Read this in Simplified Chinese.
Yoru Studio is one person's workspace for turning ideas into finished creative work: catch a spark in the inbox, pull it into a mother project, break it into sub-projects (video / photo essay / long-form article / asset delivery), plan storyboards, run field shoots with an offline-safe queue, log what actually happened, then close the loop with a retrospective. Deliverables live under platform versions so the same cut can ship as Douyin / Bilibili / a Xiaohongshu image set without duplicating the project itself.
It is written for one person — the creator — running it on their own box. There is no multi-tenant story, no team seats, no SaaS backend. When you install it, the whole system lives on one machine you control.
What is here
Reading the source is the authoritative answer to "what does it actually do?" — the summary below is a map, not the territory.
Inbox → Mother project → Sub-project → Platform version: the full spine of a creative workflow, with a fast-track that lets a good idea skip straight into an active sub-project when you know where it belongs.
Storyboards with a list view and a board view, drag-to-reorder, per-shot reference images, XLSX export, and a printable version for on-set use.
Schedule and calendar: precise times, all-day dates, and fuzzy windows ("this week", "the weekend") coexist in one calendar; overdue is computed, not remembered, so nothing quietly rots.
Reminders and in-site notifications, deduplicated at the database layer so a restart never fires the same alert twice.
Execution records for shoots / re-shoots / screen recordings / writing sessions — attach the record to whichever project layer actually matches what you did.
Retrospectives, light or full; every field is optional. The structure is there to remind you, not to demand.
Attachments in four shapes: uploaded images (with thumbnails), path pointers (e.g.
NAS/2026/Aug shoots/), external links, and text snippets. Soft-deleted files sit in a recycle bin for 30 days.Field mode: mobile-first page for on-set use. If the network drops, edits queue in IndexedDB and sync when connectivity returns.
Full export: JSON + uploads bundle for takeout, from either the CLI or the settings page.
Backups: online SQLite backup on a schedule, and optional restic scripts for encrypted off-site copies with a real restore-drill runner.
MCP channel for AI agents (Claude, ChatGPT, Codex, …) — see the section below.
Related MCP server: mcp-devtools
Design stance
Single user, single account. The data model carries a workspace column so a future multi-user version does not have to rebuild the schema, but everything in the shipped code assumes exactly one user.
No external services required. SQLite on disk, files on disk. No Redis, no message queue, no third-party auth. You can run it on a $5/month VPS.
Small footprint. Target is app 512 MiB / scheduler 256 MiB / (optional) reverse-proxy sidecar 128 MiB. A 2 GiB VM is enough.
The server does not build the frontend. The Vite bundle is built locally (or in CI) and shipped as pre-built files. Deployment machines never need Node.
Content over ceremony. The retro form has no required fields — the schema exists to remind you what to think about, not to gatekeep saving.
Tech stack
Backend: Python 3.12, FastAPI, SQLite (with
uvfor dependency management).Frontend: React 19 + TypeScript, built with Vite.
Deployment: Docker Compose (single-host). Reverse-proxying and TLS are your call — Cloudflare Tunnel, Caddy, Nginx, Tailscale Funnel, or just SSH tunnels for local-only use all work.
Testing: pytest for the backend, vitest for the frontend.
MCP channel: connect AI agents
Yoru Studio exposes a Model Context Protocol (MCP) server so agents that speak MCP — Claude Desktop, ChatGPT desktop, Codex CLI, Claude Code, and others — can read from and (append to) your studio without you copy-pasting.
Eight tools total, all scoped to append-only writes with idempotency:
Read (5):
list_projects— mother-project list with counts.get_project— one mother's full detail, including its sub-projects.get_sub_project— one sub-project, with storyboard / execution records / retrospective folded in.get_schedule— upcoming (14 or 30 days), all overdue, near-term fuzzy events.get_inbox— pending or discarded inbox items.
Write (3, all append-only, all idempotent):
capture_inspiration— drop a spark into the inbox.append_storyboard_shots— atomically add N shots to a video sub-project's storyboard.append_execution_record— log a shoot / write session / test.
Every write tool takes an idempotency_key. Retry with the same key returns the first result; a different payload with the same key is a hard conflict. Nothing an agent does can silently overwrite work you already have.
Two auth paths behind the same /mcp endpoint (spec §5.1 of docs/spec/ in the source):
Static Bearer token for personal / single-agent use. You mint one long random string, store its
sha256in the environment, and give the token to the agent.OAuth 2.0 with PKCE + Dynamic Client Registration for connectors that expect it (ChatGPT's connector is the current case that requires it).
Both paths can coexist. Both are optional — leave both unset and the /mcp route never mounts.
Quick start
Two paths depending on how you want to run it: from source (for development, or if you prefer to manage Python yourself), or via Docker Compose (for a stable single-host install).
From source
Requires Python 3.12 and uv, plus Node 20+ for the frontend.
# 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 APILocal mode binds to loopback and skips authentication for developer convenience. To try the auth flow locally, follow the "Enabling remote mode" section below.
Other CLI commands:
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_HASHRun the tests:
uv run pytest # backend
cd frontend && npm test # frontendDocker Compose
The docker-compose.yml in this repo defines three services: app (the FastAPI + built SPA), scheduler (a 60-second-tick loop that runs backups, reminders, retention), and cloudflared (a reference reverse-proxy sidecar — swap it for whatever fits your infrastructure).
Reverse-proxying / TLS is deliberately out of scope of the app: pick your own. Reasonable choices include:
Cloudflare Tunnel (the reference
cloudflaredservice indocker-compose.yml, with the provisioning script inscripts/provision-cloudflare-tunnel.py).Caddy or Nginx as a host-level reverse proxy, terminating TLS with your own certs.
Tailscale Funnel for private-first hosting.
Just SSH forward
-L 8000if you only want it on your own machine.
If you use Cloudflare Tunnel, either edit or remove the cloudflared service and unset STUDIO_TRUSTED_PROXY_IPS in .env.production. If you use another proxy, set STUDIO_TRUSTED_PROXY_IPS to your proxy's IP so real client IPs land in the audit log.
Deployment steps (once your Docker host is ready):
# 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 has a longer walkthrough covering the reference layout, the backup automation scripts under scripts/, and the operation lock the deploy and backup jobs share.
Enabling remote mode
Remote mode is what turns the app from "local dev with no auth" to "public URL behind a proxy with session cookies". Set at minimum:
STUDIO_MODE=remoteSTUDIO_SESSION_SECRET— a random string, at least 32 characters.STUDIO_AUTH_PASSWORD_HASH— the output ofuv run studio hash-password.STUDIO_ALLOWED_HOSTS— the exact hostname(s) the app will answer on (no wildcards; the app will refuse to boot with*).STUDIO_TRUSTED_PROXY_IPS— if there is a reverse proxy in front, the IP(s) it uses to talk to the app.
The app refuses to boot in remote mode if any of the required secrets are missing or if allowed_hosts is empty — this is deliberate. There is no "silently open" configuration.
Configuration
Most values live in environment variables (production is Docker-friendly that way). A subset can also live in a TOML file loaded by --config or STUDIO_CONFIG — see config/config.example.toml for the shape.
Secrets are env-only by design: they are never read from the TOML config, so bundling the config file with a deployment can never leak them.
Variable | Purpose | Default |
|
|
|
| Address the server binds to |
|
| Port the server binds to |
|
| Comma-separated list of hostnames accepted in | (empty) |
| Comma-separated list of proxy IPs whose | (empty) |
| Random string ≥32 chars used to sign session cookies (required in remote mode) | (empty) |
| scrypt-hashed login password from | (empty) |
| Where the SQLite database lives |
|
| Where uploaded attachments live |
|
| Where SQLite online backups are written |
|
| Where app logs go |
|
| Optional read-only path where the host's backup jobs drop | (unset — status shows |
| Per-file upload cap |
|
| Total upload quota per mother-project subtree |
|
| Decompression-bomb guard |
|
|
| (unset) |
|
| (unset) |
| Public URL that hosts the OAuth AS metadata; setting it wakes the OAuth path | (unset) |
| Comma-separated hostnames allowed in DCR redirect URIs (loopback always allowed) |
|
| OAuth access-token lifetime |
|
| OAuth refresh-token lifetime |
|
| OAuth authorization-code lifetime |
|
Generating hashed tokens
The intake endpoint and the MCP static-Bearer path both store sha256(token) — never the token itself — so a leaked .env.production yields nothing replayable.
# 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 elseExternal intake: hand your own feed to the inbox
There is an HTTP endpoint designed to receive items from an external feeder — an RSS scraper, a topic-radar tool, a scheduled scrape job, whatever ingests content on your behalf. The endpoint is generic: bring your own upstream, wire it here, and items land in the inbox where you triage them.
Endpoint: POST /api/inbox
Authentication: Authorization: Bearer <token>. The server compares sha256(token) against STUDIO_RADAR_TOKEN_HASH in constant time. If that env var is unset, the endpoint returns 401 to every Bearer call — the intake stays fully closed.
CSRF is not required on this path: the CSRF cookie defends against browser session replay, which is not a threat when the caller supplies its own bearer header.
Request body (JSON):
Field | Type | Notes |
| string, required, ≤500 chars | The inbox item title. Blank / missing → |
| string, optional | Your one-line hot take. |
| string, optional | Free text — pasted URLs are fine. |
| string, optional, ≤500 chars | Your feeder's identifier for this topic. Second-strongest dedup key. |
| string, optional, ≤2000 chars | Canonical URL of the item. Third-strongest dedup key. |
| string, optional, ≤500 chars | Per-delivery unique key. Strongest dedup key. |
Dedup priority: idempotency_key > radar_topic_id > canonical_url. On a repeat delivery, the server returns the row that already exists rather than creating a second one — even if you had already discarded or converted that row. Re-delivery must not overturn your triage decision.
Response:
201 Created— a brand-new row was inserted.200 OK— a repeat delivery was matched to an existing row (any status, including discarded / converted). Same body shape.400 Bad Request— missing / invalidtitle.401 Unauthorized— bad or missing bearer token, or intake not configured.
Response body:
{
"item": {
"id": 42,
"title": "…",
"source": "radar",
"status": "pending",
"created_at": "2026-08-12T12:34:56Z",
"…": "…"
},
"deduplicated": false
}Curl example:
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"
}'The field is nicknamed "radar" throughout the codebase because it was originally wired to an external content-radar tool; the endpoint itself is generic and works with any feeder that can speak HTTP.
License
Yoru Studio is licensed under GNU Affero General Public License, version 3, only (AGPL-3.0-only). See LICENSE for the full text.
In one sentence: you may self-host, use, and modify the code freely for your own creative work; if you run a modified version as a network service that other people interact with, you must offer them the source of that modified version. This is exactly what AGPL is designed to enforce — the "network use" clause (§13) makes the reciprocal obligation trigger on running it, not just on distributing it.
Expectations
This is a personal project. It exists because one creator needed it and decided to share it.
Not a product. There is no roadmap that anyone else is entitled to, no support SLA, and no promise that the next release will not break your setup.
Maintained on the author's own rhythm. Issues and pull requests are welcome, but replies come when they come.
You self-host it. No hosted version exists. There is no plan for one.
Data lives on your machine. Nothing calls home. Nothing is sent to a third party. That is the point of self-hosting; it is also the reason nobody is going to rescue your data if you lose it. Take backups.
If any of that reads as "not for me", that is the honest signal — please pick something else and no hard feelings.
Contributing
Bug reports are welcome. Please include enough detail that the bug can be reproduced against a clean checkout.
Feature requests: this project scopes itself intentionally small and adds features only after real use exposes a need. A feature request that reads like "here is what I actually hit trying to use the app" is far more likely to land than one that reads like "here is a nice thing to have".
Pull requests: for anything larger than a one-file bug fix, please open an issue first to check that the direction fits. AGPL-3.0-only means contributions must be compatible with that license — by opening a pull request you agree that your contribution is under the same terms as the rest of the project.
Attribution
Built by Yoru, Claude Fable 5, and GPT 5.6 Sol — the three of us.
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
- Alicense-qualityAmaintenanceServer-enforced workflow discipline for AI agents. An MCP server providing persistent work items, dependency graphs, quality gates, and actor attribution. Schemas define what agents must produce — the server blocks the call if they don't. Works with any MCP-compatible client.199MIT
- AlicenseBqualityDmaintenanceProduction-grade MCP server that gives AI agents safe access to your local dev environment: filesystem, databases, processes, and OpenAPI specs.15323MIT
- Alicense-qualityBmaintenanceMCP 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,117Apache 2.0
- Alicense-qualityCmaintenanceA 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
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Person-owned, portable AI memory as a remote MCP server, readable and writable by any MCP client.
Personal MCP server for humans who create. Proof of authorship, license control.
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/yoruuuchan/yoru-studio-oss'
If you have feedback or need assistance with the MCP directory API, please join our Discord server