Tools — Data model
Create custom objects, fields, and lists, and edit enum options from the data model. Admin only. Deletion is intentionally not exposed.
Four tools to build and edit the data model programmatically: create an object, add fields (batch), create a list, and edit the options of a SELECT / MULTI_SELECT field. All four are admin only and execute immediately (the API token is the authorization — there is no preview step for object/field/list creation).
Data-model deletion is never exposed via MCP (or the AI agent). Removing an object or a field — deactivation or hard delete — is done manually in the app. There is intentionally no crm_delete_object / crm_delete_field tool. This is a safety boundary, not an omission. (A list can be deleted, admin-only, via crm_manage_lists with action: "delete" — see Tools — Data.)
These tools wrap the same server-side actions the app uses, so validation, multi-tenant isolation, metadata cache invalidation, and real-time propagation are identical to creating from the UI.
crm_create_field was renamed to crm_create_fields and is now a batch tool: it creates one or many fields in a single atomic migration. There is no single-field tool anymore.
crm_create_object
Create a new custom object. The object and table names are derived from the labels. You can optionally pass fields to create the object with its initial fields in one atomic migration; otherwise add fields later with crm_create_fields.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
label_singular | string | Yes | Singular display label, e.g. Produit |
label_plural | string | Yes | Plural display label, e.g. Produits |
description | string | No | Object description |
icon_name | string | No | Lucide icon name (e.g. Box) |
color | string | No | Hex color, e.g. #6366F1 |
fields | object[] | No | Optional initial custom fields, created atomically with the object. Same per-field shape as crm_create_fields (see field spec). |
Behavior
- The object is created with the base fields and a
namestandard field (the immutable first column). - The derived
name_pluralis returned asname_plural— use it asobject_nameincrm_create_fieldsand the data tools. - When
fieldsis provided, the object and all its fields are created in a single all-or-nothing migration; the response includescreated_fields. - Labels that slugify to empty (blank, or symbol/digit-only like
!!!) returnINVALID_ARGUMENT. - Fails with
DUPLICATE_OBJECTif an object with the derived name already exists.
Examples
"Create a Products object"
{
"label_singular": "Produit",
"label_plural": "Produits"
}"Create a Products object with a Price and a Stock field in one go"
{
"label_singular": "Produit",
"label_plural": "Produits",
"icon_name": "Box",
"color": "#6366F1",
"fields": [
{ "field_label": "Price", "field_type": "CURRENCY" },
{ "field_label": "Stock", "field_type": "INTEGER" }
]
}Response shape:
{
"name_plural": "produits",
"name_singular": "produit",
"created_fields": [
{ "field_name": "price", "field_type": "CURRENCY" },
{ "field_name": "stock", "field_type": "INTEGER" }
],
"action": "created"
}crm_create_fields
Add one or many fields to an existing object in a single atomic call — every field is created in one migration (all-or-nothing). object_name may target a list_* object to add per-entry fields to a list.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
object_name | string | Yes | Target object (name_plural). May be a list_* object. |
fields | object[] | Yes | Fields to create — at least one (see field spec). |
Field spec
Each entry in fields (also used by crm_create_object.fields):
| Parameter | Type | Required | Description |
|---|---|---|---|
field_label | string | Yes | Display label; the field name is derived from it. |
field_type | enum | Yes | See supported types below. |
description | string | No | Field description |
is_required | boolean | No | Default false |
is_searchable | boolean | No | Default true |
options | object[] | Cond. | { value, label, color? } — required for SELECT / MULTI_SELECT. This is the field's initial set; to edit options on an existing field use crm_manage_enum_options. |
relation_config | object | Cond. | Required for RELATION (see below). |
relation_config (for RELATION):
| Key | Type | Required | Description |
|---|---|---|---|
relation_type | enum | Yes | BELONGS_TO_ONE, HAS_MANY, or ONE_TO_ONE |
target_object | string | Yes | Target object name (name_plural) |
target_field_label | string | No | Label for the auto-created inverse field |
Supported field types
crm_create_fields (and crm_create_object.fields) accept the batch-creatable set (BATCH_FIELD_TYPES):
TEXT, LONG_TEXT, RICH_TEXT, EMAIL, PHONE, URL, NUMBER, INTEGER, DECIMAL, PERCENT, CURRENCY, DATE, DATETIME, DURATION, BOOLEAN, SELECT, MULTI_SELECT, RELATION, DATE_RANGE, DATETIME_RANGE, USERS, EMAILS, PHONES, ADDRESS, DOCUMENTS, JSON, COLOR, RATING, IMAGE.
Types that need bespoke configuration or a dedicated action are not creatable here and are managed in the app: CALCULATED, ROLLUP, EXTERNAL_LOOKUP, ELAPSED_TIME, PIPELINE, MANY_TO_MANY, MORPH_RELATION, DEPENDENT_RELATION.
Behavior
SELECT/MULTI_SELECTrequire a non-emptyoptionsarray;RELATIONrequiresrelation_config.target_object. Invalid specs reject the whole batch before any DDL withINVALID_FIELDS(the error carries the allowed types inavailable_values).- Field names are derived from labels; a collision within the batch, or with an existing field on the object, is rejected (
INVALID_FIELDS/DUPLICATE_FIELD) — nothing is silently skipped. - Returns
INVALID_OBJECTifobject_namedoes not exist (the error lists available objects). - The response reports
created(the created fields),count, andaction: "created".
Examples
"Add a Stage field to opportunities with options Lead / Won / Lost"
{
"object_name": "opportunities",
"fields": [
{
"field_label": "Stage",
"field_type": "SELECT",
"options": [
{ "value": "lead", "label": "Lead" },
{ "value": "won", "label": "Won", "color": "#16A34A" },
{ "value": "lost", "label": "Lost", "color": "#DC2626" }
]
}
]
}"Add Price, Stock and a Supplier link to products in one migration"
{
"object_name": "produits",
"fields": [
{ "field_label": "Price", "field_type": "CURRENCY" },
{ "field_label": "Stock", "field_type": "INTEGER" },
{
"field_label": "Supplier",
"field_type": "RELATION",
"relation_config": {
"relation_type": "BELONGS_TO_ONE",
"target_object": "companies",
"target_field_label": "Products supplied"
}
}
]
}"Add a per-entry Priority field to a list"
{
"object_name": "list_investors",
"fields": [
{ "field_label": "Priority", "field_type": "NUMBER" }
]
}Response shape:
{
"object_name": "produits",
"created": [
{ "field_name": "price", "field_type": "CURRENCY" },
{ "field_name": "stock", "field_type": "INTEGER" },
{ "field_name": "supplier", "field_type": "RELATION" }
],
"count": 3,
"action": "created"
}crm_create_list
Create a multi-object list — a cross-object collection of records. Entries are managed afterwards with crm_manage_lists.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | List display name (must be unique) |
allowed_objects | string[] | Yes | Object names (name_plural) whose records can be added — at least one |
description | string | No | List description |
icon_name | string | No | Lucide icon name (default List) |
color | string | No | Hex color |
Behavior
- A list is materialized as a hidden
list_<slug>object holding one entry row per added record. allowed_objectsare filtered to the objects the caller can view. The response reports the effectiveallowed_objectsand, when any were silently dropped (not visible to the caller), adropped_objectsarray — so a partial result is detectable.- If none of the requested objects are visible / valid, the call fails with
INVALID_LIST. - Returns
list_idandentry_object_name(thelist_*object you can target withcrm_create_fields).
Examples
"Create an Investors list for companies and contacts"
{
"name": "Investors",
"allowed_objects": ["companies", "contacts"]
}Response shape (one object was not visible to the caller and was dropped):
{
"list_id": "a1b2c3d4-...",
"entry_object_name": "list_investors",
"allowed_objects": ["companies"],
"dropped_objects": ["contacts"],
"action": "created"
}crm_manage_enum_options
Edit the options of an existing SELECT / MULTI_SELECT field: append new options, relabel/recolor existing ones, and/or remove options. Works on system fields too (options are stored inline per field). Use this to change a field's options after creation — crm_create_fields only sets the initial set.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
object_name | string | Yes | Object (name_plural) owning the field. May be a list_* object. |
field_name | string | Yes | The SELECT / MULTI_SELECT field name (not the label). |
preview | boolean | No | Read-only: return each option with its record usage count (no mutation). Use this before a destructive remove. |
add | object[] | No | Options to append: { value, label, color? }. value is snake_case, lowercase ASCII, unique within the field. |
relabel | object[] | No | Label/color edits on existing options: { value, label?, color? }. color: null clears the color. Never touches data. |
remove | string[] | No | Option values to delete. |
remapping | object | Cond. | Required when remove is set. A map { removedValue: targetValue | null } covering every removed value in use — either move records to another value, or null to clear the field on those records. |
You must provide at least one of add, relabel, remove, or preview; otherwise the call returns INVALID_PARAMS.
Behavior
preview: truereturns the field's currentoptionsplus a per-valueusagecount and performs no mutation — use it to build a complete, saferemapping.- Removing an option always deletes it from the field definition. Any record still using a removed value is remapped per
remapping; an incomplete remapping is rejected so no record is ever orphaned. - The response reports
removed_options(the values deleted) andremapped_records(the number of rows moved) separately — aremapped_recordsof0does not mean the option was kept (it had no records in use). - Fails with
INVALID_FIELDif the field doesn't exist or is notSELECT/MULTI_SELECT, andINVALID_OBJECTif the object doesn't exist.
Option removal is the only destructive action in this group. Always call with preview: true first to see usage counts, then build a complete remapping before removing.
Examples
"What are the options on opportunities' Stage field, and how many deals use each?"
{
"object_name": "opportunities",
"field_name": "stage",
"preview": true
}"Add a 'Negotiation' option and recolor 'Won' green on the Stage field"
{
"object_name": "opportunities",
"field_name": "stage",
"add": [
{ "value": "negotiation", "label": "Negotiation", "color": "#F59E0B" }
],
"relabel": [
{ "value": "won", "label": "Won", "color": "#16A34A" }
]
}"Remove the 'lost' option, moving its deals to 'closed'"
{
"object_name": "opportunities",
"field_name": "stage",
"remove": ["lost"],
"remapping": { "lost": "closed" }
}Response shape:
{
"object_name": "opportunities",
"field_name": "stage",
"removed_options": ["lost"],
"remapped_records": 12,
"action": "updated"
}Errors
| Code | Description |
|---|---|
PERMISSION_DENIED | The token is not an organization admin. Data-model changes are admin only. |
INVALID_ARGUMENT | Labels derive an empty object name (blank or symbol/digit-only). |
DUPLICATE_OBJECT | An object with the derived name already exists. |
INVALID_OBJECT | object_name does not exist (the error lists available objects). |
INVALID_FIELDS | A field spec is invalid (e.g. SELECT without options, RELATION without target_object) or uses an unsupported field_type (the error lists allowed types). |
DUPLICATE_FIELD | A field with the derived name already exists on the object (or collides within the batch). |
INVALID_FIELD | For crm_manage_enum_options: the field doesn't exist or is not SELECT / MULTI_SELECT. |
INVALID_PARAMS | For crm_manage_enum_options: none of add / relabel / remove / preview was provided. |
INVALID_LIST | The list has no allowed objects, or none the caller can view. |
CREATE_OBJECT_FAILED / CREATE_FIELDS_FAILED / CREATE_LIST_FAILED / MANAGE_ENUM_FAILED | The underlying migration failed; the message carries the cause. |