plan_deploy
ActiveTool of cloud.redu/mcp
Turns YOUR repo classification (you scan the repo and pass what you found) into a complete, approvable deploy plan WITHOUT creating anything: picks the VM + managed-Postgres sizes, prices them at the real pricing_rules rates, and checks they FIT your quota — so a plan that can't provision is caught HERE, before any spend. You pass what you detected in the repo (runtime, port, needs_postgres/redis/vector_db); it returns resources + £/hr + £/mo + a feasibility verdict + a checkpoint summary to confirm with the user. Defaults: app VM m1.medium, managed Postgres m1.small; pass single_vm to collapse onto one VM. Only Postgres is auto-provisionable today — Redis / vector-DB needs are flagged, not provisioned. Any containerizable app works (node, python, go, ...) — it deploys as a container, so the language doesn't gate it. Set serves_http:false for a non-web repo (a library, CLI, or language runtime with no HTTP server) and it returns a clean not-a-web-service verdict instead of a costed VM plan. Set heavy_build:true for resource-heavy builds (compiled-from-source native code, a monorepo/turborepo build, a large Node heap) and it raises the app VM to a build-capable floor so the on-VM build doesn't get OOM-killed. Also returns a brand-named markdown report (Mermaid diagram + cost) to save as redu-deploy-plan.md and show the user. Every deploy leaves TWO MANDATORY files at the repo root with DIFFERENT purposes: redu-deploy-plan.md = THIS run's plan/estimate, and redu.md = the DURABLE deploy memory the NEXT deploy reads. If a redu.md exists, READ it FIRST and reuse its known-good plan + recorded fixes; if NONE exists, one MUST be created at the end of the deploy (from get_deployment's redu_md_markdown). They are SEPARATE files — even if your own memory/notes from a prior deploy call redu-deploy-plan.md 'the record', the durable record is redu.md, so do not skip creating it.
Parameters schema
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"runtime"
],
"properties": {
"port": {
"type": "integer",
"description": "Port the app's HTTP server listens on (PORT env / framework default / Dockerfile EXPOSE of a real app port — NOT a debug/IPC port). Omit if the repo has no HTTP server.",
"exclusiveMinimum": 0
},
"start": {
"type": "string",
"description": "How the app starts (package.json start script / Procfile / Dockerfile CMD)."
},
"worker": {
"type": "boolean",
"description": "HEADLESS WORKER / daemon: the repo runs a long-lived process with NO HTTP server (a chaos-monkey, a background/queue worker, an on-infra agent runner). Set TRUE to plan a WORKER deploy — a private VM with SSH access but NO public URL and NO health probe. serves_http/port are then not required (a serves_http:false repo is NOT rejected). Deploy it with deploy_app worker:true."
},
"runtime": {
"type": "string",
"minLength": 1,
"description": "Detected app language/runtime (node, python, go, ruby, ...). Informational — the app deploys as a container, so the language does not gate the deploy."
},
"vm_count": {
"type": "integer",
"default": 1,
"maximum": 10,
"minimum": 1,
"description": "Number of app VMs (microservices). v1: usually 1."
},
"db_engine": {
"enum": [
"postgres",
"mysql",
"mariadb"
],
"type": "string",
"default": "postgres",
"description": "Managed DB engine to plan. For WordPress/WooCommerce clusters use mariadb or mysql."
},
"db_flavor": {
"type": "string",
"default": "m1.small",
"description": "Preferred managed Postgres VM size (default m1.small). Resolved against the real flavor list."
},
"single_vm": {
"type": "boolean",
"default": false,
"description": "Force everything onto a single VM if the user prefers."
},
"app_flavor": {
"type": "string",
"default": "m1.medium",
"description": "Preferred app VM size (default m1.medium). Resolved against the real flavor list."
},
"app_profile": {
"enum": [
"generic",
"wordpress",
"woocommerce"
],
"type": "string",
"default": "generic",
"description": "Detected app profile. Set wordpress/woocommerce when source inspection finds wp-config.php, wp-content, WordPress/WooCommerce packages/plugins, or wordpress/woocommerce compose images. This is used for cluster safety."
},
"deploy_mode": {
"enum": [
"guided",
"yolo"
],
"type": "string",
"description": "guided (default) = ONE approval gate: the user approves the plan, then you proceed with the plan's defaults WITHOUT further sub-questions. yolo = auto-proceed end to end without stopping to ask, using sensible defaults. Sticky for the session once set here or via check_deploy_prerequisites."
},
"heavy_build": {
"type": "boolean",
"description": "Set TRUE when the BUILD (not the running app) is resource-heavy — the container is built ON the VM today, so a build that needs more RAM/CPU than the idle app must be sized up or it OOMs mid-build. Signals: compiled-from-source native code (Rust/C++/CGO/Go-from-source), a monorepo/turborepo build, a Node build with a large heap (NODE_OPTIONS=--max-old-space-size), or bundling Chromium. When true, the plan raises the app VM to a build-capable floor (≥ m1.large) so `deploy_app`'s on-VM build doesn't get OOM-killed. The default m1.medium (4 GB) builds light apps fine but OOMs heavy ones."
},
"needs_redis": {
"type": "boolean",
"default": false,
"description": "App uses Redis (deps redis/ioredis/bullmq/celery or REDIS_URL)."
},
"serves_http": {
"type": "boolean",
"description": "Whether the repo actually RUNS an HTTP server that listens on a port. Set FALSE for a library, CLI tool, or language runtime that has no web server (e.g. a package you `import`, or a `bun`/`node`-style runtime) — redu can only deploy web services, so a non-server repo is reported as not-a-web-service instead of being costed. Note: an `EXPOSE` of a debug/IPC port (Chrome DevTools 9222/9242, metrics) is NOT an HTTP listener — set false. Leave unset only if you're confident it serves HTTP."
},
"has_container": {
"type": "boolean",
"default": false,
"description": "Whether the repo already has a Dockerfile / compose file."
},
"needs_compose": {
"type": "boolean",
"default": false,
"description": "Set TRUE when the repo ships a docker-compose.yml / compose.yaml that runs MULTIPLE services (app + its own db/redis/worker containers) as a stack — then deploy with deploy_compose (podman-compose on ONE VM), NOT deploy_app. A single-service compose that just wraps one Dockerfile can still use deploy_app. plan_deploy raises the app VM to a build-capable floor since a multi-container stack needs more RAM."
},
"cluster_target": {
"type": "boolean",
"default": false,
"description": "Set TRUE when the user asked to deploy this app as an autoscaling cluster. For WordPress/WooCommerce this requires managed MySQL/MariaDB plus a Redu media space mounted at wp-content/uploads (or an explicitly configured central_media_origin); local uploads are unsafe."
},
"media_space_id": {
"type": "integer",
"description": "Existing Redu media space id to reuse for WordPress/WooCommerce cluster uploads. Get it from list_media_spaces. Omit when create_media_space:true.",
"exclusiveMinimum": 0
},
"needs_postgres": {
"type": "boolean",
"default": false,
"description": "App uses Postgres (deps pg/prisma/sqlalchemy/drizzle or DATABASE_URL)."
},
"containerizable": {
"type": "boolean",
"default": true,
"description": "Whether the app can run in a container. Almost always true (a container is the delivery unit); set false ONLY if the app fundamentally can't be containerized — then redu can't deploy it yet."
},
"needs_vector_db": {
"type": "boolean",
"default": false,
"description": "App uses a vector DB (deps qdrant-client / langchain+embeddings or QDRANT_URL)."
},
"media_mount_path": {
"type": "string",
"default": "/mnt/redu-media/uploads",
"description": "Host mount path on app members for the shared uploads filesystem. Redu mounts this into /var/www/html/wp-content/uploads."
},
"media_origin_url": {
"type": "string",
"format": "uri",
"description": "Public base URL where WordPress wp-content/uploads is served when cluster_media_mode:'central_media_origin'. Do not use the DB VM as this origin."
},
"cluster_media_mode": {
"enum": [
"local_uploads",
"central_media_origin",
"media_space"
],
"type": "string",
"default": "local_uploads",
"description": "For WordPress/WooCommerce cluster_target:true, use media_space as the default real fix: Redu creates/reuses an NFS media VM backed by a volume and mounts it at wp-content/uploads. central_media_origin is only for an already-configured external origin. local_uploads is refused at cluster time."
},
"create_media_space": {
"type": "boolean",
"default": false,
"description": "For WordPress/WooCommerce cluster_target:true: set TRUE when no suitable media space exists. The plan will include a small media VM + attached volume and deploy_app/deploy_compose will create it."
},
"media_space_flavor": {
"type": "string",
"default": "m1.small",
"description": "Preferred media VM size when create_media_space:true. Resolved against list_flavors."
},
"media_space_size_gb": {
"type": "integer",
"default": 20,
"maximum": 2048,
"minimum": 1,
"description": "Size of the media space data volume in GB when create_media_space:true."
}
},
"additionalProperties": false
}No endpoints wrapped at confidence ≥ 0.70.
Parent server
cloud.redu/mcp
1/7 registries