@capydb/mcp
v2.6.0
Published
Official CapyDB MCP server - managed Postgres projects, preview databases, backups, restores, and SQL for AI agents.
Maintainers
Readme
@capydb/mcp
Official CapyDB MCP server. Gives AI agents (Claude Code, Cursor, and any other Model Context Protocol client) safe, structured access to your managed Postgres: projects, preview databases, backups, restores, imports, SQL, and observability. Every CapyDB project runs in its own isolated database cell - a dedicated Postgres runtime reached with normal connection strings.
Runs locally over stdio, or remotely at https://mcp.capydb.dev/mcp, and talks to the CapyDB
control plane API - no local database access required. Serves both the 2026-07-28 protocol
revision and the 2025-era revisions, so it works with current hosts and with clients that have not
adopted the new revision yet.
Remote server (no install)
Claude on the web, desktop and mobile, and any client that supports remote MCP servers with OAuth, can connect to the hosted server:
https://mcp.capydb.dev/mcpclaude mcp add --transport http capydb https://mcp.capydb.dev/mcpinitialize, tools/list, the ephemeral-database tools and get_status_history work without signing in. The first call to
a tool that needs an account is answered with an HTTP 401 challenge, and the client runs the OAuth
flow: the CapyDB control plane (https://api.capydb.dev) is the authorization server, the user signs
in and picks a workspace in the dashboard, and the access token is an agent API key (listed and
revocable under Settings → API keys, expiring after 90 days). See
docs.capydb.dev/docs/guides/integrations/claude.
The same code serves both transports: src/http.ts is the remote entry, deployed to Vercel from this
repository (api/, vercel.json).
Install (local stdio server)
No install needed; run it with npx:
npx @capydb/mcpOr add it to Claude Code directly:
claude mcp add capydb -- npx @capydb/mcpAuthentication
No setup is required. Credentials are resolved in this order:
CAPYDB_API_KEYenvironment variable - always wins. Use this for headless/CI setups.The CapyDB CLI's saved login - if you have run
capydb auth login, the MCP server reuses that credential (same config file, same revocation point).First-run browser approval - with no credential at all, the server still starts. The first tool call returns a one-time approval URL:
CapyDB needs a one-time approval. Ask the user to open:
https://capydb.dev/dashboard/cli/login?session=...- then retry this tool.Open the link, approve in the dashboard (signing up and picking a plan inline if needed), and retry the tool. The minted API key is saved to the shared CLI config file (
chmod 600) and no further approval is ever needed. Keys minted this way are labeled as agent-created in the dashboard key list, where they can be audited and revoked.
The shared config file lives at the CLI's config path: ~/Library/Application Support/capydb/config.json
on macOS, $XDG_CONFIG_HOME/capydb/config.json (default ~/.config/...) on Linux, %AppData%\capydb\config.json
on Windows.
Configuration
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| CAPYDB_API_KEY | no | - | Explicit CapyDB API key; skips the device login. Create one in the dashboard under Organization → API Keys. Use a project-scoped key for long-lived setups so the agent can only touch the project it is working on. |
| CAPYDB_API_URL | no | https://capydb.dev/api/capydb | Control plane base URL. Only change this for self-hosted / staging setups. |
| CAPYDB_APP_URL | no | derived from CAPYDB_API_URL | Dashboard origin used for device-login approval URLs. |
Claude Code (.mcp.json)
{
"mcpServers": {
"capydb": {
"command": "npx",
"args": ["@capydb/mcp"]
}
}
}Cursor (.cursor/mcp.json)
{
"mcpServers": {
"capydb": {
"command": "npx",
"args": ["@capydb/mcp"]
}
}
}For headless/CI, add "env": { "CAPYDB_API_KEY": "capy_..." } to the server entry.
Tools
| Tool | What it does | Notes |
| --- | --- | --- |
| list_regions | Region ids projects can be created in (e.g. eu-north-1), with display names | read-only |
| list_postgres_versions | Postgres majors open for new databases, with channel (previous/stable/current/beta) and the default | read-only |
| get_status_history | Public per-region daily uptime and incidents | anonymous, read-only |
| get_usage | Organization storage, connection and database counts against plan limits, per project | read-only |
| list_audit_events | The organization's audit trail (who did what, when), newest first | read-only |
| create_project | Create a Postgres project and wait for provisioning | async; waits up to 5 min |
| list_projects | List your Postgres projects | read-only |
| get_project | Get one project (state, plan, limits, environment, always_on) | read-only |
| update_project_settings | Change environment and the sleep policy (always_on) | org-wide key or org admin; idempotent |
| retry_provisioning | Provision a project again whose provisioning failed | async job; idempotent; org-wide key or org admin |
| get_notification_preferences | Which notification emails the organization gets, and the extra recipients | read-only |
| update_notification_preferences | Change alert emails and recipients; fields not passed keep their values | org admin + organizations:write (not granted to the remote connector); idempotent |
| get_connection_strings | Pooled + direct URLs for a project (plus app, the app_user URLs, once the split role is enabled) | secret-bearing output |
| get_app_role | Whether the project has the split-role runtime login app_user | read-only |
| enable_app_role | Issue app_user, a login row-level security applies to | async job; 404 where the platform does not offer it yet |
| rotate_app_role | Replace the app_user password | destructive (the old password stops working), async job |
| sync_integration_env | Push connection env vars again to a connected Vercel / Netlify / Cloudflare integration | destructive (overwrites edited values), async job |
| create_ephemeral_database | Create a throwaway database with no account or login; destroyed after 72h unless claimed | anonymous, secret-bearing output (claim token, shown once) |
| get_ephemeral_database | State, expiry and (once ready) connection strings of an unclaimed ephemeral database, by claim token | anonymous, read-only, secret-bearing output |
| destroy_ephemeral_database | Destroy an unclaimed ephemeral database early with its claim token; frees its slot | anonymous, destructive, idempotent |
| claim_ephemeral_database | Keep an ephemeral database: attach it to your organization as a normal project | idempotent; needs an account with an active subscription |
| create_preview_database | Create a disposable preview/branch DB (empty or clone) | async job |
| list_preview_databases | List previews with state and TTL | read-only |
| delete_preview_database | Delete a preview and its role | destructive, async job |
| reset_preview_database | Reset a preview back to its base state | destructive to the preview, async job |
| extend_preview_ttl | Extend a preview's TTL | mutates TTL only |
| get_preview_connection_strings | Pooled + direct URLs for a preview | secret-bearing output |
| run_preview_sql | Run a SQL statement against a preview database | destructive to the preview; allow_unqualified_writes to rehearse a destructive statement |
| create_backup | On-demand backup of the project DB | async job |
| export_database | Logical export (pg_dump custom-format archive) of the project DB; expires after 7 days | async job |
| list_exports | List a project's exports, newest first | read-only |
| get_export_download | Short-lived (15 minute) download URL for a completed export | read-only |
| list_extensions | List available Postgres extensions with enablement + update state | read-only |
| enable_extension | Enable an extension (CREATE EXTENSION IF NOT EXISTS) | async job; restarts the database for requires_restart extensions (e.g. pg_cron) |
| disable_extension | Disable an extension (DROP EXTENSION, no CASCADE) | destructive, async job; restarts the database for requires_restart extensions |
| update_extension | Update an enabled extension to the platform-provided version | async job |
| suggest_indexes | Index candidates from the predicates queries actually ran, costed as hypothetical indexes | read-only; needs pg_qualstats (+ hypopg for estimates) |
| get_index_hygiene | Unused and redundant indexes, each with a DROP INDEX CONCURRENTLY statement | read-only; no extensions needed |
| major_upgrade_preflight | Check whether the DB can move to a PostgreSQL major, without changing anything | read-only, async job |
| get_upgrade_status | The major upgrade in flight and its rollback window | read-only |
| upgrade_postgres_major | Move the DB to a newer PostgreSQL major (previous DB kept 72h for rollback) | destructive, async job; needs the user's approval token and a preflight passed within the hour |
| confirm_major_upgrade | End the rollback window early, destroying the previous DB | destructive, async job; approval token |
| rollback_major_upgrade | Swap back to the previous DB, discarding writes since the cutover | destructive, async job; approval token |
| list_backups | List backups incl. verification state | read-only |
| get_backup_schedule | The scheduled backup: UTC time, active flag, retention | read-only |
| update_backup_schedule | Change the scheduled backup; fields not passed keep their values | destructive (pausing or shorter retention reduces what can be restored), idempotent |
| restore | Restore a backup / restore point / PITR timestamp into a preview | destructive to the target preview; cannot overwrite production; reports a clamped PITR target in pitr |
| list_restore_points | List named restore points + the PITR window | read-only |
| create_restore_point | Pin an existing backup key or a PITR timestamp before a risky change | backup keys come from list_backups after create_backup completes |
| delete_restore_point | Delete a restore point after the change is verified | destructive |
| import_preflight | Check an external source DB before an import | read-only, connects out |
| import_database | Import an external database into the project | destructive, requires confirm: true |
| query_sql | Run a read-only SQL statement against the live project DB | read-only (READ ONLY transaction); row-capped, 15s timeout, recorded in SQL history |
| execute_sql | Run a SQL statement that changes data or schema | destructive; row-capped, 15s timeout, recorded in SQL history |
| get_schema | Complete schema document: tables, columns, keys, enums, extensions | read-only; prefer over catalog queries |
| generate_types | Generate TypeScript / Zod / Drizzle / Go / Python code from the live schema | read-only; style: supabase for supabase-js compat, pydantic for pydantic models, package for Go |
| lint_schema | Missing primary keys, unindexed foreign keys, duplicate/redundant/unused indexes, bloat - project or preview | read-only |
| list_tables | List tables and views | read-only |
| get_table_rows | Read rows from a table | read-only |
| get_observability | Live metrics: connections, size, active/slow queries, alerts, scale-to-zero wake latency | read-only |
| get_logs | Recent database log entries, with severity filter and tail cursor | read-only |
| search_logs | Search archived logs (up to 30 days) by SQLSTATE, severity and text | read-only; 503 where log search is not enabled |
| get_recent_errors | Recent ERROR/FATAL/PANIC lines grouped by SQLSTATE + message, each with the failing statement and a retryable verdict | read-only; call first when a job or query fails |
| explain_query | The planner's plan for one statement (EXPLAIN without ANALYZE) | read-only (READ ONLY transaction); refuses ANALYZE and multi-statement input |
| list_alerts | Open + recently resolved project alerts (storage, connections, backups, health advisories) | read-only |
| acknowledge_alert | Mark an alert as seen | idempotent; does not resolve the alert |
| get_job | Poll an async job until completed/failed | read-only |
| list_jobs | List a project's async jobs | read-only |
| list_kv_stores | K/V stores across the organization | read-only |
| get_kv_store | One project's K/V store (state, capacity, eviction) | read-only; 404 = no store yet |
| get_kv_credentials | K/V REST + RESP endpoints | read-only; the token is never returned |
| create_kv_store | Provision the project's K/V store | async job; secret-bearing output |
create_project notes: the project's plan is derived from the organization's billing state and cannot
be chosen per project. If the organization has no active plan, the tool fails with a link to
https://capydb.dev/dashboard/settings/billing (1 month free) so the user can pick one and retry.
Safety model
- Overwrite restore is not exposed. The
restoretool only targets preview databases (new or existing). Overwriting the project database is irreversible: the control plane refuses it on production projects, and on a non-production project it needs an org-wide key or the org admin role plus a single-use approval token. It stays in the dashboard, the CLI and the API. - Major upgrade steps need the user's approval.
upgrade_postgres_major,confirm_major_upgradeandrollback_major_upgradeeach take a single-useapproval_token. The control plane mints those only for a person (an org admin in the dashboard) and refuses API keys, so an agent cannot approve its own upgrade or rollback - it can only carry out one the user approved. - K/V flush, rotate-token and delete are not exposed. A K/V store keeps only a periodic snapshot -
no backups, no point-in-time recovery - so each of those is one irreversible step away from
unrecoverable data. They stay in the dashboard and the CLI, behind a confirmation.
create_kv_storereturns the plaintext token once, because that is the only response that carries it. - Every tool has a
titleand declares its effect: read-only tools carryreadOnlyHint: true, and every other tool carriesdestructiveHint-truefor the ones that delete or overwrite data (delete_preview_database,reset_preview_database,disable_extension,restore,delete_restore_point,import_database,destroy_ephemeral_database,execute_sql,run_preview_sql,update_backup_schedule,rotate_app_role,sync_integration_env,upgrade_postgres_major,confirm_major_upgrade,rollback_major_upgrade),falsefor the ones that only add - so clients can require approval. Reads and writes never share a tool. - Connection-string tools are clearly marked secret-bearing; instruct your agent not to persist their output.
execute_sqlexecutes against the live database. Prefer rehearsing risky SQL on a preview created withcreate_preview_database(modeclone) throughrun_preview_sql.- Credential hygiene: the device-login key is org-wide, expires after 90 days, and is meant for
interactive sessions. For long-lived or shared agent setups, create a project-scoped key in the
dashboard and pass it via
CAPYDB_API_KEYinstead. Every key - including agent-minted ones - is listed with its provenance in the dashboard and can be revoked there at any time.
Typical flows
Fresh machine to running database
- Any tool → one-time browser approval → 2.
create_project→ 3.get_connection_strings.
Branch database per task
create_preview_database(modeclone) → 2.get_jobuntilcompleted→get_preview_connection_strings→ work → 4.delete_preview_database.
Investigate production state
get_observability → list_tables → query_sql with SELECTs (use max_rows to keep results small).
Recover data without touching production
list_backups → restore with backup_key and a preview_name → query the preview → copy what you need.
Development
pnpm install
pnpm typecheck # tsgo (TypeScript native preview)
pnpm lint # oxlint
pnpm build # tsdown → dist/index.js (stdio), dist/http.js, dist/vercel.js
pnpm test # builds, then tests the HTTP entry against a stub control plane
node dist/index.js # CAPYDB_API_KEY=capy_... to skip the device login
# Remote entry against a local control plane (backend `docker compose up`, with
# CAPYDB_OAUTH_ISSUER=http://localhost:8090 and CAPYDB_OAUTH_RESOURCES=http://localhost:3333/mcp):
CAPYDB_API_URL=http://localhost:8090 node scripts/dev-http.mjs # http://localhost:3333/mcpThe API client is hand-written against the control plane's OpenAPI spec
(backend/internal/httpapi/openapi.json in the CapyDB monorepo layout). For a full typed SDK, see
@capydb/sdk.
License
MIT
