MCP

Tools reference

Every MCP tool, what it does, and whether it writes.

Every MCP tool, grouped by primitive. Read-only tools never change state and set the MCP readOnlyHint annotation, so clients can auto-approve them. db_exec, db_branch, fs_write and memory_forget also set destructiveHint.

Tools act only on the group the API key or OAuth grant is scoped to (locally, the group in the /mcp/<group> path), and its tool allowlist controls which of them the agent sees. primitive_list is always available, whatever the allowlist. See Auth & scoping. Your client can fetch the full JSON Schema of each tool's input with tools/list.

A group can hold several primitives of each type, each with an id and a name. Agents discover, then use: call primitive_list first, then pass one of its results as primitive (the id or the name) to every db_, fs_, queue_, memory_, vault_, kv_ and storage_ tool, and to primitive_snapshot and primitive_fork. When the group has exactly one primitive of the tool's type, primitive can be left out. An unknown, ambiguous or wrong-type primitive returns an error telling the agent to call primitive_list to see the available primitives.

Group

ToolDescriptionRead-only
primitive_listList this group's primitives (id, name, type). Call it first: other tools take one as primitive.yes
primitive_createCreate a named database, filesystem, queue, memory, vault, key-value store or object storage in this group.no
primitive_snapshotCreate a named restore point for one primitive.no
primitive_forkCopy one primitive into a new primitive in this group.no
  • primitive_list: type? to filter. Returns { data: [{ id, name, type, paused }] } for the caller's group.
  • primitive_create: type (db, fs, queue, memory, vault, kv or storage), name. Returns { id, name, type }.
  • primitive_snapshot: primitive? (id or name), label? (the snapshot's name).
  • primitive_fork: primitive? (the source, id or name), new_name? (default <name>-fork-<6 chars>). The copy lands in the caller's own group.

Database

ToolDescriptionRead-only
db_queryRun a read-only SQL query and return rows.yes
db_execExecute a write statement or migration.no
db_branchCreate, promote or discard a database branch.no
  • db_query: primitive?, sql, params? (array for ?, object for named parameters), branch?. Statements that write are rejected, even if the key also allows db_exec.
  • db_exec: primitive?, then sql and params?, or statements: [{ sql, params? }] to run several in one transaction; branch?.
  • db_branch: primitive?, action (create, promote, discard or list), branch, force?.

Filesystem

ToolDescriptionRead-only
fs_readRead a file or list a directory.yes
fs_writeWrite, move or delete files.no
fs_searchGlob and full-text search across the workspace.yes
fs_forkFork a directory for a sub-agent; large files are shared, not copied.no
  • fs_read: primitive?, path, list?, recursive?. A file comes back as { path, encoding, content, size, truncated }, with at most 256 KiB of content; binary files are base64.
  • fs_write: primitive?, action (write by default, move, delete or mkdir), path, content?, encoding? (utf8 or base64), to? for move, recursive? for delete.
  • fs_search: primitive?, glob, or query with an optional path; limit? up to 1,000.
  • fs_fork: primitive?, from, to?. Forks a directory inside the filesystem; to copy a whole filesystem, use primitive_fork.

Queue

ToolDescriptionRead-only
queue_sendEnqueue a message with optional delay and dedupe key.no
queue_receiveLease the next message from a queue.no
queue_ackAcknowledge, retry or dead-letter a leased message.no
  • queue_send: primitive? (the queue primitive), queue (a queue inside it), body, delay?, dedupe_key?, priority? (0–9).
  • queue_receive: primitive?, queue, lease? (default 30s), wait? (up to 20s), max? (1–10). Returns { data: [jobs] }, each with a lease_token. It isn't read-only because it takes a lease.
  • queue_ack: primitive?, queue, id, lease_token, action (ack by default, retry, fail, dead or heartbeat), in? for retry, error?.

Memory

ToolDescriptionRead-only
memory_rememberStore a typed memory (episodic, semantic, procedural).no
memory_recallHybrid search over memories, filtered by kind and tags.yes
memory_forgetDelete or supersede a memory.no
  • memory_remember: primitive?, kind, text, tags?, metadata?.
  • memory_recall: primitive?, query, kinds?, tags? (all must match), limit? (up to 50).
  • memory_forget: primitive?, action (delete by default, supersede or consolidate), id (not needed for consolidate), text and tags? for supersede.

Vault

ToolDescriptionRead-only
vault_listList secret names granted in a vault. Never values.yes
vault_useMake an HTTP request with a secret injected by reference.no
  • vault_list: primitive?. Returns names, versions and grants.
  • vault_use: primitive?, url, auth, method?, headers?, body?. auth is one of { "bearer": NAME }, { "header": { "name", "secret" } }, { "basic": { "username", "secret" } } or { "query": { "param", "secret" } }.

KV

ToolDescriptionRead-only
kv_getRead one key or many (value, version, expiry).yes
kv_listList keys by prefix, optionally with values; paginated by cursor.yes
kv_setSet a key (JSON or base64 bytes) with optional TTL and compare-and-swap, set many at once, or atomically increment.no
kv_deleteDelete one or more keys, optionally only at a given version.no
  • kv_get: primitive?, then key, or keys (up to 100) for many. A missing or expired key is null.
  • kv_list: primitive?, prefix?, cursor?, limit? (up to 1,000), values? (default false).
  • kv_set: primitive?, then key and value, with encoding? (json by default, or bytes with value in base64), ttl? and if_version? (0 means the key must not exist); or items: [{ key, value, encoding?, ttl?, if_version? }] to set up to 100 atomically; or key and incr (an integer, may be negative) with ttl? to increment. A set without ttl clears any expiry. A version mismatch fails with precondition_failed.
  • kv_delete: primitive?, then key and if_version?, or keys.

Storage

ToolDescriptionRead-only
storage_listList objects by prefix; with a delimiter, folders roll up into prefixes.yes
storage_readRead an object's bytes (text or base64, capped) or just its metadata.yes
storage_writePut, copy or delete objects, with content type, metadata and if-match/if-none-match conditions.no
storage_signCreate a time-limited URL to download or upload one object without a token.no
  • storage_list: primitive?, prefix?, delimiter?, cursor?, limit?. Returns { data, prefixes, next_cursor }.
  • storage_read: primitive?, key, head? (info only), range? (such as 0-1023 or bytes=-4096). Returns { key, content_type, etag, metadata, size, range, encoding, content, truncated }, with text as UTF-8 and binary as base64. At most 256 KiB comes back per call; without range it reads the first 256 KiB and sets truncated if there's more.
  • storage_write: primitive?, action (put by default, copy or delete), key; for put, content, encoding? (utf8 or base64), content_type?, metadata?; to for copy; if_match? and if_none_match? ("*" to create only).
  • storage_sign: primitive?, key, method? (GET by default, or PUT), expires_in? (default 15m, up to 7d), content_type?, max_size? and if_none_match? ("*" for create-only) for uploads. Returns { url, method, headers, expires_at }. Anyone holding the URL can use it until it expires, so treat this tool like write access. See Signed URLs.

Example calls

primitive_list
{ "type": "db" }
{ "data": [
  { "id": "01jbz3k8m5q2w7x9v4n6t0r1ce", "name": "orders", "type": "db", "paused": false },
  { "id": "01jbz3m2a7c4e6g8j0k2m4p6rs", "name": "cache", "type": "db", "paused": false }
] }
primitive_create
{ "type": "db", "name": "orders" }
db_query
{ "primitive": "orders", "sql": "select id, title from tasks where status = ?", "params": ["open"] }
db_exec
{ "statements": [
  { "sql": "create table tasks (id integer primary key, title text, status text)" },
  { "sql": "insert into tasks (title, status) values (?, ?)", "params": ["Write docs", "open"] }
] }
fs_write
{ "path": "/repo/plan.md", "content": "- [ ] ship it" }
queue_ack
{ "queue": "reviews", "id": "01k7c3…", "lease_token": "…", "action": "retry", "in": "1h" }
primitive_fork
{ "primitive": "workspace", "new_name": "workspace-try" }
memory_recall
{ "query": "package manager?", "kinds": ["semantic"], "tags": ["preferences"], "limit": 5 }
vault_use
{
  "url": "https://api.github.com/user",
  "method": "GET",
  "auth": { "bearer": "GITHUB_TOKEN" }
}
kv_set
{ "primitive": "state", "key": "plan", "value": { "step": 4 }, "if_version": 12 }
storage_sign
{ "primitive": "artifacts", "key": "reports/q3.pdf", "expires_in": "1h" }

Read-only profiles

To give an agent read access only, create an API key in the dashboard scoped to its group and just the read-only tools, or pick only these on the OAuth consent page (primitive_list is always allowed):

db_query, fs_read, fs_search, memory_recall, vault_list, kv_get, kv_list, storage_list, storage_read

Locally, pass the same list in the URL:

claude mcp add --transport http primitives \
  "http://localhost:7777/mcp/agent-42?tools=db_query,fs_read,fs_search,memory_recall,vault_list,kv_get,kv_list,storage_list,storage_read"