www/apps/cloud/app/cli/agents/page.mdx
import { Prerequisites, Note, Table, CodeTab, CodeTabs, } from "docs-ui"
export const metadata = {
title: Cloud CLI for AI Agents,
}
This guide is written for AI agents that manage Cloud resources through the Cloud CLI. It covers best practices, working principles, and common workflows for using the CLI in an agentic development context.
If you're a human user, copy the following instructions to your agent to get started:
Fetch https://docs.medusajs.com/cloud/cli/agents and set up the Medusa Cloud CLI.
You can also install the instructions in this document as a skill in your agent:
<CodeTabs group="agent-skills"> <CodeTab label="Claude Code" value="claude-code">claude # start claude code
/plugin marketplace add medusajs/medusa-agent-skills
/plugin install medusa-cloud@medusa
npx skills add medusajs/medusa-agent-skills
# choose the following skill:
# - using-medusa-cloud
AI agents should follow these defaults whenever they operate the CLI:
--json when parsing output. The plaintext output is for human readers and may change without warning; machine-readable JSON is stable and structured.mcloud whoami before any state change so you know which organization, project, and environment you'll affect.mcloud use to persist organization, project, and environment, then drop the flags from subsequent commands.get or list before any delete, redeploy, or trigger-build to verify you're targeting the right resource.--yes for irreversible operations. mcloud projects delete and mcloud environments delete require confirmation in interactive mode and refuse to run without --yes in non-interactive mode.mcloud environments delete errors on production environments by design. Do not attempt to bypass it.jq for extraction. Avoid string-parsing JSON; pipe --json output into jq for structured access.AI agents should run this one-time setup before any other CLI work, then never repeat it on the same machine. Skip the steps whose checks already pass.
Before doing anything else, check whether the CLI is already on the system:
mcloud --version
If the command exits with 0 and prints a version string, the CLI is installed. Skip the rest of this section and move on to Confirm Authentication and Context. If the command is not found, continue to the next step.
The CLI requires Node.js v22 or later. Check the installed version:
node --version
If the version is below v22, ask the user to upgrade Node.js (for example, via nvm or the official installer) and rerun the check before continuing. Do not attempt to upgrade Node.js without authorization.
Install @medusajs/mcloud globally with the user's preferred package manager:
npm install @medusajs/mcloud -g
Verify the install:
mcloud --version
A successful version string confirms the CLI is on PATH. If the command is not found, ask the user to check their global npm bin directory is on PATH or to reinstall with a different package manager.
Ask the user whether they already have a Cloud account.
If yes, run mcloud login to authenticate. The CLI opens a browser to complete the flow:
mcloud login
If no, run mcloud signup to open the sign-up page. After the user creates an account, run mcloud login:
mcloud signup
mcloud login
For non-interactive environments (CI, headless containers, restricted shells), skip the browser flow entirely and use an access key instead:
export MCLOUD_TOKEN=<access-key>
When MCLOUD_TOKEN is set, the CLI uses it on every command and mcloud login is rejected. See the login command reference for personal vs organization access keys.
Run mcloud whoami to verify authentication, then move on to setting the active context:
mcloud whoami --json
Before running any command that mutates state, AI agents should verify the active identity and scope:
mcloud whoami --json
The response includes the auth kind, expiry (for JWT-based auth), and the active organization, project, and environment. Inspect auth.kind and organization.id to assert the CLI is ready to use:
mcloud whoami --json | jq -e '.auth.kind != "none" and .organization.id != null'
Exit code 0 means authenticated and scoped; on a non-zero exit, stop and ask the user to authenticate or set the active context.
If MCLOUD_TOKEN is set, it overrides any credentials stored on disk and mcloud login is rejected. To switch accounts, unset the variable first.
AI agents should persist the active organization, project, and environment so subsequent commands can run without --organization, --project, or --environment flags. Pass values directly when running non-interactively:
mcloud use \
--organization org_123 \
--project proj_123 \
--environment env_123
If you only have names instead of IDs or handles, look them up first:
# Resolve organization ID by name
ORGANIZATION_ID=$(
mcloud organizations list --json \
| jq -r '.[] | select(.name == "My Organization") | .id'
)
# Resolve project handle by name
PROJECT_HANDLE=$(
mcloud projects list --organization "$ORGANIZATION_ID" --json \
| jq -r '.[] | select(.name == "My Store") | .handle'
)
# Resolve environment handle by name
ENVIRONMENT_HANDLE=$(
mcloud environments list --organization "$ORGANIZATION_ID" --project "$PROJECT_HANDLE" --json \
| jq -r '.[] | select(.name == "Production") | .handle'
)
mcloud use \
--organization "$ORGANIZATION_ID" \
--project "$PROJECT_HANDLE" \
--environment "$ENVIRONMENT_HANDLE"
To clear the active context (for example, before switching to a different account or organization), pass --clear:
mcloud use --clear
mcloud use without flags is interactive (it requires a TTY) and will not work inside CI runners, Docker RUN steps, or piped input. Always pass flags instead of relying on the interactive picker.
The deployment table returned by mcloud deployments list carries two computed status fields per row that AI agents should route on:
backend_status: lifecycle of the backend (build + rollout)storefront_status: lifecycle of the storefrontBoth fields use the same value set: created, building, built, deploying, deployed, build-failed, deployment-failed, timed-out (backend only), canceled, and idle. See the full reference in the deployments command guide.
Use --json and jq to filter for the relevant deployments:
# Most recent failed deployment for the active environment
mcloud deployments list --json \
| jq -r '[.[] | select(.backend_status == "build-failed" or .backend_status == "deployment-failed")][0].id'
# All deployments for a specific commit
mcloud deployments list --commit a1b2c3d --json | jq '.'
# Only preview deployments
mcloud deployments list --environment-type preview --json | jq '.'
For one specific deployment, use mcloud deployments get:
mcloud deployments get bld_01ABC123 --json
The right log source depends on the failure mode. AI agents should route on backend_status (or storefront_status):
`build-failed`
</Table.Cell>
<Table.Cell>
Build step (Docker, dependencies, compilation).
</Table.Cell>
<Table.Cell>
[`mcloud deployments build-logs`](../commands/deployments/page.mdx#deployments-build-logs)
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`deployment-failed`
</Table.Cell>
<Table.Cell>
Rollout step (the build succeeded but the runtime crashed).
</Table.Cell>
<Table.Cell>
[`mcloud logs --deployment <id>`](../commands/logs/page.mdx)
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`timed-out`
</Table.Cell>
<Table.Cell>
Build or rollout exceeded the time budget.
</Table.Cell>
<Table.Cell>
Both: `build-logs` first, then runtime `logs`.
</Table.Cell>
</Table.Row>
</Table.Body>
</Table># Find the most recent build-failed deployment
DEPLOYMENT_ID=$(
mcloud deployments list --json \
| jq -r '[.[] | select(.backend_status == "build-failed")][0].id'
)
# Inspect deployment metadata (commit, environment, timestamps)
mcloud deployments get "$DEPLOYMENT_ID" --json
# Read the build output
mcloud deployments build-logs "$DEPLOYMENT_ID"
# For storefront build failures, pass --type storefront
mcloud deployments build-logs "$DEPLOYMENT_ID" --type storefront
build-logs returns a build_status field (created, in-progress, succeeded, failed, timed-out, canceled). When failed, check the build's metadata.failed_docker_layer (visible via mcloud deployments get --json) to identify the failing layer.
When the build succeeded but the rollout failed, the build logs won't help. Read the runtime logs scoped to that deployment instead. The --deployment flag accepts both deployment IDs (depl_...) and build IDs (anything else); the CLI resolves a build ID to its latest deployment automatically.
# Find the most recent deployment-failed deployment
DEPLOYMENT_ID=$(
mcloud deployments list --json \
| jq -r '[.[] | select(.backend_status == "deployment-failed")][0].id'
)
# Read the runtime logs for that specific deployment
mcloud logs --deployment "$DEPLOYMENT_ID" --limit 1000
# Filter to error-level lines only
mcloud logs --deployment "$DEPLOYMENT_ID" --search error --limit 1000
# Filter by HTTP status (5xx)
mcloud logs --deployment "$DEPLOYMENT_ID" --metadata status=500 --limit 1000
# Machine-readable: pipe to jq for structured analysis
mcloud logs --deployment "$DEPLOYMENT_ID" --json | jq '.[] | {timestamp, source, message}'
--follow cannot be combined with --json. To process logs in a script, use a bounded time window with --from/--to and --json.
After fixing the underlying issue, AI agents have two options. They are not interchangeable:
<Table> <Table.Header> <Table.Row> <Table.HeaderCell> Command </Table.HeaderCell> <Table.HeaderCell> What it does </Table.HeaderCell> <Table.HeaderCell> When to use </Table.HeaderCell> </Table.Row> </Table.Header> <Table.Body> <Table.Row> <Table.Cell> [`mcloud environments redeploy <env>`](../commands/environments/page.mdx#environments-redeploy)
</Table.Cell>
<Table.Cell>
Re-runs the **active deployment's existing build**.
</Table.Cell>
<Table.Cell>
The fix is environment-side (variable change, infra issue) and the build itself is fine.
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
[`mcloud environments trigger-build <env>`](../commands/environments/page.mdx#environments-trigger-build)
</Table.Cell>
<Table.Cell>
Starts a **new build from the tracked branch**.
</Table.Cell>
<Table.Cell>
The fix is in the source code that's already on the tracked branch.
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>redeploy requires the environment to have an active deployment. If it doesn't, run trigger-build first to create one.
# After fixing an environment variable
mcloud environments redeploy env_123
# After pushing a fix to the tracked branch
mcloud environments trigger-build env_123
# Verify the new build is running
mcloud deployments list --environment env_123 --limit 5 --json \
| jq '.[] | {id, backend_status, commit_hash, updated_at}'
Environment variables are scoped to a single environment. AI agents should pass --reveal to print plaintext secret values only when the user has explicitly asked to see them.
# List all variables (secrets masked)
mcloud variables list --json
# Get a single variable by key (requires active project and environment)
mcloud variables get DATABASE_URL --json
# Get a single variable by ID (works without project/environment context)
mcloud variables get var_01XYZ --json
# Reveal a secret value when explicitly requested
mcloud variables get STRIPE_SECRET_KEY --reveal --json | jq -r '.value'
Avoid passing --reveal unless the user explicitly asked to see the secret value. The plaintext value is captured by terminal scrollback, log aggregators, and process listings.
To replicate a Cloud environment's variables locally, export them to a .env file:
mcloud variables list --reveal --json \
| jq -r '.[] | "\(.key)=\(.value)"' \
> .env
Use this flow when creating a preview environment for a feature branch or tearing down environments after a pull request closes:
# Create a long-lived environment that tracks a branch
mcloud environments create \
--name "Staging" \
--branch develop
# Inspect an environment's current state
mcloud environments get env_123 --json | jq '{id, name, type, status, external_id}'
# Delete an environment without prompting (production environments are protected)
mcloud environments delete env_123 --yes
environments delete returns a non-zero exit code on production environments. Always check the type field via environments get --json before attempting a delete in an automated workflow.
mcloud login (browser flow), mcloud use (without flags), and any delete command without --yes require an interactive TTY. They will error in CI runners, Docker RUN steps, or piped input.MCLOUD_TOKEN precedence. When MCLOUD_TOKEN is set, file-based credentials are ignored and mcloud login is rejected. To switch accounts, unset MCLOUD_TOKEN first.--organization (or an organization in the active context); an organization access key is already scoped to one organization. See the login reference for details.organizations list requires personal auth. Organization access keys cannot list organizations and the command will return 401. Use a personal access key or browser login to enumerate organizations.mcloud logs --deployment accepts both. IDs that start with depl are deployments; everything else is treated as a build ID and resolved to the build's latest deployment. Other commands (deployments get, deployments build-logs, environments redeploy) take build IDs only.--json and --follow are incompatible. Streaming logs with --follow always prints plaintext. For programmatic ingestion, use bounded time windows with --from/--to and --json.