Skip to main content
Glama

Count CRM Records

count_crm_records
Read-only

Count the CRM records matching a filter, and return a small sample. For a population question a PERSON asked -- 'how many contacts have no mobile phone'. Reads a local mirror, calls no CRM API, spends nothing, changes nothing. matched is the whole count; the sample is capped and says so. NOT how you write a scope: a run's filter is resolved when the run is dispatched, so composing needs no counts and no record ids. If you are composing a plan, you do not need this. A FILTER WIDENS AS WELL AS NARROWS, and the widening case is the one that gets asked one term at a time. 'Our procurement contacts' is not several questions -- it is ONE group with combinator OR over the words that name the concept: title contains_word Procurement, OR Purchasing, OR Sourcing, OR Buyer, OR department is Purchasing. Ask it as one call. Asking each term separately costs a call per guess, answers each in isolation so nothing tells you the union, and double-counts anyone whose title carries two of the words. Groups nest, so an OR over synonyms sits inside an AND with the rest of the question -- those people, and no activity since a date.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "connection_id": "<connection_id>",
      "object_type": "<object_type>"
    },
    "name": "count_crm_records"
  }
}

Input Schema

NameRequiredDescriptionDefault
rootNoThe root of the filter tree. A group combines nodes with AND or OR; a node is either another group or a condition naming a field, an operator, and a value, and groups NEST -- an OR over the several words that name one concept, inside an AND with the rest of the question, is one filter and one call. EVERY NODE CARRIES ITS OWN `kind`: "group" on a group, "condition" on a condition. It is what selects the node type, so a nested group that omits it is refused before anything else is read. Call list_filterable_fields first: the fields and the operators each accepts are specific to this connection's CRM. OMIT IT ENTIRELY to count every record of the object on this connection -- that is the same scope a run with no filter operates on, and it needs no conditions to express.
limitNoHow many matching records to return, up to 200. Omit for 10, or for none when there is no root. 0 returns the count alone.
fieldsNoThe fields to return on each sample record, by the names list_filterable_fields gives. Omit for every field, which is fifty or more on most objects: name the few the question needs.
offsetNoHow many matching records to skip, to page through more than one limit holds. Records come in a stable order, so offset 0, 200, 400 reads them all.
aggregateNoOne number over EVERY matching record, not the sample: sum, avg, min or max of a number field. What won deals are worth is the sum of amount over opportunities where is_won is true.
object_typeYesWhich CRM object to count. One of: account, contact, lead, opportunity, case.
connection_idYesThe CRM connection to read. Required. Call list_crm_connections to get one.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changed
    • addedInput schema / $defs / FilterAggregateIn
      Added value: +{
      +  "description": "One number over every matching record, not the sample.",
      +  "properties": {
      +    "field": {
      +      "title": "Field",
      +      "type": "string"
      +    },
      +    "function": {
      +      "enum": [
      +        "sum",
      +        "avg",
      +        "min",
      +        "max"
      +      ],
      +      "title": "Function",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "function",
      +    "field"
      +  ],
      +  "title": "FilterAggregateIn",
      +  "type": "object"
      +}
    • addedInput schema / additionalProperties
      Added value: +false
    • addedInput schema / properties / aggregate
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/FilterAggregateIn"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "One number over EVERY matching record, not the sample: sum, avg, min or max of a number field. What won deals are worth is the sum of amount over opportunities where is_won is true."
      +}
    • addedInput schema / properties / fields
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "The fields to return on each sample record, by the names list_filterable_fields gives. Omit for every field, which is fifty or more on most objects: name the few the question needs.",
      +  "title": "Fields"
      +}
    • addedInput schema / properties / limit
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maximum": 200,
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "How many matching records to return, up to 200. Omit for 10, or for none when there is no root. 0 returns the count alone.",
      +  "title": "Limit"
      +}
    • addedInput schema / properties / offset
      Added value: +{
      +  "default": 0,
      +  "description": "How many matching records to skip, to page through more than one limit holds. Records come in a stable order, so offset 0, 200, 400 reads them all.",
      +  "minimum": 0,
      +  "title": "Offset",
      +  "type": "integer"
      +}
  2. First observed

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=false, and destructiveHint=false. The description adds operational context beyond those annotations: it reads a local mirror, calls no CRM API, spends nothing, changes nothing, and returns a capped sample while `matched` is the full count.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The response shape and primary use case are front-loaded, and the paragraphs separate purpose, non-use, and filter-composition advice. It is longer than necessary and repeats some filter guidance already present in the schema, but the structure is clear and most sentences carry useful routing or behavioral information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex filter-count tool with seven parameters and no output schema, the description supplies the missing high-level behavior: read-only local execution, full count vs capped sample, and when not to use it. Parameter-level details are covered thoroughly by the schema, so nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all seven parameters in detail. The description adds useful conceptual guidance for the `root` filter, especially the one-call OR-over-synonyms pattern and double-counting risk, though it does not add much for the non-filter parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource: count CRM records matching a filter and return a small sample. It also distinguishes the tool from run/plan composition, which is enough to separate it from the many run-oriented siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly names the use case (a population question a person asked), gives a concrete example, and states when not to use it (when composing a plan or scope). It also explains how to structure synonym groups in one call rather than guessing term by term.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.