SpacetimeDB over MCP
A SpacetimeDB host speaks MCP, so an MCP-aware client can operate a live database with tool calls
instead of shell commands. If the client exposes
tools, use them for anything that
reads or changes a running database.
Check the tool list before deciding they are missing. The tools are passive: they appear as
spacetimedb.list_databases
,
,
,
, and
, and nothing announces them.
Which to reach for
| Task | Use |
|---|
| List databases, read a schema, run SQL, call a reducer | MCP tools |
| init, build, publish, generate, start, logs | CLI (see the skill) |
The MCP tools only operate a database that already exists. They cannot scaffold a project, compile a
module, publish, or generate bindings, so the two are complementary rather than alternatives. Prefer
the tools when they are present: they are typed, they return JSON, and the client can gate the
destructive ones. When no MCP client is attached, the equivalent CLI commands are correct.
The tools
| Tool | Arguments | Returns |
|---|
| none | the databases you own, with identity and names |
| | tables and reducers as JSON |
| , , optional | rows as JSON |
| , , optional (JSON array) | the reducer outcome |
| optional | a health check |
lists only your own databases, so it is empty for an anonymous identity. Start there
when you do not know the database name.
Two shapes, so read first
A server is either host-wide or scoped to one database. Do not assume which:
Host-wide (
with no database, or
). Every data tool takes a required
argument, a name or an identity, and
is offered:
json
{ "name": "sql", "arguments": { "database": "mydb", "sql": "SELECT * FROM message" } }
Scoped (
, or
POST /v1/database/<db>/mcp
). The connection fixes the
database, so there is no
argument and no
:
json
{ "name": "sql", "arguments": { "sql": "SELECT * FROM message" } }
When
runs inside a project with a
that has a single unambiguous
, it uses that server unless
or
is passed. It does not infer a
database from the config; omitting the database argument still means host-wide mode.
Rules that do not change
The tools run with your identity, exactly as the HTTP API does. The model is the same as everywhere
else, so the
skill still governs:
- Reducers are the write path. Use to change data. It runs in a transaction that either
fully commits or fully rolls back.
- SQL writes require ownership. reads public tables; writing through it needs you to own
the database. Prefer .
- Private tables are not client-readable. still shows a private table's
declaration, so a error from usually means the table is private rather than
missing. Access depends on your identity, so do not assume a private table is readable.
- Tool errors come back in band. A failed reducer or a bad query returns a result with
and the message as text, not a transport failure. Read the text before retrying.
Inspecting a database
list_databases {}
get_schema { "database": "mydb" }
sql { "database": "mydb", "sql": "SELECT * FROM message" }
call { "database": "mydb", "reducer": "send_message", "args": ["hello"] }
Pass
to
to wait for a durably confirmed read.
Troubleshooting
| Message | Meaning |
|---|
database argument must be a string
| The server is host-wide and you omitted |
unknown tool: list_databases
| The server is scoped to one database already |
| No such database on this server, or a name where an identity was meant |
| The table is private, or you are querying the wrong database |
| No tools at all | No MCP server is connected. Use the CLI instead ( skill) |
is UNSTABLE and subject to breaking changes. If a client cannot start it, fall back
to the CLI commands in the
skill.