MCP · Tool

query

Read CRM data through OQL — filter, sort, select fields, and aggregate across contacts, deals, actions, notes, calls, and meetings.

Last updated Jul 17, 2026

query is the primary read tool. It accepts a JSON query object that the OnePageCRM Query Language (OQL) understands and runs it. Everything OQL can express — filters, ordering, field projection, aggregates, date helpers — is available here.

Signature

{
  "type": "object",
  "properties": {
    "query": {
      "type": "object",
      "properties": {
        "select":    { "description": "Field array, [\"*\"], or aggregates." },
        "from":      { "type": "string", "description": "Entity name." },
        "where":     { "type": "object", "description": "Filter conditions (AND'd)." },
        "order_by":  { "type": "array",  "description": "Sort order." },
        "group_by":  { "type": "array",  "description": "Group fields (max 3)." },
        "having":    { "type": "object", "description": "Post-aggregation filter (requires group_by)." },
        "distinct":  { "type": "boolean", "description": "Unique combinations of the selected fields." },
        "limit":     { "type": "integer" }
      }
    }
  },
  "required": ["query"]
}

The query argument is a JSON OQL query — the same shape shown throughout the OQL docs.

Entities you can query

contacts, companies, deals, actions, notes, calls, meetings. See OQL Entities for the fields each one exposes.

Examples

Today’s open actions:

{
  "query": {
    "from": "actions",
    "select": ["*"],
    "where": { "date": "TODAY()", "completed": false },
    "limit": 50
  }
}

Won deals this quarter, by owner:

{
  "query": {
    "from": "deals",
    "select": ["count()", { "sum": ["amount"] }],
    "where": { "status": "won", "close_date": "THIS_QUARTER()" },
    "group_by": ["owner_id"],
    "order_by": [{ "sum_amount": "desc" }]
  }
}

A specific contact by email:

{
  "query": {
    "from": "contacts",
    "select": ["id", "first_name", "last_name", "emails"],
    "where": { "emails.address": "jane.doe@acmesolar.example" }
  }
}

For more patterns, see OQL Recipes.

Response shape

{
  "rows": [ /* one object per result row */ ],
  "row_count": 17
}

When a result set is clipped to the response cap, a "truncated": true flag is added — it is omitted otherwise. If you see it, ask for a tighter filter or a smaller select.

Operators and functions

OQL supports =, !=, <, >, <=, >=, in, between, like, {"is": null}, and {"is not": null}. Date helpers (TODAY(), THIS_QUARTER(), LAST_QUARTER(), DAYS_AGO(n), …) and the aggregate functions count(), sum, avg, min, max, median, and percentile are available, each with an optional distinct modifier. Grouped results can be filtered after aggregation with having, and distinct: true returns unique combinations of the selected fields. The authoritative references are:

Errors

  • Schema errors — unknown entity or unknown field on the entity.
  • Syntax errors — malformed where clauses, unsupported operators.
  • Execution errors — limit exceeded, type mismatch, etc.

Each error comes back as a structured response (not an exception) so the agent can correct itself and retry on the next turn.

Scope

crm.readonly is sufficient. crm also works (write scope includes read).

Results are always filtered to records the authenticated user can see — query doesn’t bypass per-user permissions, even when the account has multiple users.