Developers

Build with your own agent.

One MCP for everything a game needs: projects, a managed repo and storage, engine templates and skills, sprites, sound and meshes on your credits, hosted Blender, and deploys to the game's own address. Model spend stays on your Claude or Codex subscription.

claude mcp add --transport http looping https://neighborly-octopus-690.convex.site/mcp

Then run /mcp → Authenticate. Sign-in is a link. Every connection gets its own key; see and revoke them in your Studio.

The workflow

From a connected agent to a listed game with a token. Every build is checked against the game rules before it goes live.

  1. 01Connect

    Add the MCP to Claude or Codex and approve the link it opens.

  2. 02Create

    project_create: <slug>.looping.gg reserved at once, plus a private repo and a bucket for a game built here.

  3. 03Build

    Your own workflow, or the looping-build skill: engine_scaffold → repo_commit → site_deploy, with asset_start, sprite_install and audio_install for art and sound.

  4. 04Publish

    game_publish a local build directory (or inline files). Checked against the game rules, live at once, immutable.

  5. 05List

    Test it on its own address first; game_list puts it in the catalog when it is ready.

  6. 06Launch

    project_launch returns the launch page; the creator signs the token into existence.

Tools

56 tools, straight from the MCP's own definitions.

Account and projects · 6
  • looping_whoamiread

    Who this key is and what it can act on: the account, the selected project (stage, credits, routing, settings, market), and which capabilities are live. Call first. If no project is selected, project_list then project_select or project_create.

  • project_listread

    List the game projects this account owns: slug, stage, credits, repo, and play URL.

  • project_selectread

    Choose the project (by slug) that project tools act on. The choice is remembered on the server for this key, so it holds across sessions and clients.

  • project_createwrite

    Create a new game project (nothing is launched): a name, a brief of a few sentences, and optionally the engine (an id from engine_list). origin 'agent' (the default) provisions a private repository, blob storage, and the project's own origin at <slug>.looping.gg for a game built here; origin 'upload' reserves only the origin, for a game built elsewhere that game_publish will put live. Returns the slug and selects it. Creating costs nothing.

  • project_launchwrite

    Get the page where the deployer launches the project's token on Robinhood Chain. The launch is signed in the deployer's own wallet (pairing GG, ETH or USDG, creator fee up to 10%, optional developer buy), so an agent cannot launch: once the game has a live build and the deployer has decided to launch, call it with confirm: true and it returns launch_url to hand to them; without confirm it refuses. Everything before launch works without a token.

  • project_creditsread

    The project's two balances: fee balance (claimable, in the quote asset) and credit balance (USD cents: available, reserved, minted from fees, spent), with recent receipts. Generation and Blender jobs spend the credit balance; shortfalls are topped up automatically from the deployer's account credits.

Repo and storage · 11
  • infra_statusread

    The project's platform-managed repository (private by default), blob storage bucket, hostname, and Blender workspace, with provisioning state. Created automatically with a project built here.

  • infra_provisionwrite

    Retry provisioning of the repository, the bucket, and the hostname if any is pending or failed.

  • repo_treeread

    List every file in the project's managed repository (and its commit history when tracked on the platform).

  • repo_readread

    Read one file from the managed repository. Text comes back as utf-8; binaries as base64.

  • repo_commitwrite

    Commit files to the managed repository in one commit: paths and contents (utf-8 text, or base64 with encoding). The platform is the git client, so no GitHub account is needed. Returns the commit sha and URL.

  • repo_archiveread

    A short-lived download URL for the whole repository as tar.gz, for a local checkout or export.

  • repo_visibilitywrite

    Make the managed repository public or private. Private by default; only on the deployer's explicit request.

  • storage_putwrite

    Store a blob in the project's bucket: text or base64 content, or source_url to copy a file (for example a completed asset job URL) server-side. Keys are paths like assets/boat.png.

  • storage_getread

    Read a blob from the project's bucket (text as utf-8, binaries as base64, up to 6 MB inline).

  • storage_listread

    List objects in the project's bucket, optionally under a prefix.

  • storage_deletedestructive

    Delete one object from the project's bucket.

Publish a game · 2
  • game_publishwrite

    Put a game build live on the project's own address (<slug>.looping.gg). Over the stdio server give dir: an absolute local directory holding index.html (or a folder that contains it); the files are uploaded straight to the games worker with a signed ticket and checked there. Over the remote MCP give files inline (text, or base64 with encoding; small builds only). Either way the build must meet the game rules (index.html at the root, no server code, 100 MB total, 25 MB per file, 1,000 files, no wallet or seed-phrase prompts, no page redirects) or it is refused with the reasons. Every publish is an immutable version, playable at once on the project page for anyone with the link; it stays out of the catalog until game_list. note is what changed in this build. Returns the play URL, the build label, whether the game is listed, and the launch page URL when no token exists yet.

  • game_listwrite

    List the game in the Looping catalog (Discover and the markets) or take it off. Listing needs a live build. An unlisted game stays playable on its own address and project page for anyone with the link, which is how a creator tests a build before making it public or launching a token.

In-game purchases · 5
  • store_itemsread

    The game's store catalog and its mode (test until the token launches, then live; off when paused): every item's sku, name, kind (unlock or consumable), units, price (in dollars, converted at checkout, or an exact token amount), the tokens it can be paid in, and any pending price increase. Game code names items by sku only and reads this through the SDK (looping.store.items()).

  • store_item_upsertwrite

    Add or change one store item. Price it in dollars (usd, converted to the chosen token at checkout with live rates) or exactly in a token (token: GAME | GG | USDG | ETH, amount in base units: 18 decimals except USDG's 6). pay lists what buyers may pay in (the game's own token GAME, GG, USDG, ETH); a token-priced item always accepts its own token. kind unlock is owned once; consumable stacks by units per purchase and is spent with looping.store.consume(). A raised price applies after 24 hours (the old one is signed until then; the change is public on the game page); a cut applies at once. The platform fee is the game's pairing (0% GG-paired, else 10%), never set here. Agree the items and prices with the creator before adding them; every change is public on the game page.

  • store_item_removewrite

    Take an item off sale. Players who own it keep it; re-adding the sku restores it.

  • store_salesread

    Purchases as the chain settled them (and test-mode ones before launch): buyer, sku, token, amount, dollar value, fee and transaction; totals per token; how many wallets own each item. Live proceeds sit in the launchpad's fee escrow for the game's fee recipient and are claimed from the Token tab.

  • store_settingswrite

    Pause (enabled=false) or resume purchases for this game. While paused the catalog stays visible and no quotes are signed. A pause by Looping operators cannot be lifted here.

Multiplayer and fair play · 4
  • rooms_statusread

    How the project's multiplayer rooms are doing right now: the stored rooms policy (enabled, mode, wallets_only, max_players, messages_per_second, tick_rate, when and by whom it was set), live rooms and players plus usage per day from the rooms worker (player-seconds by mode, sandbox time, joins, and results_lost: signed results a room had to abandon; null when the worker cannot be reached, with metered_at, when usage was last read, and unreachable_since while it cannot be), open reports (wallet reports on players not yet banned; guest reports count separately) and how many players are banned. New guest ids are bounded per project per hour (a flood raises an alert). Read it before rooms_configure or player_ban, and whenever the deployer asks about online play, cost, or a complaint.

  • rooms_configurewrite

    Set the project's rooms policy; give only the fields to change. enabled false refuses every room token, so nobody can join until it is true again. mode is relay (the room passes messages through and the host client decides; co-op, party, turn-based, chat) or authoritative (the room runs the build's rules.js in a sandbox and signs verified results; versus, arena, races: pick it when cheating would harm other players). Authoritative mode requires credits on the project (rooms are metered) and caps rooms at 16 players. wallets_only refuses guests so a ban follows the wallet. max_players is the most one room may hold (2-32; a game still asks for fewer per room), messages_per_second the per-connection rate (1-30), tick_rate the simulation rate in authoritative mode (5-30). The response is the stored, normalized config: every field clamped to the platform's limits, plus updated_at and by. Rooms already open keep their mode and size; new tokens carry the new policy, and wallets_only alone reaches open rooms too (each switches on the next newer token it sees, and its guests are out at join and at their next renewal). Read the looping-fairplay skill for which mode fits the game.

  • players_listread

    Players the project has seen, as pseudonymous per-game ids (never wallets): player, kind (wallet or guest), name, last_seen, and banned_until with ban_reason while a ban is in force. banned true lists current bans only; limit is 1-200. Use it to find the id a report names before player_ban, and to check that a ban or a lift landed.

  • player_banwrite

    Ban a player from the project's rooms, saves, reports and every score attributed to the id for hours (1 to 8760, a year), or lift a ban with hours 0; an anonymous score (posted with no token) is not a player and is not covered, which any client can post whether banned or not. player is the pseudonymous id from the operator alert's body, players_list, or a room's join event; a wallet's ban follows the wallet across devices, a guest's ban only that browser's storage (set rooms_configure wallets_only when that matters). It takes effect at the player's next token, within 15 minutes; a connection already open is closed when its token expires. A ban resolves the reports filed against that player (rooms_status's reports_open). reason is for the deployer and operators, not shown to the player. Bans are the deployer's decision: reports never ban on their own.

Hosting on <slug>.looping.gg · 3
  • site_statusread

    The project's reserved hostname (<slug>.looping.gg), what is live there, the build history for rollback, and the player API base. Reserved automatically when the project is created. The round and score routes live on that origin: POST /_looping/api/round (room token required) mints a server-seeded round { round, seed, version, exp } for the live version, and POST /_looping/api/score { round, score, tape? } records the round's score; a well-formed tape from a minted round is replayed against that version's sim.js in a sandbox and the score is marked verified when it reproduces, otherwise the score is player-reported.

  • site_deploywrite

    Deploy a bundle the platform already holds to the project's own origin: bucket_prefix (everything under that prefix in the project's bucket, e.g. builds/v3/) or repo_dir (a directory of the managed repository, e.g. dist/, or '.' for the root without docs and dotfiles); files (inline; text or base64 with encoding) also works for small bundles, though game_publish is the tool for a build. The bundle is checked against the game rules before it goes live: index.html at the bundle root, size limits, no server code, and no wallet or seed-phrase prompts; a bundle that fails is refused with the report. Each deploy is an immutable version served with a strict CSP; the project page embeds it in a sandboxed iframe. Games post scores with fetch('/_looping/api/score', {method:'POST', headers:{'x-looping-token': await rooms.token()}, body: JSON.stringify({round, score, tape})}) and read GET /_looping/api/leaderboard and GET /_looping/api/store/items: the score's player is the room token in x-looping-token and nothing else (without the header the row is anonymous). A verified score needs a round minted by POST /_looping/api/round and the input tape engine-core's recorder wrote; the engine templates do this, ship sim.js (export simulate(args): the headless round the platform replays to check a score) and pin full engine versions in the import map (https://engines.looping.gg/<pkg>@<x.y.z>/src/index.js): keep both in the bundle and never replace the pin with an @major.minor alias, or every score of the game stays player-reported. Paid content lives under paid/<sku>/ and is served only with a content ticket (rooms.paidUrl in engine-core; the looping-fairplay skill), so any other paid/ layout is refused. Purchases go through the game SDK (runtime.store in engine games, https://engines.looping.gg/sdk@0.0/src/looping.js for any HTML game: store.buy(sku) opens the platform's checkout); no keys, prices or wallet code are ever shipped in the bundle. label is what changed in this build.

  • site_rollbackwrite

    Make an earlier build live again on the project's origin (versions come from site_status history).

Engines, skills, pipelines · 6
  • engine_listread

    The platform's game engines (top-down shooter, platformer, adventure, isometric, FPS, and the shared core) and asset pipelines with versions, docs, skills, and CDN URLs. Start here when building a game; then engine_docs and skill_read, then engine_scaffold.

  • engine_docsread

    Read an engine's documentation: README.md (API and tuning), ROADMAP.md, CHANGELOG.md.

  • engine_scaffoldwrite

    Copy an engine's template game (index.html, main.js, tuning.json, levels/ or rooms/, theme.css, loop.json) into the selected project's repository and deploy it to the project's origin so there is a playable game immediately. Then iterate with repo_commit and site_deploy following the engine's skill.

  • skill_listread

    The skills the platform ships: how to build a game here from scratch (looping-build), publish a build made anywhere (looping-publish), build with each engine, run the asset pipelines, direct the art, use hosted Blender, and rig and animate characters. Read the one matching your task before acting.

  • skill_readread

    Read a skill (SKILL.md) by name, e.g. looping-build, looping-publish, looping-multiplayer, looping-fairplay, looping-topdown-shooter, looping-platformer, looping-adventure, looping-isometric, looping-fps, looping-engine-core, looping-pipelines, looping-art-direction, looping-blender, looping-rig.

  • pipeline_readread

    Read an asset pipeline definition (sprite-sheet, tileset, character-pack, sfx-set, voice-lines, music-set, cover-art, ui-kit): inputs, steps, prompts, models. Run it locally with `looping-pipeline` from @looping/pipelines, or follow its steps with asset_* tools.

Generation on project credits · 9
  • asset_modelsread

    Catalog of generation models billed to the project's credits: images (FLUX), playable character sprite sheets, tileset and prop sheets (Looping's own jobs, packed into the engines' atlas format), textured meshes (Meshy 6), speech, sound effects and music (ElevenLabs), with prices in cents and the price version. One account, one balance, every provider.

  • asset_quoteread

    Quote a generation job against the project's credits. Returns quote_id, cost_cents, and expiry (10 minutes). Does not spend. params: image_size (square, square_hd, portrait_4_3, portrait_16_9, landscape_4_3, landscape_16_9), num_images (1–4), seed; mesh art_style, pose_mode ('t-pose' for characters), rig: true (+$0.15, Meshy rigging → preset 'meshy'), height_meters, or model meshy/rigging with source_job_id | model_url | key to rig an existing model; audio voice; sfx duration_seconds; sprite: four models. looping/sprite-3d (60¢ + a 105¢ rigged model unless mesh_job_id names one) prerenders a rigged Meshy character in Blender from one fixed camera for every facing and frame: the consistent path, the default for playable characters; params mesh_job_id, view (low top-down | high top-down | side), directions, clips (idle, walk, run), size, shading (toon | flat | textured), name, scale; needs blender_workspace ready. looping/sprite-sheet (15¢ per facing) draws four poses per facing in one image and slices it: quick, for enemies and NPCs; params size, view, clips (up to 3), directions, style, reference (this character's own key art only), name, scale. looping/tileset-sheet (15¢ per four tiles): params tiles ("char|role" pairs matching the level legend), size, style, reference. looping/prop-sheet (20¢): params props (named objects), size, style, reference. All four return a sheet plus result.skins_entry for sprite_install.

  • asset_startwrite

    Start a quoted job. Reserves the quoted cost from project credits (auto top-up from the account if short), runs the provider, settles at the quoted cost on completion, refunds on provider failure. Idempotent by request_uuid: never retry an uncertain start under a new UUID. Requires the deployer's generate consent for this session and max_cost_cents at or above the quote.

  • asset_statusread

    Inspect a job: queued, running, complete, failed, or refunded, with cost and output count. Pass request_uuid instead to find a job after an uncertain start.

  • asset_uploadwrite

    Store a file you already have (a logo, a reference sheet, a voice clip) on the platform and get a URL to cite as a generation reference (asset_quote params.reference), a storage_put source_url, or a blender_run source_url. base64 content up to 6 MB, or source_url to copy server-side. Free.

  • asset_waitread

    Wait until any of the given jobs finishes (complete, failed, or refunded) or timeout_seconds (max 50) passes, then return the finished jobs and the ids still pending. One call instead of a poll loop.

  • asset_urlread

    A download URL and content type for a complete job's first output. Use it to look at the result, as a storage_put source_url, or as a repo_commit input.

  • audio_installwrite

    Commit a complete speech, sound-effect or music job into the repository as assets/audio/<name>.mp3 and merge it into assets/audio.json, which every engine template loads (audio.loadSounds). A sound effect named after an engine cue (hit, hurt, pickup, jump, land, shoot, explode, dash, ui, win, lose, reload) replaces the synthesized placeholder wherever the engine already plays it; other names play where the game calls audio.play(name). Music installs as a track the game starts with audio.track(name) (loop and volume optional); speech installs as a voice line for audio.say(name). kind is inferred from the job.

  • sprite_installwrite

    Commit a complete sprite job (kind sprite) into the repository as assets/<name>.png + assets/<name>.json and merge the entry into assets/skins.json (the adventure template loads it and draws characters, tiles and props from it; the other engines need loadSkins and their own draws). name is the skins key the engine looks up (player, slime, skeleton, npc, or an enemy kind you defined); scale overrides the draw scale. Look at the atlas (asset_url) before installing; anything without a skin keeps its placeholder.

Hosted Blender and motion · 10
  • blender_workspacewrite

    The project's hosted Blender workspace (a private Linux machine with Blender 4.5 LTS). First call creates it and starts the install; poll until blender is ready. Subsidized by the platform; jobs are billed per run.

  • blender_runwrite

    Run Blender headless on the workspace: a Python script (bpy) plus optional inputs (text, base64, source_url, source_key: an object in the project bucket, or source_path: a motion collection file such as tools/rig_humanoid.py or humanoid-v1/motions.glb), and the output paths it writes (relative to the job directory, e.g. out/model.glb, out/preview.png). Outputs land in the project's bucket under blender/<job>/ and come back with storage keys. Billed to project credits per started job; requires the deployer's generate consent and a fresh request_uuid (never retry an uncertain run under a new UUID). 10-minute limit.

  • blender_jobread

    Inspect a Blender job: status, exit code, log tail, outputs with storage keys. Poll every few seconds while running.

  • blender_job_listread

    The project's recent hosted Blender jobs.

  • motion_listread

    The platform's motion collection: shared humanoid libraries (motion-only GLBs with named clips: walk, run, jump, vault, ledge_grab, crawl…), sample rigged characters, the 24 humanoid roles, and bone-name presets (meshy, looping). Start here before rigging or animating a character.

  • motion_readread

    Read a collection text file: a library manifest (clips, timing, source profile), a rig profile, or a README. Paths come from motion_list.

  • motion_fetchwrite

    Copy a collection file (a library's motions.glb, a profile, a sample character GLB) into the project bucket at key, so hosted Blender jobs can take it as a source_key input and storage_get can download it.

  • motion_inspectread

    Inspect a rigged character (key in the project bucket, job: a completed mesh asset job such as a Meshy rig, or a sample): skin joints, existing clips, which bone-name preset matches, and whether a profile binds every joint (limb lengths, rest signature). Fix the rig in hosted Blender or supply { bones } until the check passes.

  • motion_applywrite

    Bake selected library clips onto the character's own rig (retarget by anatomy, proportional root motion, optional contact IK windows) and write <out>/character.glb + character.json to the project bucket. Mesh, weights and materials are untouched. profile: a preset ('meshy'), 'sample:<id>', a library profile id, or { bones }. retarget (optional) overrides: root_offset_m, rotation_offsets, limb_ik 'source-endpoints' with ik_chains/ik_windows/contact_space. Free, no credits.

  • motion_exportwrite

    Grow the collection: export a character's authored clips (from hosted Blender, or a motion_apply result) as a motion-only library (<out>/motions.glb + library.json) in the project bucket. clips are names (loop, in-place assumed) or { name, loop, root_motion: 'in-place'|'embedded' }; manifest_key (a character.json) supplies exact clip metadata instead. Share the keys to have it reviewed and published.

The game SDK

The only way a game reaches money, identity or other players.

Games run on their own origin in a sandboxed frame and never see a wallet, key or session. The SDK grows out of engine-core's runtime: rounds, scores the platform can verify by replaying the round, the keyless player API, multiplayer rooms on the game's own origin, and in-game purchases. A game names an item by SKU; the platform draws its own checkout over the frame from a quote it signed, the Store contract pays the game's fee recipient through the launchpad escrow (0% platform fee for GG-paired games, 10% otherwise), and the game reads what the player owns. Prices live on the platform (store_item_upsert), never in game code. Rooms come with P3.

  • Built into every Looping engine as runtime.store
  • A script tag for any HTML game: engines.looping.gg/sdk@0.0/src/looping.js
  • Test mode before the token launches: build and test the shop, nothing is charged
  • A Unity .jslib bridge with P3
import { looping } from "https://engines.looping.gg/sdk@0.0/src/index.js";
// or, in an engine game: const runtime = createRuntime(); runtime.store / runtime.player()

await looping.player();                    // { signedIn, name }: a short name, never the wallet or keys
const { items, mode } = await looping.store.items();   // the catalog, prices set on the platform
const r = await looping.store.buy("golden-lantern");  // the platform draws its own checkout over the game
                                           // → { sku, txHash, test, count } once it is owned
await looping.store.owned();               // [{ sku, count, test }], verified on the platform: restore on load
await looping.store.consume("continues-5"); // spend one of a consumable

const room = await looping.rooms.join("harbor-1");   // P3: wss://*.looping.gg

Engines and skills

Published to engines.looping.gg and served by engine_list, engine_docs, skill_list and skill_read.

Top-down@looping/engine-topdown

Twin-stick and heist games, patrols and line of sight.

Platformer@looping/engine-platformer

Side-scrollers with tuned jump arcs and tilemaps.

Adventure@looping/engine-adventure

Zelda-style rooms, props from a sheet, lantern lighting.

Isometric@looping/engine-isometric

Tile worlds viewed at an angle.

FPS@looping/engine-fps

First-person 3D with physics.

Unity WebGLcoming in P3

Hosted under the platform's security rules. Coming.

looping-publishlooping-buildlooping-storelooping-multiplayerlooping-fairplaylooping-art-directionlooping-blenderlooping-riglooping-engine-corelooping-topdown-shooterlooping-platformerlooping-adventurelooping-isometriclooping-fpslooping-pipelines

What a game page may do

The security policy sent with every game on <slug>.looping.gg.

RuleAllowedWhy
ScriptsInline, eval, public CDNsAny game code runs; it just can't reach a wallet
NetworkIts own origin, the platform API, *.looping.gg, wss://*.looping.ggRooms fit without opening the policy
Payments, camera, microphoneDeniedPurchases go through the platform's checkout
Forms, plugins, embeddingNone; framed only by the platformNo cookies are set