{
  "tools": [
    {
      "name": "whoami",
      "description": "Show the account this token belongs to, its policy and projects.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "project.create",
      "description": "Create a project: a git repo plus production and staging environments, each with its own Postgres database. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Lowercase name, 3-40 chars, e.g. acme-crm"
          }
        },
        "required": [
          "name"
        ]
      }
    },
    {
      "name": "project.list",
      "description": "List projects with their environments, live releases and URLs.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "project.get",
      "description": "Show one project: git remote, environments, live release per environment, URLs.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "project.delete",
      "description": "Delete a project, its repo, environments and databases. Irreversible. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "project.share",
      "description": "Share a project with another person, e.g. a friend or teammate, by email. Once they accept, they and their own agents can change the code, deploy, go live and use its databases, from their own Plinth account. Only the owner can delete the project, change its plan or domains, or share it. The owner approves each share. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "email": {
            "type": "string",
            "description": "Their email address"
          }
        },
        "required": [
          "project",
          "email"
        ]
      }
    },
    {
      "name": "project.members",
      "description": "Who a project is shared with: the owner, members, and invitations not yet accepted.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "project.unshare",
      "description": "Stop sharing a project with someone (owner), or leave a project shared with you (pass your own email). Also cancels a pending invitation.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "email": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "email"
        ]
      }
    },
    {
      "name": "code.write",
      "description": "Commit files to the project without git: for agents that cannot run git or the CLI (e.g. Claude or ChatGPT in the cloud). Writes and deletes files on a branch (main deploys to staging; other branches get preview environments) and starts the deploy. Send whole files; text as utf8, binary as base64. Up to 5 MB per file.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "branch": {
            "type": "string",
            "description": "Default main"
          },
          "message": {
            "type": "string",
            "description": "Commit message"
          },
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string"
                },
                "content": {
                  "type": "string"
                },
                "encoding": {
                  "type": "string",
                  "description": "utf8 (default) or base64"
                }
              },
              "required": [
                "path",
                "content"
              ]
            }
          },
          "delete": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Paths to remove"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "code.list",
      "description": "List files in the project repo (path and size) on a branch or commit.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "ref": {
            "type": "string",
            "description": "Branch or commit, default main"
          },
          "prefix": {
            "type": "string",
            "description": "Only files under this folder"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "code.read",
      "description": "Read one file from the project repo. Text comes back as utf8; binary files as base64.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "path": {
            "type": "string"
          },
          "ref": {
            "type": "string",
            "description": "Branch or commit, default main"
          }
        },
        "required": [
          "project",
          "path"
        ]
      }
    },
    {
      "name": "git.remote",
      "description": "Get the authenticated git remote URL for pushing. Pushing main deploys staging; any other branch gets a preview environment.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "git.log",
      "description": "Recent commits on a branch.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "branch": {
            "type": "string",
            "description": "Default main"
          },
          "limit": {
            "type": "number"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "git.branches",
      "description": "Branches and their head commits.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "git.revert",
      "description": "Revert a commit on a branch server-side. The new commit deploys like a push.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "commit": {
            "type": "string"
          },
          "branch": {
            "type": "string",
            "description": "Default main"
          }
        },
        "required": [
          "project",
          "commit"
        ]
      }
    },
    {
      "name": "env.list",
      "description": "Environments for a project with live release and URL.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "env.secrets.set",
      "description": "Set an environment variable for an environment. Restarts the env so it takes effect.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "key": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "key",
          "value"
        ]
      }
    },
    {
      "name": "env.secrets.list",
      "description": "List environment variable names (values are never returned).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "env.secrets.import",
      "description": "Set many environment variables at once from .env text (KEY=value lines; # comments, quotes and \"export\" are fine). One restart at the end. Keys starting with VITE_/NEXT_PUBLIC_/PUBLIC_ also reach the build.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "dotenv": {
            "type": "string",
            "description": "Contents of a .env file"
          },
          "replace": {
            "type": "boolean",
            "description": "Remove variables not in the file (default false)"
          }
        },
        "required": [
          "project",
          "env",
          "dotenv"
        ]
      }
    },
    {
      "name": "env.secrets.unset",
      "description": "Remove an environment variable.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "key": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "key"
        ]
      }
    },
    {
      "name": "deploy",
      "description": "Rebuild and deploy the head of the branch an environment tracks (staging tracks main). Production only changes via promote.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "commit": {
            "type": "string",
            "description": "Optional commit sha; defaults to branch head"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "deploy.status",
      "description": "Releases for an environment, newest first, with status and build log of the latest. Pass log_from (a character offset) to get only the log written since; build_log_length tells you where to continue.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "limit": {
            "type": "number"
          },
          "log_from": {
            "type": "number"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "deploy.cancel",
      "description": "Stop a build that is still running (the latest one in the environment, or a given release id). The live release keeps serving.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "release": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "promote",
      "description": "Promote the release running on one environment to another (default staging to production). Applies pending migrations first. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "from": {
            "type": "string",
            "description": "Default staging"
          },
          "to": {
            "type": "string",
            "description": "Default production"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "rollback",
      "description": "Point an environment back at its previous release (or a given release id). Does not roll back the database.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "release": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "db.query",
      "description": "Run SQL against an environment database. Returns up to 500 rows. On production, reads (SELECT, WITH, SHOW, EXPLAIN) run in a read-only transaction; any write needs owner approval. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "sql": {
            "type": "string"
          },
          "params": {
            "type": "array",
            "items": {}
          }
        },
        "required": [
          "project",
          "env",
          "sql"
        ]
      }
    },
    {
      "name": "db.migrations",
      "description": "Applied and pending migrations (files in migrations/*.sql, applied in name order).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "db.migrate",
      "description": "Apply pending migrations from the live release now (deploys do this automatically). Takes a snapshot first. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "db.snapshot",
      "description": "Take a snapshot (pg_dump) of an environment database.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "db.snapshots",
      "description": "List snapshots for an environment. Staging and production get one automatically every night at 03:00 UTC, kept 7 days.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "db.restore",
      "description": "Restore an environment database from a snapshot. Takes a safety snapshot first. Production needs owner approval. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "snapshot": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "snapshot"
        ]
      }
    },
    {
      "name": "db.connection",
      "description": "Get the DATABASE_URL for an environment (the same one the app receives). Production needs owner approval. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "cron.add",
      "description": "Schedule a job: Plinth POSTs to path on the environment at each tick (5-field cron, UTC), with the header x-plinth-cron-secret. Paths under /api/cron/ refuse any other caller. Outside production jobs start paused unless enabled is true. Jobs can also be declared in plinth.json \"crons\".",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "name": {
            "type": "string"
          },
          "schedule": {
            "type": "string",
            "description": "e.g. \"0 9 * * 1\" or \"*/5 * * * *\""
          },
          "path": {
            "type": "string",
            "description": "e.g. /api/cron/digest"
          },
          "enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "project",
          "env",
          "name",
          "schedule",
          "path"
        ]
      }
    },
    {
      "name": "cron.list",
      "description": "Cron jobs on an environment with last run and next run.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "cron.pause",
      "description": "Pause a cron job (it stays defined but does not run).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "name"
        ]
      }
    },
    {
      "name": "cron.resume",
      "description": "Resume a paused cron job.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "name"
        ]
      }
    },
    {
      "name": "cron.remove",
      "description": "Delete a cron job.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "name"
        ]
      }
    },
    {
      "name": "cron.run",
      "description": "Run a cron job now and return its result.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "name"
        ]
      }
    },
    {
      "name": "cron.runs",
      "description": "Recent runs of a cron job.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env",
          "name"
        ]
      }
    },
    {
      "name": "domains.connect",
      "description": "Map a domain you own to an environment. Point its DNS at the Plinth host; returns the record to create.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "host": {
            "type": "string",
            "description": "e.g. crm.acme.co"
          }
        },
        "required": [
          "project",
          "env",
          "host"
        ]
      }
    },
    {
      "name": "domains.list",
      "description": "Domains mapped to a project.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "domains.verify",
      "description": "Check the TXT record of a connected domain; once it matches, the domain is served.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "host": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "host"
        ]
      }
    },
    {
      "name": "domains.remove",
      "description": "Unmap a domain.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "host": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "host"
        ]
      }
    },
    {
      "name": "billing.status",
      "description": "Whether a card is on file, this month's spend, the spend cap and recent charges.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "project.upgrade",
      "description": "Move a project to Pro ($19/month per project): own domains and more room. Charges the owner's card now (prorated) after they approve. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "project.downgrade",
      "description": "Move a project back to the free plan. Its custom domains stop being served. The subscription shrinks with a prorated credit.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "billing.card",
      "description": "Ask the owner to add or replace the payment card. Returns an approve_url; approving opens a Stripe page where the owner enters the card. Plinth never sees card numbers. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "domains.search",
      "description": "Check if domains can be bought here, with price. Pass a name (\"acme\" checks acme.com, .dev, .app, .io, .co, .net, .ai, .org) or a full domain.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "e.g. acme or acme.dev"
          }
        },
        "required": [
          "query"
        ]
      }
    },
    {
      "name": "domains.buy",
      "description": "Buy a domain and connect it to an environment: registers it, points DNS at Plinth, issues HTTPS. Always shows the owner the exact price first. Standard registrations only. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "domain": {
            "type": "string",
            "description": "e.g. acme.dev (run domains.search first)"
          },
          "years": {
            "type": "number",
            "description": "1-10, default 1"
          }
        },
        "required": [
          "project",
          "env",
          "domain"
        ]
      }
    },
    {
      "name": "domains.orders",
      "description": "Domains bought through Plinth on this account, with price, status and expiry.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "logs.query",
      "description": "Logs for an environment: app stdout/stderr, build, cron and system lines. Filter by text and stream.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "since": {
            "type": "string",
            "description": "30s, 15m, 2h, 7d (default 15m)"
          },
          "grep": {
            "type": "string"
          },
          "stream": {
            "type": "string",
            "description": "stdout, stderr, build, cron, system"
          },
          "limit": {
            "type": "number"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "metrics.get",
      "description": "Request count, error rate and latency percentiles for an environment.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "since": {
            "type": "string"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "analytics.get",
      "description": "Visitors and page views per day, top pages, where visitors come from, and phone vs desktop. No cookies; visitors are counted per day. Free shows today; Pro up to 90 days.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "days": {
            "type": "number",
            "description": "Default 30 (Pro) or 1 (Free)"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "seo.setup",
      "description": "Check how search engines see an environment (title, description, robots.txt, sitemap, noindex) and get the steps to connect OpenSEO (openseo.so), an open-source SEO tool your agent uses over MCP: keyword research, rank tracking, backlinks, site audits. The owner signs up on OpenSEO; Plinth does not share any data with it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Default production"
          }
        },
        "required": [
          "project"
        ]
      }
    },
    {
      "name": "env.status",
      "description": "Debug an environment: is it running, restarts, out-of-memory kills, memory/CPU use, live release, and the last errors from its logs.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "env.restart",
      "description": "Restart an environment on its current release (fresh sandbox, same code and data).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "env.exec",
      "description": "Production needs owner approval. Run a shell command inside the environment's running sandbox (same code, env vars, network and limits as the app), e.g. \"node -e '...'\", \"ls\", \"env | sort\". 30s timeout, 20 KB of output. Code is read-only; /tmp is writable. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "command": {
            "type": "string"
          },
          "timeout_seconds": {
            "type": "number"
          }
        },
        "required": [
          "project",
          "env",
          "command"
        ]
      }
    },
    {
      "name": "http.probe",
      "description": "Send one HTTP request to the environment from inside Plinth and return status, headers, timing and the first 8 KB of the body. Use it to reproduce a failing route.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "path": {
            "type": "string",
            "description": "e.g. /api/orders?id=3"
          },
          "method": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "headers": {
            "type": "object"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "requests.query",
      "description": "Recent HTTP requests to an environment: method, path, status, time taken. Filter to failures with min_status 500, or by path.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "project": {
            "type": "string",
            "description": "Project name"
          },
          "env": {
            "type": "string",
            "description": "Environment: production, staging, or a preview name"
          },
          "since": {
            "type": "string"
          },
          "min_status": {
            "type": "number"
          },
          "path": {
            "type": "string"
          },
          "limit": {
            "type": "number"
          }
        },
        "required": [
          "project",
          "env"
        ]
      }
    },
    {
      "name": "approvals.list",
      "description": "Approvals requested by this account, newest first. status: pending, approved, denied, cancelled, superseded (default all). Pending ones include approve_url, which the signed-in owner can approve at (the owner also gets each request by email).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "pending, approved, denied, cancelled, superseded (default all)"
          }
        },
        "required": []
      }
    },
    {
      "name": "approval.cancel",
      "description": "Withdraw a pending approval request you made (for example one that is no longer needed). The owner can no longer approve it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "approval.status",
      "description": "Check an approval. When approved, result holds the action output.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "owner.notify",
      "description": "Message your human owner on their phone (Telegram, WhatsApp or SMS, whichever they connected in the console; email if none). Use it for things they should know now: a deploy is live, something broke, you are blocked on them. Keep it short and plain. Up to 30 a day.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "What to tell them, in one to three plain sentences"
          }
        },
        "required": [
          "message"
        ]
      }
    },
    {
      "name": "support.send",
      "description": "Send the Plinth team a bug report, feature request or question. Include what you tried and what happened. Recent errors for the project are attached automatically. Replies show up in support.list.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "bug, feature, question or other"
          },
          "title": {
            "type": "string",
            "description": "One line"
          },
          "body": {
            "type": "string",
            "description": "Details: steps, expected vs actual, commands, error text"
          },
          "project": {
            "type": "string",
            "description": "Optional project it is about"
          },
          "env": {
            "type": "string",
            "description": "Optional environment"
          }
        },
        "required": [
          "kind",
          "title",
          "body"
        ]
      }
    },
    {
      "name": "support.list",
      "description": "Your support tickets with their status and the team's reply.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "webhooks.add",
      "description": "Send Plinth events to a URL (your bot, Slack, Discord, Telegram, Zapier...). Events: deploy.succeeded, deploy.failed, approval.requested, approval.decided, app.down, app.up, support.created, support.replied, charge.succeeded, signup.approved. Leave events empty for all. Payloads are JSON with a \"text\" summary and an x-plinth-signature HMAC header; Slack/Discord webhook URLs and Telegram sendMessage URLs work as-is.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "https URL"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "authorization": {
            "type": "string",
            "description": "Optional Authorization header value, e.g. \"Bearer abc\". Stored encrypted."
          }
        },
        "required": [
          "url"
        ]
      }
    },
    {
      "name": "webhooks.list",
      "description": "Your webhooks with their last delivery status.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "webhooks.remove",
      "description": "Delete a webhook.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "webhooks.test",
      "description": "Send a test event to all your webhooks; check webhooks.list a few seconds later for the result.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "console.signin",
      "description": "Get the owner into the web console. Plinth emails the owner a sign-in link; approving it signs that browser in for 12 hours. The agent never receives a session. May return pending_approval: the owner is emailed a link to approve; tell them it is waiting, then poll approval.status.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "token.rotate",
      "description": "Replace your own agent token with a new one; the old one stops working immediately. Save the new token in ~/.plinth/config.json (the CLI does this for you).",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "agents.list",
      "description": "Agents that have a key to this account, when each was last used, and which one you are.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "required": []
      }
    },
    {
      "name": "agents.revoke",
      "description": "Owner only. Remove an agent's access to this account immediately.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      }
    },
    {
      "name": "policy.set",
      "description": "Owner only. Choose which approval types run without asking. Keys: project.create, project.delete, promote.production, migration.destructive, db.restore.production, billing.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "auto_approve": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "auto_approve"
        ]
      }
    }
  ]
}