MCP Server
Data API
Webase apps with data models get a runtime data API for free. Generated apps read and write records via standard HTTP; agents read and write the same records via MCP. Both sides hit the same MongoDB collection.
Endpoints (HTTP, called by the generated app)
| Method | Path | Body | Description |
|---|---|---|---|
GET | /api/v1/apps/:app_slug/data/:model_slug | — | List records |
GET | /api/v1/apps/:app_slug/data/:model_slug/:document_id | — | Show one record |
POST | /api/v1/apps/:app_slug/data/:model_slug | { record: {...} } | Create |
PUT | /api/v1/apps/:app_slug/data/:model_slug/:document_id | { record: {...} } | Update |
DELETE | /api/v1/apps/:app_slug/data/:model_slug/:document_id | — | Delete |
Auth
- Anonymous — if the application has
auth_required: false(the default), no auth header is required. - App user — if
auth_required: true, requests must includex-app-token: <app_user.auth_token>. - Owner — the application owner's Devise session has full access; this is what the in-app editor uses.
Record key format
Records are stored with field IDs (numeric, as strings) as the keys, plus id, created_at, updated_at. Every read returns documents in this canonical form. The generated app needs to know which field id corresponds to which name — fetch the schema once via list_data_models at boot.
// Example record from /api/v1/apps/my-blog/data/posts:
{
"id": "65d2c8b9f1234abc56789def",
"42": "Daily standup planning", // field id 42 = "title"
"43": "Discussed the new feature...", // field id 43 = "body"
"created_at": "2025-...",
"updated_at": "2025-..."
}
MCP shortcuts
When an agent reads / writes records via MCP, the friction goes away:
create_record/update_recordaccept arecordmap keyed by field name, slug, or id — Webase translates to ids before persisting.list_records/get_recordaccepthumanize_keys: trueto swap field ids for field names in the response.
tools/call create_record
{
application_id_or_slug: "my-blog",
model_id_or_slug: "posts",
record: { "title": "Hello", "body": "World" }
}
A minimal DataService for browser_bundler apps
A typical pattern: write a small service module that wraps the data API and resolves field-id keys via the schema. Webase auto-injects src/services/DataService.ts when missing — agents can either rely on that or write their own.
// Prefer the injected DataService:
// import DataService from '@services/DataService'
// await DataService.list('posts')
//
// If you must call the API directly, every URL is scoped by the app slug:
const base = `/api/v1/apps/${appSlug}/data`
export async function list(modelSlug) {
const r = await fetch(`${base}/${modelSlug}`, {
headers: appToken ? { 'x-app-token': appToken } : {}
})
return r.json()
}
export async function create(modelSlug, record) {
const r = await fetch(`${base}/${modelSlug}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...(appToken ? {'x-app-token': appToken} : {}) },
body: JSON.stringify({ record })
})
return r.json()
}