@fifth-door/mcp
v0.4.2
Published
Fifth Door MCP server — sign in and publish games to Fifth Door from any MCP client
Readme
@fifth-door/mcp
The public Fifth Door MCP server: sign in to Fifth Door and publish games from Cursor, Claude Code, Codex, or any MCP client. Runs locally over stdio so it can read the game directory being published; talks to Fifth Door exclusively over REST with a per-user session token.
Install
Published package (@latest keeps users on the newest version — npx caches otherwise). @latest resolves when the client launches the server, so a running client keeps the version it started with; after a release, restart the MCP server (or the editor) to pick up the new one.
Cursor — one-click: see fifthdoor.com/docs/mcp, or add to .cursor/mcp.json:
{
"mcpServers": {
"fifth-door": {
"command": "npx",
"args": ["-y", "@fifth-door/mcp@latest"]
}
}
}Claude Code:
claude mcp add fifth-door -- npx -y @fifth-door/mcp@latestCodex:
codex mcp add fifth-door -- npx -y @fifth-door/mcp@latestFrom this monorepo (already registered in .mcp.json, pointed at the local dev stack):
bun packages/mcp/src/index.tsTools
The tables below, tools.json, and the ## Tools section of docs/publish-from-your-editor.md are written by bun run generate-tools from the registered tools (src/tooling/catalog.ts); catalog.test.ts fails when they are stale. Edit descriptions in src/tools/, not here.
Account
| Tool | What it does |
| --- | --- |
| login | Sign in to Fifth Door. |
| whoami | Show which Fifth Door account this MCP is signed in as. |
| logout | Sign out of Fifth Door on this machine by deleting the cached session token. |
Publish
| Tool | What it does |
| --- | --- |
| publish_game | Publish a static web game directory to Fifth Door and get its play URL. |
Your games
| Tool | What it does |
| --- | --- |
| list_my_games | List the games published by the signed-in Fifth Door account: slug, title, visibility, and play URL. |
| set_game_visibility | Set a published game's visibility: "public" lists it on Fifth Door's Discover feed, "unlisted" makes it playable by link only. |
Gameplay previews
| Tool | What it does |
| --- | --- |
| generate_game_preview | Record a gameplay preview for a published game without supplying a video: an agent reads the game's source and writes a controller that plays it, a worker records the run, and the liveliest 6 seconds become the clip Discover loops on the game's card. |
| get_game_preview_status | Check on a gameplay preview recording started by generate_game_preview (or queued automatically when the game went public): whether it is queued, running, done, or failed, and the clip's URL once it is ready. |
| set_game_preview | Attach a gameplay clip you already have to a published game, replacing whatever the card loops today. |
| clear_game_preview | Remove a published game's gameplay preview. |
Game jams
| Tool | What it does |
| --- | --- |
| list_jams | Show this week's Fifth Door weekly jam: its theme, deadline, and entry count. |
| enter_jam | Enter one of the signed-in account's published games into this week's jam. |
| withdraw_from_jam | Withdraw one of the signed-in account's games from a game jam. |
Platform SDK docs
| Tool | What it does |
| --- | --- |
| list_sdk_services | List what the Fifth Door platform can do for a game, as the docs index of one SDK library release: saved progress and shared records (collections), play-time LLM and image generation, multiplayer (realtime, presence, claims), daily games, camera and microphone input, share and invite, background audio, plus the setup guide for a project outside Studio. |
| get_sdk_docs | Read one Fifth Door SDK doc by topic id from an exact library release: platform-sdk for the core reference, a capability id from list_sdk_services (collections, generate, daily, camera-and-mic, social, audio), or a guide id (setup). |
publish_game always uploads authored source alongside the playable bundle (required for content rating and later rehydrate). When directory is a build output such as dist/, pass sourceDirectory as the project root. Each publish also creates or updates an idle Studio session so Insights and listing metadata are available in the app; it does not start an agent turn.
The server never writes SDK files into a project. Adding the SDK is the setup guide (get_sdk_docs({ version, topic: "setup" })): pin one release in a script tag or install @fifth-door/platform-sdk, then read the topics from that same release. Earlier releases shipped an add_sdk tool that copied the checkout's docs and helpers from /api/prism/devkit.zip; that route stays up for them.
The two SDK tools are thin callers of /api/platform/sdk/latest.json, /api/platform/sdk/<version>/index.json, and /api/platform/sdk/<version>/docs/<topic>. The API builds the index from the release's own index.json; this server holds no docs, no frontmatter parsing, and no knowledge base of its own, so the same index and docs are reachable without the MCP (the web docs page reads the same routes). Learning and changing the project are separate: both tools are read-only and need no login, so an agent can assess a capability before touching anything. An exact version is read from that release or fails; it never falls forward to a newer one, because docs for a release the project does not pin describe an API the project does not have. The setup guide ends with a project note the agent leaves (AGENTS.md, CLAUDE.md, or the README) naming the pinned release and these two tools, so a later session reads the release the game was written against rather than the newest.
Cover art
Covers render inside a 4:3 landscape box on every browse surface (GameCard.tsx), with object-contain — so a 16:9 screenshot or a square image shows with bars around it rather than being cropped. Other surfaces reuse the same image at 3:2 (share cards) and 5:1 (banners), and those crop.
- Letter the game's title into the artwork. A card is the cover plus a creator row — the title is drawn nowhere on it, so a cover without the name ships as an untitled picture. Fifth Door's own cover generator bakes the title in for the same reason (
packages/assets/src/generation/cover-art.ts). - Export at 4:3:
1200x900, or1600x1200for a sharper card. - Keep the title and hero subject inside the middle ~70%, out of the corners.
publish_gamereads the cover's header and warns in its output when the aspect is off or the image is under 800px wide. It cannot see whether the title is on the image, so that part is on the caller.
Gameplay previews
Discover loops a short muted clip on a game's card instead of the still cover, when the artifact has one (platform_artifacts.preview_video_url).
Going public queues a recording automatically for any game that has no preview yet (applyArtifactVisibility), so an MCP-published game normally gets one without asking. generate_game_preview exists to record one for a game that is still unlisted, or to replace a bad clip (regenerate: true). It runs an agent over the published source to write a controller, then records that controller under Playwright on a GPU worker — several minutes, so poll get_game_preview_status.
set_game_preview is the manual path: hand it a local video and the server transcodes the first 8 seconds into a card-sized h.264 loop. Trim before uploading.
Configuration
Everything arrives via env vars in the MCP client config — this package never reads monorepo state.
| Variable | Default | Purpose |
|---|---|---|
| FIFTH_DOOR_API_URL | https://api.beta.fifthdoor.com | API origin |
| FIFTH_DOOR_WEB_URL | https://play.beta.fifthdoor.com | Web origin (play URLs) |
| FIFTH_DOOR_TOKEN | — | Token override for CI/scripting; skips login. Use an fd_ API key generated on the account page (or a raw session token) |
Credentials are cached in ~/.config/fifth-door/credentials.json (0600), keyed by API origin.
Server-side counterpart
- Device flow: better-auth
deviceAuthorizationplugin (packages/api/src/auth.ts), approval page at/device(packages/web/src/routes/device.tsx),device_codetable. - API keys:
api_tokenstable +ApiTokenRepository; minted on the account page (apiTokensRPC router), accepted as bearer tokens by the platform REST routes. - Publish + management:
POST /api/platform/publish(session or API-key bearer ⇒ owned, slug-guarded publish; session publishes requiresourceFiles),GET /api/platform/me,GET /api/platform/me/artifacts,PATCH /api/platform/me/artifacts/:slug/visibility(packages/api/src/routes/platform.ts). - Previews:
POST/DELETE /api/platform/me/artifacts/:slug/preview(raw video body ⇒writePlatformPreviewtranscode),POST/GET /api/platform/me/artifacts/:slug/preview/generation(same queue Studio and the go-public path use). Shared save/clear lives inpackages/api/src/lib/artifactPreview.ts. - Game jams:
GET /api/platform/jams,POST/DELETE /api/platform/me/artifacts/:slug/jam-entries[/:jam](shared entry rules inpackages/api/src/lib/gameJamEntries.ts). - User-facing setup guide:
docs/publish-from-your-editor.mdhere, rendered at/docs/mcp(packages/web/src/components/docs/McpDocsPage.tsx).
Release
Publishing is automated by .github/workflows/publish-mcp.yml: bump version in this package.json, merge to main, and CI publishes to npm via trusted publishing (GitHub OIDC) — it no-ops when the version is already on npm.
The MCP Registry listing io.github.fifthdoor/mcp is described by server.json and published by hand once the version is on npm: bump both version fields in server.json to match, then from this directory run mcp-publisher login github (any member of the fifthdoor GitHub org) and mcp-publisher publish. The registry verifies npm ownership through mcpName in package.json, which must equal the server name.
Publishes carry no provenance attestation. npm only verifies a sigstore bundle whose source repository is public, and fifthdoor/conduit is private; trusted publishing enables provenance by default, so the workflow sets NPM_CONFIG_PROVENANCE=false to turn it back off. Making the repo public is the only way to get provenance back.
One-time bootstrap (npm requires the package to exist before a trusted publisher can be configured):
- Create the
fifth-doororg on npmjs.com (owns the@fifth-doorscope). - First publish manually:
cd packages/mcp && npm publish(runsprepublishOnlybuild; needsnpm login). - On npmjs.com → package Settings → Trusted Publisher → GitHub Actions → repository
fifthdoor/conduit, workflowpublish-mcp.yml. From then on, no tokens anywhere.
bun run build produces dist/index.js (Node-runnable; esbuild stays external because it ships a platform-native binary).
