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 include x-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_record accept a record map keyed by field name, slug, or id — Webase translates to ids before persisting.
  • list_records / get_record accept humanize_keys: true to 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()
}