Repository navigation
SDK CLI and MCP
The tools that talk to an AstroBaaS install from the outside: the astrobaas
npm package (a typed client, the core types and the CLI) and the
astrobaas-mcp server that lets an AI agent work with your content. This page
is for developers building a frontend or automation, and for anyone connecting
an AI client.
Everything here is a convenience over the REST API described in Headless and REST API. Nothing in the API requires these tools.
| Package | Install | What it is for |
|---|---|---|
astrobaas |
npm install astrobaas@alpha |
The typed client (astrobaas/client), the public types and helpers (astrobaas/core), the plugin registry (astrobaas/plugins), and the astrobaas CLI. |
astrobaas-mcp |
npx -y astrobaas-mcp |
A zero-dependency Model Context Protocol server. |
Pre-1.0 releases are published under the alpha dist-tag, so ask for
astrobaas@alpha explicitly. The reasoning is in
PUBLISHING.md.
Both packages need Node 22.12 or later.
The npm package does not give you a running site. To run the CMS itself, clone the repository (see Installation).
A small, dependency-free TypeScript client. It uses the global fetch, so it
runs in Node, Deno, edge runtimes and browsers. Every method returns the
unwrapped data from the response envelope and throws AstroBaasError on any
failure.
import { createClient, AstroBaasError } from 'astrobaas/client';
const baas = createClient('https://cms.example.com', {
apiKey: process.env.ASTROBAAS_KEY, // omit for anonymous, published-only reads
timeoutMs: 10_000, // abort slow requests
retries: 2, // retry 429, 5xx and network errors
});
const posts = await baas.posts.list({ status: 'published', limit: 10 });
const post = await baas.posts.get('hello-world');
try {
await baas.posts.create({ title: 'From the SDK', status: 'draft' });
} catch (e) {
if (e instanceof AstroBaasError) console.error(e.status, e.code, e.reason, e.message);
}| Option | Default | Meaning |
|---|---|---|
apiKey |
none | Sent as Authorization: Bearer <key>. Change it later with setApiKey(key). |
fetch |
global fetch
|
Inject your own, for SSR frameworks or tests. |
headers |
{} |
Extra headers on every request. |
timeoutMs |
none | Abort a request after this many milliseconds. |
retries |
0 |
Retries on 429, 5xx and network errors. |
retryBackoffMs |
250 |
Base of the exponential backoff. A 429 waits for Retry-After instead. |
AstroBaasError carries:
| Property | Meaning |
|---|---|
status |
HTTP status, or 0 for a network error or timeout. |
code |
The envelope's error.code (NOT_FOUND, VALIDATION_ERROR, …), or TIMEOUT / NETWORK. |
reason |
The specific cause, for example checkout.too_many_unpaid or IDEMPOTENCY_IN_PROGRESS. |
params |
Values that go with reason, for example { max: 5 }. |
details |
Per-field validation messages. |
| Namespace | Methods | Endpoint group |
|---|---|---|
posts |
list, page, listAll, get, related, create, update, remove
|
/api/posts |
content(type) |
list, page, listAll, get, create, update, remove
|
/api/content/{type} |
media |
list, upload, update, remove
|
/api/media/* (staff) |
products |
list, page, listAll, get, create, update, remove, notifyWhenBack
|
/api/products |
orders |
list, page, get, quote, place, update, ship, refund
|
/api/orders |
customers |
list, page
|
/api/customers (staff) |
coupons |
list, create, update, remove
|
/api/coupons (staff) |
keys |
list, create, rotate, revoke
|
/api/keys (admin) |
webhooks |
list, register, remove, deliveries, redeliver
|
/api/webhooks (admin) |
audit |
list |
/api/audit (admin) |
auth |
me, login, logout, forgotPassword, resetPassword, twoFactor.setup/enable/disable
|
/api/auth/*, /api/2fa/*
|
| (root) |
locales(), request(method, path, body?)
|
anything else |
request() is the escape hatch for endpoints without a typed helper. It still
unwraps the envelope and throws on errors.
page() returns one page with its metadata; listAll() walks every page for
you.
const p = await baas.posts.page({ limit: 20, page: 2 });
// { items, total, count, limit, offset, page, hasMore }
const everything = await baas.content('event').listAll();orders.place() always sends an Idempotency-Key, generating one if you do
not pass it. Pass your own when your code retries a failed call, so the retry
is recognised as the same attempt:
const key = crypto.randomUUID(); // once per "Place order" click
const quote = await baas.orders.quote({ items: [{ product_id, qty: 1 }] });
const order = await baas.orders.place(
{ email: 'buyer@example.com', items: [{ product_id, qty: 1 }] },
{ idempotencyKey: key },
);Prices are always computed on the server. See Commerce.
The client also exports verifyWebhookSignature(secret, rawBody, header),
a constant-time HMAC check that runs anywhere WebCrypto exists. Usage is on
the Webhooks page.
astrobaas/core is the public surface that plugins and themes build against.
It exports:
- the domain types (
Post,User,Product,Order,MediaFile,CustomEntity, …) and theStorageinterface type; -
definePlugin,defineTheme,PluginManager,pluginManagerand thePLUGIN_HOOKScatalogue; -
registerContentTypeand the content-type definitions; - utilities:
sanitizeHtml,validate,slugify,ApiResponseBuilder,fireEvent,webhookMatches,signWebhook,sendEmail,recordAudit; -
LocalDB, for code that runs inside the AstroBaaS process.
Anything exported here is covered by the stability promise in STABILITY.md: pre-1.0 it may change, but breaking changes are always listed under Breaking in the changelog. See Plugins and Themes.
astrobaas/plugins exposes the plugin registry the server boots
(BUNDLED_PLUGINS, ensurePluginsBootstrapped, reloadPlugins,
pluginBootstrapReport). Most projects will not need it.
The package installs an astrobaas binary. In a clone of the repository it is
also available as node bin/astrobaas.mjs.
npx astrobaas@alpha --helpThese work on the files in the current directory. They need no running site.
| Command | What it does |
|---|---|
astrobaas init [--force] |
Write a .env (from .env.example) with a freshly generated AUTH_SECRET. Refuses to overwrite an existing .env without --force. |
astrobaas secret |
Print a new 32-byte hex secret to stdout, and nothing else. |
astrobaas setup |
Create or replace the admin account, interactively. Works on the JSON store only; it refuses when DATABASE_URL is set. |
astrobaas plugin new <id> |
Scaffold a code plugin in src/plugins/<id>/. |
astrobaas plugin manifest <id> |
Scaffold a declarative plugin manifest (<id>.manifest.json), installable at runtime from the admin. |
astrobaas plugin package <id> |
Scaffold a standalone plugin package with its own build, for loading through ASTROBAAS_PLUGINS. |
astrobaas plugin validate <file> |
Validate a declarative manifest with the same rules the installer uses. Needs a repository checkout. |
astrobaas theme new <id> |
Scaffold a theme in src/themes/<id>/. |
astrobaas version |
Print the version. |
A typical first run in a fresh clone:
npx astrobaas init && npm install && npm run setup && npm run devThese go through the REST API, never the database directly, so every rule the routes enforce still applies. Set the site and a key first:
export ASTROBAAS_URL=https://cms.example.com
export ASTROBAAS_KEY=abk_…| Command | What it does | Key needs |
|---|---|---|
astrobaas content types |
List the registered content types, with read and write policy. | any key without scopes |
astrobaas content list <type> |
List up to 200 entries. | read access to the type |
astrobaas content export <type> |
Print every entry as JSON, paging to the end. | read access to the type |
astrobaas backup export > site-backup |
Download a full archive to stdout. Refuses to write binary to a terminal. | admin |
astrobaas backup run |
Run the configured off-site backup now. | admin |
astrobaas clone <src> <dst> --yes |
Download an archive from one site and restore it into another. Overwrites the target. | admin on both |
Add --json to content types and content list for machine-readable
output, and --base <url> to override ASTROBAAS_URL for one call. clone
uses ASTROBAAS_SOURCE_KEY and ASTROBAAS_TARGET_KEY when the two sites need
different keys, refuses when source and target are the same URL, and does
nothing without --yes. A restore has driver rules of its own; read
Backups and storage before cloning between installs.
The repository also has npm run scripts for work that is not part of the
published CLI, such as npm run reset-password and the importers
(import:md, import:wp, import:woo). See Importing.
astrobaas-mcp exposes a running AstroBaaS install as
Model Context Protocol tools, so an AI
client such as Claude Desktop or Claude Code can read and write its content. It
speaks newline-delimited JSON-RPC over stdio, has no dependencies, and talks to
your site over the same REST API as everything else. Nothing of AstroBaaS
needs to be installed on the machine that runs it.
The same server also ships inside the astrobaas package as its
astrobaas-mcp binary.
| Variable | Default | Meaning |
|---|---|---|
ASTROBAAS_URL |
http://localhost:4321 |
Base URL of your install. |
ASTROBAAS_KEY |
none | An API key. Without one, only public reads work. |
The key's role and scopes decide what the agent can do. Give it the least that
works: a key scoped to posts:* and content:read cannot touch orders,
customers or settings however the agent is prompted. See
Headless and REST API.
Claude Desktop (claude_desktop_config.json), and any client that uses the
same mcpServers shape:
{
"mcpServers": {
"astrobaas": {
"command": "npx",
"args": ["-y", "astrobaas-mcp"],
"env": {
"ASTROBAAS_URL": "https://cms.example.com",
"ASTROBAAS_KEY": "abk_..."
}
}
}
}Claude Code:
claude mcp add astrobaas \
-e ASTROBAAS_URL=https://cms.example.com \
-e ASTROBAAS_KEY=abk_... \
-- npx -y astrobaas-mcpOn startup the server writes to stderr (never stdout, which is the protocol channel): a ready line, then either the role the key resolved to or a warning that the key check failed. Check your client's MCP log if tools fail.
There are 33 tools. Ask the agent to call whoami first to confirm the
connection and the key's role.
| Area | Tool | Endpoint | Access |
|---|---|---|---|
| Identity | whoami |
GET /api/auth/me |
any |
| Posts | list_posts |
GET /api/posts |
public (published only without a key) |
get_post |
GET /api/posts/{slug} |
public | |
create_post |
POST /api/posts |
author+ | |
update_post |
PUT /api/posts/{ref} |
author+ (authors: own posts only) | |
delete_post |
DELETE /api/posts/{ref} |
author+ (authors: own posts only) | |
list_revisions |
GET /api/posts/{ref}/revisions |
key required | |
| Custom content | list_content |
GET /api/content/{type} |
depends on the type |
create_content |
POST /api/content/{type} |
editor+ | |
update_content |
PUT /api/content/{type}/{id} |
editor+ | |
delete_content |
DELETE /api/content/{type}/{id} |
editor+ | |
| Catalogue | list_products |
GET /api/products |
public |
get_product |
GET /api/products/{ref} |
public | |
create_product |
POST /api/products |
products:write |
|
update_product |
PUT /api/products/{id} |
products:write |
|
delete_product |
DELETE /api/products/{id} |
products:write |
|
import_products |
POST /api/commerce/import |
products:write |
|
list_product_categories |
GET /api/product-categories |
public | |
list_brands |
GET /api/brands |
public | |
| Orders | list_orders |
GET /api/orders |
staff, orders:read
|
get_order |
GET /api/orders/{id} |
staff | |
set_order_status |
PUT /api/orders/{id} |
staff | |
list_customers |
GET /api/customers |
staff, customers:read
|
|
list_payment_methods |
GET /api/payments |
public | |
| Media | list_media |
GET /api/media/get |
staff key |
| Editorial | search |
GET /api/search |
public |
list_categories |
GET /api/categories/get |
public | |
list_locales |
GET /api/locales |
public | |
| Site | get_settings |
GET /api/settings/get |
public keys only, all for staff |
update_settings |
POST /api/settings/update |
admin | |
list_plugins |
GET /api/plugins |
admin | |
set_plugin_active |
POST /api/plugins/toggle |
admin | |
get_theme |
GET /api/themes/get |
public |
The catalogue, order and customer tools only work while commerce is switched on. A few things the tool descriptions tell the agent, and that are worth knowing yourself:
- Money is integer minor units:
price_cents: 1999means 19.99. Floats are refused. -
set_order_statuschanges fulfilment status and moves stock; it never moves money. -
import_productsreports rejected rows rather than skipping them silently. Withreplace: trueit empties the catalogue first, and that is not transactional, so take a backup first. - Settings have a public read path. Never ask an agent to store credentials in them; use environment variables.
Published posts are also exposed as MCP resources, astrobaas://post/<slug>,
so a client can attach an article as context without a tool call. The list
holds up to 100 recent posts, and reading one returns its HTML.
An agent that writes a frontend does not need the MCP server. Point it at
https://cms.example.com/llms.txt (a plain-text brief of the API) and
/openapi.json. Both are public.
- Headless and REST API: the endpoints these tools call
-
Webhooks:
baas.webhooks.*and signature verification -
Plugins and Themes: building on
astrobaas/core -
Backups and storage: what
backupandclonemove - INTEGRATION.md §4, §6 and §8
- packages/astrobaas-mcp/README.md
- src/client/index.ts: the client source
AstroBaaS is free software under GPL-3.0-or-later. This wiki describes the latest release; the repository and its CHANGELOG are the final word. Found a mistake here? Open an issue.
Getting started
Using the CMS
Building with it
Extending
Commerce and email
Operating
Project