Amba

Your app's MCP

Every Amba app has its own MCP endpoint whose tools are the app's collections and deployed functions — typed list/get/find/insert/update/delete/aggregate per collection, typed invocation per function, behind an explicit exposure allowlist you control.

The MCP server at mcp.amba.dev exposes Amba's own platform tools — the ones an agent uses to provision a backend. Your app gets a second MCP surface whose tools are your app's own collections and deployed functions, projected into typed tools.

Expose a recipes collection and your app's MCP endpoint gains recipes_list, recipes_get, recipes_find, recipes_insert, recipes_update, recipes_delete, and recipes_aggregate — no tool code to write. The find tool carries a typed, per-column where schema, so an agent queries your data without hand-writing any query strings. Expose a deployed function and it becomes a callable tool too — typed, when the function declares its input schema.

Expose, then connect

Nothing is exposed by default. The agent surface is an explicit allowlist: a collection or function only becomes a tool after you opt it in. That keeps an internal audit_log collection from ever appearing to an in-app agent just because it exists.

// PUT /v1/admin/projects/<project-id>/app-mcp/exposure
// (or the amba_app_mcp_set_exposure platform MCP tool)
{ "collections": ["recipes"], "functions": ["send_welcome_email"] }

The lists are full-set replacements per kind: send the complete set you want exposed; an empty array hides everything of that kind.

Then point your MCP client at your app's endpoint:

Server URL:   https://mcp.amba.dev/app/<your-project-id>/mcp
Bearer auth:  Authorization: Bearer <your-developer-token>

Your project id is shown in the console and returned by amba_developer_signup. The same Bearer token the platform MCP uses works here.

Live generation. Tools are generated from your exposed collections at connect time. Alter a collection, change the allowlist, or redeploy a function and the next tools/list reflects it — no redeploy of anything else, no manual registration.

What you get per collection

For every exposed collection, your app's MCP exposes:

ToolWhat it does
<collection>_listPage through rows, newest first. Returns a next_cursor.
<collection>_getFetch one row by id.
<collection>_findQuery with a typed, per-column where filter.
<collection>_insertInsert a row — only your writable columns are accepted.
<collection>_updateMerge-patch a row by id.
<collection>_deleteSoft-delete (or hard: true to remove — developer scope only).
<collection>_aggregatecount / sum / avg / min / max, optionally grouped.
<collection>_find_nearestVector similarity search — appears automatically when the collection has a vector column (end-user scope).

Two meta tools come along for discovery: <app>_list_collections (the index of exposed collections/functions and their tools) and <app>_whoami (which app + scope you're connected to).

Typed inputs, generated descriptions

Inputs are derived from your live schema. Server-managed columns (id, created_at, updated_at, and friends) are stamped automatically and never appear as input. A text column becomes a string field; an integer column a whole number; an array column an array — and each find filter exposes the operators that make sense for the type (eq, gt, in, like, contains, …):

// recipes_find
{
  "where": { "calories": { "lt": 200 }, "title": { "ilike": "%cake%" } },
  "order": "created_at desc",
  "limit": 20,
}
// recipes_insert — only writable columns
{ "title": "Birthday Cake", "calories": 540 }

Every tool ships an SDK-grade description generated from your columns, so an agent never needs to leave the chat to figure out the shape.

Functions as tools

An exposed deployed function appears as <app>_fn_<name> on the end-user scope and invokes through the same execution path (and URL) every other caller uses — same credentials, same rate limits, same identity headers.

Declare the function's input shape at deploy time and the tool is fully typed:

// metadata for `amba functions deploy` / POST .../functions/deploy
{
  "name": "send_welcome_email",
  "mcp": {
    "description": "Send the branded welcome email to a user.",
    "input_schema": {
      "type": "object",
      "properties": {
        "user_id": { "type": "string", "description": "The recipient app user id" },
        "template": { "type": "string", "enum": ["short", "full"] },
      },
      "required": ["user_id"],
    },
  },
}

The supported schema subset is type: "object" with string / number / integer / boolean / array / object properties, enum, and required — anything outside it is rejected at deploy time rather than silently ignored. A function without a declared schema still works as a tool: it gets a generic { body?, query? } input and a description that says so honestly. Promoting an old version restores the annotation that shipped with it.

A round-trip an agent can do

  1. Provision a recipes collection through the platform MCP (amba_collections_create).
  2. Expose it: amba_app_mcp_set_exposure with collections: ["recipes"].
  3. Connect to https://mcp.amba.dev/app/<project-id>/mcp.
  4. recipes_insert a row, then recipes_find it back — typed, end to end.

That's the wedge: the moment you model your data, one exposure call makes it a typed agent tool surface.

Pagination that just works

list and find default to created_at desc ordering and return a next_cursor from the very first page — pass it back as cursor for the next one. An agent paginates a large collection without ever reading docs.

Two scopes

The same endpoint serves two credential modes:

  • Developer scopeAuthorization: Bearer <developer token>. Operates across all rows (no per-user scoping). This is the building agent's mode: seed data, inspect state, migrate content. (Function tools live on the end-user scope only — function execution authenticates with client keys.)
  • End-user scopeX-Api-Key: <client key> plus Authorization: Bearer <end-user session token>. Tools execute through the same enforcement path as the client SDK: reads and writes honor each collection's access policy (owner reads return only the signed-in user's rows; public reads return everything), and ownership is stamped from the session. This is the in-app assistant's mode — an agent acting for one signed-in user can only ever see and touch what that user could.

There is no policy bypass: the MCP layer never compiles a query — every call proxies to the same routes the SDK uses, so a policy you set once holds everywhere.

Configuration

GET/PATCH /v1/admin/projects/<project-id>/app-mcp/config (or amba_app_mcp_get_config / amba_app_mcp_update_config) controls the surface:

  • enabled — kill switch for the whole agent surface (default on; the allowlist already defaults everything to hidden).
  • auth_mode — which credentials may connect: all (default), client_only (only your app's client keys + end-user sessions — the developer mode is rejected), or developer_only.
  • slug — reserve a friendly hostname label for your agent surface (lowercase DNS label, globally unique).

Hostname

Setting a slug reserves https://<slug>.mcp.amba.host/mcp for your app. Hostname availability is rolling out — until it activates for your account, use the path-addressed endpoint above (connection.url in the config response); both addresses serve the same surface, with the same auth and the same allowlist, so nothing about your setup changes when the hostname goes live.

Metering

Tool calls against your app's MCP are metered as agent tool calls — a usage axis you can watch alongside MAU, events, and storage in amba_billing_status, amba billing status, and the console's billing page. Successful calls count; failed calls don't.

On this page