Percher
NPM · @PERCHER/MCP · 2 COMPONENTS · SCANNED SEP 20
MCP-native hosting: publish and operate AI-built web apps live at name.percher.run.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security98
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- 65 of 234 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency6
- Repository check failed: no source repository is declared. See how to fix → View diagnostics → Fail
- Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
- License check failed: the license (FSL-1.1-MIT) isn't a recognized OSI-approved license. See how to fix → Fail
- Actively maintained (last published 0 days ago).Pass
- Security-disclosure policy not yet verified: we couldn't inspect the source repository.Unverified
Schema Quality & AI Usability59
- AI-judged instruction clarity (good).Pass
- Context-footprint check failed: tool/resource definitions use about 14266 tokens (~264/item across 54 items; 54 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management87
- Stability observed for 26 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage75
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 25% of tool parameters carry a description.Partial
Tool Safety75
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- 0 of 5 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "percher_publish" implies "publish" and declares no destructiveHint at all, which the MCP spec reads as destructive by default. See how to fix → Fail
- An AI judge read all 55 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
How do I install the Percher MCP server?
Percher runs locally as an npm package, launched with npx -y @percher/mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · @percher/mcp
claude mcp add app-percher-percher -- npx -y @percher/mcp
{
"mcpServers": {
"app-percher-percher": {
"command": "npx",
"args": [
"-y",
"@percher/mcp"
]
}
}
} {
"servers": {
"app-percher-percher": {
"command": "npx",
"args": [
"-y",
"@percher/mcp"
]
}
}
} codex mcp add app-percher-percher -- npx -y @percher/mcp
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"app-percher-percher": {
"type": "local",
"command": [
"npx",
"-y",
"@percher/mcp"
],
"enabled": true
}
}
} openclaw mcp add app-percher-percher --command npx --arg -y --arg @percher/mcp
mcp_servers:
app-percher-percher:
command: "npx"
args: ["-y", "@percher/mcp"] {
"McpServers": {
"app-percher-percher": {
"Transport": "stdio",
"Command": "npx",
"Arguments": [
"-y",
"@percher/mcp"
]
}
}
} assistant mcp add app-percher-percher -t stdio -c npx -a -y @percher/mcp
{
"mcpServers": {
"app-percher-percher": {
"command": "npx",
"args": [
"-y",
"@percher/mcp"
]
}
}
} Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 20 Sept 26 +11
- Known CVEs: unverified → pass ▲ security
- Dependency health: unverified → 0.87 ▲ functional
- 19 Sept 26 −13
- Known CVEs: pass → unverified ▼ security
- Stability: 0.80 → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- Schema quality: 236 → 264 ▼ functional
- Schema quality: 236 → 263 ▼ functional
- Dependency health: 0.81 → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Capabilities: pass → unverified ▼ functional
- License: pass → fail ▼ functional
- Dependency health: 0.81 → 0.87 ▲ functional
- Schema quality: Schema quality not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. functional
- Licence: MIT → FSL-1.1-MIT functional
- Package version: 0.6.15 → 1.0.3 functional
- Package version: 0.6.15 → 1.0.2 functional
- 18 Sept 26 −2
- Stability: pass → 0.80 functional
- 17 Sept 26 0
- Stability: 0.97 → pass security
- 16 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 93 to 97. That category is still filling its 30-day observation window: 28 days of observed history at the previous scan, 29 at this one. The score rises as the window fills, whether or not the server changes.
- 14 Sept 26 0
- Dependency health: 0.87 → 0.81 ▼ functional
- 13 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 83 to 87. That category is still filling its 30-day observation window: 25 days of observed history at the previous scan, 26 at this one. The score rises as the window fills, whether or not the server changes.
- 12 Sept 26 −2
- Stability: pass → 0.83 functional
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 20 Sept 2026 · Analysed npm/@percher/mcp@1.0.3
Provenance No attestation
The registry publishes no build provenance for this version, so there is nothing to verify.
| Result | No attestation |
|---|---|
| Ecosystem | npm |
Background: How many MCP packages publish verified provenance →
Dependencies 234 packages
| Packages resolved | 234 |
|---|---|
| Stale | 65 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
percher_account_delete ~598
Request account deletion (GDPR Art. 17). Fail-closed: the API rejects the request if the account has any blockers (owned apps, accepted collaborators, pending invites, open PR previews, pending outgoing transfers, in-flight deploys, active restore jobs). Server-side preflight before delete: the handler always runs percher_account_deletion_preview-equivalent logic against the API and short-circuits if any blocker is present. The DELETE /account endpoint is NEVER invoked when blockers exist — the response is `{ status: 'blocked', blockers, recovery: { nextAction: 'ask_user', prompt } }`. The agent surfaces `recovery.prompt` verbatim; the user resolves blockers via the existing tools (percher_delete_app for apps, percher_share for collaborators, percher_transfer for outgoing transfers) and retries. Note: agents SHOULD still call percher_account_deletion_preview directly first so the user sees the blocker state before they ack the destructive intent — the handler-side preflight is the safety net, not the only gate. On a clean account the request is accepted asynchronously: `{ status: 'finalizing', finalizeJobId, recovery: { nextAction: 'none' } }`. The server flips users.status='deleting', revokes API tokens server-side (this very session's token included — the next tool call will return INVALID_TOKEN), writes a `account.delete_requested` audit row, and enqueues the account_delete finalizer job. Finalization completes within seconds for a clean account. Inputs: `{ confirm: <user's email> }` — must equal the signed-in user's email exactly. The server enforces this server-side; client-side check is UX-only. Recovery actions: - `none` → terminal success; do not call again. - `ask_user` (`reasonCode: account_deletion_blocked`) → surface the blocker list to the user, wait for them to clear it, then re-run percher_account_deletion_preview to verify before re-calling this tool. Sunset: if the platform is shutting down (read-only mode), this tool returns an error expl…
| Name | Type | Req | Description |
|---|---|---|---|
| confirm | string | yes | Must equal the signed-in user's email address. The server rejects anything else with CONFIRMATION_REQUIRED. The account must be CLEAN first — owned apps, accepted collaborators, pending invites, open… |
No output schema declared.
No examples provided.
percher_account_deletion_preview ~285
Inspect what would block account deletion. Pure read — no mutation. Returns `{ canDelete, ownedAppCount, blockers: [{ kind, count, details }] }`. Use BEFORE percher_account_delete to surface the blocker list to the user. A clean account returns `canDelete: true` with `blockers: []`. Blocker kinds (each maps to a specific cleanup action via the existing routes): - `apps_owned` — call percher_delete_app per app or transfer ownership. - `apps_with_collaborators` — accepted + non-expired shares; owner revokes via the share routes. - `apps_with_pending_invites` — live pending share invites; owner revokes or waits for them to lapse. - `apps_with_active_pr_previews` — open PR previews; user closes/merges the PRs so the webhook tears the previews down. - `pending_outgoing_transfers` — live pending transfers initiated by this user; owner cancels via the transfer routes. - `deploys_in_progress` — wait for the deploy to finish, then retry. - `active_restore_jobs` — wait for the restore job to finish, then retry. Stale rows (expired pending transfers, expired pending invites) are filtered server-side — the preview is pure-read and does NOT mutate any row.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
percher_analytics ~132
Visitor analytics for apps owned by Starter, Maker or Max subscribers; collaborators use the app owner's plan. Free/anonymous apps have no visitor statistics. Cookie-free, server-side access-log stats with no setup: unique visitors, sessions, bounce rate, top pages, referrers, entry pages, countries, devices, browsers and OS. Bots/scanners are excluded and reported as totalBotRequests/totalScannerRequests. `days`: 1-90 (default 7). Updates every 15 minutes; new apps may initially show zero.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| days | integer | – | – |
No output schema declared.
No examples provided.
percher_app_insights ~132
Cost optimization + reliability suggestions for an app: idle apps to archive, memory pressure needing an upgrade, over-provisioned plans that could downgrade, and deploy-regression warnings. Use proactively during check-ins ('is everything fine with my apps?'), when the user asks about their bill, or when they're thinking about cleaning up. Returns { insights[], summary } sorted critical > warning > info. For plan changes suggested by this tool, follow up with percher_billing (action='upgrade' or 'portal') to hand the user a one-click URL. Read-only.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
percher_app_resources ~211
Per-app CPU + RAM time-series for the requested window. Returns timestamps + metric arrays (zipped: timestamps[i] aligns with metrics.cpuPct[i] / metrics.rssBytes[i]). Use this when an agent or user asks 'how is my app doing over time?' or 'is my app trending hot?' — answers in one call rather than tailing logs. Window choice matters for response size: '1h' (~120 samples) and '24h' (~2880 samples) hit the raw table; '7d' (~2016 5-min aggregates) and '30d' (~8640) hit the rollup. 30d is max-only — sub-max callers get a 7d response with a `note` explaining the downgrade. Pick the smallest window that answers the question (a 30d max response can run into hundreds of KB). Read-only.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| metrics | array | – | – |
| window | string | – | – |
No output schema declared.
No examples provided.
percher_app_topology ~154
Single-app dependency snapshot for AI agent introspection. Returns the app's node graph — Caddy route, custom domain(s), app container (with live RAM/CPU when running), PocketBase sidecar + volume, KV store, GitHub/Forgejo webhook, and scheduled (cron) jobs — each with status 'healthy' | 'degraded' | 'down' | 'absent'. Use when the user asks 'what does my app depend on?', 'is everything wired up?', or 'why isn't my X working?' before guessing at logs. Read-only. Returns { appId, appName, generatedAt, nodes[], edges[] }; discriminate on node.type.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
percher_appstore_kit ~174
Write app-store starter files into the project for taking a Percher-hosted app to the Apple App Store / Google Play: a PWA manifest.json + service worker, a Capacitor config, and assetlinks.json / apple-app-site-association templates. Use when the user asks to 'prep my app for the app store / Play Store' or 'make it installable'. Emits starter files only — the user still owns signing, store accounts, and review; existing files are skipped unless force is set.
| Name | Type | Req | Description |
|---|---|---|---|
| bundleId | string | – | – |
| fingerprint | string | – | – |
| force | boolean | – | – |
| name | string | – | – |
| outDir | string | – | – |
| packageName | string | – | – |
| teamId | string | – | – |
| url | string | – | – |
No output schema declared.
No examples provided.
percher_backups ~64
List available backups for an app. Returns sidecar metadata — backup_id, timestamp, size, sha256, components — without GPG-decrypting anything. Use before percher_restore to show the user what they can restore from.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
percher_billing ~121
Billing (Polar). action='upgrade' returns a checkout URL for a paid plan (plan: 'starter' | 'maker' | 'max') — surface the URL so the user confirms payment in their browser; Percher does NOT change the subscription server-side. action='portal' returns the customer-portal URL for managing an existing subscription (downgrade, cancel, update card, invoices); url is null for users who never subscribed, in which case suggest action='upgrade'.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| plan | string | – | – |
No output schema declared.
No examples provided.
percher_cache_reset ~104
Reset an app's build cache. Use when a deploy keeps reusing a stale dependency install or you suspect a corrupted package cache — it bumps the app's cache generation so the NEXT normal deploy does a one-time cold dependency install (later deploys go warm again, downloading only changed packages). For a single forced fresh build instead, pass noCache:true to percher_publish. Returns { ok, app, cacheGeneration, message }.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
percher_capabilities ~69
Discover what this Percher instance and account support: available runtimes, feature flags (anonymous deploys, preview branch, inspect links, cron), plan limits and current usage. Call once at the start of a session, or when unsure whether a feature exists, instead of guessing from error messages.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
percher_claim_app ~165
Claim an anonymous (account-less) app into the signed-in account. Use after percher_publish with anonymous=true — the claim token from that response is persisted locally, so a bare call works in the same project. Pass app + claimToken explicitly to claim from elsewhere. Claiming lifts the anonymous restrictions (outbound network, database, env vars) on the next deploy and removes the 72h expiry. Returns status='claimed' on success, or status='needs_token' when no claim token is available (surface that to the user).
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | App name to claim (defaults to the persisted anon state or percher.toml) |
| claimToken | string | – | The one-time claim token returned by the anonymous publish (pcl_…) |
No output schema declared.
No examples provided.
percher_create_from_template ~162
Create a new app from a scaffolding template. For a small full-stack app that needs a database + sign-in, use 'capsule' (PocketBase db + auth + realtime, pre-wired). Templates (30): capsule, static, node, python, nextjs, hono, express, fastify, bun, flask, sveltekit, astro, remix, nuxt, vite-react, vite-vue, preact, solid, elysia, htmx, django, eleventy, hugo, laravel, rails, phoenix, go, rust, dotnet, java.
| Name | Type | Req | Description |
|---|---|---|---|
| directory | string | – | – |
| force | boolean | – | – |
| name | string | yes | – |
| template | string | yes | – |
No output schema declared.
No examples provided.
percher_data ~188
App data + capsule OAuth sign-in. Default (no action / action='status'): read-only PocketBase data view — mode, version, collections, stats, admin link. action='oauth_set' enables/rotates an OAuth provider (provider default 'google', clientId, clientSecret) — writes the secret into PocketBase + platform-only encrypted storage (NEVER the env store) and returns redirectUri, which the user must paste into the provider console (Tier A is not fully automatic). action='oauth_remove' clears a provider; action='oauth_status' lists configured providers (names + client ids, never secrets). OAuth actions are owner-only and require the app's PocketBase to be running.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | – | – |
| app | string | – | – |
| clientId | string | – | – |
| clientSecret | string | – | – |
| provider | string | – | – |
No output schema declared.
No examples provided.
percher_data_export ~221
Download a snapshot of the app's PocketBase data (data.db, auxiliary.db + WAL, storage/) as a .tar.gz file. Use when the user says: 'export my data', 'download my database', 'I want a backup of my app data', 'GDPR data portability', or similar. Returns the local file path the tarball was written to, plus its size in bytes. Rate-limited: 1 export per 24h on free plan, more on paid plans — 429 with code EXPORT_RATE_LIMITED if exceeded. Only works for apps with data.mode = 'pocketbase'. Returns NO_POCKETBASE error otherwise. If the app is sleeping (auto-sleep), wake it first by visiting its URL (auto-sleep wakes on first request), then retry.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | App name or id. Defaults to the app in percher.toml. |
| out | string | – | Output file path. Defaults to ./<app>-pb-<timestamp>.tar.gz in the current directory. |
No output schema declared.
No examples provided.
percher_delete_app ~245
Permanently delete an app and all its data (container, database, domains, env vars, deploy history). This cannot be undone. You MUST set confirm: true AND acknowledgeText to exactly 'DELETE: <appName>' (e.g., 'DELETE: my-blog'). Only use when the user explicitly asks to delete an app — never on your own initiative. Sunset: while the platform is shutting down (read-only mode) this returns an error — deletes are paused so the export window stays open. MCP cannot override it; direct the user to confirm with their password in the dashboard. Do not retry.
| Name | Type | Req | Description |
|---|---|---|---|
| acknowledgeText | string | yes | Acknowledgement string. Must equal the literal text 'DELETE: <appName>' where <appName> is the app being deleted. Example: for an app named 'my-blog', pass 'DELETE: my-blog'. Case-sensitive. |
| app | string | – | App name to delete (defaults to percher.toml app name) |
| confirm | boolean | yes | Must be true to confirm deletion. This is a destructive operation that permanently removes the app, its container, database, domains, env vars, and deploy history. |
No output schema declared.
No examples provided.
percher_deploys ~85
List recent deploys for an app — id, status (queued/building/deploying/live/failed), createdAt, errorMessage. Use after percher_publish fails to find the failing deploy ID, then call percher_deploys_inspect with that ID. Default limit: 10.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| limit | integer | – | – |
No output schema declared.
No examples provided.
percher_deploys_inspect ~215
Low-level diagnostic — prefer percher_doctor unless recovery explicitly points here (typically `recovery.nextAction = 'inspect_build_log'` for a known build_failed deploy). Inspects a single deploy: full status, errorMessage, buildLog (when available), and `events` — per-stage timings (queue → build → start → health → swap → canary → done) that localize a slow or failing stage without parsing the build log; empty on servers that predate stage events. Pass `latestFailed: true` to auto-pick the most recent failed deploy on the app (it never covers a deploy that went live but is broken). On success returns { deploy, buildLog, events } with no `recovery` field. The buildLog is the same text the dashboard shows under Deploys → expand row, and is the canonical source of truth for build-time failures.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| id | string | – | – |
| latestFailed | boolean | – | – |
No output schema declared.
No examples provided.
percher_diff ~123
See what changed between two deploy versions: file list with per-file +/− stats, optional unified patch. base/head default to the previous/current live deploy, so a bare call answers 'what changed in the last deploy?'. Set patch:true for the full diff (owner-only). When a deploy fails or an app breaks for an unclear reason, start with percher_doctor — it can point here with the right versions.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| base | string | – | – |
| head | string | – | – |
| patch | boolean | – | – |
No output schema declared.
No examples provided.
percher_doctor ~1,111
Recovery hub for analysis, troubleshooting, health checks, and 'what should I do next?'. Checks app health: auth, API, container, route, PocketBase, env, deploy status. Use after deployment issues or when the user asks why their app isn't working — and any time another tool's recovery returns `nextAction: 'run_doctor'`. Prefer this over manually choosing percher_logs, percher_deploys_inspect, or percher_reproduce. Doctor inspects the relevant signals and returns a recovery that points at the right low-level tool if one is needed. Agents should use mode=auto unless a recovery args field explicitly specifies another mode. Returns the same structured `recovery` shape as percher_publish and percher_wait_for_deploy, plus a `status`, a `diagnosis` (title + explanation + reasonCode + phase), a `summary` line, and the per-check `checks` array. Read `recovery.nextAction` to decide what to do next — never regex-parse the summary or check list: - `none` → result.status='ok', recovery.reasonCode='none'. Surface result.summary; no further action. - `open_login` → result.status='blocked', reasonCode='auth_required'. Call percher_login. - `fix_config` → result.status='blocked', reasonCode='config_invalid'. percher.toml is invalid; the file path and structured issues live on `recovery.problems` (each entry is { file, line?, column?, message }). Ask the user or auto-repair. - `wait_deploy` → result.status='in_progress'. A deploy is queued/building/deploying (or app is provisioning). Call percher_wait_for_deploy with `recovery.args` ({ app, deployId, timeoutSeconds }) — do NOT start a new deploy. - `run_doctor` → result.status='needs_action'. Doctor is routing you back to itself with extra context (reasonCode `build_failed` for a failed deploy; `runtime_crashed` for a crashed container). Call percher_doctor again with `recovery.args` exactly — those args carry `mode` (e.g. 'deploy' or 'runtime') and often `deployId`. On the second call, doctor performs deep analysis usin…
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| deployId | string | – | – |
| mode | string | – | – |
No output schema declared.
No examples provided.
percher_domain ~99
Custom domains for an app. action='add' attaches a domain and returns the DNS records to set; action='verify' checks DNS and activates the domain once the TXT and CNAME/A checks pass; action='list' lists domains with their verification status; action='remove' detaches one. domain is required for add/verify/remove.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| app | string | – | – |
| domain | string | – | – |
No output schema declared.
No examples provided.
percher_env_list ~81
List environment variables (values masked). Returns { values, detailed }: values is the live-resolved KEY→masked record, detailed lists every stored row with its scope ('all' | 'live' | 'preview' — live/preview rows override 'all' for that deploy type; previews resolve with the preview overlay).
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
percher_env_set ~159
Set environment variables for an app. Use when percher_publish reports missing env vars, or when the user needs to configure secrets like API keys. Pass values as { key: value } pairs. Optional scope: 'all' (default) applies to the live app and every preview, while 'live'/'preview' apply only to that deploy type and override the 'all' value there.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| scope | string | – | Env scope: 'all' (default) applies to the live app and every preview; 'preview' applies only to preview deploys and overrides 'all' there; 'live' applies only to the live app and overrides 'all' ther… |
| values | object | yes | – |
No output schema declared.
No examples provided.
percher_env_unset ~106
Unset an environment variable. Optional scope picks which stored value to remove: 'all' (default), or 'live'/'preview' to drop just that deploy type's override.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| key | string | yes | – |
| scope | string | – | Which scoped value to remove: 'all' (default), 'live', or 'preview'. Use 'preview' to drop a preview-only override without touching the value live deploys see. |
No output schema declared.
No examples provided.
percher_export ~140
Download an export bundle for an app — source code, percher.toml, env keys, custom domains, deploy history, migration README, and (for PocketBase apps) a pb_data.zip + schema.json. Writes the .tar.gz to the working directory and returns the local path. Env VALUES are not included; the user must use the dashboard's Settings → Export and confirm their password to include encrypted env values. The download link is single-use and expires in 15 minutes — call this tool fresh each time the user asks to export.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| deliveryKind | string | yes | – |
| out | string | – | – |
No output schema declared.
No examples provided.
percher_forgejo ~331
Connect a Percher app to a Forgejo (or Gitea) repo — self-hosted or codeberg.org — for auto-deploy on push, or rotate its webhook secret. Same flow as percher_github but against any HTTPS Forgejo/Gitea host. action='connect' clones the repo server-side, queues an initial deploy, and generates a webhook secret + setup instructions the user applies in Forgejo Settings → Webhooks. Returns { app, repoUrl, branch, deployId, webhookInstructions?, webhookSetupFailed?, webhookSetupError?, summary }. Check webhookSetupFailed FIRST: if true, call this tool again with action='setup_webhook' to retry (deployId is still valid); if absent, show result.webhookInstructions (settingsUrl, payloadUrl, secret, events). action='setup_webhook' regenerates the webhook secret for an already-connected app. Returns { app, branch, webhookInstructions, summary }. result.webhookInstructions.secret is the signing secret. Surface it via the safest channel your interface supports (boxed credential block, copy button, secret-input widget) — do NOT echo it as plaintext. Shown exactly once; recommend dashboard rotation after testing if the transcript could leak. Optional `autoPreviews: true` converts pushes to non-tracked branches into preview deploys at <app>--p-<branch-slug>.percher.run.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| app | string | – | – |
| autoPreviews | boolean | – | – |
| branch | string | – | – |
| repoUrl | string | – | – |
No output schema declared.
No examples provided.
percher_github ~420
Connect a Percher app to a PUBLIC GitHub repo for auto-deploy on push, or rotate its webhook secret. After connecting, every push to the tracked branch triggers a fresh deploy. Use when the user says 'connect my GitHub repo', 'auto-deploy from GitHub', 'deploy on every push', or similar. action='connect' clones the repo server-side, queues an initial deploy, and generates a webhook secret + setup instructions. Returns { app, repoUrl, branch, deployId, webhookInstructions?, webhookSetupFailed?, webhookSetupError?, summary }. Check webhookSetupFailed FIRST: if true, webhook setup failed — call this tool again with action='setup_webhook' to retry (the initial deploy is still queued; deployId is valid, track it with percher_deploys_inspect); if absent, show result.webhookInstructions (settingsUrl, payloadUrl, secret, events) so the user adds the webhook in GitHub. action='setup_webhook' regenerates the webhook secret for an already-connected app — use after a failed connect, or to rotate. Returns { app, branch, webhookInstructions, summary }. result.webhookInstructions.secret is the signing secret. Surface it via the safest channel your interface supports (boxed credential block, copy button, secret-input widget) — do NOT echo it as plaintext into the assistant reply or any markdown that gets archived. Shown exactly once; recommend dashboard rotation after testing if the transcript could leak. Only PUBLIC GitHub repos are supported. For private repos, use PERCHER_TOKEN with bunx percher publish in GitHub Actions instead. Optional `autoPreviews: true` converts pushes to non-tracked branches into preview deploys at <app>--p-<branch-slug>.percher.run (without it, those pushes are silently skipped).
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| app | string | – | – |
| autoPreviews | boolean | – | – |
| branch | string | – | – |
| repoUrl | string | – | – |
No output schema declared.
No examples provided.
percher_hook ~373
Per-app deploy hooks: secret URLs that trigger a rebuild when POSTed — no auth header, the URL itself is the credential. Wire one into a headless CMS publish button (Sanity, Contentful, Strapi), a cron rig, or a CI job so content changes redeploy the app without touching git. action='create' (name: 1-64 chars, label it after the caller, e.g. 'sanity-publish') returns { id, name, token, hookUrl, createdAt }. token and hookUrl are shown EXACTLY ONCE — the server stores only a hash and can never return them again. Relay the URL verbatim and tell the user to store it in their CMS/CI secret store NOW; treat it like a password (anyone holding it can trigger builds), so don't echo it into archived transcripts more than needed. Triggering is NOT an MCP tool — the CMS/cron/CI does it: POST <hookUrl> → 202 { deployId, app }. An app with a connected GitHub/Forgejo repo rebuilds the latest commit of its tracked branch; an app without one re-runs the latest live deploy's build. Rate limit: 6 requests/min per hook (429 beyond); unknown tokens get a plain 404. action='list' returns each hook's id, name, createdAt, lastUsedAt, and lastDeployId — never the URL or token (unrecoverable by design; lastUsedAt makes a leaked URL observable). action='revoke' (id from list) deletes the hook immediately; rotate a hook by revoking it and creating a fresh one.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| app | string | – | – |
| id | string | – | – |
| name | string | – | – |
No output schema declared.
No examples provided.
percher_import ~94
Import a project from Vercel or Netlify by parsing their config files (vercel.json, netlify.toml) and generating percher.toml. Auto-detects the provider if not specified. For GitHub import, use the dashboard — it clones server-side.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | App name to import into |
| from | string | – | Provider to import from (auto-detected if omitted) |
No output schema declared.
No examples provided.
percher_init ~70
Generate percher.toml configuration for the current project. Usually not needed — percher_publish auto-generates config. Use this only to customize config before deploying.
| Name | Type | Req | Description |
|---|---|---|---|
| dataMode | string | – | – |
| force | boolean | – | – |
| interactive | boolean | – | – |
| name | string | – | – |
No output schema declared.
No examples provided.
percher_inspect_link ~119
Create (default) or revoke a public read-only inspect link for an app: a shareable URL showing live status and recent deploy history without login. Returns inspectUrl. Calling create again rotates the token (the old link dies). Pass revoke=true to kill the link. The public view is sanitized — no logs, no env, no deploy notes, no owner identity.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | App name (defaults to percher.toml) |
| revoke | boolean | – | Revoke the app's inspect link instead of creating one |
No output schema declared.
No examples provided.
percher_invites ~115
Your incoming app-collaboration invites (account-wide, resolved server-side from your email — no app context). action='list' shows pending invites; expired and already-accepted rows are excluded. action='accept' grants access and is idempotent — a repeat returns `alreadyAccepted: true` rather than erroring. action='decline' rejects a pending invite or leaves an already-accepted one. shareId comes from action='list'.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| shareId | string | – | – |
No output schema declared.
No examples provided.
percher_login ~79
Authenticate with Percher. Usually not needed — percher_publish handles auth automatically. Use this when `recovery.nextAction = 'open_login'`, or to pre-authenticate before other operations like percher_env_set or percher_logs.
| Name | Type | Req | Description |
|---|---|---|---|
| apiUrl | string | – | – |
| force | boolean | – | – |
| token | string | – | – |
No output schema declared.
No examples provided.
percher_logs ~150
Low-level diagnostic — prefer percher_doctor unless recovery explicitly points here. Returns a finite snapshot of recent application logs (default 200 lines); use percher_deploys_inspect for a deploy's build log. Use when recovery points at logs or the user asks to see them. MCP cannot stream: follow:true is rejected; use the CLI to follow logs continuously.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| deployId | string | – | – |
| follow | boolean | – | MCP returns a snapshot; only false is supported. |
| level | string | – | – |
| search | string | – | – |
| since | string | – | – |
| source | string | – | – |
| tail | integer | – | – |
No output schema declared.
No examples provided.
percher_open ~30
Get the app URL (browser open is a no-op in MCP)
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
percher_publish ~2,015
Use for any deploy intent: 'publish', 'deploy', 'ship', 'host this', 'put this online'. Always follow `recovery.nextAction` exactly on every response — never regex-parse summaries. MCP defaults to async (`waitForLive=false`) unless the user asks to block; resume with percher_wait_for_deploy. Do NOT use for unknown failures or 'why is my app broken?' — call percher_doctor. Returns the live URL on success or a `recovery.nextAction` on failure. Replaces percher_login/percher_init for end-to-end flows. Use when: you have the project's files on local disk (Claude Code, a terminal) — this reads your cwd. Not when: no local filesystem (a browser session) — the hosted connector's publish tools handle inline files / public-repo URLs / connected repos there. Guide: percher.app/docs/hosted-mcp. ### Inputs - `dryRun` — verify bundle without uploading; consumes no slot. - `check` — validation deploy: build → start → health → teardown (no swap/route). Shares live managed PocketBase and /app/data; writes remain after teardown. Use a separate app for isolated data. Runs code; dryRun is manifest-only. Consumes PREVIEW quota. Success: `status: 'check_passed'`, `recovery.nextAction: 'none'`, no URL. - `preview` — <app>--p-<slug>.percher.run; keeps the live version. Shares managed PocketBase and /app/data with live; writes remain after discard. Use a separate app for isolated data. Free: 1 slot/app, auto-rotates (`replacedPreview=true`). Paid: parallel previews; explicit discard at the limit. - `force` — skip suspicious-bundle warnings. - `message` — note shown in deploy history. - `noCache` — skip image cache, force fresh build. Use when 'my changes aren't showing up'. Response `cacheStatus` tells you which path ran: `image_reused` (no build, prior image re-tagged — re-run with `noCache: true` if changes aren't reflected), `layer_hit` (fresh build, BuildKit reused most layers), or `fresh` (fresh build, no meaningful cache). Legacy `cacheHit` boolean is `true` iff `cach…
| Name | Type | Req | Description |
|---|---|---|---|
| anonymous | boolean | – | Publish WITHOUT an account. Creates a throwaway anonymous app that expires in 72h unless claimed (percher_claim_app). The app runs with no outbound network, no database, and no env vars until claimed… |
| check | boolean | – | Validation deploy: build → start → health, then tear the container down (no swap, no route). Keeps the live version running, but executes code against shared managed PocketBase and /app/data; writes… |
| dryRun | boolean | – | Show what would be deployed (file count, bytes, top files) without uploading or building. Useful for verifying the bundle before a real deploy. |
| force | boolean | – | Deploy even if the bundle omits git-tracked directories; also silences the size and missing-build-env warnings |
| message | string | – | Deploy note (visible in deploy history and version timeline) |
| noCache | boolean | – | Skip the image-cache lookup and force a fresh build. Use this when you suspect the cached image doesn't reflect your latest source — the new build's resulting image still gets cached, so future deplo… |
| preview | boolean | – | Deploy as preview without replacing the live version. Shares managed PocketBase and /app/data with live; writes remain after discard. Use a separate app for isolated data. |
| waitForLive | boolean | – | If true (default), publish blocks until the deploy is live or failed. If false, publish returns as soon as the deploy is queued and the agent can resume with percher_wait_for_deploy. Recommended for… |
No output schema declared.
No examples provided.
percher_redeploy ~267
Re-run an existing deploy without re-uploading source. Use when: the user says 'redeploy', 'rerun', 'try again with the same code', or 'deploy that one again' AND the source hasn't changed. Not when: the code changed (use percher_publish) or nothing is deployed yet. Hits the image cache when the build inputs are unchanged so it's typically <10s wall-clock. Pass `noCache: true` to force a fresh build of that same source — the stale-image escape hatch when a re-run keeps serving old bytes. Defaults to the latest live deploy when no deployId is given. Counts against the daily deploy quota; fails with TARBALL_GONE once that deploy's source has been evicted. Returns the same shape as percher_publish (status, url, timing, recovery, problems[]).
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | App name. Defaults to the [app].name in the current directory's percher.toml. |
| deployId | string | – | Specific deploy id (e.g. dep_abc123). Defaults to the latest live deploy for the app. |
| noCache | boolean | – | Force a fresh build — skip the image cache. The stale-image escape hatch when a re-run keeps serving old bytes. |
No output schema declared.
No examples provided.
percher_rename ~55
Rename an app and change its subdomain. The old name is reserved for 60 days. Can only be used once every 30 days per app.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| name | string | yes | – |
No output schema declared.
No examples provided.
percher_reproduce ~232
Low-level diagnostic — prefer percher_doctor unless recovery explicitly points here. Downloads a deploy's source tarball and (if nixpacks is installed locally) re-runs the build on the user's machine. Use as a SECONDARY recovery affordance after percher_deploys_inspect didn't yield a clear fix — surfaced via recovery.alternativeActions on build-failure paths. Privacy: env keys are returned, env VALUES are NOT exfiltrated. Returns { status, tmpDir, currentAppEnvKeys, builtLocally, summary }. NOTE: currentAppEnvKeys reflects the CURRENT app env, NOT a deploy-time snapshot — if env was rotated since the failed deploy, this list reflects the rotation. status='extracted_and_built' means local nixpacks succeeded → cloud may have been infra-flake.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | App name. Defaults to the [app].name in the current directory's percher.toml. |
| deployId | string | yes | Deploy id (e.g. dep_abc123) to reproduce. Required — usually the failed deploy you want to debug. |
No output schema declared.
No examples provided.
percher_reset_superuser ~75
Reset PocketBase superuser credentials. Creates a new superuser password and injects POCKETBASE_ADMIN_EMAIL + POCKETBASE_ADMIN_PASSWORD as env vars. Use when PocketBase auth fails or credentials are lost. Requires a redeploy after to apply.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| reveal | boolean | – | – |
No output schema declared.
No examples provided.
percher_restore ~202
Restore an app's DATA from a backup. It does not change which version of the code is deployed — that is percher_rollback, and the two are independent: restoring data leaves today's code live, and rolling back code leaves today's data in place. `source` accepts 'latest', a UTC date 'YYYY-MM-DD', or a full backup id. `dryRun` validates without restoring. Default components: ['appdata', 'pocketbase']. Polls status until terminal (done|rolled_back|failed) — typically 30-120s. Pre-restore data is preserved server-side as `-prerestore` Docker volumes for 24h; manual undo currently requires SSH (dashboard undo coming in B.1.5). Use this for crash recovery or 'restore yesterday'-style requests.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| components | array | – | – |
| dryRun | boolean | yes | – |
| source | string | yes | – |
No output schema declared.
No examples provided.
percher_rollback ~403
Roll back an app's CODE to a previous commit. This does not touch the app's data — a database or uploaded files are restored separately with percher_restore, and the two are independent operations. Pass a `commitSha` from percher_versions, or `toLastGood: true` to have the server resolve the most recent version that went live and didn't crash-loop (errors with NO_LAST_GOOD guidance when the history has none). A bare call (neither field) errors with the 5 most recent versions and exact re-invoke commands. Each version percher_versions lists carries a `rollbackTarget`: mode 'in-window' rolls back by reusing the exact image that was live; mode 'rebuild' means that image is no longer kept, so the version has to be built again from its source (today's dependencies, so the result can differ) — pass `rebuild: true` to accept that, or the call is refused with ROLLBACK_TARGET_UNSUPPORTED; mode 'none' is not a rollback target at all and `rebuild` does not override it. Relay the refusal's message to the user — it says which case it is and what to do.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| commitSha | string | – | Version SHA to roll back to (from percher_versions / `percher versions`). Omit to pick from the most recent versions, or set toLastGood. |
| rebuild | boolean | – | Required for a version whose image is no longer kept (outside the plan's retention window, pruned, or no longer compatible). Percher then BUILDS that version again from its source, resolving today's… |
| toLastGood | boolean | – | Resolves server-side to the most recent version that went live and didn't crash-loop. |
No output schema declared.
No examples provided.
percher_set_preview_branch ~287
Pin (or clear) a GitHub/Forgejo branch as the app's stable preview address. A push to the pinned branch auto-deploys to {app}-preview.percher.run — a long-lived staging URL separate from the live app and from the ephemeral --p- previews. The preview shares managed PocketBase and /app/data with live; writes remain after discard. Use a separate app for isolated data. Unscoped env vars apply to both; preview-scoped vars can target separate external services. Use when the user wants 'a staging URL for a branch', 'a permanent preview for my dev branch', or 'auto-deploy my staging branch to a fixed address'. Requires a connected GitHub/Forgejo repo first. Inputs: `branch` — the branch to pin, or null to clear the preview branch. `app` optional (defaults to percher.toml). Returns { previewBranch, previewUrl, status, deployId }. status: 'pending' (deploy queued — live in ~90s), 'error' (branch saved but the initial deploy failed; push to retry), 'disabled' (after clearing). Surface previewUrl as the address to share. The branch must differ from the live branch.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
| branch | – | yes | Branch to pin as the preview address; pass null to clear it. |
No output schema declared.
No examples provided.
percher_share ~201
Manage an app's collaborators (owner-only). action='list' lists collaborators + pending invites; each row's `id` is the shareId. action='invite' invites by email — role 'viewer' (read-only: analytics, deploys list, crash reports) or 'admin' (deploy + env, domains, KV, logs, PocketBase ops). An invite is PENDING until the recipient accepts; it grants no access until then, expires after 30 days, and is rate-limited to 20/h. action='set_role' changes a collaborator's role (idempotent). action='revoke' removes a collaborator or a pending invite — the recipient's next request 404s with no caching window. shareId comes from action='list'.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| app | string | – | – |
| string | – | – | |
| role | string | – | – |
| shareId | string | – | – |
No output schema declared.
No examples provided.
percher_sleep ~159
Put a running app to sleep. The container stops; its routes, domains, env vars and data stay exactly as they are, and the next visitor wakes it automatically (a few seconds of cold start). Use this when a deploy, wake or scale-up was refused because the account's plan allowance is in use — the refusal names which apps are holding it, and sleeping one hands its RAM and CPU back immediately. Reversible — the next request to the app's URL brings it back, no tool call needed. Not a fix for a disk refusal: a sleeping app keeps its disk. Idempotent; an app that is already asleep returns alreadySleeping=true. Returns { status, alreadySleeping, message }.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
percher_supabase ~969
Supabase → PocketBase migration helper for Lovable / Bolt / v0 imports. Read-only against Percher — the Supabase personal access token (sbp_..., generate at https://supabase.com/dashboard/account/tokens) stays on the user's machine and is sent directly to api.supabase.com, never routed through Percher. action='inspect' introspects the source Supabase project and reports tables (user schemas only), authUsersCount, storageBuckets, and warnings up front (composite PKs, array columns, RLS policies, storage buckets needing separate migration, auth-user hash incompatibility). No file writes. Returns { status, projectRef, tables[], authUsersCount, storageBuckets[], warnings[], recovery, summary }. action='migrate_schema' runs the same introspection AND writes a migration PREVIEW to ./migration-preview/ (or outputDir): pb_schema.json (PocketBase collection-shape), MIGRATION_NOTES.md, and pb_migrate.js — a ready-to-run data-import script that copies rows from Supabase into PocketBase (reads credentials from env vars; auth users still need a password reset since bcrypt hashes don't carry over). A preview only — nothing lands in PocketBase until you run pb_migrate.js. Run action='inspect' first. Returns { status, projectRef, outputDir, filesWritten[], preview, recovery, summary }. action='rewrite_client' converts the project's Supabase SDK calls to the PocketBase SDK across every source file (auth + CRUD rewritten), plus swaps the package.json dependency and stubs .env keys — but ONLY when nothing Supabase remains (a hybrid project that still has storage/rpc/realtime/edge/un-mapped-auth calls keeps both SDKs + both env sets, which is correct; the report says so). `flags[]` lists locations still needing a human (file + line, no inline markers — also written to migration-preview/REWRITE_NOTES.md, which now starts with the same checklist as action='status'), in two kinds: kind='manual_review' was rewritten but its semantics differ (e.g. onAuthStateChange event shape, filter e…
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| apply | boolean | – | – |
| build | boolean | – | – |
| outputDir | string | – | – |
| pbIdentifier | string | – | – |
| projectRef | string | – | – |
| rootDir | string | – | – |
| scaffoldClient | boolean | – | – |
| supabaseIdentifiers | array | – | – |
| token | string | – | – |
No output schema declared.
No examples provided.
percher_transfer ~174
App ownership transfer, sender side (owner-only, app-scoped). action='initiate' offers the app to another account's email; the recipient must explicitly accept for ownership to flip (offer expires after 7 days). Rate-limited to 5/h; only one pending transfer per app — TRANSFER_ALREADY_PENDING (409) otherwise. action='cancel' cancels a pending offer (transferId; only while pending). action='list' shows the app's transfer history. On accept the app moves entirely — the previous owner loses access and any connected GitHub/Forgejo webhook is disconnected (the new owner reconnects their own). action defaults to 'initiate'.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| app | string | – | – |
| string | – | – | |
| transferId | string | – | – |
No output schema declared.
No examples provided.
percher_transfers ~155
Incoming ownership transfers, recipient side (account-wide, resolved from your email). action='incoming' lists pending, unexpired offers; transferId comes from there. action='accept' makes you the owner — atomic (all checks + the ownership flip run in one transaction; if you were already an admin collaborator, that row is dropped so you become owner, not both). Failures: APP_LIMIT_REACHED (your plan won't fit one more app), APP_ADMIN_SUSPENDED, TRANSFER_EXPIRED (after 7 days), TRANSFER_NOT_PENDING (already accepted/declined/cancelled). action='decline' rejects a pending offer.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| transferId | string | – | – |
No output schema declared.
No examples provided.
percher_unsuspend ~103
Unsuspend an app that's been auto-suspended after a failure loop. Use only AFTER fixing the underlying cause — calling unsuspend without resolving the build/runtime failure puts the app into a 1-hour cooldown where 3 more failures (instead of the standard 8) will auto-suspend it again. Returns { ok, app, flipped, summary }; flipped=false means the app was already active.
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | yes | App name or id to unsuspend |
No output schema declared.
No examples provided.
percher_versions ~23
List deployment history for an app
| Name | Type | Req | Description |
|---|---|---|---|
| app | string | – | – |
No output schema declared.
No examples provided.
What is the Percher MCP server?
Percher is an MCP server listed in the public MCP registry as app.percher/percher. MCP-native hosting: publish and operate AI-built web apps live at name.percher.run. This page covers its npm package (@percher/mcp).
Is the Percher MCP server safe to use?
Percher scores 68 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the Percher MCP server expose?
Percher exposes 54 tools: percher_publish, percher_wait_for_deploy, percher_redeploy, percher_reproduce, percher_login, and 49 more. Their descriptions and schemas cost roughly 13,843 tokens of context every time the server is loaded.
Is the Percher MCP server still maintained?
Percher is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the Percher MCP server under?
Percher declares the FSL-1.1-MIT licence, which is not on the OSI-approved list. Read the terms before using it at work, and note this covers the source only, not the cost of any service it calls.