# Plinth

> App hosting your agent runs: git, deploys, staging/production, Postgres. Owner approves risky steps.

- name: dev.tryplinth/plinth
- version: 1.0.0
- connection class: R0 (autonomous)
- trust: 83/100 flags: no-repository
- quality: 69/100 (new)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/dev.tryplinth%2Fplinth
- tools: https://api.protogrid.dev/v1/servers/dev.tryplinth%2Fplinth/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "plinth": {
      "type": "http",
      "url": "https://tryplinth.dev/mcp"
    }
  }
}
```


## Trust

- hygiene: 80
- liveness: 100
- freshness: 100
- provenance: 55
- drivers: +dns-namespace +website +reachable +uptime-100% +updated-5d-ago -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 69/100 (new)

### protocol: 75 (weight 25)

- warn `protocol.modern`: newest supported version is 2025-11-25; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
- n/a `protocol.stateless`: only applies to 2026-07-28 servers
- pass `protocol.transport`: streamable HTTP
- n/a `protocol.list_ttl`: only applies to 2026-07-28 servers

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 64 (weight 30)

- warn `tools.descriptions`: 3 of 72 tools have a description under 20 characters
- pass `tools.description_length`: descriptions are concise
- pass `tools.schemas`: every tool has an object input schema
- fail `tools.annotations`: no tool declares readOnlyHint or destructiveHint, so clients cannot tell safe calls from risky ones
- fail `tools.directory_hints`: no tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: promote (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); support.list (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); account.create (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); …
- pass `tools.token_cost`: about 6,200 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: n/a (weight 15)

- n/a `stability.changes`, `stability.rug_pull`: tool history recorded for 5 of the 7 days needed

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 72, about 6,200 tokens to load them all
- tool set hash: 902c191708dd283fa03459c23c594d60
- badge: [![protogrid quality](https://protogrid.dev/badge/dev.tryplinth/plinth.svg)](https://protogrid.dev/servers/dev.tryplinth/plinth)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

_No tool definition changes recorded._

## Remotes

- https://tryplinth.dev/mcp (streamable-http, auth none, reachable true, uptime30d 1)

## Packages

_none_

## Tools (72)

- `account.create`: Create a Plinth account for your human owner (or join theirs if their email already has one). Plinth emails them a link to approve; then call account.status with the returned signup_id and poll to collect your token.
- `account.status`: Finish signup: checks whether the owner approved, and returns your token (once) when they have.
- `agents.list`: Agents that have a key to this account, when each was last used, and which one you are.
- `agents.revoke`: Owner only. Remove an agent's access to this account immediately.
- `analytics.get`: 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.
- `approval.cancel`: Withdraw a pending approval request you made (for example one that is no longer needed). The owner can no longer approve it.
- `approvals.list`: 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).
- `approval.status`: Check an approval. When approved, result holds the action output.
- `billing.card`: 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.
- `billing.status`: Whether a card is on file, this month's spend, the spend cap and recent charges.
- `code.list`: List files in the project repo (path and size) on a branch or commit.
- `code.read`: Read one file from the project repo. Text comes back as utf8; binary files as base64.
- `code.write`: 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.
- `console.signin`: 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.
- `cron.add`: 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".
- `cron.list`: Cron jobs on an environment with last run and next run.
- `cron.pause`: Pause a cron job (it stays defined but does not run).
- `cron.remove`: Delete a cron job.
- `cron.resume`: Resume a paused cron job.
- `cron.run`: Run a cron job now and return its result.
- `cron.runs`: Recent runs of a cron job.
- `db.connection`: 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.
- `db.migrate`: 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.
- `db.migrations`: Applied and pending migrations (files in migrations/*.sql, applied in name order).
- `db.query`: 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.
- `db.restore`: 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.
- `db.snapshot`: Take a snapshot (pg_dump) of an environment database.
- `db.snapshots`: List snapshots for an environment. Staging and production get one automatically every night at 03:00 UTC, kept 7 days.
- `deploy`: Rebuild and deploy the head of the branch an environment tracks (staging tracks main). Production only changes via promote.
- `deploy.cancel`: Stop a build that is still running (the latest one in the environment, or a given release id). The live release keeps serving.
- `deploy.status`: 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.
- `domains.buy`: 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.
- `domains.connect`: Map a domain you own to an environment. Point its DNS at the Plinth host; returns the record to create.
- `domains.list`: Domains mapped to a project.
- `domains.orders`: Domains bought through Plinth on this account, with price, status and expiry.
- `domains.remove`: Unmap a domain.
- `domains.search`: 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.
- `domains.verify`: Check the TXT record of a connected domain; once it matches, the domain is served.
- `env.exec`: 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.
- `env.list`: Environments for a project with live release and URL.
- `env.restart`: Restart an environment on its current release (fresh sandbox, same code and data).
- `env.secrets.import`: 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.
- `env.secrets.list`: List environment variable names (values are never returned).
- `env.secrets.set`: Set an environment variable for an environment. Restarts the env so it takes effect.
- `env.secrets.unset`: Remove an environment variable.
- `env.status`: Debug an environment: is it running, restarts, out-of-memory kills, memory/CPU use, live release, and the last errors from its logs.
- `git.branches`: Branches and their head commits.
- `git.log`: Recent commits on a branch.
- `git.remote`: Get the authenticated git remote URL for pushing. Pushing main deploys staging; any other branch gets a preview environment.
- `git.revert`: Revert a commit on a branch server-side. The new commit deploys like a push.
- `http.probe`: 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.
- `logs.query`: Logs for an environment: app stdout/stderr, build, cron and system lines. Filter by text and stream.
- `metrics.get`: Request count, error rate and latency percentiles for an environment.
- `policy.set`: Owner only. Choose which approval types run without asking. Keys: project.create, project.delete, promote.production, migration.destructive, db.restore.production, billing.
- `project.create`: 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.
- `project.delete`: 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.
- `project.downgrade`: Move a project back to the free plan. Its custom domains stop being served. The subscription shrinks with a prorated credit.
- `project.get`: Show one project: git remote, environments, live release per environment, URLs.
- `project.list`: List projects with their environments, live releases and URLs.
- `project.upgrade`: 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.
- `promote`: 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.
- `requests.query`: Recent HTTP requests to an environment: method, path, status, time taken. Filter to failures with min_status 500, or by path.
- `rollback`: Point an environment back at its previous release (or a given release id). Does not roll back the database.
- `seo.setup`: 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.
- `support.list`: Your support tickets with their status and the team's reply.
- `support.send`: 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.
- `token.rotate`: 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).
- `webhooks.add`: 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.
- `webhooks.list`: Your webhooks with their last delivery status.
- `webhooks.remove`: Delete a webhook.
- `webhooks.test`: Send a test event to all your webhooks; check webhooks.list a few seconds later for the result.
- `whoami`: Show the account this token belongs to, its policy and projects.
