
Description
Use when doing ANY task against a Monospace instance. Triggers: reading, creating, updating, deleting, querying, filtering, sorting, or paginating data via the Monospace REST API or the @monospace/sdk (createClient, readMany, createOne, updateOne); generating a typed SDK client (`npx @monospace/sdk generate`, monospace.config.ts); connecting to or using the Monospace MCP server; minting API keys or authenticating; inspecting collections, fields, relations, or schema. Do NOT use for legacy Directus v9 / @directus/sdk — Monospace is a different product with a different API and SDK.
SKILL.md
Monospace
Drive a Monospace instance from an agent: query and mutate data via the REST API or the typed SDK, generate instance-correct types, and use the MCP server. This page is a router — read the principles and the inline traps, then load the reference for the task.
Core principles
1. You almost certainly don't know this API. Don't guess — use the ground truth.
Monospace is not in most training data, so do not invent endpoints, SDK methods, or types from memory. The SDK is @monospace/sdk (createClient + per-collection delegates). Get the real shape from generated types (npx @monospace/sdk generate) or the live OpenAPI doc (GET /api/<project>/openapi), plus the references below. (If you happen to know Directus: it is a different product — don't assume its APIs carry over.)
2. Generate types, then write against them.
The most reliable way to get the data shape right is to generate a typed client from the running instance: npx @monospace/sdk generate reads the live OpenAPI document and emits a typed client matching that instance's schema. Prefer generated types over hand-written shapes. See references/sdk.md.
3. Verify against current docs / OpenAPI before implementing.
For anything not covered here, fetch the canonical OpenAPI doc (GET /api/<project>/openapi, or /api/system/openapi) or the Monospace docs. The OpenAPI doc is generated from the live schema, so it is always correct for the instance.
4. Inspect before you mutate, then verify. Read the schema / list items (read-only) before writing. After a write, read it back to confirm. A change without verification is incomplete.
5. Recover, don't loop.
If an approach fails 2-3 times, stop and reconsider — check the error body (it carries a message), the schema, and permissions. Retrying the same call rarely fixes it.
Critical traps (read before writing any data code)
These are verified, easy-to-miss behaviors. Getting them wrong fails silently.
- Responses are enveloped as
{ "data": ... }. A list returns{ data: [...] }, a single item{ data: {...} }. The SDK strips the top-level envelope for you, but nested to-many relations stay enveloped — relation data sits underrelation.data, and the SDK does NOT unwrap it. Reach intoitem.<relation>.data(to-one relations are accessed directly). - Methods take a single options object, not positional args.
readOne/updateOne/deleteOnetake{ key, ... };createOne({ data: <object>, fields })(single object underdata);createManytakes{ data, fields };updateManytakes{ filter, data, fields };deleteManytakes{ filter, fields? }. There is noreadOne(id)form. Collections are cased as named (client.Articles, notclient.articles). - Deletes return no content unless
fieldsis provided.deleteOne({ key })/deleteMany({ filter })return void; passfieldsonly when you need deleted rows back. fieldsdefaults to top-level primitives only. Relations are not returned unless you select them. The SDK sendsfields: ['*']by default (top-level), so request nested fields explicitly to get relations.- Filter operators are underscore-prefixed.
_eq _neq _lt _lte _gt _gte _in _nin _between _nbetween _contains _icontains _ncontains _nicontains _starts_with _nstarts_with _ends_with _nends_with _null; combine with_and _or _not; for to-many relations use quantifiers_some _every _none._nullis only valid on nullable fields. Full table in references/rest-api.md. - Sort uses the object form, not
-field. Usesort: [{ <field>: { direction: 'asc' | 'desc' } }]. The-created_atshorthand is rejected by the engine. - No
searchparam, nopage/cursor pagination, no aggregates yet. Paginate withlimit(default 100) +offset; requestmeta=totalCountwhen you need the total matching row count. Aggregate/group params parse but are silently ignored today.
Connect to a Monospace instance
You need three things: the host (engine base URL), the project slug (Monospace is multi-project; most data routes are /api/<project>/...), and a token. Create an API key in the Studio under Account → Access → API Keys (/account/access#api-keys; API endpoint POST /api/system/api-keys), or log in with POST /api/auth/providers/<name>/password/login for a user access token. Prefer Authorization: Bearer <token> for agents/scripts; the API also accepts an access_token query parameter or session cookie, but send only one credential source per request.
Two ways an agent works with the data:
- MCP server — best for agentic CRUD + schema work inside a chat/coding agent. Set it up below.
- SDK / REST — best for writing application code. See references/sdk.md and references/rest-api.md.
MCP server setup (recommended for agentic work)
The Monospace MCP server is served by the engine, per project, over streamable-HTTP.
- Endpoint:
POST https://<host>/api/<project>/mcp(per-project; POST only; protocol2025-11-25). - Auth:
Authorization: Bearer <token>or, only when headers are unavailable,access_token=<token>query parameter populated from a secret store (API key or user access token). Do not send both. Use session cookies for browser flows, not agent config. The project needs theai:mcpentitlement, and each tool runs under the token's RBAC.
Config (.mcp.json at the project root):
{
"mcpServers": {
"monospace": {
"type": "http",
"url": "https://YOUR_HOST/api/YOUR_PROJECT/mcp",
"headers": { "Authorization": "Bearer ${MONOSPACE_API_KEY}" }
}
}
}
Tools exposed (7): list_items, create_items, update_item, delete_item (CRUD under the caller's permissions), read_schema (needs dataModel:read), read_data_sources (dataModel:read + dataSource:read), and mutate_schema (dataModel:edit — can be destructive).
Troubleshooting: curl -s -o /dev/null -w "%{http_code}" -X POST https://<host>/api/<project>/mcp — a 401 means it's up but unauthenticated (expected without a token); 403 means the credential is valid but forbidden by RBAC or missing entitlement; 404 means the path is wrong; a hang or refusal means it's unreachable. If tools aren't visible: confirm the URL includes the right <project>, the credential is present (Authorization: Bearer header or access_token query parameter, not both), and the project has ai:mcp enabled. Full details + RBAC and the per-tool input schemas: references/mcp-and-auth.md.
Generate a typed SDK client (codegen)
npx @monospace/sdk init # scaffold monospace.config.ts (output defaults to ./src/generated/monospace)
npx @monospace/sdk login # store credentials in the OS keyring (or set MONOSPACE_API_KEY)
npx @monospace/sdk generate # fetch the live OpenAPI and emit <output>/index.ts
The generated index.ts exports a createClient bound to your instance's schema — import it from your generated output (default ./src/generated/monospace; match your project's path/alias), not from @monospace/sdk, for fully-typed queries. Remote mode fetches GET /api/<project>/openapi (auth required); local mode reads a saved OpenAPI JSON via input. Details, flags, and a zero-to-typed-client sequence: references/sdk.md.
Reference guides
| Topic | Reference | Load when |
|---|---|---|
| Query engine, envelope, endpoints, error shapes, raw REST | references/rest-api.md | Calling the API directly, or in a non-TS language |
createClient, typed delegates, codegen workflow, error classes | references/sdk.md | Writing TypeScript against the SDK or generating types |
| CRUD recipes with the traps annotated | references/data-workflows.md | Reading/writing data and you want a known-good pattern |
MCP tools + schemas, API keys, auth modes, .mcp.json | references/mcp-and-auth.md | Setting up MCP, authenticating, or choosing/using a tool |
More from Directus
View publisherrstore-directus
integrate rstore with Directus
rstore
Jul 12API DevelopmentDatabaseDirectusrstore-monospace
integrate rstore with Monospace REST APIs
rstore
Jul 12OpenAPIREST APIrstore-nuxt
integrate rstore into Nuxt applications
rstore
Jul 12FrontendNuxtVuerstore-nuxt-drizzle
expose Drizzle data in Nuxt applications
rstore
Jul 12API DevelopmentDatabaseDrizzleNuxtrstore-nuxt-monospace
integrate Monospace into Nuxt applications
rstore
Jul 12API DevelopmentDirectusNuxtVuerstore-vite-directus
integrate Directus into Vite applications
rstore
Jul 12API DevelopmentDirectusViteVue