Skip to main content
Glama
apito-io
by apito-io

Apito MCP Server

Version 1.3.0 — see CHANGELOG.md.

A Model Context Protocol (MCP) server for Apito - an API builder and headless CMS. This server enables LLMs like Claude to interact with Apito's system GraphQL API to create models, manage fields, and build schemas.

System vs public GraphQL: All MCP tools in this repo call the system GraphQL surface (console-style operations such as getModelData, model and field mutations). The public per-project GraphQL API (e.g. taskList for end users) can differ in auth, SaaS tenant routing, and nested relation resolution. When debugging “works in MCP / system but not on public,” compare endpoints and credentials; do not assume identical behavior.

Features

  • Model Management: Create, list, query, and delete models in your Apito project

  • Field Management: Add, update, rename, and delete fields with explicit type specification

  • Relation Management: Create relations between models (has_one, has_many)

  • Full Field Type Support: All Apito field types including text, multiline, number, date, boolean, media, object, repeated, list (with sub-types), and geo

  • Resources: Expose model schemas as MCP resources for easy access

  • Error Handling: Comprehensive error handling with detailed messages

  • Cloudflare Workers: Deploy as a remote MCP server for use with any MCP client

  • Project-Dependent API Keys: API keys are passed per-request, allowing different projects to use the same worker

  • Schema versioning (pro): Stage schema mutations into a draft; verify via get_effective_schema; user publishes in Console — MCP never publishes

  • Platform management (v1.3): Full project administration beyond schema — tenant catalog, app end-users, auth testing, roles/settings/API keys, webhooks/plugins/functions/media, and extended data operations (~99% Console admin via system GraphQL)

  • Edition split: APITO_MCP_EDITION=open hides pro-only tools (tenant catalog, some schema versioning extras); default is pro

Related MCP server: mcp-graphql-tools

Platform management tools (v1.3)

Prior to v1.3, MCP covered schema design, draft versioning (read), and model data CRUD only. SaaS operators still had to open Console for tenants, app users, roles, webhooks, and similar admin tasks. v1.3 adds ~50 platform tools that mirror Console system GraphQL — so an LLM agent can provision tenants, manage end-users, configure project settings, and run integration setup in one MCP session alongside schema work.

All platform tools use the same transport as existing MCP tools: system GraphQL (/system/graphql + X-Apito-Key). They are not public /secured/graphql operations. Tool descriptions are tagged [pro], [core], or [core/pro] for a future open-mcp vs pro-mcp package split.

Tool catalog by domain

Domain

Tools

Engine GraphQL (representative)

SaaS tenants [pro]

list_tenants, create_tenant, update_tenant, delete_tenant, generate_tenant_token, search_tenant_by_domain

getTenants, createTenant, updateTenant, deleteTenant, generateTenantToken, searchTenantsByDomain

App end-users

search_app_users, create_app_user, update_app_user, delete_app_user, reset_app_user_password, login_app_user, google_oauth_state, login_app_user_google

searchUsers, createUser, updateUser, deleteUser, resetUserPassword, loginUser, googleOAuthState

Schema versioning extras [pro]

get_schema_diff, list_schema_versions, list_schema_change_events, discard_schema_draft

schemaDiff, schemaVersions, schemaChangeEvents, discardSchemaDraft

Project admin

list_roles, get_permissions_catalog, upsert_role, duplicate_role, delete_role, get_project_settings, update_project_settings, list_api_keys, create_api_key, delete_api_key, get_auth_settings, update_auth_settings, get_storage_settings, update_storage_settings, list_team_members, update_team_members

currentProject, upsertRoleToProject, generateProjectToken, updateProjectAuthentication, etc.

Integrations

list_webhooks, create_webhook, delete_webhook, list_plugins, configure_plugin, remove_plugin, list_functions, upsert_function, delete_function, list_media, upload_media_from_url, delete_media

createWebHook, upsertPlugin, upsertFunctionToProject, uploadImageFromURL, etc.

Data plane

list_data, connect_relation, disconnect_relation, get_model_document_counts, list_document_revisions, reorder_fields

getModelData, upsertModelData (connect/disconnect), modelDocumentCounts, listDocumentRevisions, rearrangeSerialOfFieldType

Typical workflows

SaaS tenant onboarding [pro]

  1. list_tenants — inspect catalog rows (id, name, domain, metadata).

  2. create_tenant — provision a tenant (name, optional domain, optional data JSON string). On per-tenant separate DB projects, engine provisions the tenant database.

  3. generate_tenant_token — mint a tenant-scoped API token (tenant_id, duration as YYYY-MM-DD, optional role). Sensitive — treat like a secret.

  4. search_tenant_by_domain — resolve tenant by hostname for login routing (project_id, domain).

Pass tenant_id on subsequent data and app-user tools, or set TENANT_ID / X-Apito-Tenant-ID globally for the session.

App end-user administration

  1. search_app_users with project_id (and tenant_id on SaaS) — paginated user list.

  2. create_app_user — requires password plus email and/or phone; optional role, username, tenant_id.

  3. update_app_user / reset_app_user_password / delete_app_user — lifecycle management by user_id.

Auth testing (local + Google)

Read apito://saas-auth-guide or call get_saas_auth_guide first.

  • Local: login_app_user with project_id, password, and email or phone → returns { token, user }. Use token as Bearer on public /secured/graphql (not the MCP system API key).

  • Google: google_oauth_state → open OAuth URL in a browser → login_app_user_google with code + state (or id_token). MCP cannot complete OAuth without a human pasting the callback code.

Returned JWTs and generated API tokens are sensitive. Do not log or commit them.

Project settings & access control

  • Roles: list_rolesget_permissions_catalogupsert_role (name, api_permissions, logic_executions, is_admin). Use duplicate_role / delete_role as needed.

  • Settings: get_project_settings / update_project_settings for name, description, and settings payload.

  • API keys: list_api_keyscreate_api_key (returns token once) → delete_api_key to revoke.

  • Auth & storage: get_auth_settings / update_auth_settings, get_storage_settings / update_storage_settings.

  • Console team: list_team_members / update_team_members (add/remove operators on the project).

Integrations

  • Webhooks: list_webhookscreate_webhook (events, model, url, name) → delete_webhook.

  • Plugins: list_plugins (by type enum, e.g. STORAGE, FUNCTION) → configure_plugin / remove_plugin.

  • Functions: list_functionsupsert_functiondelete_function.

  • Media: list_mediaupload_media_from_urldelete_media by ids.

Extended data operations

  • list_data — same engine op as get_data but documented for filtering/pagination; supports where, status, search, tenant_id.

  • connect_relation / disconnect_relation — relation updates via upsertModelData connect/disconnect maps (use get_relation_graph for field names).

  • get_model_document_counts — row counts per model.

  • list_document_revisions — revision history for a document.

  • reorder_fields — change field serial order within a model.

Existing data tools (get_data, upsert_data, delete_data, duplicate_data) now accept optional tenant_id per call in addition to env/header routing.

SaaS routing & edition

Tenant scope — three equivalent ways to route a request to a tenant:

Method

Where

Tool argument tenant_id

Per-call override (preferred when switching tenants in one session)

TENANT_ID / APITO_TENANT_ID

Stdio MCP client env

X-Apito-Tenant-ID

Remote Cloudflare worker header

Edition — set APITO_MCP_EDITION=open to hide pro-only platform tools (list_tenants, get_schema_diff, list_schema_versions, list_schema_change_events, discard_schema_draft, get_saas_auth_guide). Default is pro (full surface). This prepares a future split into open-mcp vs pro-mcp packages without changing tool names today.

Resources & guides

Resource / tool

Purpose

apito://saas-auth-guide / get_saas_auth_guide

App user login flows, tenant rules, token handling

apito://saas-model-guide / get_saas_model_guide

Common vs tenant-scoped models

apito://schema-versioning-guide

Draft/publish workflow (MCP never publishes)

Intentionally excluded

MCP does not expose destructive or irreversible Console workflows that belong in human-reviewed UI:

  • Schema publish (approveSchemaChanges), rollback (rollbackSchemaVersion), flush sync (flushSchemaSync), execution repair mutations

  • deleteProject, billing/subscription ops, plugin build trigger

MCP stages schema changes and reads drafts; operators publish manually in Console. discard_schema_draft is included as a safe undo for unstaged drafts only.

Smoke tests

pnpm test:tenant-users   # edition filtering + optional live tenant/user queries
pnpm test:versioning     # schema versioning unit + optional live checks

Live tenant/user tests need APITO_API_KEY, APITO_PROJECT_ID, and optionally TENANT_ID.

Schema versioning workflow (pro projects)

When PRO_SCHEMA_VERSIONING_ENABLED=true on the engine, schema mutations stage a draft instead of applying immediately.

  1. Call get_schema_migration_guide (or read apito://schema-migration-guide) before any migration or bulk schema work.

  2. Call get_schema_versioning_status at the start of schema work.

  3. Use create_model, add_field, add_relation, etc. — changes go to the draft changeset.

  4. Verify with get_effective_schema or get_schema_preview (source: "draft").

  5. Review get_schema_change_plan for the publish timeline.

  6. End with summarize_schema_draft_for_review — tells the user to open Console → Project Settings → Schema Changes → Publish manually.

  7. upsert_data / get_data only work on published (live) models.

Read tools accept optional source: live | draft | effective (default: effective when a draft exists). Resources: apito://schema-migration-guide, apito://schema-versioning-guide.

MCP never calls publish mutations (approveSchemaChanges, etc.).

See SCHEMA_MIGRATION_GUIDE.md for full migration dos/donts (nested fields, live vs draft, delete/add pitfalls).

SaaS tenant headers

For per-tenant database scope, set TENANT_ID or APITO_TENANT_ID in stdio env, or send X-Apito-Tenant-ID on remote worker requests (included in CORS allowlist). Most platform and data tools also accept per-call tenant_id in tool arguments.

Set APITO_MCP_EDITION=open to hide pro-only platform tools (tenant catalog, get_schema_diff, list_schema_versions, etc.). Default is pro (full surface).

SaaS model scope (common vs tenant-scoped)

On SaaS projects, models can be:

Scope

MCP flag

Meaning

Tenant-scoped (default)

omit is_common_model

Each tenant sees only their own rows

Common (project-wide)

is_common_model: true

All tenants share the same rows — no tenant isolation

Examples: app_release_policy and a shared medicine catalog in hospital SaaS should be common. patient, appointment, and order should stay tenant-scoped.

  • Tool: get_saas_model_guide — full guide with examples and decision checklist

  • Resource: apito://saas-model-guide

  • create_model accepts is_common_model

  • update_model toggles is_common_model on existing models (metadata-only, immediate on pro)

  • list_models shows scope per model (common, tenant-scoped, tenant catalogue)

Call get_project_context first on SaaS projects, then get_saas_model_guide before creating models.

MCP Client Configuration (Cursor / mcp-remote)

Add the apito-mcp server to your MCP client config (e.g. Cursor ~/.cursor/mcp.json or project .cursor/mcp.json):

{
  "mcpServers": {
    "apito-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://apito-mcp.apito.workers.dev/sse",
        "--header",
        "X-Apito-Key:${APITO_API_KEY}",
        "--header",
        "X-Apito-Tenant-ID:${TENANT_ID}"
      ],
      "env": {
        "APITO_API_KEY": "ak_your-api-key-here",
        "TENANT_ID": "optional-tenant-id-for-saas"
      }
    }
  }
}

Replace ak_your-api-key-here with your Apito API key. The X-Apito-Key header is sent with each request to the remote worker.

MCP Tools

create_model

Create a new model in Apito.

Arguments:

  • model_name (required): Name of the model

  • single_record (optional): Whether this is a single-record model

  • is_common_model (optional, SaaS): When true, creates a project-wide common model — all tenants share rows, no tenant scoping. See get_saas_model_guide.

update_model

Update model metadata (not fields).

Arguments:

  • model_name (required): Model to update

  • is_common_model (optional): Mark model as common (true) or tenant-scoped (false)

  • single_page_model (optional): Single-record settings model

At least one of is_common_model or single_page_model is required.

get_schema_migration_guide

Returns the full schema migration guide: dos/donts for any source (JSON export, live preview, gap diff). Covers sequential mutations, live vs draft, nested parent_field, delete/add pitfalls, verification with get_schema_preview, SaaS patterns, and publish handoff. Call this before bulk schema work. Same content as resource apito://schema-migration-guide. See also SCHEMA_MIGRATION_GUIDE.md.

get_saas_model_guide

Returns the SaaS model classification guide: when to use common vs tenant-scoped models, with examples (app_release_policy, hospital medicine catalog). No arguments.

add_field

Add a field to an existing model. You must specify field_type and input_type explicitly.

Arguments:

  • model_name (required): Name of the model

  • field_label (required): Label/name of the field

  • field_type (required): Field type (see valid combinations below)

  • input_type (required): Input type (see valid combinations below)

  • field_sub_type (optional): Required for list fields. Valid values: dynamicList, dropdown, multiSelect

  • parent_field (optional): Parent field name for nested fields

  • is_object_field (optional): Whether this field can contain nested fields (auto-set for object and repeated types)

  • field_description (optional): Field description

  • validation (optional): Validation rules (see below for requirements)

  • serial (optional): Serial number for field ordering

Valid Field Type Combinations:

  • Text Field: field_type="text", input_type="string" - Single line text input

  • Rich Text Field: field_type="multiline", input_type="string" - Multiline editor with formatting

  • DateTime Field: field_type="date", input_type="string" - Date & Time input

  • Dynamic Array: field_type="list", field_sub_type="dynamicList", input_type="string" - Flexible list allowing multiple items

  • Dropdown Menu: field_type="list", field_sub_type="dropdown", input_type="string" - Predefined list for single selection

    • REQUIRES: validation.fixed_list_elements (array of strings) and validation.fixed_list_element_type="string"

  • Multi-Checkbox Selector: field_type="list", field_sub_type="multiSelect", input_type="string" - Allows selecting multiple options

    • REQUIRES: validation.fixed_list_elements (array of strings) and validation.fixed_list_element_type="string"

  • Boolean Field: field_type="boolean", input_type="bool" - True or False toggle

  • File Upload: field_type="media", input_type="string" - Upload images or files

  • Integer Field: field_type="number", input_type="int" - Whole numbers only

  • Decimal Field: field_type="number", input_type="double" - Decimal numbers

  • GeoPoint Field: field_type="geo", input_type="geo" - Latitude & Longitude

  • Object Schema: field_type="object", input_type="object", is_object_field=true - Single object with multiple fields

  • Array Schema: field_type="repeated", input_type="repeated", is_object_field=true - List of objects with multiple fields

Example - Simple Field:

{
  "model_name": "dentalAssessment",
  "field_label": "Date",
  "field_type": "date",
  "input_type": "string"
}

Example - Dropdown Field:

{
  "model_name": "dentalAssessment",
  "field_label": "Status",
  "field_type": "list",
  "field_sub_type": "dropdown",
  "input_type": "string",
  "validation": {
    "fixed_list_elements": ["active", "inactive", "pending"],
    "fixed_list_element_type": "string"
  }
}

Example - Nested Object Field:

{
  "model_name": "dentalAssessment",
  "field_label": "Chief Complaint",
  "field_type": "object",
  "input_type": "object",
  "is_object_field": true
}

Then add nested fields with parent_field="chief_complaint":

{
  "model_name": "dentalAssessment",
  "field_label": "Complaint",
  "field_type": "text",
  "input_type": "string",
  "parent_field": "chief_complaint"
}

update_field

Update an existing field in a model.

Arguments:

  • model_name (required): Name of the model

  • field_name (required): Identifier of the field to update

  • field_label (required): New label for the field

  • field_type (optional): New field type

  • input_type (optional): New input type

  • field_description (optional): New description

  • validation (optional): Updated validation rules

rename_field

Rename a field in a model.

Arguments:

  • model_name (required): Name of the model

  • field_name (required): Current field identifier

  • new_name (required): New field identifier

  • parent_field (optional): Parent field name if this is a nested field

delete_field

Delete a field from a model.

Arguments:

  • model_name (required): Name of the model

  • field_name (required): Field identifier to delete

  • parent_field (optional): Parent field name if this is a nested field

delete_model

Irreversible — removes the model from the project schema and deletes all rows in that model. Uses system updateModel(type: delete, model_name). The engine blocks deletion until all schema relations involving this model are removed: get_model_schema for this model must show no connections, and no other model may list this model in connections[].model; use delete_relation for each edge first.

Safety: You must pass acknowledge_permanent_deletion: true (literal boolean) or the tool refuses without calling the API. Get explicit human confirmation before using.

Arguments:

  • model_name (required): Name of the model to delete

  • acknowledge_permanent_deletion (required): Must be true

list_models

List models in the project. Optional source: live, draft, or effective (default: effective when a draft exists).

Arguments:

  • source (optional): Schema source (see Schema versioning workflow)

get_schema_versioning_status

Returns whether schema versioning is enabled, active version, draft changeset id, and pending operation count.

get_schema_preview

Read schemaPreview JSON. source required: live, draft, or version (with optional version int).

get_effective_schema

Merged live+draft schema (console overlay parity). Primary verification tool after staging mutations.

get_schema_change_plan

Publish plan from schemaChangeExecutionRecords. Optional changeset_id.

summarize_schema_draft_for_review

Markdown summary of effective schema + change plan + user publish instructions.

get_model_schema

Get the complete schema for a model including all fields and their types. Optional source (default: effective when draft exists).

Arguments:

  • model_name (required): Name of the model to get schema for

  • source (optional): live, draft, or effective

get_project_query_structure

Get the Apito project GraphQL query structure: which operations exist for each model. Apito uses a consistent naming convention: for model Task you get task(_id), taskList, taskListCount, createTask, updateTask, deleteTask, upsertTaskList. CamelCase matters — model names are converted to camelCase for operation names.

Note: Public project GraphQL reflects published (live) schema only. Draft-only models appear after Console publish.

Use this tool when you need to know what GraphQL operations to call for querying or mutating project data. The schema is dynamic per project, so call this early to discover available operations.

Arguments: None

Returns: A mapping of each model to its operations:

  • Queries: {singular}(_id) (single by ID), {singular}List (paginated list), {singular}ListCount (count)

  • Mutations: create{Model}, update{Model}, delete{Model}, upsert{Model}List

add_relation

Create a relation between two models. Relations define how models are connected (e.g., a Patient has many DentalAssessments, or a DentalAssessment belongs to one Patient).

Arguments:

  • from_model (required): Source model name (the model that will have the relation field)

  • to_model (required): Target model name (the model being related to)

  • forward_connection_type (required): Forward relation type from source to target. Valid values: "has_many" (one-to-many) or "has_one" (one-to-one)

  • reverse_connection_type (required): Reverse relation type from target back to source. Valid values: "has_many" (one-to-many) or "has_one" (one-to-one)

  • known_as (optional): Optional alternate identifier for this relation (custom name for the relation field)

Example:

{
  "tool": "add_relation",
  "arguments": {
    "from_model": "dentalAssessment",
    "to_model": "patient",
    "forward_connection_type": "has_many",
    "reverse_connection_type": "has_one",
    "known_as": "assessments"
  }
}

This creates:

  • Forward: dentalAssessment has many patient

  • Reverse: patient has one dentalAssessment

upsert_data

Create or update a record in a model. Maps to Apito's upsertModelData system mutation.

Arguments:

  • model_name (required): Name of the model

  • payload (required): JSON object of field values to create/update

  • _id (optional): Document ID for updates (omit for create)

  • status (optional): Document status: "draft" or "published" (default: "published")

  • local (optional): Locale for localized content (default: "en")

  • connect (optional): JSON for connecting relations — {"author_id": "uuid"} for has_one, {"tag_ids": ["uuid1","uuid2"]} for has_many

  • disconnect (optional): JSON for disconnecting relations

Relation Connect Pattern: Keys use {modelName}_id for has_one and {modelName}_ids for has_many (where modelName is the related model name or known_as).

get_data

Query or list records from a model with optional filters, pagination, and search. Maps to Apito's getModelData system query.

Arguments:

  • model_name (required): Name of the model

  • page (optional): Page number (default: 1)

  • limit (optional): Records per page (default: 10)

  • where (optional): JSON filter object

  • status (optional): Filter by status: "all", "draft", or "published"

  • search (optional): Text search query

delete_data

Delete a record by ID. Maps to Apito's deleteModelData system mutation.

Arguments:

  • model_name (required): Name of the model

  • _id (required): Document ID to delete

duplicate_data

Duplicate a record by ID. Returns the new record ID. Maps to Apito's duplicateModelData system mutation.

Arguments:

  • model_name (required): Name of the model

  • _id (required): Document ID to duplicate

Example: Create a category and connect an article to it

{
  "tool": "upsert_data",
  "arguments": {
    "model_name": "Category",
    "payload": {
      "name": "Technology",
      "slug": "technology"
    }
  }
}

Returns the new category with id. Then create an article connected to that category:

{
  "tool": "upsert_data",
  "arguments": {
    "model_name": "Article",
    "payload": {
      "title": "My First Post",
      "slug": "my-first-post"
    },
    "connect": {
      "category_id": "<category-id-from-above>"
    }
  }
}

MCP Resources

Model schemas and the query structure guide are exposed as resources with URIs:

  • apito://schema-versioning-guide - Draft vs live schema, verification tools, MCP never publishes, data after publish

  • apito://project-query-guide - Apito query structure: response shape (id, data, meta), multiline/geo/media sub-selection, naming, where filters, relation list filters (default for has_one / has_many / M:N — e.g. studentList(relation: { class: { _id: { eq: "…" } } })), connection filter (advanced anchor traversal only — not for everyday related-model filtering), pagination, mutations

  • apito://field-design-guide - Object vs repeated vs relation field selection rules

  • apito://model/{modelName} - Model schema as JSON (effective schema when draft exists)

Field Type Reference

Available Field Types

  • text - Single line text input

  • multiline - Multiline editor with formatting

  • number - Number field (use int or double input_type)

  • date - Date & Time input

  • boolean - True or False toggle

  • media - File upload

  • object - Single object with multiple fields

  • repeated - Array of objects with multiple fields

  • list - List field (requires field_sub_type)

  • geo - GeoPoint (latitude & longitude)

Available Input Types

  • string - String value

  • int - Integer number

  • double - Decimal number

  • bool - Boolean value

  • geo - Geographic coordinates

  • object - Object structure

  • repeated - Array structure

Query Sub-Selection (CRITICAL for multiline, geo, media, object, repeated)

When querying these fields, you must use a sub-selection. Bare selection causes GraphQL error "must have a sub selection":

  • multilinecontent { html } or bio { text } (pick html, text, or markdown)

  • geolocation { lat lon }

  • mediathumbnail { url } or image { url } (or other subfields)

  • object / repeated → select nested fields

List Field Sub Types

When using field_type="list", you must specify field_sub_type:

  • dynamicList - Dynamic Array (flexible list allowing multiple items)

  • dropdown - Dropdown Menu (predefined list for single selection)

    • Requires: validation.fixed_list_elements and validation.fixed_list_element_type="string"

  • multiSelect - Multi-Checkbox Selector (allows selecting multiple options)

    • Requires: validation.fixed_list_elements and validation.fixed_list_element_type="string"

Example: Creating a Dental Assessment Model

The MCP server provides basic CRUD operations. The LLM should parse schema definitions and call the appropriate tools. Here's how an LLM would create a dental assessment model:

  1. Create the model:

{
  "tool": "create_model",
  "arguments": {
    "model_name": "dentalAssessment"
  }
}
  1. Add fields one by one:

{
  "tool": "add_field",
  "arguments": {
    "model_name": "dentalAssessment",
    "field_label": "Date",
    "field_type": "date",
    "input_type": "string"
  }
}
  1. Add object field:

{
  "tool": "add_field",
  "arguments": {
    "model_name": "dentalAssessment",
    "field_label": "Chief Complaint",
    "field_type": "object",
    "input_type": "object",
    "is_object_field": true
  }
}
  1. Add nested fields:

{
  "tool": "add_field",
  "arguments": {
    "model_name": "dentalAssessment",
    "field_label": "Complaint",
    "field_type": "text",
    "input_type": "string",
    "parent_field": "chief_complaint"
  }
}

Development

# Type check
pnpm run typecheck

# Schema versioning unit (+ optional live) tests
npx tsx test-schema-versioning.ts

# Build
npm run build

# Development mode (Cloudflare)
npm run dev

Error Handling

The server provides detailed error messages including:

  • GraphQL error codes and paths

  • Validation errors

  • Network errors

  • Field type ambiguity warnings

All errors are logged to stderr (important for STDIO servers).

Best Practices

  1. Model Names: Avoid reserved names (list, user, system, function)

  2. Explicit Types: Always specify field_type and input_type explicitly - don't rely on automatic detection

  3. List Fields: For dropdown and multiSelect, always provide validation.fixed_list_elements and validation.fixed_list_element_type

  4. Nested Fields: Set is_object_field=true for object and repeated field types

  5. Parent Fields: Use parent_field parameter when adding nested fields to object or repeated fields

  6. API Keys: For remote deployments, API keys are project-dependent and must be provided per-request, not stored as Cloudflare secrets

  7. Relations: Use add_relation to create bidirectional relationships between models

  8. List filters by related model: On public *List queries, use relation — not connection — to filter by linked models (has_one, has_many, M:N). Example: studentList(relation: { class: { _id: { eq: "…" } } }) when student has one class. Read apito://project-query-guide for full examples; connection is only for advanced anchor-document traversal.

Public GraphQL: relation vs connection list filters

When calling the public project GraphQL API (not MCP’s system getModelData):

Goal

Use

Example

Students in a given class

relation

studentList(relation: { class: { _id: { eq: "01KW4M8K7WR57HB3G0DWN48CTZ" } } })

Students where class code is C100

relation

studentList(relation: { class: { code: { eq: "C100" } } })

Articles with a tag

relation

articleList(relation: { tag: { _id: { eq: "…" } } })

Traverse from a known parent doc with direction metadata

connection (advanced)

See apito://project-query-guide

connection is for a specific graph-navigation case (anchor _id + connection_type + to_model + relation_type). For everyday “filter this list by my relation to model X”, always use relation.

query MyQuery {
  studentList(relation: { class: { _id: { eq: "01KW4M8K7WR57HB3G0DWN48CTZ" } } }) {
    id
    data { name }
    class {
      id
      data { name code }
    }
  }
}

Cursor IDE

Add to ~/.cursor/mcp.json:

Local (STDIO):

{
  "mcpServers": {
    "apito": {
      "command": "npx",
      "args": [
        "tsx",
        "/Users/your-username/Projects/apito/apito-mcp/src/index.ts"
      ],
      "env": {
        "APITO_API_KEY": "your-api-key-here",
        "APITO_GRAPHQL_ENDPOINT": "https://api.apito.io/system/graphql"
      }
    }
  }
}

Remote (Cloudflare Workers):

{
  "mcpServers": {
    "apito-production": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://apito-mcp.apito.workers.dev/sse",
        "--header",
        "X-Apito-Key:${APITO_API_KEY}"
      ],
      "env": {
        "APITO_API_KEY": "your-api-key-here"
      }
    }
  }
}

Note: The API key is passed via the X-Apito-Key header using the --header flag. The env.APITO_API_KEY environment variable is automatically substituted by mcp-remote.

Restart Cursor after configuration.

VS Code

Install the MCP extension and configure in settings:

{
  "mcp.servers": {
    "apito": {
      "command": "npx",
      "args": ["tsx", "/path/to/apito-mcp/src/index.ts"],
      "env": {
        "APITO_API_KEY": "your-api-key-here"
      }
    }
  }
}

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%/Claude/claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "apito": {
      "command": "npx",
      "args": ["tsx", "/path/to/apito-mcp/src/index.ts"],
      "env": {
        "APITO_API_KEY": "your-api-key-here",
        "APITO_GRAPHQL_ENDPOINT": "https://api.apito.io/system/graphql"
      }
    }
  }
}

ChatGPT / OpenAI

ChatGPT doesn't directly support MCP, but you can use the remote Cloudflare Workers endpoint via HTTP/SSE. You'll need to use an MCP proxy or client library.

Other MCP Clients

Any MCP-compatible client can connect to:

  • Local: STDIO transport via npx tsx src/index.ts

  • Remote: SSE transport via https://apito-mcp.apito.workers.dev/sse (requires mcp-remote proxy)

Environment Variables

For Remote Deployments (Cloudflare Workers):

The API key is not stored as a Cloudflare Worker secret. It must be provided by the MCP client in each request. This allows the same worker to serve multiple projects.

Optional: Set GraphQL endpoint secret if you need to override the default:

# Set GraphQL endpoint (optional, defaults to https://api.apito.io/system/graphql)
npx wrangler secret put APITO_GRAPHQL_ENDPOINT --env production

For Local Deployments (STDIO):

Set environment variables in your MCP client configuration (see examples above).

Testing the Connection

You can test the MCP server connection using the MCP Inspector or by checking if tools are available in your client. The server should expose schema tools (create_model, add_field, …), data tools (get_data, upsert_data, …), schema versioning read tools, and platform tools (list_tenants, search_app_users, list_roles, …). Run pnpm test:tenant-users for tenant/user smoke tests and pnpm test:versioning for schema versioning tests.

License

MIT

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/apito-io/apito-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server