Builder API and MCP server

A machine is a JSON document, never code — which is what makes it safe to let your own tools, or your own AI, design one.

What you can do

Any signed-in account can download the MCP server from the account page and run its local tools: start from a template, validate against the same validator the server runs, soak ten thousand balls, tune a shot, read the rulesheet, and write the machine to a file the browser Builder opens with “Open a file”.

Saving a draft to your account, remixing, and publishing to the arcade go through the Builder API, which needs a key. Minting a key is part of Pro.

Get a key

On the account page, under Builder API and AI tools, name the key and choose what it may do. A key is shown once, at mint; the list shows its label and its first eight characters. An account may hold 5 live keys, a key expires a year after it is made, and any tool using a revoked key stops at once.

  • machines:read — list your machines and read any version of your own, published or draft.
  • machines:write — create machines, save drafts, remix a published machine, run the dry-run validator.
  • machines:publish — publish a saved version to the arcade; the irreversible one, so it is its own scope.

Every request

The base URL is https://rteunfaeoysdeqlbahsv.supabase.co/functions/v1/pinball-client-v1. Every request carries the public anon key, your key as the bearer, an identification block, and — on every POST — an idempotency key that stays the same across retries.

Every answer is an envelope with a contractVersion, a requestId, a serverTime and either data or an error with a code, a message and, for a refused input, the fields it refused. Quote the requestId of any refusal when you write to support.

  • unauthenticated (401): no key, a revoked or expired key, or a key on a route that takes none.
  • forbidden (403): a live key without the scope this route needs.
  • entitlement_required (402): the account is not Pro; the message says which capability.
  • moderation_blocked (451): a moderator has stopped this author; contact support.
  • validation_failed (422): the document was refused; fields is keyed by document path.
  • rate_limited (429): a cap below; fields names which.
  • payload_too_large (413): over 524288 bytes.
  • conflict (409): a version that already exists, a slug already taken, a remix in flight.
apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InJ0ZXVuZmFlb3lzZGVxbGJhaHN2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQwMzE5MTMsImV4cCI6MjA4OTYwNzkxM30.aGLvfg3z6MO1xiKrlECKnesQvU7dJvKA4VO9cJTQq8w
authorization: Bearer hpk_…
x-pinball-meta: {"clientKind":"tool","appVersion":"1.0.0","buildNumber":1,"contractMajor":1,"contractMinor":1,"requestId":"<uuid v4>"}
idempotency-key: <8 to 128 characters of [A-Za-z0-9_-], the same across retries; every POST>

The routes

The full OpenAPI description is at https://pinballgame.ca/contracts/pinball/v1/openapi.yaml.

  • GET /machines/mine — machines:read — your machines, with their versions and statuses.
  • GET /machines/{machineId}/versions/{semver} — machines:read — one version; a key reads its owner’s drafts, and published versions are public.
  • POST /machines — machines:write — a new machine from a title and an era; answers its id and the first version number.
  • POST /machines/validate — machines:write — the verdict on a definition, the budgets and the moderation screen, without writing anything.
  • POST /machines/{machineId}/versions — machines:write — save a draft under a semver; the document is revalidated here.
  • POST /machines/{machineId}/versions/{semver}/publish — machines:publish — publish a saved version; a first publication goes to a person.
  • POST /machines/{machineId}/versions/{semver}/remix — machines:write — fork a published version into a machine of your own, ancestry recorded.
  • POST /api-keys, GET /api-keys, POST /api-keys/{keyId}/revoke, GET /package — a signed-in session only, never a key.
curl -s -X POST "$BASE/machines/validate" \
  -H "apikey: $ANON" -H "authorization: Bearer $HCC_PINBALL_API_KEY" \
  -H "x-pinball-meta: {\"clientKind\":\"tool\",\"appVersion\":\"1.0.0\",\"buildNumber\":1,\"contractMajor\":1,\"contractMinor\":1,\"requestId\":\"$(uuidgen)\"}" \
  -H "idempotency-key: validate-$(date +%s)" \
  -H "content-type: application/json" \
  --data-binary @machine.json

The machine document

The schema is https://pinballgame.ca/contracts/pinball/v1/machine/schema.json — JSON Schema 2020-12, additionalProperties false everywhere, so an unknown field is refused by name. The format version is 2.0. NEON NOVA and IRON FATHOM are worked examples of every block, readable at their public version routes.

The rules are a closed grammar: 18 actions and 23 operators, an expression depth of 16 and 256 nodes, and event chains to depth 8. There is nothing else to call.

The validator sorts what it finds into seventeen classes, and every one runs on the server again at save and at publish: Schema; Bounds; Geometry — containment, overlap, flipper crossing, flipper outboard gap, trap and reachability; Layer integrity; References; Rules — termination, budget and reachability; Display; Art; Audio; Budgets; and Playability, which is the ten-thousand-ball soak the MCP server runs locally.

  • Colliders 400 · Devices 120 · Lamps 160 · Rules 400 · Modes 24 · Simultaneous balls 6.
  • Art program ops per surface 250 · Display scenes 64 · Audio cues 120 · Document 524288 bytes.

Limits

  • 5 live keys per account.
  • 50 machines per author; 200 draft saves per author per day.
  • 5 publications per author per day; 50 published versions per author.
  • 120 saves or dry runs per key per hour.
  • Validation takes about 20 ms per document, on the shipped machines and on the worst case at every budget.

Content rules

No licensed or recognisable real-world machines, themes, manufacturers or trade dress. Ever. A machine that recreates a released table, borrows its name, its art or its rules, is refused by the product’s own screen and by a person.

Every author’s first publication is reviewed by a person before it appears in the arcade; later publications are reviewed on report or on a sample. Text on the playfield, the display and in speech is screened for invisible characters, mixed scripts, contact details and trade dress, and the dry run returns that screen’s findings so you can see them before a publish rather than after. A version can be taken down by a moderator at any time; a moderator can also block an author, which revokes every key on the account.

The MCP server

Download the file from the account page — one file, no dependencies, Node 22 or newer; the page shows its SHA-256 beside the link. The server speaks MCP over stdio and reads one environment variable, HCC_PINBALL_API_KEY. Without it every local tool still works and the remote tools are not offered.

Claude Desktop reads claude_desktop_config.json; Cursor reads .cursor/mcp.json; VS Code reads .vscode/mcp.json with the same object under "servers" rather than "mcpServers".

  • Local, no key: new_machine, validate_machine, soak_machine, shot_harness, test_rules, rule_coverage, describe_rules, screen_text, canonical_hash, export_json.
  • With a key: builder_link, list_my_machines, get_machine, create_machine, save_version, remix_machine, validate_remote, and publish_version — irreversible, only when you have said so in so many words.
  • Playing a draft: open its builder_link in a desktop browser, where test play runs the real simulation. The native Quest application cannot open a draft yet; publish, and the machine is in the arcade on every surface.
claude mcp add hcc-pinball -e HCC_PINBALL_API_KEY=hpk_… -- node C:\Tools\hcc-pinball-mcp.js
{
  "mcpServers": {
    "hcc-pinball": {
      "command": "node",
      "args": ["C:\\Tools\\hcc-pinball-mcp.js"],
      "env": { "HCC_PINBALL_API_KEY": "hpk_…" }
    }
  }
}

Set up your AI to build machines, step by step

Terms

A machine designed with an AI or through the Builder API is your machine, published under your name, subject to the same content rules and the same review, and you are responsible for it. The MCP server file is licensed for use with an HCC Pinball Arcade account: no redistribution, no reverse engineering. The full terms are on the terms page.

Support

Write to Holmes Computer Consultants at https://www.holmesconsultants.com and quote the requestId from any refusal; it is the join between what you saw and what the server recorded.