Tools — Data
Global search, analytics, export/import, activity feed, calendar events, and lists.
Eight tools for searching, aggregating, charting, exporting/importing, and managing CRM data at scale.
crm_global_search
Search across ALL objects in one call. Returns matching records grouped by object type, each with its real match total.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Search term (minimum 2 characters) |
limit | number | No | Max results per object. Default 20, max 50. |
offset | number | No | Offset for pagination within each object. Default 0. |
object_name | string | No | Restrict the search to a single object (e.g. contacts, companies) |
filters | string | No | Advanced filter as a JSON FilterGroup (same shape as crm_find_records), combined with the text match. Objects lacking a referenced field are skipped. |
sort | string | No | Override relevance order: a JSON array [{"field":"...","direction":"asc"|"desc"}] |
Behavior
- Runs the SAME search path as the in-app global search (unaccent + trigram ILIKE over fields flagged searchable, plus compound EMAILS/PHONES). Results match the UI.
- Searches every object readable through the generic boundary; metadata-hidden internals (interactions, threads, etc.) are excluded, and RBAC view-level is enforced per object.
- Results are grouped by object type. Each group carries
objectName,objectLabel, the realtotal, and the page ofrecords. - When
object_nameis provided, only that object is searched.
Examples
"Find everything related to Acme"
{
"query": "acme"
}Returns matches across contacts, companies, opportunities, and any custom objects:
{
"query": "acme",
"results": [
{ "objectName": "companies", "objectLabel": "Companies", "total": 1, "records": [/* … */] },
{ "objectName": "contacts", "objectLabel": "Contacts", "total": 3, "records": [/* … */] }
],
"total": 4
}"Search only contacts named Martin, newest first"
{
"query": "martin",
"object_name": "contacts",
"sort": "[{\"field\":\"created_at\",\"direction\":\"desc\"}]"
}crm_aggregate_records
Calculate aggregations on a CRM object, optionally grouped by one field.
Renamed from crm_aggregate. This tool has an attached MCP App — grouped results render as a chart (KPI / bars / donut) inside Claude.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
object_name | string | Yes | Target object |
field | string | Yes | Field to aggregate (for COUNT you may pass id — it counts all rows) |
function | enum | Yes | One of COUNT, COUNT_DISTINCT, SUM, AVG, MIN, MAX, MEDIAN, RANGE, STDDEV, VARIANCE, PERCENT_FILLED, PERCENT_EMPTY, COUNT_NULL |
group_by | string | No | Field to group by — produces one row per distinct value |
filter_field | string | No | Single simple filter condition (use filters for AND/OR) |
filter_operator | enum | No | equals, not_equals, contains, starts_with, ends_with, greater_than, less_than, greater_equal, less_equal, in, is_null, is_not_null. For in, filter_value is comma-separated. |
filter_value | string | No | Value to filter against |
filters | string | No | Advanced filter as a JSON FilterGroup (same shape as crm_find_records), combined with AND on top of filter_field/filter_value |
Behavior
- The function is re-validated against the field's real type.
SUM/AVG/MIN/MAX/MEDIAN/RANGE/STDDEV/VARIANCErequire a numeric field (NUMBER, INTEGER, DECIMAL, PERCENT, RATING, CURRENCY, or a numeric CALCULATED/ROLLUP).COUNT/COUNT_DISTINCT/PERCENT_FILLED/PERCENT_EMPTY/COUNT_NULLwork on any field. - An invalid function/field combination returns
INVALID_OPERATIONwith the allowed list. - CURRENCY fields can be passed directly — their amount is summed (multi-currency amounts are summed without conversion).
- Composite parents (CURRENCY, DATE_RANGE, …) resolve to their canonical child (amount, start) automatically.
- RBAC is enforced — no view access returns
PERMISSION_DENIED. - Limitations: single
group_byonly (no second axis / top-N), single simple filter (usefiltersfor richer slices), no date bucketing.
Examples
"How many contacts do I have per status?"
{
"object_name": "contacts",
"field": "id",
"function": "COUNT",
"group_by": "status"
}Grouped responses return one row per distinct value:
{
"object_name": "contacts",
"field": "id",
"function": "COUNT",
"group_by": "status",
"results": [
{ "group": "prospect", "value": 42 },
{ "group": "customer", "value": 18 },
{ "group": null, "value": 3 }
]
}"Sum deal amount for open deals"
{
"object_name": "opportunities",
"field": "amount",
"function": "SUM",
"filters": "{\"type\":\"AND\",\"conditions\":[{\"field\":\"stage\",\"operator\":\"not_equals\",\"value\":\"closed\"}]}"
}Scalar responses return a single value:
{
"object_name": "opportunities",
"field": "amount",
"function": "SUM",
"value": 184500
}crm_manage_dashboards
List dashboards, or pin a chart — typically one just built with crm_aggregate_records — onto one. The MCP App attached to crm_aggregate_records calls this tool from its "add to dashboard" button, but you can also call it directly.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
action | list | add_chart | create | delete | Yes | list = visible dashboards; add_chart = append to dashboard_id; create = new dashboard named dashboard_name holding the chart; delete = remove dashboard_id (owner/admin only). |
dashboard_id | string | Cond. | Target dashboard (add_chart / delete). |
dashboard_name | string | Cond. | New dashboard name (create). |
object_name | string | Cond. | Chart object (= crm_aggregate_records object_name). |
metric_field | string | Cond. | Aggregated field (= crm_aggregate_records field). |
aggregation | string | Cond. | Aggregation function, e.g. COUNT / SUM / AVG (= crm_aggregate_records function). |
group_by | string | No | Group-by field — omit for a single-value KPI. |
filters | string | No | Original FilterGroup JSON (= crm_aggregate_records filters). |
chart_type | bar | doughnut | indicator | Cond. | bar/doughnut for grouped charts, indicator for a single-value KPI. |
title | string | Cond. | Chart title shown on the dashboard. |
comparison | boolean | No | Persist period-over-period comparison on the chart. |
comparison_period | previous_month | previous_quarter | previous_year | No | The comparison window. |
date_field | string | No | Date field scoping the comparison (default created_at). |
For add_chart / create, pass the same params you used for crm_aggregate_records (object_name, metric_field, aggregation, group_by, filters) plus chart_type and title.
Example
"Pin this 'contacts by source' chart to my Sales dashboard"
{
"action": "add_chart",
"dashboard_id": "d1a2b3c4-…",
"object_name": "contacts",
"metric_field": "id",
"aggregation": "COUNT",
"group_by": "source",
"chart_type": "doughnut",
"title": "Contacts by source"
}crm_export_records
Export CRM data as JSON or CSV. UUID references are resolved to display values — never raw UUIDs.
Renamed from crm_export. Admin-only.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
object_name | string | Yes | Source object |
format | enum | No | json or csv. Default json. |
fields | string[] | No | Fields to include (default: all main fields) |
filter_field | string | No | Single simple filter condition (use filters for AND/OR) |
filter_operator | enum | No | equals, not_equals, contains, starts_with, ends_with, greater_than, less_than, greater_equal, less_equal, in, not_in, between, is_null, is_not_null. For in/not_in, filter_value is comma-separated. |
filter_value | string | No | Filter value |
filters | string | No | Advanced filter as a JSON FilterGroup (same shape as crm_find_records), combined with AND on top of filter_field |
sort_by | string | No | Field to sort the export by |
sort_dir | enum | No | asc or desc (default asc) |
limit | number | No | Max records to export. Default 500, hard cap 10000. |
Behavior
- Admin-only — non-admin tokens return
PERMISSION_DENIED. - RBAC and object visibility are enforced; reference fields (relations, rollups) are resolved from UUID to the target's display value.
- When
fieldsis omitted, all main fields are exported and internal/noise columns (full-text vector, raw enrichment blobs) are stripped. An explicitfieldslist is honoured verbatim. - The hard limit is 10000 records per call.
Examples
"Export all contacts as CSV"
{
"object_name": "contacts",
"format": "csv"
}"Export the 200 newest open opportunities, name and amount only"
{
"object_name": "opportunities",
"format": "csv",
"fields": ["name", "amount"],
"filter_field": "stage",
"filter_operator": "not_equals",
"filter_value": "closed",
"sort_by": "created_at",
"sort_dir": "desc",
"limit": 200
}crm_import_records
Multi-step import that mirrors the Kasar platform import flow: the AI proposes a column→field mapping, the user validates it, then it runs through the same engine the platform uses (relations, dedup, field/enum creation).
Renamed from crm_import and now a multi-step flow. Admin-only. Always present the mapping to the user and get confirmation before action='execute'.
The action sequence
analyze— passobject_name+data. Returns animport_job_idand a proposed mapping per column (each column has itssuggestion,sample_values, andconfidence), plus the object's target fields.- Review/adjust the mapping, then present it to the user.
preview(optional) — passimport_job_id(+ anymappingoverrides). Returns transformed sample rows, theeffective_mapping, column diagnostics, and duplicate detection so the user can validate.execute— only after the user confirms. Imports ≤2000 rows immediately and returns counts; larger imports are queued on the worker (poll withstatus).status— passimport_job_idto get progress/result of a queued import.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
action | enum | Yes | analyze, preview, execute, or status |
object_name | string | Cond. | analyze: target object (namePlural) |
format | enum | No | analyze: data format json or csv (default json) |
data | string | Cond. | analyze: records to import — a JSON array string or a CSV string |
import_job_id | string | Cond. | preview/execute/status: the id returned by analyze |
mapping | object[] | No | preview/execute: per-column overrides of the analyze suggestion (only the columns you change) — see below |
import_options | object | No | preview/execute: duplicate strategy + default values — see below |
add_to_list_ids | string[] | No | execute (sync only): add every created record to these list UUIDs |
create_list_name | string | No | execute (sync only): create a list with this name and add every created record |
Each mapping entry:
| Field | Type | Description |
|---|---|---|
column | string | The CSV column / record key this decision applies to |
action | enum | map, new_field, relation, or ignore |
field | string | action='map': existing CRM field name |
new_field_name | string | action='new_field': snake_case field name |
new_field_label | string | action='new_field': human label |
new_field_type | enum | action='new_field': a Kasar field type (TEXT, NUMBER, SELECT, DATE, …) |
enum_options | string[] | action='new_field' SELECT/MULTI_SELECT: option labels to seed |
target_object | string | action='relation': namePlural of the related object |
lookup_field | string | action='relation': field on the related object to match the value against |
relation_type | enum | action='relation': BELONGS_TO_ONE or MANY_TO_MANY |
import_options:
| Field | Type | Description |
|---|---|---|
duplicate_strategy | enum | create (default), update, or skip. update/skip require duplicate_fields. |
duplicate_fields | string[] | Fields to match existing records on (for update/skip) |
default_values | object | Values for required fields not mapped from a column |
Behavior
- Admin-only across every step.
analyzestages the data and produces a deterministic gold-standard mapping; pass only the columns you change inmapping.executere-checks create permission. Imports of 2000 rows or fewer run synchronously and return inline counts (created,updated,skipped,failed, plus new-field / enum / M2M details). Larger imports are queued on the BullMQ worker and returnmode: "queued"— poll withstatus.add_to_list_ids/create_list_nameapply only to synchronous (≤2000) imports; for queued imports alists_noteexplains they were not applied.
Examples
Step 1 — analyze
{
"action": "analyze",
"object_name": "contacts",
"format": "json",
"data": "[{\"first_name\":\"Alice\",\"last_name\":\"Martin\",\"email\":\"alice@example.com\"},{\"first_name\":\"Bob\",\"last_name\":\"Dupont\",\"email\":\"bob@example.com\"}]"
}Step 3 — preview with one override (deduplicate on email)
{
"action": "preview",
"import_job_id": "job-uuid",
"mapping": [
{ "column": "email", "action": "map", "field": "email" }
],
"import_options": { "duplicate_strategy": "skip", "duplicate_fields": ["email"] }
}Step 4 — execute (after user confirms)
{
"action": "execute",
"import_job_id": "job-uuid",
"import_options": { "duplicate_strategy": "skip", "duplicate_fields": ["email"] }
}Step 5 — poll a queued import
{
"action": "status",
"import_job_id": "job-uuid"
}crm_find_activity
Consolidated activity for ONE record — interactions (every channel), tasks, and notes — in a single call. Prefer this over separate queries, and use it to show a contact/company's interactions (it never mixes contacts). Requires a specific record: pass object_name (plural, e.g. contacts/companies) and record_id — resolve the record first with crm_global_search if you don't have its id. For your own recent messages not tied to one record, use crm_inbox instead.
This tool has an attached MCP App: it renders a record-scoped Activity widget (interactions grouped by thread + tasks + notes, with channel filters, inline thread reading, and "new email" / "LinkedIn reply" compose) in clients that support MCP Apps — for any view (view only changes the text shape, never whether it displays).
Renamed and redesigned from crm_activity_feed.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
object_name | string | Yes | Object type of the record (e.g. contacts, companies, opportunities) |
record_id | string | Yes | UUID of the record |
view | enum | No | sections (default) = three independently-paginated sections; timeline = one merged chronological feed (newest first) |
include | enum[] | No | Sections to include: any of interactions, tasks, notes. Default all three. |
channel | enum | No | Filter interactions by channel: all (default), email, linkedin, whatsapp, phone, meeting |
contact_id | string | No | On a company feed, restrict interactions to one contact's threads |
task_status | enum | No | Tasks section completion filter: open, completed, or all |
task_mode | enum | No | Tasks section due-date preset (open tasks): today, overdue, upcoming |
notes_quick_filter | enum | No | Notes section: all or my_items (only notes you authored) |
interactions_cursor | string | No | Pagination cursor for the interactions section |
tasks_cursor | string | No | Pagination cursor for the tasks section |
notes_cursor | string | No | Pagination cursor for the notes section |
limit | number | No | Max items per section (max 50). In timeline view, max merged items returned. Default 20. |
Behavior
- The record is resolved once (existence + RBAC visibility) and augmented with a
displaylabel. sectionsview returns each requested section as{ items, total, has_more, next_cursor }, paginated independently via its own cursor.timelineview merges interactions, tasks, and notes into one chronological feed (newest first); each item carries akindofinteraction,task, ornote, plus per-sectioncounts.- Items are normalized: interaction
{id, channel, date, direction, subject, preview, participants, thread_id}, task{id, title, status, due_date, assignee, priority}, note{id, title, preview, author, date}. - Interactions are only tracked on contacts and companies. On any other object the interactions section is returned as
{ available: false, reason }. - Interaction
previewfollows the app visibility model: the thread owner sees their content; a non-owner is gated by the thread'scontent_visibility, sopreviewmay be a masking placeholder. Non-owned private threads (LinkedIn/WhatsApp) are dropped entirely.
Examples
"Show me everything on this contact"
{
"object_name": "contacts",
"record_id": "uuid-contact"
}"Give me one merged timeline for this company, emails only"
{
"object_name": "companies",
"record_id": "uuid-company",
"view": "timeline",
"channel": "email"
}Paginate the tasks section
{
"object_name": "contacts",
"record_id": "uuid-contact",
"include": ["tasks"],
"tasks_cursor": "<next_cursor from a previous call>"
}crm_find_events
List meeting events recorded in the CRM (meeting recorder + synced calendar meetings) within a date range. Read-only.
Renamed from crm_manage_events. Creating or editing live calendar events is not available via MCP (it requires a connected Google/Microsoft calendar), so only list is supported.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
action | enum | No | Only list is supported. Default list. |
start_date | string | Yes | Range start, ISO 8601 (e.g. 2026-06-01 or 2026-06-01T00:00:00Z) |
end_date | string | Yes | Range end, ISO 8601 |
limit | number | No | Max events. Default 50, max 200. |
Behavior
- Returns
{ events, total }, ordered by start time ascending. - Row-level OBJECT_VISIBILITY is enforced.
- Heavy meeting columns (transcript text/segments, raw metadata, audio, content blocks) are omitted — you get titles, times, and status, not full transcripts.
- Invalid dates return
INVALID_ARGUMENT. If the workspace has no meetings/calendar data, returnsNOT_SUPPORTED.
Example
"List my meetings for June 2026"
{
"start_date": "2026-06-01",
"end_date": "2026-06-30"
}crm_manage_lists
Manage multi-object lists (custom collections). Lists can contain records from different objects (contacts, companies, etc.).
To CREATE a list use crm_create_list. This tool manages existing lists.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
action | enum | Yes | list, get, get_entries, add, remove, update, or delete |
list_id | string | Cond. | List UUID (required for every action except list) |
record_id | string | Cond. | Single record UUID to add/remove |
record_ids | string[] | Cond. | Record UUIDs for batch add/remove (preferred over record_id when adding multiple in one call) |
object_type | string | Cond. | Object type of the record(s), e.g. contacts, companies — required for add/remove |
name | string | No | New list name (update only) |
description | string | No | New description (update only) |
icon_name | string | No | New icon (update only) |
color | string | No | New color (update only) |
cursor | string | No | Pagination cursor (from nextCursor of a previous list/get_entries call) |
limit | number | No | Max items per page. Default 50, max 100. |
Behavior
listreturns all available lists for the current user (paginated).getreturns a single list's record.get_entriesreturns the members of a list, ENRICHED: each entry carries{ entry_id, record_id, object_type, record, entry_fields }whererecordis the target's display (name + image) andentry_fieldsare the per-entry custom field values — no need to chaincrm_find_records.addaccepts a singlerecord_idor a batch viarecord_ids, validated against the list's allowed object types. Reportsadded,skipped_already_in_list, and anyfailed.removeaccepts a singlerecord_idor batchrecord_ids. Reportsremovedandnot_in_list.update(rename / recolor / re-icon) anddelete(drop the list — destructive and irreversible) both require an organization admin token.
Examples
"Add this contact to my priority list"
{
"action": "add",
"list_id": "uuid-priority-list",
"object_type": "contacts",
"record_id": "uuid-contact"
}Batch-add several contacts
{
"action": "add",
"list_id": "uuid-priority-list",
"object_type": "contacts",
"record_ids": ["uuid-1", "uuid-2", "uuid-3"]
}List the enriched entries
{
"action": "get_entries",
"list_id": "uuid-priority-list",
"limit": 50
}Rename a list (admin)
{
"action": "update",
"list_id": "uuid-priority-list",
"name": "Q3 Priority Accounts"
}