Compile a JSON product spec into an Android APK. Paid per build via x402 (USDC on Base).
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Takes a JSON Product Requirements Document and emits a compiled Flutter application. Built as a LangGraph loop with four subagents and a QA gate that runs the real Flutter toolchain.
The design goal is not "generates plausible code" but zero-error compilation: if the output fails CI, the loop has failed.
PRD to Flutter APK on Apify Store β generate and read the source for free; pay only for the packaged APK. No account beyond Apify's own, nothing to install.
(An earlier version of this README pointed at a self-hosted x402 service on a VM. That deployment has been retired β the source and the payment-gate design it proved out are unchanged, just no longer running on that box.)
examples/generated-field-notes/ is
unmodified output β 23 files generated from the 45-line
todo_app.prd.json beside it, checked in so you
can read exactly what a build gives you. Nothing was hand-fixed for
presentation. Start with
GENERATED.md.
No credentials and no Flutter SDK needed β the defaults are fully offline:
That validates the PRD, runs the loop, and writes a Flutter project to
generated_apps/current_build/.
To grade the output with the real toolchain instead of the offline stub:
CLAUDE.md calls this an M2M microservice; this is the part a machine buyer calls.
| Endpoint | |
|---|---|
POST /builds | PRD in; 202 + job id, or 402 with an x402 challenge |
GET /builds/{id} | status, log, diagnostics |
GET /builds/{id}/apk | the artifact |
GET /healthz | includes whether payment is configured |
Builds take minutes, so the API is asynchronous. x402_payment_verified in a
submitted PRD is discarded: the PRD is buyer-supplied, so trusting that field
would let anyone assert their own payment. Only the server's verifier sets it.
Payment is real x402: the buyer signs an EIP-3009 TransferWithAuthorization
(EIP-712), and the service recovers the signer, checks recipient, amount, chain
and validity window, and claims the nonce atomically so one signature buys
exactly one build.
Configure nothing and the service refuses every payment β it fails closed rather
than falling back to the development shared secret. /healthz reports which
mode is active.
Verification is not settlement. A valid signature proves the payer
authorised a transfer; it does not prove they hold the balance or that the
transfer landed on-chain. Set X402_FACILITATOR_URL and the service submits the
authorization for on-chain execution and blocks the 202 until it confirms β
so a build only starts once the money has actually moved. Without it,
/healthz reports settlement: verification-only and the service is accepting
signed promises.
Before the nonce is claimed the service asks the facilitator's /verify
endpoint whether the payment would settle. Insufficient funds is recoverable β
the payer tops up and re-presents the same signature β so burning their
authorization for it would be needlessly destructive.
Settlement distinguishes three outcomes, not two. A refusal ("insufficient funds") is definite and is not retried. A timeout is unknown: the facilitator may have broadcast and failed to answer, so the build is refused while recording that the buyer may have been charged. Retrying a transport failure is safe β an EIP-3009 nonce is single-use on-chain, so a duplicate submission reverts rather than charging twice.
Verified end to end on Base Sepolia β a real transaction, a real APK:
The payer needs USDC only β no ETH. The facilitator submits the transaction and pays gas, which is the point of EIP-3009; if a wallet is being asked for testnet ETH, something is wired wrong. Faucet: https://faucet.circle.com.
scripts/check_x402_funding.py reports whether a payer is funded by asking the
facilitator's /verify, rather than introducing a second source of truth that
could disagree with the one the gate actually uses.
Set REDIS_URL and both the nonce store and the job store move to Redis;
/healthz reports multi_process_safe. Nonce consumption uses SET NX EX,
one atomic round trip, so the time-of-check/time-of-use protection holds across
workers rather than only within one interpreter. A Redis outage refuses payment
rather than allowing replays.
The money moves on-chain before the build starts, so losing a build to a deploy
means having taken payment for nothing. Execution is therefore durable, not just
job state: POST /builds settles the payment, writes the PRD onto the job
record, and pushes the id onto a queue. Workers pull from it.
An API process builds as well as accepts by default, so a single-container
deployment needs neither of those flags; set BUILD_WORKER_EMBEDDED=0 once
requests and builds want scaling apart.
A worker holds a lease on the job it is building and renews it while it works.
Kill the worker and the lease lapses, another worker returns the job to the
queue, and it is rebuilt from the stored PRD β which is why the PRD is stored
rather than captured in a closure, as it was when execution lived inside the
accepting process. scripts/verify_durable_execution.py demonstrates exactly
that, across real processes and a real SIGKILL.
Two things this deliberately does not promise. A lease bounds duplicate work
rather than preventing it: a worker partitioned from Redis for longer than its
lease is indistinguishable from a dead one, so its build may be handed on while
it is still running. renew returning False is how the stalled worker learns to
discard its result, but the overlap is real, and it costs compute rather than
money β the payment settled once, before the job was queued. And retries are
bounded (BUILD_MAX_ATTEMPTS, default 3): without that, one build that
reliably kills its worker would be requeued into the next one and take the fleet
down a process at a time.
| Variable | Default | What it is for |
|---|---|---|
BUILDS_RATE_LIMIT | 20 | POST /builds per address per window; 0 disables |
BUILDS_RATE_WINDOW_SECONDS | 60 | the window that limit applies over |
BUILD_WORKER_EMBEDDED | 1 | whether the API process also builds |
BUILD_LEASE_SECONDS | 300 | how long a silent worker keeps its job |
BUILD_HEARTBEAT_SECONDS | 30 | how often a working worker says so |
BUILD_MAX_ATTEMPTS | 3 | before a build is given up on for good |
/healthz reports durable_execution, which is true only when the queue and
the job store are both shared β a Redis queue over an in-memory job store loses
the record the build would be resumed from.
The x402 gate stops anyone getting a free build, so this is not about theft. It
is the cost of refusing: POST /builds carrying a payment header makes the
service call the facilitator's /verify and then /settle, two network round
trips with a 60-second timeout, from a synchronous endpoint. A few hundred
concurrent requests with junk authorizations exhaust the thread pool and the
service stops answering anyone β including the buyers who paid. So the limit is
on that endpoint only; polling a running build and downloading an APK are cheap
and legitimately frequent, and throttling them would punish correct behaviour.
Identifying the caller is the part that fails quietly. Behind the TLS proxy
every request arrives from Caddy's address on the compose network, so keying on
the socket peer puts every buyer in the world into one bucket β a limiter that
looks configured while blocking either everyone or nobody. The client is the
rightmost X-Forwarded-For entry, because Caddy appends the peer it actually
saw to whatever the caller sent. Taking the leftmost, which is the more common
convention, would let a caller supply their own header and mint a fresh identity
per request; there is a test that fails on exactly that.
One container that accepts payment and builds APKs, plus the Redis that makes both durable. It wants a VM with a disk: the image carries Flutter, the Android SDK and a JDK, and measures 7.71 GB, which rules out serverless targets and most PaaS free tiers.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/prd-to-flutter-apk)<a href="https://allmcps.com/mcp/prd-to-flutter-apk"><img src="https://allmcps.com/api/badge/prd-to-flutter-apk?style=directory" alt="PRD to Flutter APK on AllMCPs" /></a>