skills/mcp/SKILL.md
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 spacetimedb 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, spacetimedb.get_schema, spacetimedb.sql, spacetimedb.call, and
spacetimedb.ping, and nothing announces them.
| Task | Use |
|---|---|
| List databases, read a schema, run SQL, call a reducer | MCP tools |
| init, build, publish, generate, start, logs | spacetime CLI (see the cli 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.
| Tool | Arguments | Returns |
|---|---|---|
list_databases | none | the databases you own, with identity and names |
get_schema | database | tables and reducers as JSON |
sql | database, sql, optional confirmed | rows as JSON |
call | database, reducer, optional args (JSON array) | the reducer outcome |
ping | optional message | a health check |
list_databases lists only your own databases, so it is empty for an anonymous identity. Start there
when you do not know the database name.
tools/list firstA server is either host-wide or scoped to one database. Do not assume which:
Host-wide (spacetime mcp with no database, or POST /v1/mcp). Every data tool takes a required
database argument, a name or an identity, and list_databases is offered:
{ "name": "sql", "arguments": { "database": "mydb", "sql": "SELECT * FROM message" } }
Scoped (spacetime mcp <database>, or POST /v1/database/<db>/mcp). The connection fixes the
database, so there is no database argument and no list_databases:
{ "name": "sql", "arguments": { "sql": "SELECT * FROM message" } }
The tools run with your identity, exactly as the HTTP API does. The model is the same as everywhere
else, so the concepts skill still governs:
call to change data. It runs in a transaction that either
fully commits or fully rolls back.sql reads public tables; writing through it needs you to own
the database. Prefer call.get_schema still shows a private table's
declaration, so a no such table error from sql usually means the table is private rather than
missing. Access depends on your identity, so do not assume a private table is readable.isError: true and the message as text, not a transport failure. Read the text before retrying.list_databases {}
get_schema { "database": "mydb" }
sql { "database": "mydb", "sql": "SELECT * FROM message" }
call { "database": "mydb", "reducer": "send_message", "args": ["hello"] }
Pass "confirmed": true to sql to wait for a durably confirmed read.
| Message | Meaning |
|---|---|
database argument must be a string | The server is host-wide and you omitted database |
unknown tool: list_databases | The server is scoped to one database already |
`x` not found | No such database on this server, or a name where an identity was meant |
no such table: x | The table is private, or you are querying the wrong database |
No spacetimedb tools at all | No MCP server is connected. Use the CLI instead (cli skill) |
spacetime mcp is UNSTABLE and may not be in a released CLI yet, so a client that cannot start it
falls back to the CLI commands in the cli skill.
Reference: https://spacetimedb.com/docs