Deploy websites, manage DNS, register domains, and scale infrastructure.
Captured live from the server via tools/list.
register
Register a new agent account and get an API key.
No authentication needed. The returned API key grants read+write access
to all BorealHost API endpoints. Store it securely — it cannot be
retrieved again.
The key is automatically activated for this session — all subsequent
tool calls will use it. No extra configuration needed.
If no email is provided, a synthetic agent identity is created
(agent-{uuid}@api.borealhost.ai). If an email is provided, it links
to an existing or new human account.
Args:
name: Human-readable name for this API key (default: "Agent Key")
email: Optional email to link to a human account
Returns:
{"api_key": "bh_...", "key_id": "uuid", "prefix": "bh_...",
"scopes": ["read", "write"], "account_id": "uuid",
"message": "Store this API key securely..."}
Errors:
RATE_LIMITED: Max 5 registrations per IP per hour
VALIDATION_ERROR: Invalid email format
Parameters (2)
namestring
emailstring
set_api_key
Set your BorealHost API key for this session.
Call this if you already have an API key (from a previous registration,
checkout completion, or the BorealHost panel). All subsequent tool calls
will use this key for authentication.
No need to call this after register() — the key is set automatically.
Args:
api_key: Your BorealHost API key (format: bh_<48 hex chars>)
Returns:
{"success": true, "message": "API key set for this session",
"key_prefix": "bh_..."}
Parameters (1)
api_keystringrequired
whoami
Check the current API key's account info, scopes, and site count.
Requires: BOREALHOST_API_KEY env var (read scope).
Returns:
{"user": {"id": "uuid", "email": "...", "date_joined": "iso8601"},
"api_key": {"id": "uuid", "name": "...", "prefix": "bh_...",
"scopes": ["read", "write"], "created_at": "iso8601"},
"account": {"sites": 2, "active_subscriptions": 1}}
Errors:
UNAUTHORIZED: Missing or invalid API key
No parameters.
request_api_key
Request an API key for a site you are running on (challenge-response).
This starts a two-step verification flow:
1. A claim token is written to your container at ~/.borealhost/.claim_token
(mode 600, owner admin — only readable if you're on the container)
2. Read that file and call claim_api_key(token) within 1 hour
This proves you have access to the container without storing any secrets
on disk permanently. The claim token is single-use and ephemeral.
No authentication needed — the proof is reading the file from the container.
Args:
site_slug: The site identifier (your BorealHost site slug)
Returns:
{"status": "pending", "site_slug": "my-site",
"expires_in_seconds": 3600, "claim_path": "~/.borealhost/.claim_token",
"instructions": "Read the claim token and call claim_api_key()..."}
Errors:
VALIDATION_ERROR: Unknown site slug or no active subscription
RATE_LIMITED: Too many pending claim tokens
Parameters (1)
site_slugstringrequired
claim_api_key
Claim an API key using a claim token from the container.
After calling request_api_key(), read the claim token from
~/.borealhost/.claim_token on your container and pass it here.
The token is single-use — once claimed, it cannot be used again.
The API key is automatically activated for this MCP session.
Args:
claim_token: The claim token string read from the container file
Returns:
{"api_key": "bh_...", "key_prefix": "bh_...",
"site_slug": "my-site", "scopes": ["read", "write"],
"message": "API key created and activated..."}
Errors:
VALIDATION_ERROR: Invalid, expired, or already-claimed token
Parameters (1)
claim_tokenstringrequired
list_plans
List available hosting plans with pricing and resources.
No authentication needed.
Args:
track: Filter by plan track. Valid values: "single_site", "agency".
Leave empty to list all tracks.
include_deprecated: Include deprecated plans (default: false)
Returns:
[{"slug": "site_starter", "name": "Starter", "track": "single_site",
"hosting_type": "shared", "price": {"monthly": 5, "annual": 2, "currency": "CAD"},
"resources": null, "features": {"max_sites": 1, "ai_modules": [...],
"ai_agents": [], "free_domain_annual": false}}, ...]
Parameters (2)
trackstring
include_deprecatedboolean
create_checkout
Start a new checkout session to purchase a hosting plan.
No authentication needed. After creating, call update_checkout to set
buyer info, then complete_checkout to pay.
Args:
sku: Plan SKU in format bh_{plan_slug}_{monthly|annual}.
Examples: "bh_site_starter_monthly", "bh_site_pro_annual",
"bh_site_managed_monthly", "bh_site_business_annual".
Call list_plans() to discover all available plan slugs.
Returns:
{"id": "uuid", "sku": "bh_site_starter_monthly",
"plan_slug": "site_starter", "billing_period": "monthly",
"status": "not_ready", "buyer_email": "", "requested_slug": "",
"created_at": "iso8601", "checkout_secret": "base64-token"}
Errors:
VALIDATION_ERROR: Invalid SKU format or unknown plan
RATE_LIMITED: Max 10 checkouts per IP per hour
Parameters (1)
skustringrequired
update_checkout
Set buyer email and desired site slug on a checkout session.
The checkout must be in "not_ready" status. Setting requested_slug
transitions status to "ready" (required before completing).
Args:
checkout_id: Checkout session ID from create_checkout
buyer_email: Optional email — if omitted, a synthetic agent identity
(agent-{uuid}@api.borealhost.ai) is created at completion
requested_slug: Desired site identifier. Must be 3-50 chars, lowercase
alphanumeric + hyphens, cannot start/end with hyphen.
Must be globally unique.
Returns:
{"id": "uuid", "sku": "...", "plan_slug": "...",
"billing_period": "monthly", "status": "ready",
"buyer_email": "...", "requested_slug": "my-site",
"created_at": "iso8601"}
Errors:
VALIDATION_ERROR: Invalid slug format or slug already taken
FORBIDDEN: Missing checkout_secret
NOT_FOUND: Unknown checkout_id
Parameters (3)
checkout_idstringrequired
buyer_emailstring
requested_slugstring
complete_checkout
Complete checkout with payment and start site provisioning.
The checkout must be in "ready" status.
Two payment methods:
- "stripe_checkout" (default): Returns a short, chat-safe payment URL.
**Present `payment_url` to the human — NOT `stripe_checkout_url`.**
The raw Stripe URL has a required `#fragment` that chat UIs routinely
strip when rendering markdown links, which causes Stripe to show
"page not found". `payment_url` is a short BorealHost redirect that
preserves the fragment via HTTP 302. Then poll get_checkout_status()
until status becomes "completed". The API key appears in the first
poll after payment (shown once, then cleared).
- "stripe_payment_method": Charges a Stripe PaymentMethod directly.
Requires payment_method_id. On success, returns the API key immediately.
Args:
checkout_id: Checkout session ID
payment_method: "stripe_checkout" or "stripe_payment_method"
payment_method_id: Stripe PaymentMethod ID (pm_...). Required only
for "stripe_payment_method".
Returns (stripe_checkout):
{"id": "uuid", "status": "awaiting_payment",
"payment_url": "https://borealhost.ai/pay/<id>/?s=<secret>",
"stripe_checkout_url": "https://checkout.stripe.com/c/pay/...",
"message": "Present payment_url to the human..."}
Returns (stripe_payment_method):
{"id": "uuid", "status": "completed", "api_key": "bh_...",
"api_key_message": "Store this API key securely...",
"subscription_id": "uuid", "provisioning_job_id": "uuid"}
Errors:
VALIDATION_ERROR: Missing payment_method_id for stripe_payment_method
FORBIDDEN: Checkout not in "ready" status
Parameters (3)
checkout_idstringrequired
payment_methodstring
payment_method_idstring
get_checkout_status
Poll a checkout session for status updates.
Call this after complete_checkout to track payment and provisioning.
Polling strategy:
- First 60 seconds: every 5 seconds
- After 60 seconds: every 15 seconds
- Stop after 10 minutes if not completed
Checkout statuses (in order):
- "not_ready": Missing required fields (slug)
- "ready": All fields set, awaiting payment
- "awaiting_payment": Stripe checkout page opened, waiting for human
- "in_progress": Payment received, site being provisioned
- "completed": Site ready — API key included (shown once, then cleared)
- "canceled": Checkout was abandoned
- "failed": Payment or provisioning failed
Terminal statuses: "completed", "canceled", "failed".
Args:
checkout_id: Checkout session ID
Returns (when completed):
{"id": "uuid", "status": "completed", "api_key": "bh_...",
"api_key_message": "Store this API key securely...",
"subscription_id": "uuid", "completed_at": "iso8601"}
Note: The api_key field appears ONCE in the first poll after completion,
then is permanently cleared. Store it immediately.
Parameters (1)
checkout_idstringrequired
get_site_status
Get detailed status of a hosted site including resources, domains, and modules.
Requires: API key with read scope.
Args:
slug: Site identifier (the slug chosen during checkout)
Returns:
{"slug": "my-site", "plan": "site_starter", "status": "active",
"domains": ["my-site.borealhost.ai"], "modules": {...},
"resources": {"memory_mb": 512, "cpu_cores": 1, "disk_gb": 10},
"created_at": "iso8601"}
Errors:
NOT_FOUND: Unknown slug or not owned by this account
Parameters (1)
slugstringrequired
manage_dns
Create or delete DNS records for a site.
Requires: API key with write scope.
Args:
slug: Site identifier
action: "create" or "delete"
record_type: "A", "AAAA", "CNAME", "MX", "TXT", or "SRV"
subdomain: Subdomain part (e.g. "www", "mail"). Leave empty for
the apex/root domain.
value: Record value. Required for "create". Examples:
A: "1.2.3.4", CNAME: "example.com", MX: "mail.example.com",
TXT: "v=spf1 include:_spf.google.com ~all"
ttl: Time to live in seconds (default: 3600)
Returns:
{"success": true, "record": {"type": "A", "subdomain": "www",
"value": "1.2.3.4", "ttl": 3600}}
Errors:
VALIDATION_ERROR: Missing value for create, invalid record type
NOT_FOUND: Unknown slug
Parameters (6)
slugstringrequired
actionstringrequired
record_typestringrequired
subdomainstring
valuestring
ttlinteger
deploy
Trigger a deployment for a site.
Requires: API key with write scope. This may take up to 60 seconds.
Args:
slug: Site identifier
Returns:
{"success": true, "message": "Deployment triggered"}
Errors:
NOT_FOUND: Unknown slug
Parameters (1)
slugstringrequired
install_app
Install an app template on a VPS/Cloud site.
Starts a background installation. Poll get_app_status() for progress.
Requires: API key with write scope. VPS or Cloud plan only.
Args:
slug: Site identifier
template: App template slug. Available: django, laravel, nextjs, nodejs,
nuxtjs, rails, static, forge
app_name: Short name for the app (2-50 chars, lowercase alphanumeric + hyphens).
Used as subdomain: {app_name}.{site_domain}
db_type: Database type. "none", "mysql", or "postgresql" (depends on template)
domain: Custom domain override (default: {app_name}.{site_domain})
display_name: Human-friendly name (default: derived from app_name)
Returns:
{"id": "uuid", "app_name": "forge", "status": "installing",
"message": "Installation started. Poll for progress."}
Errors:
FORBIDDEN: Plan does not support apps (shared plans)
VALIDATION_ERROR: Invalid template, app_name, or duplicate name
Parameters (6)
slugstringrequired
templatestringrequired
app_namestringrequired
db_typestring
domainstring
display_namestring
get_app_status
Get app installation status and log.
Poll this after install_app() to track progress.
Requires: API key with read scope.
Args:
slug: Site identifier
app_id: App ID from install_app() response
Returns:
{"id": "uuid", "app_name": "forge", "status": "running"|"installing"|"failed",
"install_log": "..."}
Statuses: "installing", "running", "stopped", "failed", "uninstalled"
Parameters (2)
slugstringrequired
app_idstringrequired
list_apps
List installed apps on a site.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"apps": [{"id": "uuid", "app_name": "forge", "template_slug": "forge",
"status": "running", "domain": "forge.mysite.borealhost.ai"}]}
Parameters (1)
slugstringrequired
list_snapshots
List all snapshots and scheduled snapshots for a site.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"snapshots": [{"id": "uuid", "name": "snap-...", "status": "completed",
"storage_type": "local"|"b2", "size_bytes": 1234, "size_display": "1.2 Mo",
"created_at": "iso8601"}], "scheduled": [...]}
Parameters (1)
slugstringrequired
create_snapshot
Create a local container snapshot (async).
Runs in background — returns immediately with status "creating".
Poll list_snapshots() to check when status becomes "completed" or "failed".
Available for VPS, dedicated, and cloud plans (any plan with max_snapshots > 0).
Local snapshots are stored on the host disk and count against disk quota.
Requires: API key with write scope.
Args:
slug: Site identifier
description: Optional description (max 200 chars)
Returns:
{"id": "uuid", "name": "snap-...", "status": "creating",
"storage_type": "local",
"message": "Snapshot started. Poll list_snapshots() to check status."}
Errors:
VALIDATION_ERROR: Max snapshots reached or insufficient disk quota
Parameters (2)
slugstringrequired
descriptionstring
create_b2_snapshot
Create a B2 cloud-backed snapshot (zero local disk, async).
Streams container data directly to Backblaze B2 via restic.
No local disk impact — billed separately at cost+5%.
Runs in background — returns immediately with status "creating".
Poll list_snapshots() to check when status becomes "completed".
Only available for VPS plans.
Requires: API key with write scope.
Args:
slug: Site identifier
description: Optional description (max 200 chars)
Returns:
{"id": "uuid", "name": "...", "status": "creating",
"storage_type": "b2",
"message": "B2 cloud snapshot started. Poll list_snapshots()..."}
Errors:
VALIDATION_ERROR: Not a VPS plan or max snapshots reached
Parameters (2)
slugstringrequired
descriptionstring
delete_snapshot
Delete a snapshot (local or B2).
Requires: API key with write scope.
Args:
slug: Site identifier
snapshot_id: UUID of the snapshot to delete
Returns:
{"success": true, "message": "Snapshot deleted"}
Errors:
NOT_FOUND: Snapshot not found
Parameters (2)
slugstringrequired
snapshot_idstringrequired
rollback_snapshot
Rollback a site to a previous snapshot.
WARNING: This is destructive. The current state of the container will be
replaced with the snapshot contents.
Requires: API key with admin scope.
Args:
slug: Site identifier
snapshot_id: UUID of the snapshot to rollback to
Returns:
{"success": true, "message": "Rolled back to snapshot ..."}
Errors:
NOT_FOUND: Snapshot not found or not in completed state
Parameters (2)
slugstringrequired
snapshot_idstringrequired
get_snapshot_usage
Get snapshot disk usage and quota info for a site.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"disk_quota_gb": 200, "max_snapshots": 5, "snapshot_count": 2,
"local_snapshot_bytes": 1234, "b2_snapshot_bytes": 5678,
"can_create": true}
Parameters (1)
slugstringrequired
schedule_snapshot
Schedule a snapshot for future execution.
Requires: API key with write scope. Max 3 pending schedules per site.
Args:
slug: Site identifier
scheduled_at: ISO 8601 datetime (must be in the future)
description: Optional description (max 200 chars)
Returns:
{"id": "uuid", "scheduled_at": "iso8601", "status": "scheduled"}
Errors:
VALIDATION_ERROR: Invalid datetime, not in future, or too many pending
Parameters (3)
slugstringrequired
scheduled_atstringrequired
descriptionstring
cancel_scheduled_snapshot
Cancel a scheduled snapshot.
Requires: API key with write scope.
Args:
slug: Site identifier
schedule_id: UUID of the scheduled snapshot to cancel
Returns:
{"success": true, "message": "Scheduled snapshot cancelled"}
Errors:
NOT_FOUND: Schedule not found or already executed
Parameters (2)
slugstringrequired
schedule_idstringrequired
list_backups
List all backups for a site (automatic and manual).
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
[{"id": "uuid", "backup_type": "auto"|"manual", "status": "completed",
"size_bytes": 1234, "size_display": "1.2 Mo",
"timestamp": "iso8601", "notes": "..."}]
Parameters (1)
slugstringrequired
create_backup
Create a manual backup (runs asynchronously).
The backup starts in the background. Poll list_backups() to check status.
Requires: API key with write scope.
Args:
slug: Site identifier
Returns:
{"id": "uuid", "status": "pending",
"message": "Backup started. Poll list_backups() to check status."}
Parameters (1)
slugstringrequired
restore_backup
Restore a site from a backup.
WARNING: This is destructive. The current state of the site will be
replaced. Runs asynchronously — may take several minutes.
Requires: API key with admin scope.
Args:
slug: Site identifier
backup_id: UUID of the backup to restore from
Returns:
{"success": true, "message": "Restore started..."}
Errors:
VALIDATION_ERROR: Backup not found or not in completed state
Parameters (2)
slugstringrequired
backup_idstringrequired
get_metrics
Get traffic and performance metrics for a site.
Requires: API key with read scope.
Args:
slug: Site identifier
days: Number of days of history (1–90, default: 7)
Returns:
{"requests": [...], "bandwidth": [...], "errors": [...],
"period": {"start": "iso8601", "end": "iso8601"}}
Errors:
NOT_FOUND: Unknown slug
VALIDATION_ERROR: days out of range
Parameters (2)
slugstringrequired
daysinteger
scale
Change a site's hosting plan (upgrade or downgrade).
Requires: API key with admin scope. Best practice: create a snapshot
before downgrading.
Args:
slug: Site identifier
new_plan: Target plan slug (e.g. "site_pro", "site_managed").
Call list_plans() to see available plans.
Returns:
{"success": true, "old_plan": "site_starter", "new_plan": "site_pro",
"message": "Plan changed successfully"}
Errors:
NOT_FOUND: Unknown slug
VALIDATION_ERROR: Invalid plan slug or same plan
Parameters (2)
slugstringrequired
new_planstringrequired
decommission
Delete a site and schedule resource cleanup (7-day grace period).
WARNING: This is destructive. The site will be inaccessible immediately
but data is retained for 7 days before permanent deletion.
Best practice: create a snapshot before decommissioning.
Requires: API key with admin scope.
Args:
slug: Site identifier
Returns:
{"success": true, "message": "Site scheduled for deletion",
"grace_period_days": 7}
Errors:
NOT_FOUND: Unknown slug
Parameters (1)
slugstringrequired
update_account
Update account profile fields (email, language, name).
Requires: API key with write scope.
Only provided (non-empty) fields are updated.
Args:
email: New email address
language: Language preference — "fr" (French) or "en" (English)
first_name: First name
last_name: Last name
Returns:
{"success": true, "account": {"email": "...", "language": "fr",
"first_name": "...", "last_name": "..."}}
Errors:
VALIDATION_ERROR: Invalid email format or language code
Parameters (4)
emailstring
languagestring
first_namestring
last_namestring
delete_account
Permanently anonymize the account. Cancels subscriptions, deactivates keys.
WARNING: This is irreversible. The account will be soft-deleted and all
personal data anonymized. All sites will be decommissioned.
Requires: API key with admin scope.
Returns:
{"success": true, "message": "Account anonymized"}
No parameters.
list_subscriptions
List all subscriptions with plan details, pricing, status, and site slug.
Requires: API key with read scope.
Returns:
[{"id": "uuid", "plan_slug": "site_starter", "plan_name": "Starter",
"status": "active", "billing_period": "monthly",
"price": {"amount": 500, "currency": "cad"},
"site_slug": "my-site", "created_at": "iso8601"}]
No parameters.
get_billing_portal
Get a Stripe billing portal URL for managing payment methods and invoices.
Returns a URL (not a redirect) that the human can open in a browser.
Requires: API key with read scope.
Args:
flow: Optional. Set to "payment_method_update" to go directly
to the payment method update page.
Returns:
{"url": "https://billing.stripe.com/p/session/..."}
Parameters (1)
flowstring
rotate_key
Atomically rotate an API key. Old key is immediately invalidated.
Creates a new key with the same name, scopes, and rate limits.
The new key is returned once — store it immediately.
Requires: API key with write scope.
Args:
key_id: UUID of the API key to rotate (get from whoami())
Returns:
{"api_key": "bh_...", "key_id": "uuid", "prefix": "bh_...",
"scopes": ["read", "write"], "message": "Key rotated. Store securely."}
Note: The old key stops working immediately. Update BOREALHOST_API_KEY
right away.
Parameters (1)
key_idstringrequired
create_api_key
Create a new API key with specified scopes.
Cannot create keys with higher scopes than the current key.
Site-scoped keys restrict access to a single site.
Requires: API key with write scope.
Args:
name: Human-readable name for the key (1-100 chars)
scopes: Comma-separated scopes. Options: "read", "read,write",
"read,write,admin". Default: "read"
site_slug: Optional — restrict the key to a single site.
Omit for account-wide access.
Returns:
{"api_key": "bh_...", "key_id": "uuid", "prefix": "bh_...",
"name": "My Key", "scopes": ["read", "write"],
"message": "Store this API key securely — it will not be shown again."}
Errors:
VALIDATION_ERROR: Invalid name, scopes, or max 25 active keys
FORBIDDEN: Cannot create keys with higher scopes than current key
Parameters (3)
namestringrequired
scopesstring
site_slugstring
list_api_keys
List all API keys for the account.
Shows key metadata (name, prefix, scopes, last used) but never the
full key value.
Requires: API key with read scope.
Returns:
[{"id": "uuid", "name": "My Key", "prefix": "bh_a2...",
"scopes": ["read", "write"], "is_active": true,
"created_at": "iso8601", "last_used_at": "iso8601"|null,
"site_slug": null|"my-site"}]
No parameters.
revoke_api_key
Revoke (deactivate) an API key. The key stops working immediately.
Requires: API key with write scope.
Args:
key_id: UUID of the key to revoke (from list_api_keys or whoami)
Returns:
{"success": true, "message": "API key revoked"}
Errors:
NOT_FOUND: Key not found or already revoked
Parameters (1)
key_idstringrequired
get_ssh_info
Get SSH connection info for a VPS/dedicated site.
Only available for VPS/dedicated plans (not shared hosting).
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"host": "184.107.x.x", "port": 22, "username": "admin",
"ssh_command": "ssh admin@184.107.x.x"}
Errors:
NOT_FOUND: Unknown slug
FORBIDDEN: Plan does not support SSH (shared plans)
Parameters (1)
slugstringrequired
add_ssh_key
Inject your SSH public key into a site's container for direct SSH access.
The key is appended to /home/admin/.ssh/authorized_keys.
Only available for VPS/dedicated plans.
Requires: API key with write scope.
Args:
slug: Site identifier
public_key: SSH public key string. Supported types:
ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256/384/521
Returns:
{"success": true, "message": "SSH key added",
"ssh_command": "ssh admin@184.107.x.x"}
Errors:
VALIDATION_ERROR: Invalid or unsupported key format
FORBIDDEN: Plan does not support SSH
Parameters (2)
slugstringrequired
public_keystringrequired
list_files
List files and directories in a site's container.
Path scoping depends on the plan:
- Shared plans: rooted at wp-content/ (WordPress content directory)
- VPS/dedicated plans: full filesystem access
Requires: API key with read scope.
Args:
slug: Site identifier
path: Relative path to list (empty for root of accessible area)
Returns:
{"path": "/", "entries": [{"name": "index.php", "type": "file",
"size": 1234, "modified": "iso8601"}, {"name": "uploads",
"type": "directory", "modified": "iso8601"}]}
Errors:
NOT_FOUND: Unknown slug or path doesn't exist
Parameters (2)
slugstringrequired
pathstring
read_file
Read the contents of a file from a site's container.
Max file size: 512KB. Binary files are rejected — use the site's
file manager or SSH for binary files.
Requires: API key with read scope.
Args:
slug: Site identifier
path: Relative path to the file
Returns:
{"path": "wp-config.php", "content": "<?php ...",
"size": 1234, "encoding": "utf-8"}
Errors:
NOT_FOUND: File doesn't exist
VALIDATION_ERROR: File is binary or exceeds 512KB
Parameters (2)
slugstringrequired
pathstringrequired
write_file
Write or overwrite a text file in a site's container.
Creates parent directories if they don't exist.
Requires: API key with write scope.
Args:
slug: Site identifier
path: Relative path to the file
content: File content as a UTF-8 string
Returns:
{"success": true, "path": "...", "size": 1234}
Errors:
NOT_FOUND: Unknown slug
FORBIDDEN: Protected system path
Parameters (3)
slugstringrequired
pathstringrequired
contentstringrequired
upload_file
Upload a base64-encoded file to a site's container.
Use this for binary files (images, archives, fonts, etc.).
For text files, prefer write_file().
Requires: API key with write scope.
Args:
slug: Site identifier
path: Relative path including filename (e.g. "images/logo.png")
content_b64: Base64-encoded file content
Returns:
{"success": true, "path": "images/logo.png", "size": 45678}
Errors:
VALIDATION_ERROR: Invalid base64 encoding
FORBIDDEN: Protected system path
Parameters (3)
slugstringrequired
pathstringrequired
content_b64stringrequired
delete_file
Delete a file or directory from a site's container.
Directories are deleted recursively. Protected system paths
(e.g. /etc, /usr) cannot be deleted.
Requires: API key with write scope.
Args:
slug: Site identifier
path: Relative path to delete
Returns:
{"success": true, "path": "...", "message": "Deleted"}
Errors:
NOT_FOUND: Path doesn't exist
FORBIDDEN: Protected system path
Parameters (2)
slugstringrequired
pathstringrequired
create_directory
Create a directory in a site's container.
Creates parent directories if they don't exist.
Requires: API key with write scope.
Args:
slug: Site identifier
path: Relative path of the directory to create
Returns:
{"success": true, "path": "uploads/2024", "message": "Directory created"}
Errors:
NOT_FOUND: Unknown slug
FORBIDDEN: Protected system path
Parameters (2)
slugstringrequired
pathstringrequired
list_plugins
List installed WordPress plugins with status.
Requires: API key with read scope. WordPress sites only.
Args:
slug: Site identifier
Returns:
{"plugins": [{"name": "akismet", "status": "active", "version": "5.3",
"update_available": false}, ...]}
Parameters (1)
slugstringrequired
list_themes
List installed WordPress themes with status.
Requires: API key with read scope. WordPress sites only.
Args:
slug: Site identifier
Returns:
{"themes": [{"name": "twentytwentyfour", "status": "active",
"version": "1.0", "update_available": false}, ...]}
Parameters (1)
slugstringrequired
manage_plugin
Install, activate, deactivate, or delete a WordPress plugin.
Requires: API key with write scope.
Args:
slug: Site identifier
action: "install", "activate", "deactivate", or "delete"
plugin: Plugin slug (e.g. "akismet", "jetpack", "woocommerce")
Returns:
{"action": "install", "plugin": "jetpack", "result": {...}}
Parameters (3)
slugstringrequired
actionstringrequired
pluginstringrequired
manage_theme
Install, activate, or delete a WordPress theme.
Requires: API key with write scope.
Args:
slug: Site identifier
action: "install", "activate", or "delete"
theme: Theme slug (e.g. "twentytwentyfour", "astra")
Returns:
{"action": "install", "theme": "astra", "result": {...}}
Parameters (3)
slugstringrequired
actionstringrequired
themestringrequired
wp_check_updates
Check for available WordPress core, plugin, and theme updates.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"core": {"current": "6.5", "update": "6.6"},
"plugins": [{"name": "...", "current": "1.0", "new": "1.1"}],
"themes": [...]}
Parameters (1)
slugstringrequired
wp_update_all
Update WordPress core, all plugins, and all themes.
Runs all updates in sequence. May take up to 2 minutes.
Requires: API key with write scope.
Args:
slug: Site identifier
Returns:
{"core": {...}, "plugins": [...], "themes": [...]}
Parameters (1)
slugstringrequired
list_cron
List cron jobs on a site.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"jobs": [{"line": 1, "schedule": "*/5 * * * *",
"command": "/usr/bin/php /var/www/html/wp-cron.php"}, ...]}
Parameters (1)
slugstringrequired
add_cron
Add a cron job to a site.
Requires: API key with write scope.
Args:
slug: Site identifier
schedule: Cron schedule (e.g. "*/5 * * * *", "0 2 * * *")
command: Command to execute
Returns:
{"added": true, "result": {...}}
Parameters (3)
slugstringrequired
schedulestringrequired
commandstringrequired
delete_cron
Delete a cron job by line number.
Get line numbers from list_cron().
Requires: API key with write scope.
Args:
slug: Site identifier
line_number: Line number of the cron entry to delete
Returns:
{"deleted": true}
Parameters (2)
slugstringrequired
line_numberintegerrequired
ssl_info
Get SSL certificate information for a site.
Returns certificate details, expiry date, and issuer.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"issuer": "Let's Encrypt", "domain": "example.com",
"expires_at": "iso8601", "days_remaining": 60,
"force_https": true}
Parameters (1)
slugstringrequired
ssl_renew
Force SSL certificate renewal via certbot.
Requires: API key with write scope.
Args:
slug: Site identifier
Returns:
{"renewed": true, "expires_at": "iso8601"}
Parameters (1)
slugstringrequired
list_php_versions
List available PHP versions and the currently active one.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"versions": [{"version": "8.1", "active": false},
{"version": "8.2", "active": false},
{"version": "8.3", "active": true}]}
Parameters (1)
slugstringrequired
switch_php
Switch the active PHP version for a site.
Requires: API key with write scope.
Args:
slug: Site identifier
version: Target PHP version (e.g. "8.3", "8.2", "8.1")
Returns:
{"version": "8.3", "result": {...}}
Parameters (2)
slugstringrequired
versionstringrequired
cache_status
Get cache status (Redis, WP object cache, hit rates).
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"redis_running": true, "object_cache_enabled": true,
"hit_rate": 0.95, "memory_used_mb": 12}
Parameters (1)
slugstringrequired
cache_flush
Flush all caches (Redis + WP object cache).
Requires: API key with write scope.
Args:
slug: Site identifier
Returns:
{"flushed": true}
Parameters (1)
slugstringrequired
cache_toggle
Enable or disable the WordPress object cache.
Requires: API key with write scope.
Args:
slug: Site identifier
enable: true to enable, false to disable
Returns:
{"enabled": true}
Parameters (2)
slugstringrequired
enablebooleanrequired
get_database_info
Get WordPress database information (size, tables, row counts).
Requires: API key with read scope. WordPress sites only.
Args:
slug: Site identifier
Returns:
{"database": "wp_mysite", "size_mb": 45.2,
"tables": 12, "total_rows": 15432}
Parameters (1)
slugstringrequired
optimize_database
Optimize WordPress database tables (reduces bloat).
Requires: API key with write scope.
Args:
slug: Site identifier
Returns:
{"optimized": true, "tables_optimized": 12}
Parameters (1)
slugstringrequired
database_search_replace
Search and replace in WordPress database (e.g. URL migration).
Handles serialized data safely. Use dry_run=true first to preview changes.
Requires: API key with write scope.
Args:
slug: Site identifier
old: String to search for (e.g. "http://old-domain.com")
new: Replacement string (e.g. "https://new-domain.com")
dry_run: Preview only without making changes (default: true)
Returns:
{"replacements": 42, "tables_affected": 5, "dry_run": true}
Parameters (4)
slugstringrequired
oldstringrequired
newstringrequired
dry_runboolean
list_databases
List all databases on a site's container.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"databases": ["wordpress", "app_db", ...]}
Parameters (1)
slugstringrequired
list_tables
List tables in a database.
Requires: API key with read scope.
Args:
slug: Site identifier
database: Database name
Returns:
{"tables": [{"name": "wp_posts", "rows": 1234, "size_mb": 5.2}, ...]}
Parameters (2)
slugstringrequired
databasestringrequired
execute_query
Execute a SQL query on a site's database.
Supports SELECT, INSERT, UPDATE, DELETE, and DDL statements.
Results are limited to 1000 rows for SELECT queries.
Requires: API key with write scope.
Args:
slug: Site identifier
database: Database name
query: SQL query string
Returns:
{"columns": ["id", "title"], "rows": [[1, "Hello"], ...],
"affected_rows": 0, "query_time_ms": 12}
Parameters (3)
slugstringrequired
databasestringrequired
querystringrequired
get_stack_info
Get detailed system stack information (OS, PHP, DB, web server versions).
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"os": "Debian 12", "kernel": "6.1.0",
"php": "8.3.4", "mysql": "10.11.6-MariaDB",
"nginx": "1.24.0", "wordpress": "6.5"}
Parameters (1)
slugstringrequired
get_resource_snapshot
Get current resource usage (CPU, memory, disk, load average).
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"cpu_percent": 12.5, "memory_mb": 384, "memory_total_mb": 512,
"disk_used_gb": 3.2, "disk_total_gb": 10,
"load_1m": 0.5, "load_5m": 0.3, "load_15m": 0.2}
Parameters (1)
slugstringrequired
cloudflare_proxy_status
Get Cloudflare proxy (CDN) status for a site.
Shows whether traffic is routed through Cloudflare's CDN (orange cloud)
or goes direct to origin (grey cloud / DNS-only).
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"domain": "my-site.borealhost.ai", "has_record": true,
"proxied": true, "ip": "1.2.3.4"}
Parameters (1)
slugstringrequired
cloudflare_set_proxy
Enable or disable Cloudflare CDN proxy for a site.
When enabled (orange cloud): traffic goes through Cloudflare's CDN,
gets caching, DDoS protection, and SSL termination at the edge.
When disabled (grey cloud): traffic goes directly to origin server.
Requires: API key with write scope.
Args:
slug: Site identifier
proxied: true to enable CDN proxy, false to disable
Returns:
{"domain": "my-site.borealhost.ai", "proxied": true, "ip": "1.2.3.4"}
Parameters (2)
slugstringrequired
proxiedbooleanrequired
cloudflare_purge_cache
Purge Cloudflare CDN cache for a site.
Without urls: purges all cached content for the site's subdomain.
With urls: purges only the specified URLs (max 30 per call).
Requires: API key with write scope.
Args:
slug: Site identifier
urls: Optional list of specific URLs to purge
(e.g. ["https://my-site.borealhost.ai/style.css"])
Returns:
{"purged": true, "scope": "host", "domain": "my-site.borealhost.ai"}
Parameters (2)
slugstringrequired
urlsarray
list_ftp_accounts
List FTP accounts on a site.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"accounts": [{"username": "ftpuser", "home": "/var/www/html", "uid": 1001}]}
Parameters (1)
slugstringrequired
create_ftp_account
Create an FTP account on a site.
The user is chrooted to the specified directory. Password must be
at least 8 characters. Username must be lowercase alphanumeric.
Requires: API key with write scope.
Args:
slug: Site identifier
username: FTP username (lowercase, max 32 chars)
password: Password (min 8 chars)
home_dir: Chroot directory (default: /var/www/html)
Returns:
{"success": true, "username": "ftpuser", "home_dir": "/var/www/html"}
Parameters (4)
slugstringrequired
usernamestringrequired
passwordstringrequired
home_dirstring
remove_ftp_account
Remove an FTP account from a site.
Requires: API key with write scope.
Args:
slug: Site identifier
username: FTP username to remove
Returns:
{"removed": true, "username": "ftpuser"}
Parameters (2)
slugstringrequired
usernamestringrequired
list_alert_rules
List user-configurable alert rules for a site.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
[{"id": "uuid", "metric": "disk", "operator": "gt",
"threshold": 90, "severity": "warning", "enabled": true,
"cooldown_minutes": 30, "notify_email": true}]
Parameters (1)
slugstringrequired
create_alert_rule
Create an alert rule to monitor CPU, memory, or disk usage.
When the metric crosses the threshold, a notification is sent via
email and/or webhook. Max 10 rules per site.
Requires: API key with write scope.
Args:
slug: Site identifier
metric: "cpu", "memory", or "disk" (percentage-based)
threshold: Threshold value 0-100 (e.g. 90 for 90%)
operator: "gt" (greater than) or "lt" (less than). Default: "gt"
severity: "warning" or "critical". Default: "warning"
cooldown_minutes: Min minutes between repeated alerts. Default: 30
notify_email: Send email notification. Default: true
notify_webhook: Optional webhook URL for POST notifications
Returns:
{"id": "uuid", "metric": "disk", "threshold": 90, ...}
Parameters (8)
slugstringrequired
metricstringrequired
thresholdnumberrequired
operatorstring
severitystring
cooldown_minutesinteger
notify_emailboolean
notify_webhookstring
delete_alert_rule
Delete an alert rule.
Requires: API key with write scope.
Args:
slug: Site identifier
rule_id: UUID of the alert rule to delete
Returns:
{"deleted": true, "id": "uuid"}
Parameters (2)
slugstringrequired
rule_idstringrequired
run_malware_scan
Run a ClamAV malware scan on a site's container.
Scans the web root (or specified path) for malware, viruses, and trojans.
ClamAV is installed automatically if not present. Excludes node_modules,
vendor, .git, and cache directories.
May take up to 5 minutes for large sites.
Requires: API key with write scope.
Args:
slug: Site identifier
path: Directory to scan (default: /var/www/html)
Returns:
{"infected_files": [{"path": "/var/www/html/shell.php", "threat": "Php.Malware.Agent"}],
"scanned_count": 1234, "infected_count": 1, "scan_time_s": 45.2}
Parameters (2)
slugstringrequired
pathstring
list_firewall_rules
List IP allow/deny firewall rules for a site.
Rules are implemented as Nginx allow/deny directives per container.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"rules": [{"ip": "1.2.3.4", "action": "deny"},
{"ip": "10.0.0.0/8", "action": "allow"}]}
Parameters (1)
slugstringrequired
add_firewall_rule
Add an IP firewall rule (allow or deny) and reload Nginx.
Supports IPv4, IPv6, and CIDR notation. Max 100 rules per site.
If a rule already exists for the IP, the action is updated.
Requires: API key with write scope.
Args:
slug: Site identifier
ip: IP address or CIDR (e.g. "1.2.3.4", "10.0.0.0/8", "2001:db8::/32")
action: "deny" (block) or "allow" (whitelist). Default: "deny"
Returns:
{"added": true, "ip": "1.2.3.4", "action": "deny"}
Parameters (3)
slugstringrequired
ipstringrequired
actionstring
remove_firewall_rule
Remove an IP firewall rule and reload Nginx.
Requires: API key with write scope.
Args:
slug: Site identifier
ip: IP address or CIDR to remove (must match exactly)
Returns:
{"removed": true, "ip": "1.2.3.4"}
Parameters (2)
slugstringrequired
ipstringrequired
get_logs
Retrieve container logs (error, access, or PHP).
Requires: API key with read scope.
Args:
slug: Site identifier
log_type: "error" (Nginx/Apache errors), "access" (HTTP request log),
or "php" (PHP-FPM errors, WordPress sites only)
lines: Number of lines to retrieve (1–500, default: 100)
search: Optional keyword filter — only lines containing this string
Returns:
{"log_type": "error", "lines": ["2024-01-15 ... error ...", ...],
"count": 42, "truncated": false}
Errors:
NOT_FOUND: Unknown slug
VALIDATION_ERROR: Invalid log_type or lines out of range
Parameters (4)
slugstringrequired
log_typestring
linesinteger
searchstring
list_domains
List all domains owned by the authenticated user.
Requires: API key with read scope.
Returns:
[{"domain": "example.com", "status": "active",
"expires_at": "iso8601", "auto_renew": true,
"linked_site": "my-site"}]
No parameters.
search_domain
Check domain availability and get pricing.
Requires: API key with read scope.
Args:
domain: Full domain name (e.g. "example.com", "mybiz.ca")
Returns:
{"domain": "example.com", "available": true,
"price": {"amount": 15.99, "currency": "CAD", "period": "1 year"},
"premium": false}
Note: .ca domains require ca_legal_type when registering.
Parameters (1)
domainstringrequired
register_domain
Register a new domain with WHOIS contact info and Stripe billing.
The domain cost is charged to the user's active subscription.
Free domain if plan includes free_domain_annual + annual billing + first domain.
Requires: API key with write scope.
Args:
domain: Full domain name (e.g. "example.ca", "mybusiness.com")
first_name: Registrant first name
last_name: Registrant last name
email: Registrant email address
phone: Phone number in E.164 format: "+1.5145551234"
address1: Street address (e.g. "123 Rue Principale")
city: City (e.g. "Montreal")
state: Province/state code (e.g. "QC", "ON", "BC")
postal_code: Postal/ZIP code (e.g. "H2X 1Y4")
country: ISO 3166-1 alpha-2 country code (default: "CA")
period: Registration period in years (1–10, default: 1)
ca_legal_type: Required for .ca domains. CIRA legal types:
"CCO" (Canadian citizen), "RES" (permanent resident),
"CCT" (corporation), "GOV" (government), "EDU" (education),
"ASS" (association), "HOP" (hospital), "PRT" (partnership),
"TDM" (trademark), "TRD" (trade union), "PLT" (political party),
"LAM" (library/archive/museum), "MAJ" (Her Majesty),
"INB" (Indian band), "ABO" (Aboriginal peoples),
"LGR" (legal representative)
Returns:
{"domain": "example.ca", "status": "registered",
"expires_at": "iso8601", "message": "Domain registered successfully"}
Errors:
VALIDATION_ERROR: Missing required fields, invalid phone format,
missing ca_legal_type for .ca domains
NOT_FOUND: Domain not available (already registered by someone else)
Parameters (12)
domainstringrequired
first_namestringrequired
last_namestringrequired
emailstringrequired
phonestringrequired
address1stringrequired
citystringrequired
statestringrequired
postal_codestringrequired
countrystring
periodinteger
ca_legal_typestring
domain_detail
Get full domain details including DNS and infrastructure status.
Requires: API key with read scope.
Args:
domain_name: Full domain name (e.g. "example.com")
Returns:
{"domain": "example.com", "status": "active",
"expires_at": "iso8601", "auto_renew": true,
"nameservers": ["ns1.borealhost.ai", "ns2.borealhost.ai"],
"dns_records": [...], "linked_site": "my-site"}
Errors:
NOT_FOUND: Domain not owned by this account
Parameters (1)
domain_namestringrequired
link_domain
Link a domain to a hosted site.
Attaches the domain to the specified site and triggers automatic
DNS configuration and SSL provisioning.
Requires: API key with write scope.
Args:
domain_name: Full domain name (e.g. "example.com")
site_slug: Site identifier to link the domain to
Returns:
{"success": true, "domain": "example.com",
"linked_site": "my-site", "message": "Domain linked"}
Errors:
NOT_FOUND: Domain or site not found
VALIDATION_ERROR: Domain already linked to another site
Parameters (2)
domain_namestringrequired
site_slugstringrequired
domain_settings
Update domain settings (auto-renew, WHOIS privacy, registrar lock).
Only provided (non-None) fields are updated.
Requires: API key with write scope.
Args:
domain_name: Full domain name (e.g. "example.com")
auto_renew: Enable/disable automatic renewal
whois_privacy: Enable/disable WHOIS privacy protection
locked: Enable/disable registrar lock (prevents unauthorized transfers)
Returns:
{"success": true, "domain": "example.com",
"auto_renew": true, "whois_privacy": true, "locked": true}
Errors:
NOT_FOUND: Domain not found or not owned by account
Parameters (4)
domain_namestringrequired
auto_renewboolean
whois_privacyboolean
lockedboolean
list_domain_dns
List all DNS records for a domain.
Returns DNS records at the domain level (independent of site-level
manage_dns). Use this for domains that may not be linked to a site.
Requires: API key with read scope.
Args:
domain_name: Full domain name (e.g. "example.com")
Returns:
[{"id": "record-id", "type": "A", "subdomain": "www",
"value": "1.2.3.4", "ttl": 3600}]
Errors:
NOT_FOUND: Domain not found or not owned by account
Parameters (1)
domain_namestringrequired
add_domain_dns
Add a DNS record to a domain.
Requires: API key with write scope.
Args:
domain_name: Full domain name (e.g. "example.com")
record_type: "A", "AAAA", "CNAME", "MX", "TXT", or "SRV"
value: Record value (e.g. "1.2.3.4" for A, "mail.example.com" for MX)
subdomain: Subdomain part (e.g. "www", "mail"). Empty for apex domain.
ttl: Time to live in seconds (default: 3600)
priority: MX priority (required for MX records)
Returns:
{"success": true, "record": {"id": "...", "type": "A",
"subdomain": "www", "value": "1.2.3.4", "ttl": 3600}}
Errors:
VALIDATION_ERROR: Missing value, invalid record type
NOT_FOUND: Domain not found
Parameters (6)
domain_namestringrequired
record_typestringrequired
valuestringrequired
subdomainstring
ttlinteger
priorityinteger
delete_domain_dns
Delete a DNS record from a domain.
Requires: API key with write scope.
Args:
domain_name: Full domain name (e.g. "example.com")
record_id: ID of the DNS record to delete (from list_domain_dns)
Returns:
{"success": true, "message": "DNS record deleted"}
Errors:
NOT_FOUND: Domain or record not found
Parameters (2)
domain_namestringrequired
record_idstringrequired
list_modules
List AI modules and their enabled/disabled state for a site.
Also returns the list of modules available for the site's plan.
Requires: API key with read scope.
Args:
slug: Site identifier
Returns:
{"modules": {"chatbot": true, "seo": false, "translation": false,
"content": false}, "available": ["chatbot", "seo", "translation", "content"]}
Errors:
NOT_FOUND: Unknown slug
Parameters (1)
slugstringrequired
toggle_module
Enable or disable an AI module on a site.
The module must be in the plan's available module list.
Requires: API key with write scope.
Args:
slug: Site identifier
module_name: Module to toggle. Available modules:
"chatbot" (AI chat widget), "seo" (SEO optimization),
"translation" (content translation), "content" (AI content generation)
Returns:
{"module": "chatbot", "enabled": true, "message": "Module enabled"}
Errors:
NOT_FOUND: Unknown slug or module not in plan
VALIDATION_ERROR: Invalid module name
Connect any MCP-compatible AI agent to BorealHost.ai — purchase hosting, deploy sites, manage DNS, register domains, and scale infrastructure, entirely through tool calls.
Quick Start
Remote Server (Recommended)
No installation needed. Connect directly to the hosted server: