MCP tool reference
Every Tandem MCP tool, grouped by domain. 163 tools total. Each row is a one-line purpose plus its key parameters — * marks a required parameter. Descriptions are faithful to the live tool definitions; call a tool with only its schema-required args to start.
All calls go to POST https://portal.launchtandem.com/mcp as JSON-RPC tools/call with an Authorization: Bearer tdm_… header. Only create_account_and_claim_link and create_own_organization work without auth. See Connecting agents for client setup and Capabilities overview for the resource model.
Common gating shorthand used below: read/manage = the token action required; viewer/developer/admin/owner = the org role required.
The free trial, in one paragraph
A new organization starts on the preview tier: a 14-day free trial that really deploys, with no payment method at all. Its allowance is 1 service, 1 database, 1 bucket; custom domains, domain purchase/transfer, outbound email and managed Redis are excluded outright (a card does not buy them — a subscription does). Domain renewal is allowed with a card, so a domain you already own can never lapse. At expiry, deploys are blocked (preview_expired) and containers are reclaimed — nothing is deleted: code, databases, files, env vars and domains survive, and create_subscription restores and redeploys everything automatically (resume_service is the per-service fallback). Upgrading is always two calls: set_payment_method, then create_subscription — the card is not the upgrade. Call whoami to read all of this per org before you plan.
Identity, bootstrap & recovery
| Tool |
Purpose |
Key params |
pillar_directory |
Map of the five Tandem pillars (launch/work/speak/grow/profit) — per pillar: name, status (live/beta/coming_soon), base URL, MCP endpoint (null until live; plannedMcpUrl for future homes), and auth. The same tdm_ bearer token works on every pillar’s MCP server. See The Tandem suite. No action gate. |
— |
whoami |
Call this first. Your identity + username (for a human to add you to an org), your credential’s live action mask, and per-org entitlements: tier (preview = 14-day free trial, paid = subscribed), entitlement (trial/trial_expired/paid/comped), trialActive/trialExpiresAt, canDeploy + deployBlockers, trialAllowances (used vs limit for services/DBs/buckets), lockedUntilSubscribed, and nextStep. Plan against these instead of discovering limits by hitting errors. |
— |
create_account_and_claim_link |
(no auth) Create an org + human owner, email a claim link; anonymous calls also mint an agent token bound to this session. |
ownerEmail*, organizationName*, ownerDisplayName |
create_own_organization |
(no auth) Create an org owned by YOU (the agent) with no human owner; mints an owner token. Then register + verify a recovery key before deploying. |
organizationName* |
get_claim_status |
Poll an org’s claim status → { claimed, paid, customDomain }. |
organizationId* |
get_deploy_gate_status |
Check whether an org can deploy → { billingVerified, recoveryVerified, recoveryMethod, trialActive, trialExpiresAt, blockers, allowed }. Blockers: recovery_unverified, preview_expired, billing_unverified — the last two are both cleared by set_payment_method then create_subscription (a card alone does not lift the gate). read + membership. |
organizationId* |
register_recovery_key |
Register an Ed25519 public key (SPKI); returns a challenge to sign. manage. |
organizationId*, label*, publicKey* |
verify_recovery_key |
Submit the Ed25519 signature over the challenge to activate the key. manage. |
keyId*, signature* |
list_recovery_keys |
List an org’s recovery keys (no public-key material). read. |
organizationId* |
revoke_recovery_key |
Revoke a verified recovery key. manage. |
keyId* |
Projects
| Tool |
Purpose |
Key params |
list_projects |
List projects visible to the caller (scoped by token / memberships). Each row includes an accurate deployment_count. |
— |
create_project |
Create a project in an org; optionally link a connected repo. |
slug*, name*, environment, repositoryId, organizationId |
rename_project |
Rename a project; changing slug rewrites every platform hostname + DNS + Caddy and returns hostnameChanges[]. manage + developer. |
projectId*, name, slug |
delete_project |
Cascade-delete a project and every service, bucket, and database in it. Irrevocable. manage + admin. |
projectId*, confirmSlug* |
Services
| Tool |
Purpose |
Key params |
list_services |
List services, optionally filtered by projectId. |
projectId |
read_service_config |
Read a service’s type, paths, healthcheck, domains, and env-var keys (values not returned). |
serviceId* |
import_services |
Bulk-create services in a project from service definitions (e.g. read_platform_yml output); auto-attaches platform hostnames. |
projectId*, services* |
restart_service |
Restart the current healthy deployment’s container; Caddy re-points to the new port. restart. |
serviceId* |
rollback_service |
Roll back to a previous healthy deployment (reuses the prior image, skips build). rollback. |
serviceId*, targetDeploymentId |
resume_service |
Bring a suspended service back online (suspension = the org’s free trial ended and its containers were reclaimed; nothing is deleted). Subscribing resumes automatically, so this is the fallback for when that failed. Requires the org to pass the deploy gate. deploy + developer. |
serviceId* |
delete_service |
Scoped cascade-delete of one service (deployments, env vars, domains, attachment rows). Preserves the buckets/DBs/redis/mailboxes/domains themselves; the analytics site is kept as external by default (analytics=keep|delete). manage + admin. |
serviceId*, confirmName, analytics |
Deployments & logs
| Tool |
Purpose |
Key params |
create_deployment |
Queue a deployment for a service. deploy. |
serviceId*, gitRef, gitSha |
deploy_preview |
Queue a preview deployment from a branch/ref (metadata.kind='preview'). deploy. |
serviceId*, gitRef*, gitSha |
deploy_project |
Deploy every service in a project at one gitRef (the “Deploy all” fan-out). deploy. |
projectId*, gitRef |
list_deployments |
List recent deployments (newest first) with state, git ref/sha, image ref, timestamps, errorMessage. |
serviceId*, limit |
get_deployment |
Read one deployment incl. buildLog (build failures) and containerLog (runtime failures) — always check both. |
deploymentId* |
view_logs |
Fetch recent container logs for the current healthy deployment. |
serviceId*, tail |
GitHub & repositories
Auto-deploy on push is silent by design when it succeeds — but if the org fails the deploy gate (expired trial, unconfirmed billing, unverified recovery), the push is skipped, not queued. The platform emails the org owners once per day when that happens and writes a github.push.auto_deploy.blocked_notice audit row naming the blocker, the remedy and the skipped services. Pushes resume deploying automatically once the blocker clears; no re-push is needed.
| Tool |
Purpose |
Key params |
list_github_installations |
List GitHub App installations visible to the caller. |
— |
list_installation_repositories |
List repos granted to a specific installation (cached 5 min). |
installationId* |
list_repositories |
List repos already connected to the caller’s org(s); hasInstallation flags platform.yml / auto-deploy support. |
— |
connect_repository |
Connect a repo from an installation into an org. manage + developer. |
installationId*, githubRepoNodeId*, organizationId |
set_project_repository |
Set a project’s deploy source: a connected GitHub/URL repo (repositoryId, manage) OR a Tandem Git repo (tandemGitRepoId, source:write — works for a standalone repo too). + optional auto-deploy branch. developer. |
projectId*, one of repositoryId/tandemGitRepoId, deployBranch |
read_platform_yml |
Fetch + parse platform.yml from a connected repo → services ready to import. |
repositoryId*, ref |
Git repositories (Tandem Git)
Tandem’s own private git hosting: standard HTTPS clone/push (username git, password = an access token or your deployment token). Agent credentials gate on the dedicated source:read / source:write / source:admin actions (minted default-on with new tokens); per-repo access = org role (owner/admin → all, developer → read+write, viewer → read) plus explicit share grants. See Tandem Git.
| Tool |
Purpose |
Key params |
create_git_repo |
Create a private repo; init: "template" (default) seeds platform.yml + README + .gitignore so the first push can deploy, "empty" creates a bare repo. Pass asProjectSource: {newProject} or {projectId} to wire the new repo up as a project’s deploy source in the same call — zero GitHub required, and a push to the deploy branch auto-deploys exactly like a GitHub-linked project. source:write + developer. |
name*, organizationId, projectId, description, init, asProjectSource |
list_git_repos |
List repos you can read (all your orgs + repos shared with you; narrow by org/project) with clone URL, default branch, archived flag, and your caps. source:read. |
organizationId, projectId |
read_git_repository |
Read without cloning — what: tree (directory listing, recursive optional), file (base64 content + isBinary), commits (paged history via limit/cursor, optional path filter), branches. source:read. |
repo*, what*, ref, path, recursive, limit, cursor |
commit_git_changes |
Apply up to 200 put/delete/move operations as ONE atomic commit; baseSha gives optimistic concurrency (stale → ref_conflict + currentSha), createBranchFrom creates the branch first. source:write + repo write access. |
repo*, branch*, message*, operations*, baseSha, createBranchFrom |
share_git_repo |
Drive-style sharing: grant independent canRead/canWrite/canAdmin to a principal or email (unknown email → account + setup link), or revoke: true to remove. source:admin + repo admin access. |
repo*, principalId|email, canRead, canWrite, canAdmin, revoke |
import_repository |
Migrate a repository INTO Tandem Git (one-time copy). source: {githubRepositoryId} copies an existing GitHub-connected repo (repointProject: true switches its project(s) onto the new Tandem repo); source: {url} clones any public https git URL (tandemRepoName required; optional project: {name} or {id}). Async — poll with get_source_status. Never copies refs/pull/*. source:write + developer + unscoped agent credential. |
source*, tandemRepoName, repointProject, project, organizationId |
export_repository_to_github |
Migrate a Tandem repo OUT to GitHub (one-time copy). githubRepoNodeId must name an EMPTY repo you created yourself (App tokens can’t create repos or overwrite history — verified by the worker before pushing). then: "repoint" switches the project(s) to the GitHub repo afterward. Async — poll with get_source_status. source:write + developer + unscoped agent credential. |
repo*, installationId*, githubRepoNodeId*, then |
get_source_status |
Poll a migrate job (jobId) or a repo’s most recent one plus its mirror link state (repo) — state/progress/error, and if mirrored: mode, status, lag, last error. source:read. |
repo|jobId |
configure_git_mirror |
Continuous “Mirror to GitHub” (single-primary, never multi-master — not the one-time import/export above). action: enable (requires mode + github: {githubRepositoryId} or {installationId, githubRepoNodeId}) starts it; pause/resume toggle; switch_primary runs a final sync then flips authority (diverged commits backed up, never lost); disable stops mirroring (both repos stay intact). source:admin + org admin + unscoped agent credential. |
repo*, action*, mode, github |
Environment variables
| Tool |
Purpose |
Key params |
list_env_vars |
List a service’s env-var keys, scopes, and masked previews (never full values). |
serviceId* |
set_env_var |
Set/overwrite one env var (encrypted at rest). scope = runtime (default) / build / both. |
serviceId*, key*, value*, scope |
set_env_vars |
Bulk-set env vars in one atomic call — paste a whole .env as content, or pass vars. Prefer this over repeated set_env_var. replaceAll also deletes keys not in the call (file-sync). |
serviceId*, content, vars, scope, replaceAll |
delete_env_var |
Delete an env var by key (applies on next deploy/restart). |
serviceId*, key* |
Databases (Postgres / MySQL)
| Tool |
Purpose |
Key params |
list_databases |
Discover databases (the entry point — every other DB tool needs a databaseId). Non-secret metadata + service attachments; org-wide rows add projectSlug/organizationSlug. Omit projectId to list across all visible orgs. |
projectId |
get_database |
Fetch one DB’s non-secret metadata by UUID. |
databaseId* |
provision_database |
Provision a tenant DB + user; auto-creates DATABASE_URL on the service. kind picks the engine. |
projectId*, kind, label, attachServiceId |
reveal_database_credentials |
Full internal credential bundle (host/port/db/user/password/URL). Audit-logged. |
databaseId* |
reveal_database_public_credentials |
Credentials with the public host for external access (only connects from an allowlisted IP). Audit-logged. |
databaseId* |
query_database |
Run SQL against the DB as the tenant role (full read/write; the portal SQL runner’s equivalent). Multiple statements allowed — last result set returned. Audit-logged. manage + developer. |
databaseId*, sql*, maxRows |
export_database |
Enqueue a full dump of the DB (schema + data) to a .sql file — the portal’s Export button equivalent. Returns the job (state queued); the worker runs pg_dump/mysqldump. Audit-logged. manage + developer. |
databaseId* |
list_database_allowlist |
List the DB’s public-access IP allowlist (CIDRs). |
databaseId* |
add_database_allowlist |
Grant a CIDR public access (firewall + engine-level grant); optional ttlHours. |
databaseId*, cidr*, label, ttlHours |
remove_database_allowlist |
Revoke an allowlist entry by id. |
databaseId*, entryId* |
delete_database |
Drop the DB + role, remove DATABASE_URL from attached services. Irreversible. manage + developer. |
databaseId*, confirmName |
Object storage (S3-compatible buckets)
| Tool |
Purpose |
Key params |
create_bucket |
Create a bucket + scoped creds; optionally inject the six S3_* env vars on a service. |
projectId*, label, attachServiceId |
list_buckets |
List buckets in a project and which services each is attached to. |
projectId* |
attach_bucket_to_service |
Inject the six S3_* env vars on a service (idempotent). |
bucketId*, serviceId* |
detach_bucket_from_service |
Remove the S3_* env vars; bucket + objects kept. |
bucketId*, serviceId* |
reveal_bucket_credentials |
Full bucket credential bundle (endpoint/region/keys). Audit-logged. |
bucketId* |
delete_bucket |
Delete a bucket (must be empty first); revokes creds, removes S3_* vars. No undo. |
bucketId* |
set_bucket_cors |
Replace the bucket’s CORS policy (browser-only; not access control). A "*" origin is rejected unless allowAnyOrigin: true. Audit-logged. |
bucketId*, rules*, allowAnyOrigin |
get_bucket_cors |
Read the bucket’s CORS rules (no endpoint/creds). |
bucketId* |
Redis / Valkey
| Tool |
Purpose |
Key params |
provision_redis |
Provision a managed Valkey instance (async — poll list_redis for ready). tier = small/default/large. Subject to deploy gate + RAM budget. |
projectId*, label, tier, attachServiceId |
list_redis |
List instances with status/tier/persistence and attached services (poll for ready). |
projectId* |
reveal_redis_credentials |
Host/port/password + full REDIS_URL (only when ready). Audit-logged. |
redisId* |
attach_redis_to_service |
Inject REDIS_URL on a service (idempotent; must be ready). |
redisId*, serviceId* |
detach_redis_from_service |
Remove REDIS_URL; instance + data kept. |
redisId*, serviceId* |
delete_redis |
Tear down the instance + data volume (async). No undo. |
redisId* |
Email
Email is custom-domain-only — onboard a domain before creating mailboxes or sending. See Email for the full flow.
| Tool |
Purpose |
Key params |
add_email_domain |
Onboard a custom domain for send+receive; returns DNS records (MX, DKIM, SPF, DMARC). |
projectId*, domain* |
list_email_domains |
List onboarded email domains + SES/DKIM/inbound status. |
projectId* |
verify_email_domain |
Re-check a domain’s verification against SES + DNS. |
domainId* |
remove_email_domain |
Remove an onboarded domain (refuses if mailboxes remain). |
domainId* |
set_dmarc_reporting |
Configure DMARC aggregate-reporting ownership (no lock-in): managed (Tandem collector), external (your own rua), or both. Provisions/removes the external-destination auth record. |
mode*, domainId|domain+projectId, externalRua |
get_dmarc_summary |
Email Health for one domain: DMARC pass-rate, failing sources, reporter coverage, and advisory (safeToQuarantine / safeToReject). Use before tightening policy. |
domainId|domain+projectId, sinceDays |
set_dmarc_policy |
Set the published DMARC policy p= none→quarantine→reject (and back) — managed + reversible. Tightening gated on get_dmarc_summary advisory unless force=true. Managed/both only (external hosts its own _dmarc). Reporting rua preserved. |
policy*, domainId|domain+projectId, force |
create_email_api_key |
Create a transactional send-API key (Bearer for POST /api/email/send); returned once. Optional allowedDomains. |
projectId*, name*, allowedDomains |
list_email_api_keys |
List send-API keys (never the secret). |
projectId* |
revoke_email_api_key |
Revoke a send-API key by id. |
projectId*, keyId* |
provision_email |
Provision a real mailbox (IMAP+SMTP+JMAP) on an onboarded domain; optionally inject EMAIL_* on a service. |
projectId*, domain*, localPart, label, attachServiceId |
list_emails |
List mailboxes in a project (address, DNS status, attachments). No passwords. |
projectId* |
attach_email_to_service |
Inject EMAIL_* (IMAP+SMTP+JMAP) on a service (idempotent). |
mailboxId*, serviceId* |
detach_email_from_service |
Remove EMAIL_*; mailbox + mail kept. |
mailboxId*, serviceId* |
reveal_email_credentials |
Full connection profile (IMAP/SMTP host/port/user/password + JMAP url/token). Audit-logged. |
mailboxId* |
rotate_email_credentials |
Rotate the mailbox password (set or auto-generate); re-injects into attached services. |
mailboxId*, password |
delete_email |
Delete a mailbox (all stored mail lost); tears down domain DNS if it was the last one. No undo. |
mailboxId* |
set_email_inbound_webhook |
Forward inbound mail as HMAC-signed JSON POSTs to a URL; returns a signing secret once. |
mailboxId*, url* |
get_email_inbound_webhook |
Show the mailbox’s webhook config (secret never returned). |
mailboxId* |
remove_email_inbound_webhook |
Stop forwarding; mail still arrives in the mailbox. |
mailboxId* |
share_mailbox |
Grant a principal capabilities on a mailbox: view/categorize/manage/send (independent — send-only and categorize-only are valid). Unknown email → creates a mail-only account (no org) + emails a setup link; they set a password and land in the shared mailbox (invited:true in the response). Re-share replaces caps. |
mailboxId*, principalId|email, canView*, canCategorize*, canManage*, canSend* |
revoke_mailbox_grant |
Revoke a subject’s grant (disappears from their webmail on next sync); history kept. |
mailboxId*, principalId|email |
list_mailbox_grants |
Who has access to a mailbox + each subject’s caps, incl. pending invites. |
mailboxId* |
Domains
| Tool |
Purpose |
Key params |
list_domains |
List everything domain-related for the org in one call: registrations (Tandem-registered apexes — carries the domainOrderId that renew_domain/set_domain_auto_renew take, plus status, expiresAt, autoRenew, attachedServices; in-flight purchases/transfers included so you can poll an approval or transfer), externalZones (DNS hosted here but bought elsewhere), attachedHostnames (hostname → service, kind platform|custom, verified, redirect). Read-only. read + any role. |
organizationId, includeInFlight |
check_domain_availability |
Check availability + registrar price for hostnames or a stem across default TLDs. Read-only. |
hostnames, stem |
purchase_domain |
Register a domain + attach it to a service. Paid plans credit the first year (Pro 1, Scale 3, capped at $15); returns costCents (charged), creditAppliedCents, renewalPriceCents (undiscounted — always disclose it). Owner runs synchronously; others get an approvalUrl. manage; deploy gate + a chargeable card (not covered by the free trial). |
organizationId*, hostname*, serviceId |
attach_domain |
Attach an already-owned or external hostname to a service (auto A record for subdomains of a Tandem-registered apex; else DNS instructions + automatic recheck until it resolves). manage + developer. |
serviceId*, hostname* |
verify_domain |
Force an immediate DNS recheck for an attached custom hostname (the sweep also rechecks automatically); activates the domain when DNS resolves. manage + developer. |
hostname* |
reassign_domain |
Move an attached hostname to another service in the same org in one step (keeps DNS verification; routes refresh automatically). manage + developer. |
hostname*, serviceId* |
detach_domain |
Detach a hostname from its service (unpublishes the platform A record, discards verification state; a Tandem registration itself is untouched). Prefer reassign_domain for moves. manage + developer. |
hostname* |
renew_domain |
Renew a Tandem-registered domain one year (payment + approval path). manage + developer; deploy gate + a chargeable card (not covered by the free trial). |
organizationId*, domainOrderId, hostname, years |
set_domain_auto_renew |
Toggle auto-renew (no charge, no deploy gate). manage + developer. |
organizationId*, autoRenew*, domainOrderId, hostname |
transfer_domain |
Transfer a domain in from another registrar (charges one year; needs EPP authCode). manage + developer; deploy gate + a chargeable card (not covered by the free trial). |
organizationId*, hostname*, authCode*, projectId, serviceId |
SMS & phone numbers (US/CA)
Numbers, A2P compliance, and messaging over Telnyx. Call get_sms_setup_status first for any number — it is the one status tool that says exactly what is pending and which tool resumes it, and whether production sends are allowed yet (canSend). Same org-role gates and Wave-1 stores as the /api/sms/* REST surface. When Telnyx is unconfigured every tool returns sms_unavailable.
Recommended flow: search_phone_numbers → purchase_phone_number → a compliance path (toll-free = fastest/free; or 10DLC = higher throughput) → send_sms. Sends are blocked until compliance is approved (the error carries the setupStatus).
| Tool |
Purpose |
Key params |
search_phone_numbers |
Search buyable US/CA inventory. read + developer. |
type* (local|toll_free), countryCode, areaCode, locality, administrativeArea, contains, organizationId |
purchase_phone_number |
Buy a number (lazily creates the org messaging profile). Owner-under-threshold buys synchronously; others get an approvalUrl. manage + developer; deploy gate. |
e164*, numberType*, label, organizationId |
list_phone_numbers |
List the org’s numbers, each with unified setupStatus + attachments. read + viewer. |
organizationId |
release_phone_number |
Detach from all services + give up at the carrier (irreversible). manage + developer. |
numberId*, confirm* (the number’s E.164) |
register_sms_brand |
Register the org’s 10DLC brand (one per org). Standard = EIN + companyName; SOLE_PROPRIETOR = name + mobilePhone, returns otpRequired. manage + developer; deploy gate. |
entityType*, displayName*, companyName, ein, firstName, lastName, mobilePhone, address fields, organizationId |
confirm_sms_brand_otp |
Submit the sole-prop mobile OTP PIN (expires 24 h). Degrades to action_required if Telnyx can’t automate it. manage + developer. |
brandId*, pin*, organizationId |
create_sms_campaign |
Submit a 10DLC campaign under an approved brand. Validated locally first (returns errors on failure — no charge); $15/submission so approval-gated (approvalUrl over threshold). manage + developer; deploy gate. |
brandId*, usecase*, description*, sampleMessages*, messageFlow*, keywords, organizationId |
assign_number_to_campaign |
Link a number to a campaign (enforces the 49/campaign T-Mobile cap). manage + developer. |
campaignId*, numberId* |
submit_tollfree_verification |
Submit the toll-free verification (fastest/free path). Validated locally (full state name, additionalInformation, ≥1 opt-in evidence URL, EIN). manage + developer. |
business/contact fields, phoneNumbers*, useCase*, optInWorkflowImageUrls*, messageVolume*, additionalInformation*, organizationId |
get_sms_setup_status |
THE status tool — unified state + reason + concrete remediation + the exact next tool + canSend. Call first. read + viewer. |
numberId* |
send_sms |
Send SMS/MMS from an owned number. Compliance-gated (allowPending for a pending toll-free number); enforces rate limit + the acting principal’s spend cap. Returns segments + estimated cost. manage + developer. |
numberId|from, to*, text, mediaUrls, allowPending, organizationId |
list_sms_messages |
List messages (bodies decrypted for the owner), newest first. read + viewer. |
numberId, direction, status, limit, organizationId |
attach_phone_number_to_service |
Inject the SMS_* runtime env vars (URL/key/number/webhook-secret) on a service. Idempotent. manage + developer. |
numberId*, serviceId* |
detach_phone_number_from_service |
Remove the injected SMS_* env vars. manage + developer. |
numberId*, serviceId* |
set_sms_inbound_webhook |
Point inbound messages + delivery events at your HTTPS URL (HMAC X-Tandem-Signature); returns the signing secret once. manage + developer. |
numberId*, url* |
remove_sms_inbound_webhook |
Stop forwarding inbound (messages still stored). manage + developer. |
numberId* |
DNS records
| Tool |
Purpose |
Key params |
list_dns_records |
List records in the zone owning a hostname (+ zone metadata). Read-only. read. |
hostname* |
create_dns_record |
Create a record (A/AAAA/CNAME/ALIAS/NS/TXT/MX/SRV/CAA). manage + developer. |
hostname*, name*, type*, content*, priority, weight, port, flags, tag, ttl |
update_dns_record |
Replace a record by id (full desired fields, not a patch). manage + developer. |
hostname*, recordId*, name*, type*, content* |
delete_dns_record |
Delete a record by id (platform-managed records protected). manage + developer. |
hostname*, recordId* |
take_over_dns_record |
Claim a Tandem-managed web-serving record (apex/www, service routing) so your org edits it from then on — for hosting the site elsewhere while Tandem stays the nameserver. manage + developer. |
hostname*, recordId* |
import_dns_zone |
Bulk-import a BIND zone file (e.g. cPanel whmapi1 dumpzone) into an already-adopted zone. Skips SOA/NS; platform-RRset collisions reported (not created) for take-over then re-import; dryRun returns the diff without writing. manage + developer. |
hostname*, zoneFile*, dryRun |
Web analytics
| Tool |
Purpose |
Key params |
provision_analytics |
Enable Tandem Analytics on a service; injects the two TANDEM_ANALYTICS_* vars; returns the install <script>. |
serviceId* |
provision_external_analytics |
Enable analytics for a site hosted anywhere (no service, no env vars — the returned <script> is the whole integration). Idempotent per (project, domain). |
projectId*, domain* |
convert_analytics_to_external |
Rebind a service’s site as standalone external — same website id, full history preserved. Use when an app moves off Tandem. |
serviceId*, domain |
set_analytics_custom_host |
First-party upgrade: serve the tag from the site’s own domain (default analytics.<domain>); auto-publishes DNS when the zone is hosted here, else returns the record to add. |
serviceId/siteId, host |
verify_analytics_custom_host |
Check the custom host resolves to the platform and activate it (route + cert publish; snippet switches over). |
serviceId/siteId |
remove_analytics_custom_host |
Drop the custom host; the assigned host keeps serving so installed tags keep working. |
serviceId/siteId |
get_analytics_install_snippet |
Return the install <script> for a site. |
serviceId or siteId |
list_analytics |
List a project’s analytics sites, service-bound and external (kind, externalDomain, site id). |
projectId* |
disable_analytics |
Disable a site (removes vars + website + data). |
serviceId or siteId |
get_analytics_summary |
Headline metrics over a window (pageviews/visitors/visits/bounces vs previous window). |
serviceId/siteId, range, startTime, endTime, filters |
get_analytics_breakdown |
Top values for one axis (type = referrer/country/url/device/event/…). |
serviceId/siteId, type*, limit |
get_analytics_timeseries |
Pageviews + sessions over time bucketed by unit (hour/day/month). |
serviceId/siteId, unit, timezone, range |
get_analytics_realtime |
Visitors active right now (~last 5 min). |
serviceId/siteId |
get_analytics_markers |
Timeline of deploys + domain/DNS changes from the audit log (pair with timeseries). |
serviceId/siteId, range |
delete_service also accepts analytics: keep|delete — keep (default) converts the service’s site to external so the history survives the deletion.
Members
| Tool |
Purpose |
Key params |
list_members |
List an org’s members (humans + agents) with role/email/setup status. read. |
organizationId* |
invite_member |
Invite a human by email with a role (owner-invite of an existing account is a pending invitation). manage + admin. |
organizationId*, email*, role*, displayName |
set_member_role |
Change a member’s role (by userId or principalId; can’t demote the only owner). manage + admin. |
organizationId*, role*, userId, principalId |
remove_member |
Remove a member (can’t remove the only owner). manage + admin. |
organizationId*, userId, principalId |
Limits & policies
| Tool |
Purpose |
Key params |
get_limits |
Read a principal’s action mask, spend cap, and approval threshold. Omit principalId for your own live mask; omit organizationId for the global row. |
organizationId, principalId |
set_limits |
Set a principal’s limits (actionMask can only narrow). Org-scoped needs owner; global needs platform admin. manage. |
principalId*, organizationId, actionMask, spendCapCents, spendPeriod, approvalThresholdCents |
Billing
| Tool |
Purpose |
Key params |
get_billing_status |
Read funding provider, tier (preview = the free trial, which does deploy; paid = subscribed), previewExpiresAt, billing/deploy-gate flags, customer + default payment method, subscription, blockers. hasPaymentMethod and tier are independent — a card does not move an org off preview. read + viewer. |
organizationId* |
get_subscription |
Read the latest subscription (plan/status/period/cancelAtPeriodEnd). { subscription: null } just means the org is on (or has lapsed from) the free trial. read + viewer. |
organizationId* |
list_invoices |
List invoices newest-first, live from the provider (hosted + PDF links). read + viewer. |
organizationId*, limit |
get_usage |
Summarize tier + previewExpiresAt/previewServiceLimit + billable resource counts (services/DBs/buckets/domains) + application egress over the last 30 days (egress30d: bytes, gb, metered). metered: false means egress was not measured for the org, not that it was zero. Also returns 30-day daily averages for the two gauge metrics: services30d (avgDaily, metered) — the average billable services held per day, distinct from the live resources.services count — and dbStorage30d (avgDailyBytes, avgDailyGb, metered) for tenant-database storage. Each gauge’s metered: false means no sample was recorded (poller off, or every database unreachable); the average is meaningless then and must not be read as zero usage. On a trial, compare the live counts against the 1 service / 1 database / 1 bucket allowance. Also returns currentPeriod: the projected overage for THIS calendar month from the shared usage aggregator (the same computation the invoice and the allotment warnings use), with per-metric used/included/overageQuantity/unitPriceCents/overageCents in each metric’s billable unit (GB-month, “1,000 emails”, service-month, GB), the flat SMS addOns (no allotment; charge from published rates), and projectedOverageCents (unitPriceCents: null means the plan doesn’t meter that metric). And overagePeriods — overage close-out history newest-window-first (periodStart, periodEnd, mode shadow|live, status, totalOverageCents, providerInvoiceId); mode: "shadow" rows are “what you WOULD be billed” before real charging is enabled, and the list is empty until the overage engine is turned on. Display only — nothing here charges or blocks. Mirrors the portal Billing → Usage + “Projected overage this period” cards. read + viewer. |
organizationId* |
set_payment_method |
Begin attaching a payment method (hosted setupUrl + SetupIntent; no charge). Step 1 of 2 — a card alone leaves the org on the trial; follow with create_subscription. manage + owner. |
organizationId* |
list_plans |
List subscribable plans (allotments, metered overages) with BOTH cadences priced: monthlyPriceCents, annualPriceCents, per-interval intervals.{month,year}.{offered,priceCents,priceAvailable}, and annualSavings (cents / percent / months free). read + admin. |
organizationId* |
create_subscription |
Upgrade the org to a paid plan (idempotent). The only call that ends the trial: lifts preview_expired, drops the trial resource caps, un-suspends + redeploys reclaimed services, and unlocks custom domains, outbound email and managed Redis. Needs a card on file (else card_required → set_payment_method). planCode defaults to pro when available. interval is month (default) or year for annual billing — check list_plans first, an unavailable cadence returns plan_price_not_configured. Does NOT switch an existing subscription between cadences. manage + owner. |
organizationId*, planCode, interval |
change_plan |
Move an org’s active subscription to a different plan in place (e.g. starter→pro, pro→scale) — a plan change, not cancel+resubscribe. Swaps the subscription’s price and prorates the mid-cycle switch (credit for unused time on the old plan, prorated charge for the new). Requires an active subscription (no_active_subscription otherwise — use create_subscription first). Errors: plan_unknown, same_plan, plan_price_not_configured (check list_plans). interval month (default) or year. manage + owner. |
organizationId*, planCode*, interval |
defer_org_billing |
Platform admin only. Defer an org’s billing until a date — charge them, but not before then (typically a client who prepaid a previous host through that date). Applies immediately to an existing subscription and is also recorded for a not-yet-subscribed org to pick up at subscribe time; enforced provider-side as a trial, so billing resumes automatically. Distinct from the billingEnabled comp switch (comp = never charge, deferral = start later; an org may carry both) and from the free trial (which precedes any subscription). Domain fees still charge, and deferral does not credit already-paid time. deferUntil: null clears it. manage + platform admin. |
organizationId*, deferUntil*, reason |
Annual billing. Interval is a dimension of a plan’s price, not a separate
plan: annual Pro and monthly Pro grant identical entitlements (services,
allotments, domain credits) and differ only in price and cadence. Annual is
priced at 10x the monthly rate (“2 months free”). Included allotments are always
per calendar month — an annual Pro org gets 10 GB storage per month, not
120 GB for the year; list_plans states this as allotmentPeriod: "month".
The portal Billing page offers the same monthly/yearly choice to humans.
Support tickets
Support is staffed by humans and AI agents; set handlerPreference (human / agent / any) to say who you want. There is no push channel on MCP — poll list_support_tickets and check unread. Requesters are also notified by email (agent-opened tickets email the org owners) and, if configured, an org webhook.
| Tool |
Purpose |
Key params |
open_support_ticket |
Open a ticket with the platform team (platform-side problems, questions, escalations). manage + developer. |
subject*, body*, organizationId, priority, handlerPreference, projectId, serviceId |
list_support_tickets |
List the org’s tickets, newest activity first; unread=true means support replied since last read — poll this. read + viewer. |
organizationId, status, includeClosed |
get_support_ticket |
Read a ticket’s full thread; reading marks it read for your org. read + viewer. |
ticketId* |
reply_support_ticket |
Reply and/or close (close:true); replying to a waiting/resolved ticket reopens it. manage + developer. |
ticketId*, body, close |
get_support_webhook |
Show the org’s ticket-update webhook config (secret never returned). read + admin. |
organizationId |
set_support_webhook |
Register an HTTPS endpoint for HMAC-signed support.ticket.updated POSTs (verify X-Tandem-Signature); secret returned once; url:null removes. manage + admin. |
url*, organizationId |
admin_list_support_tickets |
PLATFORM ADMIN: the cross-org support queue; filter by status/handlerPreference/unreadOnly. |
status, handlerPreference, organizationId, unreadOnly, includeClosed |
admin_get_support_ticket |
PLATFORM ADMIN: full thread including internal notes; marks platform-side read. |
ticketId* |
admin_reply_support_ticket |
PLATFORM ADMIN: reply to the requester (notifies them), or internal:true for a platform-only note. |
ticketId*, body*, internal |
admin_update_support_ticket |
PLATFORM ADMIN: triage — set status (resolved notifies requester), assign to a platform-admin principal, set priority. |
ticketId*, status, assigneePrincipalId, assigneeDisplay, priority |