Skip to content

MCP — Model Context Protocol

Vaultbase ships a first-party MCP server. Any AI agent that speaks the Model Context Protocol — Claude Desktop, Cursor, Continue, Cline, Zed, ChatGPT — can connect and:

  • Browse collections + schemas
  • Query, create, update, delete records
  • Read logs + audit trail
  • Inspect users, hooks, settings (Phase 2)
  • Run admin tasks (Phase 2)

All gated by API token scopes, all recorded in the audit log.

The /_/mcp admin page bundles three things:

  • Connect — pick a token + client (Claude Desktop / Cursor / raw vaultbase binary / direct HTTP), get a copy-paste config snippet with the deployment URL pre-filled.
  • Live clients — currently-connected SSE agents (token name, scopes, IP, user-agent, connected_at). Refreshes every 10s.
  • Catalog — every tool / resource / prompt the LLM can see, with sticky search across names + descriptions + URIs + prompt-arg names.
  1. Mint an MCP token:
Terminal window
vaultbase token mint --name "Claude Desktop" --scope mcp:read --ttl 1y
# → vbat_eyJhbGciOiJIUzI1NiIs…
  1. Add the server to Claude Desktop’s config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"vaultbase": {
"command": "vaultbase",
"args": ["mcp"],
"env": {
"VAULTBASE_MCP_TOKEN": "vbat_eyJhbGciOiJIUzI1NiIs…"
}
}
}
}
  1. Restart Claude Desktop. The vaultbase server appears in the MCP icon tray. Ask things like:
  • “How many records in the posts collection?”
  • “Show me failed login attempts in the last hour.”
  • “What does the users collection schema look like?”

Same pattern — each editor has its own MCP-server config block. Use the same command: "vaultbase", args: ["mcp"], and the same env-vars. Any client implementing the Model Context Protocol works.

Tokens carry scopes that gate which MCP tools they can invoke. Mint with the narrowest set the consumer needs.

ScopeAllows
mcp:readEvery read tool — list / get / describe / read_logs / read_audit_log
mcp:writeEvery write tool — create / update / delete records
mcp:adminImplies all mcp:* (set + future admin-mutation tools)
mcp:sqlPhase 2: raw SQL tool
adminImplies every other scope (use sparingly)

Mint multi-scope tokens explicitly:

Terminal window
vaultbase token mint --name "Cursor laptop" --scope mcp:read --scope mcp:write --ttl 90d

Auto-generated per collection (using the live schema):

ToolRequired scope
vaultbase.list_<collection>(filter?, sort?, page?, perPage?, fields?, skipTotal?)mcp:read
vaultbase.get_<collection>(id)mcp:read
vaultbase.create_<collection>(data)mcp:write
vaultbase.update_<collection>(id, data)mcp:write
vaultbase.delete_<collection>(id)mcp:write

Static admin tools (4):

ToolRequired scopePurpose
vaultbase.list_collectionsmcp:readenumerate collections
vaultbase.describe_collectionmcp:readfull schema + rules + history flag
vaultbase.read_logsmcp:readrecent JSONL request logs
vaultbase.read_audit_logmcp:readwho-did-what trail

Auth-collection user listing was a separate static vaultbase.list_users tool in v0.10. v0.11 promoted auth collections to first-class — the auto-generated vaultbase.list_<auth-col> covers it now (with full filter / sort / pagination + password_hash always stripped).

The LLM discovers the full list via tools/list after the initialize handshake — no manual registration.

Phase 2 adds admin-mutation tools — schema management, hook/route/job authoring, flag updates, settings writes, raw SQL, factory-style seeding.

Schema management (mcp:admin):

ToolPurpose
vaultbase.create_collectionMint a new collection (base/auth/view) with fields + rules
vaultbase.alter_collectionRename, replace fields, alter rules; ALTER TABLEs the underlying SQL table
vaultbase.delete_collectionDrop the collection + its vb_<name> table

Hooks / routes / jobs (mcp:read for list, mcp:admin for write):

ToolPurpose
vaultbase.list_hooks / create_hook / update_hook / delete_hookServer-side JS hooks (before/after × CRUD)
vaultbase.list_routes / create_route / delete_routeCustom HTTP routes mounted at /api/v1/custom/*
vaultbase.list_jobs / create_job / delete_job / run_job_nowUTC cron jobs

Feature flags:

ToolScopePurpose
vaultbase.evaluate_flagmcp:readEvaluate a flag against an arbitrary context object
vaultbase.update_flagmcp:adminUpsert a flag (rules + variations + default)
vaultbase.delete_flagmcp:adminDelete by key

Webhooks:

ToolScopePurpose
vaultbase.list_webhooksmcp:readList configured webhooks
vaultbase.dispatch_webhook_eventmcp:writeFire a custom event — subscribers receive HMAC-signed POST

Settings:

ToolScope
vaultbase.list_settings / get_settingmcp:read
vaultbase.update_settingmcp:admin

Encrypted-at-rest settings keys (smtp.password, oauth2.*.client_secret, etc.) decrypt on read — treat list/get-setting responses as sensitive even though they’re admin-equivalent visibility.

Raw SQL (mcp:sql):

vaultbase.run_sql(query, params?, allow_write?)

Read-only by default — non-SELECT statements require allow_write: true and bypass every safety net (RBAC, validation, hooks, audit). Result set hard-bounded to 100 rows. Prefer the typed tools.

Data seeding (mcp:write):

vaultbase.seed(collection, count, overrides?)

Generates fake records per field type — Lorem text, bounded numbers, fake emails, random world coords for geoPoint, random selects, vector arrays of correct dim. Hard cap 1000 records per call. overrides lets the LLM pin specific field values across all generated rows.

Phase 3 unlocks remote agents and adds two passive surfaces alongside tools: Resources and Prompts.

Mounted at /api/v1/mcp/. Same Authorization: Bearer vbat_… auth as the rest of the admin API.

Verb / pathPurpose
POST /api/v1/mcpOne JSON-RPC request → one response (or 204 for notifications)
GET /api/v1/mcp/eventsSSE stream for server → client notifications (tools/listChanged, …)

Stateless — each POST is an independent turn. The SSE leg is purely for server-initiated traffic; clients that want bidirectional flow open both legs at once. The bundled @vaultbase/mcp npm package does this for clients that only know how to speak stdio.

URI-addressable read-only blobs. The LLM pulls passive context without burning a tool call. Requires mcp:read.

Static (resources/list):

URIContents
vaultbase://collectionsCollection enumeration
vaultbase://audit/recentLast 50 audit entries
vaultbase://settingsNon-secret settings (encrypted keys masked)
vaultbase://server/infoVaultbase version + MCP protocol version

Templates (resources/templates/list):

URI templateContents
vaultbase://collection/{name}Full schema for one collection
vaultbase://record/{collection}/{id}One record (rules apply)
vaultbase://logs/{date}Daily JSONL request logs (YYYY-MM-DD)

Methods: resources/list, resources/templates/list, resources/read.

Reusable prompt templates the LLM client can offer as slash-commands.

PromptPurpose
design-collectionInterview-driven collection design
debug-requestWalk logs + audit for a failing request
audit-rulesSecurity review of one collection’s rules
import-from-pocketbaseStep-by-step migration plan
optimize-schemaIndex + denormalisation suggestions

Methods: prompts/list, prompts/get.

Stdio↔HTTP bridge for clients that only speak stdio (Claude Desktop, Cursor, Continue, Cline, Zed, …). Source at github.com/vaultbase-sh/mcp, ships as @vaultbase/mcp on npm.

Pure TypeScript, single bin, no Bun runtime needed on the client:

Terminal window
npx @vaultbase/mcp --url https://api.example.com --token vbat_…

Claude Desktop config:

{
"mcpServers": {
"vaultbase": {
"command": "npx",
"args": ["-y", "@vaultbase/mcp"],
"env": {
"VAULTBASE_URL": "https://api.example.com",
"VAULTBASE_MCP_TOKEN": "vbat_…"
}
}
}
}

The bridge does not parse or modify MCP messages — it only frames them for whichever transport is on the other side. All MCP semantics (scopes, audit, prompt-injection markup) stay in the Vaultbase server.

API tokens authenticate as the admin who minted them. The token is “acting as” that admin; collection rules + admin endpoints see them as that admin’s principal. Scopes further restrict what they may do:

verified API token → minting admin's identity → tool's required scope
→ tool calls existing
core APIs (records.ts,
collections.ts, …)
→ audit log records the
actor as `mcp:<tokenName>`

Force-logout-all (bumping the admin’s password_reset_at) invalidates their MCP tokens too as a side effect. Per-token revoke is one click in the admin UI or vaultbase token revoke <id> from the CLI.

Tool results that include record content (logs, audit entries, list/get responses) are wrapped in <user-data label="…">…</user-data> markers so the LLM treats them as data, not instructions. Pair this with normal prompt-engineering hygiene on the model side; vaultbase can’t prevent all injection paths but markup helps the LLM disambiguate.

Terminal window
vaultbase mcp --read-only

Strips the registry to read-only tools regardless of token scopes. Defence-in-depth for ad-hoc debugging — paste your most-permissive token but still can’t accidentally write through it.

Every successful MCP tools/call that mutates state goes through the existing audit-log path with actor_id set to the minting admin and the token’s name in the summary field. So “which AI agent did this” is one query away — see Audit log and API tokens.

Max records per list_* tool call100 (configurable cap, hard-enforced)
Default read_logs limit200 entries (max 1000)
Default read_audit_log limit50 (max 500)
Token expiryconfigurable; 1y is sensible for AI agents
Remote agentsSupported via the Phase-3 HTTP+SSE transport (above)
Prompt injection via record contentmitigated via <user-data> markup; not eliminated

After connecting Claude Desktop:

You: How many users signed up last week?

Claude: Calls vaultbase.list_collections → finds users collection → calls vaultbase.list_users({ filter: "created_at > 1700000000" }) → reports the count. (v0.11 auto-generates list_<auth-col> per auth collection; it reads the per-collection table with password hashes stripped.)

You: Why are some /api/v1/auth/users/login calls returning 401 today?

Claude: Calls vaultbase.read_logs(filter: { method: "POST", path: "/api/v1/auth/users/login", status: 401 }) → sees five entries → reads adjacent audit trail → reports likely cause (brute-force lockout per IP).