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.
Admin UI
Section titled “Admin UI”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.
Quick start (Claude Desktop)
Section titled “Quick start (Claude Desktop)”- Mint an MCP token:
vaultbase token mint --name "Claude Desktop" --scope mcp:read --ttl 1y# → vbat_eyJhbGciOiJIUzI1NiIs…- Add the server to Claude Desktop’s config
(
~/Library/Application Support/Claude/claude_desktop_config.jsonon macOS,%APPDATA%\Claude\claude_desktop_config.jsonon Windows):
{ "mcpServers": { "vaultbase": { "command": "vaultbase", "args": ["mcp"], "env": { "VAULTBASE_MCP_TOKEN": "vbat_eyJhbGciOiJIUzI1NiIs…" } } }}- Restart Claude Desktop. The vaultbase server appears in the MCP icon tray. Ask things like:
- “How many records in the
postscollection?” - “Show me failed login attempts in the last hour.”
- “What does the
userscollection schema look like?”
Cursor / Continue / Cline / Zed
Section titled “Cursor / Continue / Cline / Zed”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.
Scopes
Section titled “Scopes”Tokens carry scopes that gate which MCP tools they can invoke. Mint with the narrowest set the consumer needs.
| Scope | Allows |
|---|---|
mcp:read | Every read tool — list / get / describe / read_logs / read_audit_log |
mcp:write | Every write tool — create / update / delete records |
mcp:admin | Implies all mcp:* (set + future admin-mutation tools) |
mcp:sql | Phase 2: raw SQL tool |
admin | Implies every other scope (use sparingly) |
Mint multi-scope tokens explicitly:
vaultbase token mint --name "Cursor laptop" --scope mcp:read --scope mcp:write --ttl 90dTools — Phase 1
Section titled “Tools — Phase 1”Auto-generated per collection (using the live schema):
| Tool | Required 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):
| Tool | Required scope | Purpose |
|---|---|---|
vaultbase.list_collections | mcp:read | enumerate collections |
vaultbase.describe_collection | mcp:read | full schema + rules + history flag |
vaultbase.read_logs | mcp:read | recent JSONL request logs |
vaultbase.read_audit_log | mcp:read | who-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.
Tools — Phase 2 (shipped)
Section titled “Tools — Phase 2 (shipped)”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):
| Tool | Purpose |
|---|---|
vaultbase.create_collection | Mint a new collection (base/auth/view) with fields + rules |
vaultbase.alter_collection | Rename, replace fields, alter rules; ALTER TABLEs the underlying SQL table |
vaultbase.delete_collection | Drop the collection + its vb_<name> table |
Hooks / routes / jobs (mcp:read for list, mcp:admin for write):
| Tool | Purpose |
|---|---|
vaultbase.list_hooks / create_hook / update_hook / delete_hook | Server-side JS hooks (before/after × CRUD) |
vaultbase.list_routes / create_route / delete_route | Custom HTTP routes mounted at /api/v1/custom/* |
vaultbase.list_jobs / create_job / delete_job / run_job_now | UTC cron jobs |
Feature flags:
| Tool | Scope | Purpose |
|---|---|---|
vaultbase.evaluate_flag | mcp:read | Evaluate a flag against an arbitrary context object |
vaultbase.update_flag | mcp:admin | Upsert a flag (rules + variations + default) |
vaultbase.delete_flag | mcp:admin | Delete by key |
Webhooks:
| Tool | Scope | Purpose |
|---|---|---|
vaultbase.list_webhooks | mcp:read | List configured webhooks |
vaultbase.dispatch_webhook_event | mcp:write | Fire a custom event — subscribers receive HMAC-signed POST |
Settings:
| Tool | Scope |
|---|---|
vaultbase.list_settings / get_setting | mcp:read |
vaultbase.update_setting | mcp: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 (shipped)
Section titled “Phase 3 (shipped)”Phase 3 unlocks remote agents and adds two passive surfaces alongside tools: Resources and Prompts.
HTTP + SSE transport
Section titled “HTTP + SSE transport”Mounted at /api/v1/mcp/. Same Authorization: Bearer vbat_… auth as
the rest of the admin API.
| Verb / path | Purpose |
|---|---|
POST /api/v1/mcp | One JSON-RPC request → one response (or 204 for notifications) |
GET /api/v1/mcp/events | SSE 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.
Resources
Section titled “Resources”URI-addressable read-only blobs. The LLM pulls passive context without
burning a tool call. Requires mcp:read.
Static (resources/list):
| URI | Contents |
|---|---|
vaultbase://collections | Collection enumeration |
vaultbase://audit/recent | Last 50 audit entries |
vaultbase://settings | Non-secret settings (encrypted keys masked) |
vaultbase://server/info | Vaultbase version + MCP protocol version |
Templates (resources/templates/list):
| URI template | Contents |
|---|---|
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.
Prompts
Section titled “Prompts”Reusable prompt templates the LLM client can offer as slash-commands.
| Prompt | Purpose |
|---|---|
design-collection | Interview-driven collection design |
debug-request | Walk logs + audit for a failing request |
audit-rules | Security review of one collection’s rules |
import-from-pocketbase | Step-by-step migration plan |
optimize-schema | Index + denormalisation suggestions |
Methods: prompts/list, prompts/get.
@vaultbase/mcp npm bridge
Section titled “@vaultbase/mcp npm bridge”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:
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.
Auth model
Section titled “Auth model”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.
Prompt-injection defence
Section titled “Prompt-injection defence”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.
Read-only mode
Section titled “Read-only mode”vaultbase mcp --read-onlyStrips 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.
Audit trail
Section titled “Audit trail”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.
Limits + caveats
Section titled “Limits + caveats”Max records per list_* tool call | 100 (configurable cap, hard-enforced) |
Default read_logs limit | 200 entries (max 1000) |
Default read_audit_log limit | 50 (max 500) |
| Token expiry | configurable; 1y is sensible for AI agents |
| Remote agents | Supported via the Phase-3 HTTP+SSE transport (above) |
| Prompt injection via record content | mitigated via <user-data> markup; not eliminated |
After connecting Claude Desktop:
You: How many users signed up last week?
Claude: Calls
vaultbase.list_collections→ findsuserscollection → callsvaultbase.list_users({ filter: "created_at > 1700000000" })→ reports the count. (v0.11 auto-generateslist_<auth-col>per auth collection; it reads the per-collection table with password hashes stripped.)
You: Why are some
/api/v1/auth/users/logincalls 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).
See also
Section titled “See also”- API tokens — minting / scopes / revocation
- Authentication — wider auth model
- Security — trust boundaries
- MCP spec — protocol details