Guides

Build an Application with AI Assistance

An end-to-end walkthrough that starts Monospace, wires up your IDE and AI coding agent, bootstraps a schema, and ships a working application in about an hour.

Overview

This walkthrough shows rapid, AI-assisted development on Monospace end to end — from an empty instance to a working application or internal tool. You'll wire up your AI coding agent with the official Monospace skill and MCP server, bootstrap a schema from your IDE, and build on top with the typed SDK.

The whole thing fits in about an hour, and you start from nothing. You don't need to bring an existing database or model any data by hand. Your agent creates the schema for you over MCP, and Monospace turns it into a governed API the moment it exists.

What you'll build: an internal restock console for an operations team. It surfaces products that have dropped below their reorder threshold and lets an operator file a restock request, reading live from your workspace through one governed API.

The Build at a Glance

StageWhat you doRough time
1. Start up MonospaceLaunch the stack, sign in, create a workspace15 min
2. Connect your data sourcesSee how Monospace federates databases you already run10 min
3. Connect your IDEGet an API key, install the skill, connect the MCP server15 min
4. Bootstrap the schemaLet your agent build the data model from a prompt15 min
5. Generate the SDK and buildType-safe client, then the application itself15 min

Once it's running, the Deploy with a Service Account bonus shows how to give the application its own scoped identity for production.

A workspace is your tenant. It holds a schema and the data source connections behind it. A collection is a container for items of the same type (the equivalent of a table), and a field is a named value on an item.

Prerequisites

  • Docker Compose to run Monospace locally.
  • Claude Code (the primary agent in this guide) or another MCP-capable agent such as Cursor or Codex.
  • Node.js, for the SDK and its type generator.
  • Optionally, a PostgreSQL, MySQL, or MariaDB database if you want to connect real data in Stage 2. The tutorial bootstraps its own schema, so this is not required.

1. Start Up Monospace

Follow the Quickstart to launch the stack with Docker Compose. In short:

terminal
docker compose up -d

Once the containers report healthy, open the Studio at http://localhost:8100. The compose file sets no admin credentials, so on first run Monospace greets you with an onboarding screen. Create your admin account there, then sign in.

Your organization is the top-level container, representing your company or team. Inside it, create a workspace for this application. Name it Acme-Inventory and give it the URL slug acme-inventory. The workspace is where your schema and data source connections live.

Running locally is the fastest way to follow along. Everything here works identically against a deployed instance. Swap http://localhost:8100 for your host.

2. Connect Your Data Sources

No database to connect right now? Skip ahead. This tutorial builds its own schema in Stage 4 using the workspace's built-in data source, so you can follow the whole thing with nothing but Docker.

Federating the databases you already run is Monospace's core capability. You can connect one or many, and query across them through a single governed API without ETL or replication.

In the Studio, go to Data Model → Data Sources, add a connection, and choose your connector. Enter the connection details and use Test Connection before saving.

When you connect an existing database, Monospace runs Database Introspection: it reads your tables and maps them to collections automatically, with their fields and relations already in place.


3. Connect Your IDE

Your coding agent doesn't have Monospace in its training data. Left alone, it guesses at the API. Three pieces get it ready:

  • an API key to authenticate
  • the official skill so it knows how Monospace actually works
  • the MCP server so it can read and write your real workspace.

Get an API Key

As a new admin, the fastest way to authenticate is an API key bound to your own account. This is your personal access token for the API: it inherits your admin permissions, so it can do everything you need while building.

Open your Account Settings and go to Access, then create an API key there. Give it a name and a TTL, then copy it now, since the plaintext value is shown once.

Store it as an environment variable, never in source control:

.env
MONOSPACE_API_KEY=YOUR_API_KEY
An admin key is the right choice for building locally. When you deploy the application for real, swap it for a narrowly scoped identity, as shown in Deploy with a Service Account.

Install the Monospace Skill

The Monospace Agent Skills bundle is the official Agent Skills package. It gives your agent the ground truth for the REST API, the typed SDK, the codegen workflow, and the MCP tools, so it writes correct calls on the first try.

Install it into Claude Code from the plugin marketplace:

Claude Code
claude plugin marketplace add directus/monospace-agent-skills
claude plugin install monospace@monospace-agent-skills
Using another agent? The skill follows the open standard. Install it anywhere with npx skills add directus/monospace-agent-skills, or copy skills/monospace/ into your agent's skills directory.

Connect the MCP Server

Monospace serves an MCP endpoint per workspace, so your agent can query and mutate data through the same governed API as the rest of your stack. Every tool call runs under the permissions of the API key you connect with.

Add the server to Claude Code with a single command:

Claude Code
claude mcp add --scope project --transport http monospace \
  http://localhost:8100/api/acme-inventory/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

--scope project writes the config to a shareable .mcp.json in your project root, so anyone who clones the repo gets the same server.

If you'd rather write that file by hand, or your setup can't run the command, create it directly:

.mcp.json
{
  "mcpServers": {
    "monospace": {
      "type": "http",
      "url": "http://localhost:8100/api/acme-inventory/mcp",
      "headers": {
        "Authorization": "Bearer ${MONOSPACE_API_KEY}"
      }
    }
  }
}

Written this way, Claude Code expands ${MONOSPACE_API_KEY} from your environment, keeping the key out of the file. For Cursor, Codex, Gemini, and the OpenAI SDKs, the Configure MCP guide has the exact per-client setup. The URL and bearer token are the same everywhere.


4. Bootstrap the Schema

Here's where it starts to pay off. Instead of modeling collections by hand, describe the data model to your agent and let it build the schema over MCP.

In your IDE, give the agent this prompt:

Create three collections in the acme-inventory workspace on its built-in database.

  • Products: name (string), sku (string), reorder_threshold (integer)
  • StockLevels: product (to-one relation to Products), warehouse (string), quantity_on_hand (integer), updated_at (timestamp)
  • RestockRequests: product (to-one relation to Products), quantity (integer), status (string, one of draft, submitted, received), requested_by (string), created_at (timestamp)

Then seed five sample products with stock levels, two of them below their reorder threshold.

The agent calls read_data_sources to get the built-in database's source id, applies the model with mutate_schema, then seeds the sample data with create_items. With the skill installed, it knows the exact tools and the shape of a valid migration.

The MCP server exposes seven tools, each checked against your key's permissions:

ToolWhat it does
read_schemaInspect collections, fields, and relations
read_data_sourcesList connected data sources; include the built-in database on request
mutate_schemaCreate or alter schema
list_itemsQuery items with filter, sort, and pagination
create_itemsCreate one or more items
update_itemUpdate a single item
delete_itemDelete a single item
mutate_schema can alter or drop collections and fields. Your admin key can run it while building. A deployed application never changes schema at runtime, so the scoped identity you ship with should not have that permission.

5. Generate the SDK and Build

Now the payoff. Generate a client typed to your schema, then build the application against it with full autocomplete and compile-time safety.

Generate the Typed Client

Install the SDK, scaffold a config, and generate the client. The SDK Quickstart covers each step in depth.

npm install @monospace/sdk
npx @monospace/sdk init
npx @monospace/sdk generate

generate reads your live schema over the OpenAPI endpoint, using the same MONOSPACE_API_KEY, and writes a fully typed client. Every collection the agent created, Products, StockLevels, and RestockRequests, is now a typed property on the client.

Build the Application

The console's entire data layer is two typed SDK calls — no hand-rolled API, no ORM. Sketch them in a scratch file, src/restock.ts, to see the shape before your agent builds the UI around them.

List the products that have dropped below their reorder threshold, lowest stock first:

src/restock.ts
import { createClient } from './generated/monospace';

const client = createClient({
  url: 'http://localhost:8100',
  workspace: 'acme-inventory',
  apiKey: process.env.MONOSPACE_API_KEY,
});

const stockLevels = await client.StockLevels.readMany({
  fields: ['id', 'quantity_on_hand', { product: ['id', 'name', 'sku', 'reorder_threshold'] }],
  sort: [{ quantity_on_hand: { direction: 'asc' } }],
});

// Monospace filters compare a field to a value, not one field to another, so the
// reorder check runs here rather than in the query.
const lowStock = stockLevels.filter((level) => {
  const threshold = level.product?.reorder_threshold;
  return threshold != null && level.quantity_on_hand != null && level.quantity_on_hand < threshold;
});

The return type narrows to the exact fields you request, including the nested product relation and its reorder_threshold. See Filtering for value operators like _lt and _in, and Field Selection for nested relations.

Monospace filters compare a field to a value, not one field to another. A cross-field check — like stock below its ownreorder_threshold — runs in your code after the read, as above.

File a restock request when an operator acts on a shortage:

src/restock.ts
const request = await client.RestockRequests.createOne({
  data: {
    product: { _connect: { key: { id: lowStock[0].product.id } } },
    quantity: 100,
    status: 'submitted',
    requested_by: 'restock-console',
  },
  fields: ['id', 'status', 'quantity'],
});

The data object is typed against your schema: required fields are enforced, and unknown fields are rejected.

Now hand your agent this prompt to wrap those two calls in a clean page. It writes the real app files — a server component and a server action — so the src/restock.ts scratch can be deleted once it's done:

Using the generated @monospace/sdk client in ./generated/monospace, build a single-page restock console with Next.js (App Router). Use no UI component library and only light custom CSS.

  • In a server component, instantiate the client with MONOSPACE_API_KEY from the environment and query StockLevels, selecting each product's name, sku, and reorder_threshold; keep the rows whose quantity_on_hand is below the product's reorder_threshold, sorted lowest stock first.
  • Render the results as a table: product, SKU, warehouse, and quantity on hand.
  • Give each row a "Request restock" button that files a RestockRequests item (quantity 100, status submitted) through a server action.
  • When a request is filed, show a brief confirmation toast (inline, no extra library) and list recently filed RestockRequests (product, quantity, status, and when they were filed) in a second table below.
  • Style it with a system font, generous spacing, and a clean card-and-table look.

Because the client runs in a server component, your API key stays on the server and never ships to the browser. Start the dev server:

npm run dev

Open http://localhost:3000 and there it is: every product below its reorder threshold, each with a button that files a restock request.

That's a working application, governed end to end, in about an hour.


Bonus: Deploy with a Service Account

Your personal admin key is perfect for building. To run the console for real, give it its own identity, a service account, scoped to exactly what the running application needs and nothing more.

Create a Service Account

A service account is a non-human identity that the deployed application acts as. Create one for the restock console so its access is separate from any person's login and survives you rotating your own key.

Scope It with a Role and Policy

Access in Monospace is built from roles (containers for policies), policies (where permissions are defined), and entitlements (system-level permissions). Assign the service account a role whose policy grants only what the console needs at runtime:

GrantWhy the application needs it
Read on Products, StockLevelsList low-stock items
Create and Read on RestockRequestsFile and display restock requests
dataModel:readLet the SDK generator read the schema at build time

Notably absent: dataModel:edit and ai:mcp. The deployed console reads and writes items through the SDK. It never mutates schema or calls the MCP server, so its identity can't either.

Mint Its API Key

Create an API key belonging to the service account, then set it as MONOSPACE_API_KEY in your deployment environment in place of your admin key.

An API key grants the same access as its owner. Scope the service account to only what the application needs, keep the key in a secret store rather than source control, and rotate it if it ever leaks.

Next Steps

  • Quickstart — the full Docker Compose setup for starting Monospace
  • Configure MCP — per-client setup for Cursor, Codex, Gemini, and the OpenAI SDKs
  • SDK Quickstart — codegen, the typed client, and every CRUD method
  • Access Control — roles, policies, and entitlements in depth
  • Use Cases — other ways teams put Monospace to work
Copyright © 2026