Deploy AI-built sites and apps to EU hosting from your AI agent. OAuth sign-in, 14-day free trial.
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Discard a begin_deploy session and its staged files; the live site is untouched. Cleanup is best effort and retried later if it fails.
Session id returned by begin_deploy.
This tool isn't marked read-only, so it may change something on the server or in an account you connected.
Discard a begin_deploy session and its staged files; the live site is untouched. Cleanup is best effort and retried later if it fails.
| Argument | Type | Description |
|---|---|---|
| deployId* | string | Session id returned by begin_deploy. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"deployId"
],
"properties": {
"deployId": {
"type": "string",
"description": "Session id returned by begin_deploy."
}
}
}Start attaching a user-owned domain to an existing site: returns the DNS records the user adds at their DNS provider (a routing record that sends visitors here, plus a TXT that proves ownership). Idempotent: the same siteName and domain return the existing record. Once the records are published (usually minutes, up to 24h), call verify_custom_domain with the returned recordId; VibeDeploy also re-checks automatically for a few days and emails the user when the domain is live. The site must already exist; call deploy_site first if it does not.
| Argument | Type | Description |
|---|---|---|
| domain* | string | The user-owned hostname to attach, e.g. 'shop.example.com'. Must be a valid FQDN. |
| siteName* | string | The VibeDeploy site name to attach the domain to (e.g. 'tester'). |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"siteName",
"domain"
],
"properties": {
"domain": {
"type": "string",
"description": "The user-owned hostname to attach, e.g. 'shop.example.com'. Must be a valid FQDN."
},
"siteName": {
"type": "string",
"description": "The VibeDeploy site name to attach the domain to (e.g. 'tester')."
}
}
}Send one file in several calls when it is too big for a single tool call. Last resort: first try add_files with encoding:'gzip+base64' (about 250 KB of text in one call), begin_deploy's uploadUrl (one 100 MB tar POST) or deploy_from_url (public archive URL). When chunking, gzip+base64 each chunk too, mark the first with isFirst and the last with isLast, and send chunks of one file one after another: parallel chunks corrupt it. After a transport error, do not resend the chunk blindly: restart the file from its first chunk (isFirst truncates it).
| Argument | Type | Description |
|---|---|---|
| path* | string | Path relative to the site root, e.g. 'portaal-admin.html'. Same rules as add_files. |
| isLast* | boolean | True on the final chunk: returns the assembled file size and refreshes the session file count. |
| content* | string | This chunk's bytes, as UTF-8 text or encoded per encoding. Chunk size is limited by your client's tool-output budget, not by the server: about 80 KB of base64 (60 KB raw) per chunk is a safe upper bound. |
| isFirst* | boolean | True on the first chunk of a file: truncates any staged file at this path and creates parent directories. |
| deployId* | string | Session id returned by begin_deploy. |
| encoding | string | utf8 (default), base64 (binary), or gzip+base64 (gzip this chunk locally; the server gunzips before appending). Set per chunk. |
Add files to an open begin_deploy session; call it as often as needed, then commit_deploy publishes them together. Paths, extensions and encodings are checked on every call. A 100-250 KB text file usually fits in one call with encoding:'gzip+base64' (gzip locally, then base64); prefer that over add_file_chunk. If your shell can reach mcp.vibedeploy.be, one tar(.gz) POST to begin_deploy's uploadUrl is faster still.
| Argument | Type | Description |
|---|---|---|
| files* | any | Files to stage, same shape as in deploy_site. Re-adding a path overwrites the staged version. 500 MB per session in total. |
| deployId* | string | Session id returned by begin_deploy. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"deployId",
"files"
],
"properties": {
"files": {
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"required": [
"path",
"content"
],
"properties": {
"path": {
"type": "string",
"description": "Path relative to the site root, e.g. index.html or assets/app.js. Plain ASCII, no leading slash."
},
"content": {
"type": "string",
"description": "File content: text, or base64 as set by encoding."
},
"encoding": {
"enum": [
"utf8",
"base64",
"gzip+base64"
],
"type": "string",
"description": "utf8 (default), base64 (binary files), or gzip+base64 (gzip locally, then base64; fits 3-5x more text per call)."
}
}
},
"description": "Array form; needed for binary files."
},
{
"type": "object",
"description": "Map form: path to UTF-8 text.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
}
],
"description": "Files to stage, same shape as in deploy_site. Re-adding a path overwrites the staged version. 500 MB per session in total."
},
"deployId": {
"type": "string",
"description": "Session id returned by begin_deploy."
}
}
}Apply literal find/replace edits to several files in one call, in the served files (target 'dist', live at once) or the editable source (target 'source', shipped by build_and_deploy). Same edit rules as update_file_content. All or nothing: if any edit's match count differs from its expected count, no file is written.
| Argument | Type | Description |
|---|---|---|
| name* | string | Site name as shown by list_sites, e.g. my-portfolio. |
| files* | array | Files + edits to apply. Up to 25 files / 200 total edits per call. All-or-nothing: if any edit's match count differs from its expected count, NOTHING is written. |
| target | string | Tree to edit, dist (default) or source. Same tree applies to every file in this call. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"files"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio."
},
"files": {
"type": "array",
"items": {
"type": "object",
"required": [
"path",
"edits"
],
"properties": {
"path": {
"type": "string",
"description": "Path inside the chosen tree, e.g. index.html."
},
"edits": {
"type": "array",
"items": {
"type": "object",
"required": [
"find",
"replace"
],
"properties": {
"find": {
"type": "string",
"maxLength": 65536,
"minLength": 1,
"description": "Literal text to find (not a regex). Max 64 KB."
},
"count": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Expected matches: default 1, -1 = replace all, or an exact number."
},
"replace": {
"type": "string",
"maxLength": 65536,
"description": "Literal replacement; empty string deletes the match. Max 64 KB."
}
}
},
"minItems": 1,
"description": "Ordered edits applied to THIS file's current state."
}
}
},
"maxItems": 25,
"minItems": 1,
"description": "Files + edits to apply. Up to 25 files / 200 total edits per call. All-or-nothing: if any edit's match count differs from its expected count, NOTHING is written."
},
"target": {
"enum": [
"dist",
"source"
],
"type": "string",
"description": "Tree to edit, dist (default) or source. Same tree applies to every file in this call."
}
}
}Open a staging session for a deploy that is too large for one call: stage files with add_files (repeatable), add_file_chunk, or one tar(.gz) POST to the returned uploadUrl, then publish with commit_deploy. Use begin_deploy only when the files do not fit in one deploy_site or update_site call. Up to 5 open sessions per token; a session expires after 1 hour.
| Argument | Type | Description |
|---|---|---|
| mode* | string | How commit_deploy will apply the staged files. 'replace' wipes the live site and atomic-renames the staged set into place. 'patch' layers staged files on top of the live site (kept files = live + staged; deletes via commit_deploy's `delete` array). |
| name* | string | Name of an existing site (see list_sites). Sessions do not create sites; deploy_site does. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"mode"
],
"properties": {
"mode": {
"enum": [
"replace",
"patch"
],
"type": "string",
"description": "How commit_deploy will apply the staged files. 'replace' wipes the live site and atomic-renames the staged set into place. 'patch' layers staged files on top of the live site (kept files = live + staged; deletes via commit_deploy's `delete` array)."
},
"name": {
"type": "string",
"description": "Name of an existing site (see list_sites). Sessions do not create sites; deploy_site does."
}
}
}Build the site's stored editable source in an isolated one-shot build pod and atomically publish the output as the live site, replacing the served files (a restore point is normally taken first). Use build_and_deploy after changing stored source (write_source_files, apply_edits with target 'source'); use update_site instead to upload files that are already built. The first build saves buildCommand, outputDir and rootPath on the site, so later calls can omit them. A failed build returns its log in the error details.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| rootPath | string | Subdirectory of the source tree that holds package.json (monorepos). Empty string = source root. |
| outputDir | string | Directory to publish. Default: the saved manifest, then auto-detect (dist > build > out > public). |
| buildCommand | string | Build command override, e.g. 'npm run build:prod' or 'pnpm vite build'. Default: the saved manifest, then 'npm run build'. |
| saveManifest | boolean | Default true: save these settings on the site for later builds. false = one-off build. |
Check whether a domain can be registered and get an indicative price (VAT included where it applies). Read-only: it never buys, registers or reserves a domain. alternatives:true also checks the same name on be, com, net, eu, nl, io, dev and app. Not tied to a site. The result states whether the user's plan includes buying domains in the dashboard (purchase.dashboardUrl); a domain the user already owns is connected with add_custom_domain.
| Argument | Type | Description |
|---|---|---|
| domain* | string | The domain to check, e.g. "example.com". |
| alternatives | boolean | When true, also check the same second-level name across a canonical TLD set (be, com, net, eu, nl, io, dev, app) and return each one's availability + indicative price. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"domain"
],
"properties": {
"domain": {
"type": "string",
"description": "The domain to check, e.g. \"example.com\"."
},
"alternatives": {
"type": "boolean",
"description": "When true, also check the same second-level name across a canonical TLD set (be, com, net, eu, nl, io, dev, app) and return each one's availability + indicative price."
}
}
}Publish a begin_deploy session's staged files to the live site in one atomic step, after a secret and malware scan of the complete set (on failure the session stays open to retry or abort). Replace mode on a site that has files needs confirm:"I-want-to-replace-all-files". After a timeout or dropped connection, call it again with the same deployId: it returns the running or finished commit instead of starting a second one. Use commit_deploy only to finish a begin_deploy session; deploy_site and update_site publish in one call.
| Argument | Type | Description |
|---|---|---|
| delete | array | Patch mode only: site-relative paths to remove from the live site in this commit (e.g. the old path of a renamed file). |
| dryRun | boolean | Preview the commit (filesDeployed, deletedFiles, confirm and plan checks) without touching the live site. Skips the secret and malware scan, which the real commit still runs. |
| confirm | string | Required only for replace-mode commits against a site that already has files. Pass exactly "I-want-to-replace-all-files" to acknowledge that the live files will be deleted and replaced with the staged set. |
| deployId* | string | Session id returned by begin_deploy. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"deployId"
],
"properties": {
"delete": {
"type": "array",
"items": {
"type": "string"
},
"description": "Patch mode only: site-relative paths to remove from the live site in this commit (e.g. the old path of a renamed file)."
},
"dryRun": {
"type": "boolean",
"description": "Preview the commit (filesDeployed, deletedFiles, confirm and plan checks) without touching the live site. Skips the secret and malware scan, which the real commit still runs."
},
"confirm": {
"type": "string",
"const": "I-want-to-replace-all-files",
"description": "Required only for replace-mode commits against a site that already has files. Pass exactly \"I-want-to-replace-all-files\" to acknowledge that the live files will be deleted and replaced with the staged set."
},
"deployId": {
"type": "string",
"description": "Session id returned by begin_deploy."
}
}
}Take a point-in-time snapshot of a site's served files, a restore point the user can restore in the VibeDeploy dashboard within the plan's restore window. Served content does not change, but retention cleanup may remove older snapshots. Container data is not included. Requires an owner or admin team role. NO_VOLUME means the site was never deployed.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| label | string | Optional human-readable label for this snapshot. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"label": {
"type": "string",
"maxLength": 200,
"description": "Optional human-readable label for this snapshot."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Soft-delete a site (confirm:true required). It stops serving at once and is purged after the plan's restore window (purgesAt in the result); until then the user can restore it in the VibeDeploy dashboard. Use delete_site to remove the whole site; use remove_app instead to stop only its container services.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| confirm* | boolean | Must be exactly true to actually delete the site. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"confirm"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"confirm": {
"type": "boolean",
"const": true,
"description": "Must be exactly true to actually delete the site."
}
}
}Remove one file from the site's editable source tree. The served files do not change until build_and_deploy runs.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| path* | string | Path inside the source tree to delete, e.g. 'src/old.css'. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"path"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"path": {
"type": "string",
"description": "Path inside the source tree to delete, e.g. 'src/old.css'."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Run container services next to a site, from any public image: the user's own server (running code from the site's source tree), a database such as Postgres or MySQL, Redis, or workers, each in a gVisor sandbox. The call applies the whole config: services missing from it are stopped (their volumes are kept) and the others restart, picking up new source files. It waits until every service is ready and returns per-service status; if one is not ready, call get_app_status with logs. One service may be public: it serves the site's HTTP traffic on its port. Use "${generated:NAME}" for database passwords. API keys and other outside secrets never go in the config, the source or the chat: the user adds them in the VibeDeploy dashboard (site Settings, Secrets) and every service receives them as environment variables. Per site: up to 6 services, 2048Mi memory and 2000m CPU in total, 4 volumes, 3Gi storage. Container volumes are not included in snapshots yet.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| config | object | The app config; omit it to use vibedeploy.json from the site's source tree. Shape: {"services":{"<name>":{"image":"postgres:16-alpine","port":5432,"public":false,"env":{"KEY":"value"},"volumes":{"/var/lib/postgresql/data":"1Gi"},"command":[],"args":[],"workingDir":"/app","source":false,"sourcePath":"/app","memory":"256Mi","cpu":"500m"}}}. Services reach each other by name (host "db"). "source":true copies the source tree into sourcePath on every start, e.g. {"image":"node:22-alpine","source":true,"command":["sh","-c","npm ci && node server.js"],"port":3000,"public":true}. "$(OTHER)" embeds an earlier env var of the same service, e.g. "DATABASE_URL":"postgres://app:$(DB_PASSWORD)@db:5432/app". For Postgres set PGDATA to a subdirectory of the volume. |
| siteId |
Fetch a public tar(.gz) archive over HTTPS and deploy its files to an existing site in one call (begin_deploy, upload and commit_deploy combined). Use deploy_from_url when the files are already published at a public URL, such as a repository archive that holds only the built site (no dotfiles), or when your sandbox reaches the allowed hosts (listed under archiveUrl) but not mcp.vibedeploy.be; otherwise use deploy_site or update_site. In replace mode one top-level folder that wraps every file (as in repository archives) is removed, and a site that already has files needs confirm:"I-want-to-replace-all-files". A failed call never leaves a staging session open.
| Argument | Type | Description |
|---|---|---|
| mode* | string | replace: the archive becomes the whole site (other files are removed). patch: the archive's files are added or overwritten, the rest stays. |
| name* | string | Name of an existing site (see list_sites). This tool does not create sites. |
| confirm | string | Required only for mode "replace" on a site that already has files. Pass exactly "I-want-to-replace-all-files" to acknowledge that the live files will be deleted and replaced with the archive's files. |
| archiveUrl* | string | Public HTTPS URL of a tar or tar.gz archive (max 100 MB, 60 s). Allowed hosts, also for every redirect: github.com, codeload.github.com, *.githubusercontent.com, gist.github.com, gitlab.com, bitbucket.org, codeberg.org, *.amazonaws.com, *.r2.cloudflarestorage.com, *.backblazeb2.com, *.workers.dev, *.pages.dev, transfer.sh, 0x0.st, mcp.vibedeploy.be. GitHub, GitLab and Codeberg archive links (e.g. https://github.com/<owner>/<repo>/archive/refs/heads/main.tar.gz) are accepted, but the normal file rules apply: any dotfile except .well-known/ (such as .gitignore, .github/, .gitlab-ci.yml) or any file type outside the allowlist (such as .ts, .tsx, .yml) rejects the whole archive with INVALID_FILE_TYPE. Replace mode removes only the one wrapping folder, so the built site must sit at the repository root. |
Publish a static site or single-page app to a live HTTPS URL on the account's platform subdomain (e.g. {name}.vibedeploy.be). A new name creates the site. An existing name REPLACES EVERY FILE (files not in this call are deleted) and needs confirm:"I-want-to-replace-all-files"; preview with dryRun:true. Use update_site instead to change some files of an existing site. A 100-250 KB text file fits in this call with encoding:'gzip+base64' (gzip locally, then base64); use begin_deploy only when the files do not fit in one call. Ship a top-level 404.html for multi-page sites (otherwise unknown paths serve index.html) and use plain ASCII file names. Afterwards add_custom_domain can serve the site on the user's own domain.
| Argument | Type | Description |
|---|---|---|
| name* | string | Site subdomain. Lowercase, 3-63 chars, alphanumeric + hyphens. Must not start or end with a hyphen. |
| files* | any | Either an array of {path, content, encoding?} entries OR a path->content map. Total payload <= 500 MB. |
| dryRun | boolean | Validate and preview without writing; deletedFiles lists what would be removed. Recommended before replacing an existing site. |
| confirm | string | Required when the site already exists: exactly "I-want-to-replace-all-files", confirming that every existing file is deleted and replaced. Omit for a new site. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"files"
],
"properties": {
"name": {
"type": "string",
"description": "Site subdomain. Lowercase, 3-63 chars, alphanumeric + hyphens. Must not start or end with a hyphen."
},
"files": {
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"required": [
"path",
"content"
],
"properties": {
"path": {
"type": "string",
"description": "Path relative to the site root, e.g. index.html or assets/app.js. Plain ASCII, no leading slash."
},
"content": {
"type": "string",
"description": "File content: text, or base64 as set by encoding."
},
"encoding": {
"enum": [
"utf8",
"base64",
"gzip+base64"
],
"type": "string",
"description": "utf8 (default), base64 (binary files), or gzip+base64 (gzip locally, then base64; fits 3-5x more text per call)."
}
}
},
"description": "Array form; needed for binary files."
},
{
"type": "object",
"description": "Map form: path to UTF-8 text.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
}
],
"description": "Either an array of {path, content, encoding?} entries OR a path->content map. Total payload <= 500 MB."
},
"dryRun": {
"type": "boolean",
"description": "Validate and preview without writing; deletedFiles lists what would be removed. Recommended before replacing an existing site."
},
"confirm": {
"type": "string",
"const": "I-want-to-replace-all-files",
"description": "Required when the site already exists: exactly \"I-want-to-replace-all-files\", confirming that every existing file is deleted and replaced. Omit for a new site."
}
}
}Return the team's plan, its limits, current usage, the trial end date and the per-token MCP rate limit. Call it before deploy_site or add_custom_domain to check a plan limit instead of running into PLAN_LIMIT_EXCEEDED.
No arguments.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {}
}Show the site's container services: per-service status (ready, restarts, waiting or crash reasons, volumes), the stored config, the names of the site secrets that are set (never values) with the dashboard link where the user adds them, and optionally the recent logs of one service. Use get_app_status instead of get_site for anything about containers.
| Argument | Type | Description |
|---|---|---|
| logs | string | Service name to include recent logs for (includes the previous crashed container if it restarted). |
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| tail | integer | Log lines to return. Default 200. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"logs": {
"type": "string",
"description": "Service name to include recent logs for (includes the previous crashed container if it restarted)."
},
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"tail": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Log lines to return. Default 200."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Read the form-to-email relay config of a site, plus the resolved delivery mode, the active From address, and (for a custom sender domain) the DNS records to publish and their verification status. The submission format for the site's form is described under set_forms_config.
| Argument | Type | Description |
|---|---|---|
| siteName* | string | The site whose forms-relay config to read. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"siteName"
],
"properties": {
"siteName": {
"type": "string",
"description": "The site whose forms-relay config to read."
}
}
}Return one site's details: live URL, status, plan, served file paths, whether editable source is stored (and its build settings), custom domains, bandwidth and the last 10 deploys. Use get_site to inspect a site before editing it; use list_sites to find site names, and get_app_status for container services.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Return a privacy-safe traffic summary for a site over the last `period` days (default 7): total page views, distinct-visitor count, top pages, daily counts, device/browser breakdowns, and Web Vitals averages. Never exposes raw visitor IPs or user-agents.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| period | integer | Number of days to aggregate over (1-90). Defaults to 7. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"period": {
"type": "integer",
"maximum": 90,
"minimum": 1,
"description": "Number of days to aggregate over (1-90). Defaults to 7."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Return all custom domains attached to a site, both those added with add_custom_domain (source 'mcp', with a recordId for verify_custom_domain or remove_custom_domain) and those linked in the VibeDeploy dashboard (source 'dashboard', verified or removed on the dashboard Web Addresses page at manageUrl). Call it before add_custom_domain to avoid adding a domain twice.
| Argument | Type | Description |
|---|---|---|
| siteName* | string | The site whose custom domains to list. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"siteName"
],
"properties": {
"siteName": {
"type": "string",
"description": "The site whose custom domains to list."
}
}
}List the team's begin_deploy staging sessions, by default the active ones (open and committing), up to 50. Useful after a crash or restart to commit or abort leftovers.
| Argument | Type | Description |
|---|---|---|
| status | string | Filter by status. Default lists 'open' and 'committing' (the actionable ones). Pass an explicit status to inspect history. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"status": {
"enum": [
"open",
"committing",
"committed",
"aborted",
"expired"
],
"type": "string",
"description": "Filter by status. Default lists 'open' and 'committing' (the actionable ones). Pass an explicit status to inspect history."
}
}
}Read the DNS records VibeDeploy tracks for a site (host, type, value), oldest first, including custom-domain verification records. Read-only: it never creates, changes or deletes a DNS record.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Return SHA-256 and size of every served file. Before a redeploy, hash your local files, compare, and upload only the changed ones with update_site mode:'patch' or begin_deploy plus add_files.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Return the site's last 50 deploy and snapshot entries, newest first: how each was triggered, label, snapshot name, file count and secrets detected. Each entry's snapshot holds the content from BEFORE that entry. Restoring is done by the user in the VibeDeploy dashboard within the plan's restore window; there is no restore tool.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}List the team's sites (name, URL, status, last deploy), most recently updated first, up to 100. Use list_sites to find a site name; use get_site for one site's files, source status and history.
| Argument | Type | Description |
|---|---|---|
| includeDeleted | boolean | If true, also list soft-deleted sites still inside their plan's restore window (status 'deleted'). Default false. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"includeDeleted": {
"type": "boolean",
"description": "If true, also list soft-deleted sites still inside their plan's restore window (status 'deleted'). Default false."
}
}
}List the snapshots of a site's served files (point-in-time restore points). NO_VOLUME means the site was never deployed. Restoring a snapshot is done by the user in the VibeDeploy dashboard within the plan's restore window.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}List path, SHA-256 and size of every file in the site's editable source tree (the stored pre-build code, not the served files). Read-only. A site without a source tree returns SOURCE_NOT_STORED: write the source with write_source_files, or copy plain static served files with promote_dist_to_source.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| autoPromote | boolean | Deprecated and ignored. Use promote_dist_to_source with mode 'auto'. |
| forcePromote | boolean | Deprecated and ignored. Use promote_dist_to_source with mode 'force'. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"autoPromote": {
"type": "boolean",
"description": "Deprecated and ignored. Use promote_dist_to_source with mode 'auto'."
},
"forcePromote": {
"type": "boolean",
"description": "Deprecated and ignored. Use promote_dist_to_source with mode 'force'."
}
}
}Create the editable source tree of a site that has none by copying the files it serves, so later changes can use write_source_files, apply_edits(target:'source') and build_and_deploy. The served files do not change, and a site that already has source is left as is. Use mode 'force' only after telling the user that build output (minified bundles) is not original source.
| Argument | Type | Description |
|---|---|---|
| mode | string | auto (default): copy plain static files only and refuse build output such as hashed bundles. force: copy build output too. |
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"mode": {
"enum": [
"auto",
"force"
],
"type": "string",
"description": "auto (default): copy plain static files only and refuse build output such as hashed bundles. force: copy build output too."
},
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}Return one file the site serves now, as text (utf8) or base64 for binary files, e.g. to edit it and send it back with update_site mode:'patch'. Use read_file for the served files; use read_source_file instead for the editable source tree (get_site.sourceStored). Max 5242880 bytes; get_site.filePaths lists the paths.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| path* | string | Site-relative path of the file to read (e.g. 'index.html', 'assets/main.css'). No leading slash, no '..'. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| maxBytes | integer | Per-file size cap in bytes. Default 1048576, max 5242880. A larger file fails with FILE_TOO_LARGE instead of returning truncated bytes. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"path"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"path": {
"type": "string",
"description": "Site-relative path of the file to read (e.g. 'index.html', 'assets/main.css'). No leading slash, no '..'."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"maxBytes": {
"type": "integer",
"maximum": 5242880,
"description": "Per-file size cap in bytes. Default 1048576, max 5242880. A larger file fails with FILE_TOO_LARGE instead of returning truncated bytes.",
"exclusiveMinimum": 0
}
}
}Read up to 50 served files in one call, with the same per-file rules as read_file and 8388608 bytes in total; paths past the budget fail with BATCH_BUDGET_EXCEEDED, so request them again in another call. Use read_source_files instead for the editable source tree.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| paths* | array | Site-relative paths to read (1..50). Order is preserved in the response. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| maxBytesPerFile | integer | Per-file size cap in bytes. Default 1048576, max 5242880. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"paths"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"paths": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 50,
"minItems": 1,
"description": "Site-relative paths to read (1..50). Order is preserved in the response."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"maxBytesPerFile": {
"type": "integer",
"maximum": 5242880,
"description": "Per-file size cap in bytes. Default 1048576, max 5242880.",
"exclusiveMinimum": 0
}
}
}Return one file from the site's editable source tree (the stored pre-build code), so any chat can edit the site without the original local files. list_source_files shows the paths. Use read_source_file for source; use read_file instead for the files the site serves.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| path* | string | Path inside the source tree, e.g. 'src/App.tsx'. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| maxBytes | integer | Per-file size cap in bytes. Default 1048576, max 5242880. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"path"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"path": {
"type": "string",
"description": "Path inside the source tree, e.g. 'src/App.tsx'."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"maxBytes": {
"type": "integer",
"maximum": 5242880,
"description": "Per-file size cap in bytes. Default 1048576, max 5242880.",
"exclusiveMinimum": 0
}
}
}Read up to 50 files from the editable source tree in one call (8388608 bytes in total). Each path succeeds or fails on its own; paths past the budget fail with BATCH_BUDGET_EXCEEDED. Use read_source_files for source; use read_files instead for the files the site serves.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| paths* | array | Paths inside the source tree, e.g. 'src/App.tsx' (1 to 50). Results keep this order. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| maxBytesPerFile | integer | Per-file size cap in bytes. Default 1048576, max 5242880. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"paths"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"paths": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 50,
"minItems": 1,
"description": "Paths inside the source tree, e.g. 'src/App.tsx' (1 to 50). Results keep this order."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"maxBytesPerFile": {
"type": "integer",
"maximum": 5242880,
"description": "Per-file size cap in bytes. Default 1048576, max 5242880.",
"exclusiveMinimum": 0
}
}
}Download the external images a site references (e.g. from the old site it was rebuilt from), store them on this VibeDeploy site under assets/img/, and rewrite the HTML <img> references to local paths so the site no longer depends on the original. Call this once AFTER deploying a site rebuilt with the Website Converter. Auto-detects the external image URLs from the site's own HTML; downloads are SSRF-guarded, size/count/time capped, and applied atomically (patch mode). Images already on a VibeDeploy platform domain are skipped.
| Argument | Type | Description |
|---|---|---|
| name* | string | Site name as shown by list_sites, whose external images are downloaded and stored on the site. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, whose external images are downloaded and stored on the site."
}
}
}Stop every container service of the site; the site serves its static files again. Volumes (database data) are kept unless deleteData is true, which deletes them for good. Use remove_app to stop only the containers; use delete_site to remove the whole site.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| deleteData | boolean | Also delete every volume (database files) and generated secret. Irreversible. Default false. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"deleteData": {
"type": "boolean",
"description": "Also delete every volume (database files) and generated secret. Irreversible. Default false."
}
}
}Detach a custom domain from a site. The site itself is unaffected and keeps serving on its platform subdomain (e.g. {name}.vibedeploy.be).
| Argument | Type | Description |
|---|---|---|
| domain | string | The custom domain to remove, e.g. 'shop.example.com'. Provide this or recordId. |
| recordId | string | The recordId returned by add_custom_domain or list_custom_domains. Provide this or domain. |
| siteName* | string | The site to detach the domain from. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"siteName"
],
"properties": {
"domain": {
"type": "string",
"description": "The custom domain to remove, e.g. 'shop.example.com'. Provide this or recordId."
},
"recordId": {
"type": "string",
"description": "The recordId returned by add_custom_domain or list_custom_domains. Provide this or domain."
},
"siteName": {
"type": "string",
"description": "The site to detach the domain from."
}
}
}Search every file of a site for a literal string or a regular expression: the served files by default, or the editable source tree with target 'source'. Use it before reading files in bulk, to find the ones that matter.
| Argument | Type | Description |
|---|---|---|
| glob | string | File name filter, e.g. '*.js' or '*.{js,html}'. |
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| regex | boolean | When true, pattern is an extended regular expression (BusyBox grep -E, no PCRE). Default false: literal match. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
| target | string | 'dist' (default) searches the served files; 'source' searches the editable source tree (get_site.sourceStored). |
| pattern* | string | Text to find (ASCII, max 500 chars). Literal unless regex is true. |
| maxMatches | integer | Cap on returned matches. Default 200, hard max 1000. Truncation is reported via budgetExceeded. |
| caseInsensitive |
Configure the built-in form-to-email relay, fully self-service. Supports a custom From (via a verified sender domain or your own SMTP relay), an explicit Reply-To, and full email branding (subject template, field labels/order, logo, accent color, or a custom HTML body). Requires team role owner or admin. Pass config:null to switch the relay off. If you set a custom `sender` without an `smtpRelay`, the response returns the DNS records to publish; then call verify_forms_sender_domain. Submissions: POST JSON to the returned `endpoint` with Content-Type: application/json (UTF-8). Flat object of form fields (strings/numbers/booleans; checkbox groups may be arrays of strings, joined with ', '). Max 30 fields, 5000 chars/field, 20000 total. Response: {success:true,data:{ok:true}} or {success:false,error:{code,message}}. Rate limit: 10 submits per IP per 10 minutes. Include a hidden honeypot input (default "_gotcha") and leave it empty.
| Argument | Type | Description |
|---|---|---|
| config* | any | Full config to store (replaces existing). Pass null to disable and clear. |
| siteName* | string | The site to configure. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"siteName",
"config"
],
"properties": {
"config": {
"anyOf": [
{
"type": "object",
"required": [
"enabled",
"recipients"
],
"properties": {
"sender": {
"type": "object",
"required": [
"email"
],
"properties": {
"name": {
"type": "string",
"maxLength": 100,
"description": "Display name, e.g. \"Acme Support\"."
},
"email": {
"type": "string",
"description": "From address, e.g. [email protected]. Used once its domain is verified (verify_forms_sender_domain) or an smtpRelay is set; until then mail uses the platform address."
}
},
"description": "Custom From sender."
},
"enabled": {
"type": "boolean",
"description": "Master switch. false keeps the config but the endpoint returns 404."
},
"replyTo": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"required": [
"field"
],
"properties": {
"field": {
"type": "string",
"maxLength": 100,
"description": "Form field that holds the Reply-To address."
}
}
}
],
"description": "Reply-To: \"visitor\" (default), \"none\", a fixed email, or { field: \"<formField>\" }."
},
"subject": {
"type": "string",
"maxLength": 200,
"description": "Subject of the lead email."
},
"template": {
"type": "object",
"properties": {
"logoUrl": {
"type": "string",
"description": "https logo URL shown in the email header."
},
"bodyHtml": {
"type": "string",
"maxLength": 20000,
"description": "Full custom HTML body with {fieldName} placeholders (values HTML-escaped). Overrides the generated table."
},
"fieldOrder": {
"type": "array",
"items": {
"type": "string"
},
"description": "Display order; unlisted fields follow in submit order."
},
"footerText": {
"type": "string",
"maxLength": 2000,
"description": "Text below the submitted fields."
},
"headerText": {
"type": "string",
"maxLength": 2000,
"description": "Text above the submitted fields."
},
"accentColor": {
"type": "string",
"description": "#RRGGBB accent color."
},
"fieldLabels": {
"type": "object",
"description": "Map raw field name -> human label.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
},
"subjectTemplate": {
"type": "string",
"maxLength": 200,
"description": "Subject with {fieldName} placeholders. Overrides `subject`."
}
},
"description": "Email branding / layout."
},
"smtpRelay": {
"type": "object",
"required": [
"host",
"port",
"security"
],
"properties": {
"host": {
"type": "string",
"description": "SMTP server hostname or IP (must be public)."
},
"port": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "SMTP port, e.g. 25, 26, 465, 587."
},
"password": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Set to store/replace (encrypted at rest). Omit to keep the existing one. null to clear. Never returned on read."
},
"security": {
"enum": [
"none",
"starttls",
"tls"
],
"type": "string",
"description": "\"none\" = plaintext, \"starttls\" = STARTTLS on a plain connection, \"tls\" = implicit TLS."
},
"username": {
"type": "string",
"description": "Omit for a no-auth trusted-host relay."
},
"allowInvalidCert": {
"type": "boolean",
"description": "Accept a self-signed/mismatched cert (starttls|tls). Default false."
}
},
"description": "Deliver via your own SMTP server instead of the platform. Your server then owns SPF/DKIM. Recipients stay server-side, so this is not an open relay."
},
"recipients": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 5,
"minItems": 1,
"description": "Server-side fixed lead recipients (1-5)."
},
"confirmation": {
"type": "object",
"required": [
"enabled"
],
"properties": {
"enabled": {
"type": "boolean",
"description": "Send the confirmation email."
},
"message": {
"type": "string",
"maxLength": 2000,
"description": "Text of the confirmation email."
},
"subject": {
"type": "string",
"maxLength": 200,
"description": "Subject of the confirmation email."
},
"emailField": {
"type": "string",
"maxLength": 100,
"description": "Form field with the visitor email. Default \"email\"."
}
},
"description": "Optional confirmation email to the visitor."
},
"honeypotField": {
"type": "string",
"maxLength": 100,
"description": "Hidden field that must stay empty. Default \"_gotcha\"."
},
"allowedOrigins": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 10,
"description": "Extra origins allowed to POST. The site's own domains are always allowed."
},
"requiredFields": {
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30,
"description": "Form fields that must be filled in."
}
}
},
{
"type": "null"
}
],
"description": "Full config to store (replaces existing). Pass null to disable and clear."
},
"siteName": {
"type": "string",
"description": "The site to configure."
}
}
}Apply literal find/replace edits to one file in one call, for small changes where uploading the whole file is wasteful. Each edit states how many matches it expects; any mismatch aborts the call with no writes. Served-file (dist) edits go live at once; source edits ship with build_and_deploy. Use apply_edits for several files.
| Argument | Type | Description |
|---|---|---|
| name* | string | Site name as shown by list_sites, e.g. my-portfolio. |
| path* | string | Path inside the chosen tree, e.g. index.html. |
| edits* | array | Ordered edits `{find, replace, count?}`, applied together; if any match count differs, nothing is written. |
| target | string | 'dist' (default) edits the served file, live at once. 'source' edits the editable source tree; build_and_deploy ships it. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"path",
"edits"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio."
},
"path": {
"type": "string",
"description": "Path inside the chosen tree, e.g. index.html."
},
"edits": {
"type": "array",
"items": {
"type": "object",
"required": [
"find",
"replace"
],
"properties": {
"find": {
"type": "string",
"maxLength": 65536,
"minLength": 1,
"description": "Literal text to find (not a regex). Max 64 KB."
},
"count": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "Expected matches: default 1 (fails on 0 or more than 1), -1 = replace all, or an exact number."
},
"replace": {
"type": "string",
"maxLength": 65536,
"description": "Literal replacement; empty string deletes the match. Max 64 KB."
}
}
},
"maxItems": 50,
"minItems": 1,
"description": "Ordered edits `{find, replace, count?}`, applied together; if any match count differs, nothing is written."
},
"target": {
"enum": [
"dist",
"source"
],
"type": "string",
"description": "'dist' (default) edits the served file, live at once. 'source' edits the editable source tree; build_and_deploy ships it."
}
}
}Change files on an existing site. Default mode 'patch' writes only the listed files and keeps the rest; `delete: [paths]` removes files. mode:'replace' deletes every file not listed. Preview with dryRun:true. Use deploy_site instead to create a new site. A 100-250 KB text file fits in one call with encoding:'gzip+base64' (gzip locally, then base64); prefer that over begin_deploy plus add_file_chunk. Fails with SITE_NOT_FOUND when the site does not exist.
| Argument | Type | Description |
|---|---|---|
| mode | string | patch (default): write only the listed files; everything else stays. replace: delete every existing file and write only the listed ones. |
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| files | any | Files to write: `[{path, content, encoding?}]` (preferred) or a `{path: content}` map. <= 500 MB total. May be omitted for a delete-only call in patch mode. |
| delete | array | Patch mode only: site-relative paths to remove; other files stay. Combine with `files` to rename in one call. Rejected in replace mode. |
| dryRun | boolean | Validate and preview without writing; deletedFiles lists what would be removed. Use it before replace mode or a patch with `delete`. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
Check the records from add_custom_domain (the ownership TXT and the routing record) and, when both are right, start serving the site on that domain; the HTTPS certificate follows automatically, usually within a minute or two. If it fails, the result names each record to add, change or remove; DNS changes can take a few minutes to propagate. Calling it again on a verified domain is a harmless re-check.
| Argument | Type | Description |
|---|---|---|
| recordId* | string | The recordId returned by add_custom_domain. |
| siteName* | string | The site the domain was attached to. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"siteName",
"recordId"
],
"properties": {
"recordId": {
"type": "string",
"description": "The recordId returned by add_custom_domain."
},
"siteName": {
"type": "string",
"description": "The site the domain was attached to."
}
}
}Check the DNS records for a site's custom sender domain (DKIM TXT + SPF include). Once the DKIM record is observed, the sender domain is marked verified and the relay sends from the custom From (DKIM-signed). Until then it falls back to the platform address. DNS can take a few minutes to propagate; re-run if it fails the first time. Not needed when the site uses a custom smtpRelay.
| Argument | Type | Description |
|---|---|---|
| siteName* | string | The site whose custom sender domain to (re)check. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"siteName"
],
"properties": {
"siteName": {
"type": "string",
"description": "The site whose custom sender domain to (re)check."
}
}
}Write or overwrite files in the site's editable source tree (the first write creates it). The served files do not change until build_and_deploy runs. Use list_source_files first to see what exists. A legacy site without source storage returns SOURCE_STORAGE_NOT_ENABLED; the user can ask VibeDeploy support to enable it.
| Argument | Type | Description |
|---|---|---|
| name | string | Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId. |
| files* | array | Files to write into the source tree. Same wire shape as add_files. Re-writing a path overwrites the previous source. Per-file cap 5 MB; per-call cap 50 MB; max 200 files per call. |
| siteId | string | Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"files"
],
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"files": {
"type": "array",
"items": {
"type": "object",
"required": [
"path",
"content"
],
"properties": {
"path": {
"type": "string",
"description": "Path inside the source tree, e.g. 'src/App.tsx'. Plain ASCII, no leading slash."
},
"content": {
"type": "string",
"description": "File content: text, or base64 as set by encoding."
},
"encoding": {
"enum": [
"utf8",
"base64",
"gzip+base64"
],
"type": "string",
"description": "utf8 (default), base64 (binary files), or gzip+base64 (gzip locally, then base64; fits about 3x more text per call)."
}
}
},
"minItems": 1,
"description": "Files to write into the source tree. Same wire shape as add_files. Re-writing a path overwrites the previous source. Per-file cap 5 MB; per-call cap 50 MB; max 200 files per call."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}| expectedByteOffset | integer | Optional check: where this chunk starts in the assembled file (0 for the first chunk, else the decoded bytes sent so far). A mismatch fails with MISALIGNED_CHUNK before writing, which catches base64 split mid-byte. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"deployId",
"path",
"content",
"isFirst",
"isLast"
],
"properties": {
"path": {
"type": "string",
"description": "Path relative to the site root, e.g. 'portaal-admin.html'. Same rules as add_files."
},
"isLast": {
"type": "boolean",
"description": "True on the final chunk: returns the assembled file size and refreshes the session file count."
},
"content": {
"type": "string",
"description": "This chunk's bytes, as UTF-8 text or encoded per encoding. Chunk size is limited by your client's tool-output budget, not by the server: about 80 KB of base64 (60 KB raw) per chunk is a safe upper bound."
},
"isFirst": {
"type": "boolean",
"description": "True on the first chunk of a file: truncates any staged file at this path and creates parent directories."
},
"deployId": {
"type": "string",
"description": "Session id returned by begin_deploy."
},
"encoding": {
"enum": [
"utf8",
"base64",
"gzip+base64"
],
"type": "string",
"description": "utf8 (default), base64 (binary), or gzip+base64 (gzip this chunk locally; the server gunzips before appending). Set per chunk."
},
"expectedByteOffset": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0,
"description": "Optional check: where this chunk starts in the assembled file (0 for the first chunk, else the decoded bytes sent so far). A mismatch fails with MISALIGNED_CHUNK before writing, which catches base64 split mid-byte."
}
}
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"rootPath": {
"type": "string",
"description": "Subdirectory of the source tree that holds package.json (monorepos). Empty string = source root."
},
"outputDir": {
"type": "string",
"description": "Directory to publish. Default: the saved manifest, then auto-detect (dist > build > out > public)."
},
"buildCommand": {
"type": "string",
"description": "Build command override, e.g. 'npm run build:prod' or 'pnpm vite build'. Default: the saved manifest, then 'npm run build'."
},
"saveManifest": {
"type": "boolean",
"description": "Default true: save these settings on the site for later builds. false = one-off build."
}
}
}| string |
| Site id from list_sites or get_site. Use instead of name. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"config": {
"type": "object",
"description": "The app config; omit it to use vibedeploy.json from the site's source tree. Shape: {\"services\":{\"<name>\":{\"image\":\"postgres:16-alpine\",\"port\":5432,\"public\":false,\"env\":{\"KEY\":\"value\"},\"volumes\":{\"/var/lib/postgresql/data\":\"1Gi\"},\"command\":[],\"args\":[],\"workingDir\":\"/app\",\"source\":false,\"sourcePath\":\"/app\",\"memory\":\"256Mi\",\"cpu\":\"500m\"}}}. Services reach each other by name (host \"db\"). \"source\":true copies the source tree into sourcePath on every start, e.g. {\"image\":\"node:22-alpine\",\"source\":true,\"command\":[\"sh\",\"-c\",\"npm ci && node server.js\"],\"port\":3000,\"public\":true}. \"$(OTHER)\" embeds an earlier env var of the same service, e.g. \"DATABASE_URL\":\"postgres://app:$(DB_PASSWORD)@db:5432/app\". For Postgres set PGDATA to a subdirectory of the volume.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name",
"archiveUrl",
"mode"
],
"properties": {
"mode": {
"enum": [
"replace",
"patch"
],
"type": "string",
"description": "replace: the archive becomes the whole site (other files are removed). patch: the archive's files are added or overwritten, the rest stays."
},
"name": {
"type": "string",
"description": "Name of an existing site (see list_sites). This tool does not create sites."
},
"confirm": {
"type": "string",
"const": "I-want-to-replace-all-files",
"description": "Required only for mode \"replace\" on a site that already has files. Pass exactly \"I-want-to-replace-all-files\" to acknowledge that the live files will be deleted and replaced with the archive's files."
},
"archiveUrl": {
"type": "string",
"format": "uri",
"description": "Public HTTPS URL of a tar or tar.gz archive (max 100 MB, 60 s). Allowed hosts, also for every redirect: github.com, codeload.github.com, *.githubusercontent.com, gist.github.com, gitlab.com, bitbucket.org, codeberg.org, *.amazonaws.com, *.r2.cloudflarestorage.com, *.backblazeb2.com, *.workers.dev, *.pages.dev, transfer.sh, 0x0.st, mcp.vibedeploy.be. GitHub, GitLab and Codeberg archive links (e.g. https://github.com/<owner>/<repo>/archive/refs/heads/main.tar.gz) are accepted, but the normal file rules apply: any dotfile except .well-known/ (such as .gitignore, .github/, .gitlab-ci.yml) or any file type outside the allowlist (such as .ts, .tsx, .yml) rejects the whole archive with INVALID_FILE_TYPE. Replace mode removes only the one wrapping folder, so the built site must sit at the repository root."
}
}
}| boolean |
| Ignore upper/lower case. Default false. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"pattern"
],
"properties": {
"glob": {
"type": "string",
"description": "File name filter, e.g. '*.js' or '*.{js,html}'."
},
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"regex": {
"type": "boolean",
"description": "When true, pattern is an extended regular expression (BusyBox grep -E, no PCRE). Default false: literal match."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
},
"target": {
"enum": [
"dist",
"source"
],
"type": "string",
"description": "'dist' (default) searches the served files; 'source' searches the editable source tree (get_site.sourceStored)."
},
"pattern": {
"type": "string",
"description": "Text to find (ASCII, max 500 chars). Literal unless regex is true."
},
"maxMatches": {
"type": "integer",
"maximum": 1000,
"description": "Cap on returned matches. Default 200, hard max 1000. Truncation is reported via budgetExceeded.",
"exclusiveMinimum": 0
},
"caseInsensitive": {
"type": "boolean",
"description": "Ignore upper/lower case. Default false."
}
}
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"mode": {
"enum": [
"patch",
"replace"
],
"type": "string",
"description": "patch (default): write only the listed files; everything else stays. replace: delete every existing file and write only the listed ones."
},
"name": {
"type": "string",
"description": "Site name as shown by list_sites, e.g. my-portfolio. Provide name or siteId."
},
"files": {
"anyOf": [
{
"type": "array",
"items": {
"type": "object",
"required": [
"path",
"content"
],
"properties": {
"path": {
"type": "string",
"description": "Path relative to the site root, e.g. index.html or assets/app.js. Plain ASCII, no leading slash."
},
"content": {
"type": "string",
"description": "File content: text, or base64 as set by encoding."
},
"encoding": {
"enum": [
"utf8",
"base64",
"gzip+base64"
],
"type": "string",
"description": "utf8 (default): text written as is. base64: required for binary files (images, fonts, PDFs), otherwise the file is stored as broken text. gzip+base64: gzip locally, then base64; fits 3-5x more text per call."
}
}
},
"description": "Array form; needed for binary files."
},
{
"type": "object",
"description": "Map form: path to UTF-8 text.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
}
}
],
"description": "Files to write: `[{path, content, encoding?}]` (preferred) or a `{path: content}` map. <= 500 MB total. May be omitted for a delete-only call in patch mode."
},
"delete": {
"type": "array",
"items": {
"type": "string"
},
"description": "Patch mode only: site-relative paths to remove; other files stay. Combine with `files` to rename in one call. Rejected in replace mode."
},
"dryRun": {
"type": "boolean",
"description": "Validate and preview without writing; deletedFiles lists what would be removed. Use it before replace mode or a patch with `delete`."
},
"siteId": {
"type": "string",
"description": "Site id from list_sites or get_site. Use instead of name."
}
}
}