JSONPad MCP server
A Model Context Protocol server that lets AI
agents build and operate a backend on your JSONPad
account: lists, items, indexes, write rules, schema sync documents, item
history and, optionally, flows and identities.
It talks to the JSONPad API with one of your API tokens, so it can do exactly
what that token can: the token's permissions, your plan's limits and every
list's write rules apply as they do to your own apps. Every call it makes is a
metered request.
For the documentation, SDK and CLI references, and checking write rules and
flows without spending requests, add the JSONPad docs MCP server too
(@basementuniverse/jsonpad-docs-mcp).
Installing
Create an API token in the JSONPad dashboard.
The server is hosted at https://mcp.jsonpad.io/api (Streamable HTTP). Add it
with the URL, and your client connects with OAuth: it opens a JSONPad page
where you log in and choose what it may do (read only, read and write, or
everything, optionally for some lists, and when access ends). That creates an
API token for it, which you can delete in the dashboard to revoke its access.
In Claude Code:
claude mcp add --transport http jsonpad https://mcp.jsonpad.io/api
Or send one of your own tokens as a bearer token:
claude mcp add --transport http jsonpad https://mcp.jsonpad.io/api --header "Authorization: Bearer <token>"
Options go in the query string: ?readOnly=true, ?toolsets=lists,items,flows.
To act as an identity, add x-identity-token and x-identity-group headers.
The hosted server passes your token to the API with each request and never
stores it. A token with an IP allowlist sees the hosted server's address, not
yours, so use such tokens over stdio.
Or run this package locally, over stdio. In Claude Code:
claude mcp add jsonpad --env JSONPAD_API_TOKEN=<token> -- npx -y @basementuniverse/jsonpad-mcp
Other hosts (Claude Desktop, Cursor, ...):
{
"mcpServers": {
"jsonpad": {
"command": "npx",
"args": ["-y", "@basementuniverse/jsonpad-mcp"],
"env": { "JSONPAD_API_TOKEN": "<token>" }
}
}
}
Node 22.12 or later.
Choosing a token
Give the agent a token of its own, scoped to the lists it should touch, and add
sync-schema if it should manage lists and indexes. A token that can only view
lists, with JSONPAD_READ_ONLY=true, is a safe way to explore. Syncing flows
needs a token that is allowed everything, because a flow runs with your full
privileges: think before granting that.
Settings
JSONPAD_API_TOKEN | (required) | The API token. Never logged or echoed |
JSONPAD_API_URL | https://api.jsonpad.io | The API's URL, e.g. a local development server |
JSONPAD_READ_ONLY | false | true registers only the tools that change nothing |
JSONPAD_TOOLSETS | lists,items,indexes,history,rules,schema | Which toolsets to register |
JSONPAD_IDENTITY_TOKEN, JSONPAD_IDENTITY_GROUP | | Act as one of your app's identities, to test owner-scoped permissions, write rules and guarded values |
JSONPAD_MAX_RESULT_BYTES | 50000 | The largest result returned to the agent; bigger pages are cut short, with a hint |
Tools
| (always) | get_token_info |
lists | list_lists, get_list, create_list, update_list, delete_list |
items | list_items, search_items, get_item, create_item, update_item, merge_item_data, replace_item_data, patch_item_data, delete_item, delete_item_data |
indexes | list_indexes, create_index, update_index, rebuild_index, wait_for_index, delete_index |
history | list_events, get_event, get_stats, restore_item |
rules | test_list_rules, list_rule_denials |
schema | export_schema, plan_schema_sync, apply_schema_sync, move_lists |
flows (off by default) | run_flow |
identities (off by default) | list_identities, get_identity, create_identity, update_identity, delete_identity |
That's 32 tools by default, or 15 in read-only mode. flows adds one (none in
read-only mode), and identities five (two).
A flow can do anything you can, so run_flow is never read-only: hosts should
ask before each call. Flows are created and changed with schema sync, which
needs a token that is allowed everything.
There are also prompts (design-backend, write-list-rules,
investigate-refused-write, inspect-list and undo-changes) and resources:
jsonpad://lists/{list} | A list, as get_list returns it |
jsonpad://lists/{list}/schema | Its JSON schema |
jsonpad://lists/{list}/rules | Its write rules, as text |
jsonpad://lists/{list}/items/{item} | An item's data |
jsonpad://lists/{list}/items/{item}/versions/{version} | An item's data at an older version |
jsonpad://schema{?scope} | The account as a schema sync document |
Listing resources lists the account's lists, a page of 50 at a time. Every
resource read is a metered request.
Safeguards
- Guarded values. A guard index hides a value from API tokens, so item data
the agent reads may be incomplete, and writing it back whole would delete what
it couldn't see. Writes that would replace a guarded value are refused unless
the agent passes
overwriteGuarded; merges and patches are the safe way to
change those items.
- Conditional writes. Every read returns an
etag, and every item write
takes it back as ifMatch, so the agent never overwrites a change your app
made in the meantime.
- Confirmations.
delete_list and delete_identity need the list or
identity repeated in confirm (neither can be restored), deleting a guard
index needs confirmUnguard, and a schema sync prune needs
confirmDestructive.
- Undo. Item writes and deletes can be undone:
list_events with
restorable: true finds restore points, and restore_item restores one, even
for a deleted item.
- Pacing. Over stdio, requests are spaced to your plan's minimum gap
between requests. A briefly rate limited read is retried once; writes are
never retried.
Every result carries the account's quota and rate limit in
_meta["io.jsonpad/usage"], and how many requests the call made in
_meta["io.jsonpad/requests"]; the agent is warned when either runs low.
Developing
The server lives in the JSONPad repository, in mcp/api. It never imports
from server/src: it uses the public API through the JavaScript SDK.
npm install
npm test
npm run typecheck
npm run build
node build/cli.js --http --port 8011
The hosted mode is stateless: every POST to /api gets its own server and
session, built from that request's token, headers and query string. It's an
OAuth protected resource: a request without a token gets a 401 pointing at
/.well-known/oauth-protected-resource/api, which names the JSONPad API as
the authorization server (see server/src/services/oauth.service.ts). Each
initialize checks the token once, so a revoked one gets a 401 too. Its logs
are one JSON object per line: each request, and each tool call's name,
duration, request count and error name, never its arguments or results, and
never a token or IP. The environment variables are listed at the top of
src/cli.ts, and the deployment in docs/mcp-servers.md in the JSONPad
repository.
test/integration.test.ts runs every tool against a real API, and is skipped
unless JSONPAD_TEST_API_URL and JSONPAD_TEST_API_TOKEN are set; see the
comment at its top. test/drift.test.ts checks this package's copies of
server data (the sync document schema, the reserved index path names, error
names) and that every route the tools call allows token auth.
Before publishing, npm run release:check builds, tests and does a dry-run
pack. ~/.npmrc sets ignore-scripts, so there are no npm lifecycle hooks.
License
MIT