PocketBase MCP Server
Interact with a PocketBase instance to manage records and files in collections.
Documentation
PocketBase MCP Server
This is an MCP server that interacts with a PocketBase instance. It allows you to fetch, list, create, update, and manage records and files in your PocketBase collections.
Compatibility
| Component | Version |
|---|---|
| PocketBase server | >= v0.23 required (_superusers collection model); tested against v0.40.3 (latest stable at release time) |
pocketbase JS SDK | ^0.28.1 |
@modelcontextprotocol/sdk | ^1.30.0 |
| Node.js | >= 18 |
Notes for newer PocketBase servers:
- v0.27+: the
geoPointfield type and thegeoDistance()filter function are fully supported bylist_records/batch_records— see Filter examples with geoPoint. - v0.40.x:
Log.Datamay be truncated by the server (~16KB) and marked with"__pb_truncated__": true; log messages are limited to 8KB.list_logs/get_logoutput passes this through as-is. - v0.38+: a superuser IP whitelist can be enabled in PocketBase Settings. When active, requests from IPs outside the whitelist (including this MCP's token) are rejected with HTTP 403 — see Troubleshooting.
- v0.33+: collection/record ids may not contain
./\|"'`<>:?*%$or Windows reserved names. The migration generators validate this up front. - v0.28+: the
jsonfield type has a default maximum size of 1MB; larger payloads fail validation oncreate_record/update_record.
Installation
Installing via Smithery
To install PocketBase MCP Server for Claude Desktop automatically via Smithery:
npx -y @smithery/cli install @mabeldata/pocketbase-mcp --client claude
- Clone the repository (if you haven't already):
git clone <repository_url> cd pocketbase-mcp - Install dependencies:
npm install - Build the server:
This compiles the TypeScript code to JavaScript in thenpm run buildbuild/directory and makes the entry point executable.
Testing
Test suite (vitest, 3 layers — full guide in tests/TESTS.md):
npm test— unit + contract tests (207: 195 passing + 12 documented known-bug markers; hermetic: no PocketBase instance or network required). The contract layer locks thetools/listMCP contract via snapshot (33 tools: the 22 original + 11 additive PR-3 tools, each group snapshotted separately), a real Client↔Server handshake over InMemoryTransport, and a stdio smoke of the builtbuild/index.js.npm run test:integration— integration tests against a real PocketBase binary (56 tests): auto-downloads/caches the binary (POCKETBASE_VERSIONto pin,POCKETBASE_BINfor a local binary,PB_BIN_DIRfor an alternative cache), boots an ephemeral instance on an OS-assigned port with a unique superuser identity, and validates generated migration files with the officialmigrate up/downrunner. The PR-3 suite (pr3-tools.test.ts) boots its own dedicated instance (admin-scope endpoints — SQL, batch, backups, settings, log clear — must not race siblings on the shared server; see the file header).npm run test:all— the full suite (263 tests).npm run typecheck— tsc over src + tests.SKIP_KNOWN_BUG_TESTS=1 npm test— green baseline where known-bug marker tests are skipped instead of run.
End-to-end smoke scripts (drive the built server over stdio against a real PocketBase instance, 53 checks):
npm run smoke:contract— contract-only smoke (tools/list over stdio, no PocketBase needed).npm run smoke— full smoke: starts an ephemeral server from the binary at$POCKETBASE_BIN(default/tmp/pb-bin/pocketbase), creates a superuser, then exercises every tool category (records, collections, files, logs, crons, migrations) over the stdio JSON-RPC channel.
CI (.github/workflows/ci.yml) runs build + typecheck + hermetic tests + integration tests + smoke on a matrix of Node 18/20/22 × PocketBase v0.39.11/v0.40.3.
Configuration
This server requires the following environment variables to be set:
POCKETBASE_API_URL: The URL of your PocketBase instance (e.g.,http://127.0.0.1:8090). Defaults tohttp://127.0.0.1:8090if not set.POCKETBASE_ADMIN_TOKEN: An admin authentication token for your PocketBase instance. This is required. You can generate this from your PocketBase admin UI, see API KEYS.POCKETBASE_ENABLE_SQL: Optional, default disabled. Gates therun_sqltool (raw SQL execution). See SQL Execution (run_sql) below — only set it totrueif you understand the risks.
These variables need to be configured when adding the server to Cline (see Cline Installation section).
Available Tools
The server provides the following tools, organized by category:
Record Management
-
fetch_record: Fetch a single record from a PocketBase collection by ID.
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." }, "id": { "type": "string", "description": "The ID of the record to fetch." } }, "required": [ "collection", "id" ] }
- Input Schema:
-
list_records: List records from a PocketBase collection. Supports pagination, filtering, sorting, and expanding relations.
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." }, "page": { "type": "number", "description": "Page number (defaults to 1).", "minimum": 1 }, "perPage": { "type": "number", "description": "Items per page (defaults to 30, max 500).", "minimum": 1, "maximum": 500 }, "filter": { "type": "string", "description": "Filter string for the PocketBase query." }, "sort": { "type": "string", "description": "Sort string for the PocketBase query (e.g., \\"fieldName,-otherFieldName\\")." }, "expand": { "type": "string", "description": "Expand string for the PocketBase query (e.g., \\"relation1,relation2.subRelation\\")." } }, "required": [ "collection" ] }
- Input Schema:
-
create_record: Create a new record in a PocketBase collection.
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." }, "data": { "type": "object", "description": "The data for the new record.", "additionalProperties": true } }, "required": [ "collection", "data" ] }
- Input Schema:
-
update_record: Update an existing record in a PocketBase collection.
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." }, "id": { "type": "string", "description": "The ID of the record to update." }, "data": { "type": "object", "description": "The data to update.", "additionalProperties": true } }, "required": [ "collection", "id", "data" ] }
- Input Schema:
-
delete_record: Delete a record from a PocketBase collection by ID (permanent).
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name or ID of the PocketBase collection." }, "id": { "type": "string", "description": "The ID of the record to delete." } }, "required": [ "collection", "id" ] }
- Input Schema:
-
batch_records: Execute multiple record operations (create/update/upsert/delete) in ONE transactional batch — if any operation fails, the whole batch rolls back. Requires server-side batch enabled: on PocketBase >= v0.39
/api/batchis OFF by default; enable it viaupdate_settingswith{"batch": {"enabled": true}}(or Admin UI -> Settings), otherwise calls fail with HTTP 403 "Batch requests are not allowed".- Input Schema:
{ "type": "object", "properties": { "requests": { "type": "array", "items": { "type": "object", "properties": { "collection": { "type": "string" }, "action": { "enum": ["create", "update", "upsert", "delete"] }, "id": { "type": "string" }, "data": { "type": "object", "additionalProperties": true } }, "required": ["collection", "action"] } } }, "required": ["requests"] }
- Input Schema:
-
get_collection_schema: Get the schema of a PocketBase collection.
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." } }, "required": [ "collection" ] }
- Input Schema:
-
upload_file: Upload a file to a specific field in a PocketBase collection record.
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." }, "recordId": { "type": "string", "description": "The ID of the record to upload the file to." }, "fileField": { "type": "string", "description": "The name of the file field in the PocketBase collection." }, "fileContent": { "type": "string", "description": "The content of the file to upload." }, "fileName": { "type": "string", "description": "The name of the file." } }, "required": [ "collection", "recordId", "fileField", "fileContent", "fileName" ] }
- Input Schema:
-
list_collections: List all collections in the PocketBase instance.
- Input Schema:
{ "type": "object", "properties": {}, "additionalProperties": false }
- Input Schema:
-
download_file: Get the download URL for a file stored in a PocketBase collection record.
- Input Schema:
Note: This tool returns the file URL. The actual download needs to be performed by the client using this URL.{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." }, "recordId": { "type": "string", "description": "The name of the record containing the file." }, "fileField": { "type": "string", "description": "The name of the file field in the PocketBase collection." } }, "required": [ "collection", "recordId", "fileField" ] }
- Input Schema:
Filter examples: geoPoint
PocketBase >= v0.27 supports the geoPoint field type and the geoDistance() filter function. Both work transparently through list_records / create_record / update_record / batch_records (the filter string is passed to the server as-is):
// store a location: create_record data payload (location is a geoPoint field)
{ "title": "Office", "location": { "lat": -23.5505, "lon": -46.6333 } }
// geoDistance(lonA, latA, lonB, latB) returns KILOMETRES (verified on v0.40.3) —
// offices within 10 km of São Paulo center (list_records filter):
{ "collection": "places", "filter": "geoDistance(location.lon, location.lat, -46.6333, -23.5505) <= 10" }
// combine with other conditions:
{ "collection": "places", "filter": "active = true && geoDistance(location.lon, location.lat, -46.6333, -23.5505) < 5" }
Arguments must be plain numbers or numeric field identifiers (location.lon / location.lat for a geoPoint field); a geometry-literal like {-23.55, -46.63} is NOT valid, and geoDistance() is currently not supported in sort. Official docs: https://pocketbase.io/docs/api-rules-and-filters/ (geoDistance section).
Collection Management
-
list_collections: List all collections in the PocketBase instance.
- Input Schema:
{ "type": "object", "properties": {}, "additionalProperties": false }
- Input Schema:
-
get_collection_schema: Get the schema of a PocketBase collection.
- Input Schema:
{ "type": "object", "properties": { "collection": { "type": "string", "description": "The name of the PocketBase collection." } }, "required": [ "collection" ] }
- Input Schema:
-
get_collection_scaffolds: Get example collection schema payloads (server >= v0.37) — an object keyed by collection type (
base,auth,view) with ready-to-edit templates for building new collections.- Input Schema:
{ "type": "object", "properties": {}, "additionalProperties": false }
- Input Schema:
-
dry_run_view_query: Validate a VIEW collection SQL query without saving the collection (server >= v0.37). Returns the resulting field definitions and a sample of rows, or a validation error.
- Input Schema:
{ "type": "object", "properties": { "query": { "type": "string", "description": "The SQL SELECT statement backing the view collection." } }, "required": ["query"] }
- Input Schema:
Log Management
Note: The Logs API requires admin authentication and may not be available in all PocketBase instances or configurations. These tools interact with the PocketBase Logs API as documented at https://pocketbase.io/docs/api-logs/.
-
list_logs: List API request logs from PocketBase with filtering, sorting, and pagination.
- Input Schema:
Note: on PocketBase >= v0.40 the server may truncate{ "type": "object", "properties": { "page": { "type": "number", "description": "Page number (defaults to 1).", "minimum": 1 }, "perPage": { "type": "number", "description": "Items per page (defaults to 30, max 500).", "minimum": 1, "maximum": 500 }, "filter": { "type": "string", "description": "PocketBase filter string (e.g., \"method='GET'\")." }, "sort": { "type": "string", "description": "PocketBase sort string (e.g., \"-created,url\")." } }, "required": [] }Log.Data(~16KB, marked with"__pb_truncated__": true) and limit log messages to 8KB.
- Input Schema:
-
get_log: Get a single API request log by ID.
- Input Schema:
{ "type": "object", "properties": { "id": { "type": "string", "description": "The ID of the log to fetch." } }, "required": [ "id" ] }
- Input Schema:
-
get_logs_stats: Get API request logs statistics with optional filtering.
- Input Schema:
{ "type": "object", "properties": { "filter": { "type": "string", "description": "PocketBase filter string (e.g., \"method='GET'\")." } }, "required": [] }
- Input Schema:
-
truncate_logs: Delete ALL API request logs (server >= v0.40). DESTRUCTIVE and irreversible — requires
confirm: true.- Input Schema:
{ "type": "object", "properties": { "confirm": { "type": "boolean", "description": "Must be explicitly true to delete all logs." } }, "required": ["confirm"] }
- Input Schema:
Cron Job Management
Note: The Cron Jobs API requires admin authentication and may not be available in all PocketBase instances or configurations. These tools interact with the PocketBase Cron Jobs API.
-
list_cron_jobs: Returns list with all registered app level cron jobs.
- Input Schema:
{ "type": "object", "properties": { "fields": { "type": "string", "description": "Comma separated string of the fields to return in the JSON response (by default returns all fields). Ex.:?fields=*,expand.relField.name" } } }
- Input Schema:
-
run_cron_job: Triggers a single cron job by its id.
- Input Schema:
{ "type": "object", "properties": { "jobId": { "type": "string", "description": "The identifier of the cron job to run." } }, "required": [ "jobId" ] }
- Input Schema:
Backup Management
Note: The Backup API requires superuser authentication (server >= v0.22). Docs: https://pocketbase.io/docs/api-backups/.
-
list_backups: List all backup files available on the instance (
key,size,modified).- Input Schema:
{ "type": "object", "properties": {}, "additionalProperties": false }
- Input Schema:
-
create_backup: Queue a new database+storage backup. Optional
namemust end in.zip(letters, digits,_,-only); omitted → the server generatespb_backup_<timestamp>.zip. Backups are processed asynchronously — polllist_backupsfor the new key.- Input Schema:
{ "type": "object", "properties": { "name": { "type": "string", "description": "Optional backup filename ending in .zip." } }, "required": [] }
- Input Schema:
-
restore_backup: Restore the instance from an existing backup key. DESTRUCTIVE: replaces ALL current data. Requires
confirm: true.- Input Schema:
{ "type": "object", "properties": { "key": { "type": "string", "description": "Backup file key from list_backups." }, "confirm": { "type": "boolean", "description": "Must be explicitly true." } }, "required": ["key", "confirm"] }
- Input Schema:
Settings Management
Note: The Settings API requires superuser authentication. Secrets (SMTP password, S3 keys, OAuth2 client secrets) are returned by the server masked as
"******";update_settingsneeds the REAL new values for those fields (PATCH semantics — omitted fields keep their stored values).
-
get_settings: Fetch all app settings (sections:
meta,logs,smtp,batch,backups,s3,rateLimits, ...).- Input Schema:
{ "type": "object", "properties": {}, "additionalProperties": false }
- Input Schema:
-
update_settings: Bulk-update settings with a partial payload.
- Input Schema:
{ "type": "object", "properties": { "data": { "type": "object", "description": "Partial settings payload, e.g. { \"logs\": { \"maxDays\": 14 } }.", "additionalProperties": true } }, "required": ["data"] }
- Input Schema:
SQL Execution (run_sql — security gated)
run_sql executes arbitrary raw SQL against the PocketBase instance (server >= v0.39, endpoint POST /api/sql) with superuser privileges. Because an MCP server is typically driven by an LLM — and LLMs can be steered by prompt injection in the data they read — this tool is a much bigger blast radius than the record-level tools and is therefore:
- DISABLED BY DEFAULT. The tool is always listed (stable contract), but every call returns an explanatory error unless the MCP process was started with
POCKETBASE_ENABLE_SQL=true. No network request is made when the gate is closed. - All-or-nothing. There is no read-only mode: SQL statements that modify or drop data (
UPDATE,DELETE,DROP, PRAGMAs, ...) are just as executable asSELECT. Only enable the gate on instances you fully trust and, ideally, on a copy of your data (PocketBase is a single file — back it up first withcreate_backup). - Auditable. SQL calls land in the PocketBase request logs (
POST /api/sql), solist_logscan reconstruct what ran.
Enable explicitly, only if you accept the risks:
POCKETBASE_ENABLE_SQL=true node build/index.js
Typical (read-only) usage once enabled:
{ "name": "run_sql", "arguments": { "query": "SELECT COUNT(*) AS n FROM posts" } }
Migration Management
-
set_migrations_directory: Set the directory where migration files will be created and read from.
- Input Schema:
{ "type": "object", "properties": { "customPath": { "type": "string", "description": "Custom path for migrations. If not provided, defaults to 'pb_migrations' in the current working directory." } } }
- Input Schema:
-
create_migration: Create a new, empty PocketBase migration file with a timestamped name.
- Input Schema:
{ "type": "object", "properties": { "description": { "type": "string", "description": "A brief description for the migration filename (e.g., 'add_user_email_index')." } }, "required": ["description"] }
- Input Schema:
-
create_collection_migration: Create a migration file specifically for creating a new PocketBase collection.
- Input Schema:
{ "type": "object", "properties": { "description": { "type": "string", "description": "Optional description override for the filename." }, "collectionDefinition": { "type": "object", "description": "The full schema definition for the new collection (including name, id, fields, rules, etc.).", "additionalProperties": true } }, "required": ["collectionDefinition"] }
- Input Schema:
-
add_field_migration: Create a migration file for adding a field to an existing collection.
- Input Schema:
{ "type": "object", "properties": { "collectionNameOrId": { "type": "string", "description": "The name or ID of the collection to update." }, "fieldDefinition": { "type": "object", "description": "The schema definition for the new field.", "additionalProperties": true }, "description": { "type": "string", "description": "Optional description override for the filename." } }, "required": ["collectionNameOrId", "fieldDefinition"] }
- Input Schema:
-
list_migrations: List all migration files found in the PocketBase migrations directory.
- Input Schema:
{ "type": "object", "properties": {}, "additionalProperties": false }
- Input Schema:
-
apply_migration: Apply a specific migration file.
- Input Schema:
{ "type": "object", "properties": { "migrationFile": { "type": "string", "description": "Name of the migration file to apply." } }, "required": ["migrationFile"] }
- Input Schema:
-
revert_migration: Revert a specific migration file.
- Input Schema:
{ "type": "object", "properties": { "migrationFile": { "type": "string", "description": "Name of the migration file to revert." } }, "required": ["migrationFile"] }
- Input Schema:
-
apply_all_migrations: Apply all pending migrations.
- Input Schema:
{ "type": "object", "properties": { "appliedMigrations": { "type": "array", "items": { "type": "string" }, "description": "Array of already applied migration filenames." } } }
- Input Schema:
-
revert_to_migration: Revert migrations up to a specific target.
- Input Schema:
{ "type": "object", "properties": { "targetMigration": { "type": "string", "description": "Name of the migration to revert to (exclusive). Use empty string to revert all." }, "appliedMigrations": { "type": "array", "items": { "type": "string" }, "description": "Array of already applied migration filenames." } }, "required": ["targetMigration"] }
- Input Schema:
Migration System
The PocketBase MCP Server includes a migration system for managing database schema changes. This system allows you to:
- Create migration files with timestamped names
- Generate migrations for common operations (creating collections, adding fields)
- Apply and revert migrations individually or in batches
How apply/revert works (and its limits)
Migration files generated by this MCP (create_collection_migration, add_field_migration) embed a machine-readable marker comment (// mcp-migration-meta: {...}) describing their operations as plain data. apply_migration, revert_migration, apply_all_migrations and revert_to_migration execute those operations through the PocketBase REST API (pb.collections.*), which is the only channel available to an MCP client.
Migration files without the marker — e.g. hand-written server-side JSVM migrations created with ./pocketbase migrate create — use the server JSVM API (migrate(), new Collection(), app.save()), which does not exist in a REST client. They cannot be applied through this MCP; the apply tools return an explanatory error pointing to ./pocketbase migrate up on the PocketBase host. (Previous versions tried to evaluate those files locally with new Function, which always failed at runtime.)
Applied-state tracking is not stored server-side: apply_all_migrations / revert_to_migration take an appliedMigrations array parameter (the server's _migrations table is not exposed to REST clients). Keep that list in your own tooling, or apply/revert individual files.
Generated files remain valid JSVM migrations, so the same file can also be applied on the host with ./pocketbase migrate up (in which case PocketBase tracks the state in its own _migrations table — do not mix both execution paths for the same file).
Migration File Format
Migration files are JavaScript files with a timestamp prefix and descriptive name:
// 1744005374_update_transactions_add_debt_link.js
/// <reference path="../pb_data/types.d.ts" />
// mcp-migration-meta: {"ops":{"up":[...],"down":[...]}} <- only in MCP-generated files
migrate((app) => {
// Up migration code here
return app.save();
}, (app) => {
// Down migration code here
return app.save();
});
Each migration has an "up" function for applying changes and a "down" function for reverting them.
Usage Examples
Setting a custom migrations directory:
await setMigrationsDirectory("./my_migrations");
Creating a basic migration:
await createNewMigration("add_user_email_index");
Creating a collection migration:
await createCollectionMigration({
id: "users",
name: "users",
fields: [
{ name: "email", type: "email", required: true }
]
});
Adding a field to a collection:
await createAddFieldMigration("users", {
name: "address",
type: "text"
});
Applying migrations:
// Apply a specific migration
await applyMigration("1744005374_update_transactions_add_debt_link.js", pocketbaseInstance);
// Apply all pending migrations
await applyAllMigrations(pocketbaseInstance);
Reverting migrations:
// Revert a specific migration
await revertMigration("1744005374_update_transactions_add_debt_link.js", pocketbaseInstance);
// Revert to a specific point (exclusive)
await revertToMigration("1743958155_update_transactions_add_relation_to_itself.js", pocketbaseInstance);
// Revert all migrations
await revertToMigration("", pocketbaseInstance);
Cline Installation
To use this server with Cline, you need to add it to your MCP settings file (cline_mcp_settings.json).
-
Locate your Cline MCP settings file:
- Typically found at
~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.jsonon Linux/macOS. - Or
~/Library/Application Support/Claude/claude_desktop_config.jsonif using the Claude desktop app on macOS.
- Typically found at
-
Edit the file and add the following configuration under the
mcpServerskey. Replace/path/to/pocketbase-mcpwith the actual absolute path to this project directory on your system. Also, replace<YOUR_POCKETBASE_API_URL>and<YOUR_POCKETBASE_ADMIN_TOKEN>with your actual PocketBase URL and admin token.{ "mcpServers": { // ... other servers might be listed here ... "pocketbase-mcp": { "command": "node", "args": ["/path/to/pocketbase-mcp/build/index.js"], "env": { "POCKETBASE_API_URL": "<YOUR_POCKETBASE_API_URL>", // e.g., "http://127.0.0.1:8090" "POCKETBASE_ADMIN_TOKEN": "<YOUR_POCKETBASE_ADMIN_TOKEN>" }, "disabled": false, // Ensure it's enabled "autoApprove": [ "fetch_record", "list_collections", "get_collection_schema", "list_logs", "get_log", "get_logs_stats", "list_cron_jobs", "run_cron_job" ] // Suggested auto-approve settings } // ... other servers might be listed here ... } } -
Save the settings file. Cline should automatically detect the changes and connect to the server. You can then use the tools listed above.
Troubleshooting
- HTTP 403 on every request: since PocketBase v0.38 you can enable a superuser IP whitelist (Admin UI -> Settings). If enabled, add the IP of the machine running this MCP server (or disable the whitelist).
FATAL: POCKETBASE_ADMIN_TOKEN environment variable is required: the token env var is not set; generate an API key in the PocketBase admin UI (superuser -> API keys) and setPOCKETBASE_ADMIN_TOKEN.- Health-check warning on stderr at startup: the configured
POCKETBASE_API_URLis unreachable (instance down or wrong URL). The MCP still starts sotools/listworks, but tool calls will fail until the instance is reachable. Cannot apply ...: This migration file does not contain MCP metadata: the file is a server-side JSVM migration; run./pocketbase migrate upon the PocketBase host instead (see Migration System).
Dependencies
@modelcontextprotocol/sdk(^1.30.0)pocketbase(^0.28.1)typescript(dev dependency)@types/node(dev dependency)