MCP tool reference

Search events

search_events

search_events searches your organization's timeline: deterministic full-text over the content and resolution of every event, composed with business filters (status, tags, person, provenance) and time windows (occurrence, deadlines, updates, resolution), paginated with a keyset cursor.

Semantics

How matching works

The query runs as PostgreSQL full-text search over each event's content and resolution note. Matching is accent-insensitive (a query typed without accents matches accented stored text and vice versa), whole-word and stemmed. Quoted phrases are matched as phrases. It is not a substring search: "dev" does not match "devis".

  • Every parameter is optional and all filters compose with AND: a call passing status, tags and due_before returns only events satisfying all three families at once.
  • Range pairs form windows: due_before and follow_up_before are exclusive (strictly before that day); every other bound (since/until, *_after, updated_*/resolved_*) is inclusive. Deadline bounds are day strings (YYYY-MM-DD) compared in UTC.
  • tags takes comma-separated slugs and matches events carrying ANY of them (union) by default; set match_all_tags to true to require ALL of them (intersection).
  • Results are sorted by occurrence date, newest first, with the event id as a stable tiebreaker. One exception: status=needs_followup sorts by last update, stalest first.
  • limit defaults to 20 and is capped at 50 per page.
  • next_cursor is an opaque keyset token: pass it back as cursor to fetch the next page. It is null on the last page. Unlike OFFSET pagination, rows inserted or deleted between two pages never shift the page boundaries; an update that changes an event's sort timestamp can still move it across pages.
  • A call with no filters is valid: it returns the most recent top-level events, newest first. Sub-events are excluded unless exclude_children is set to false.
Input

Parameters

Everything the tool accepts, straight from the live inputSchema. All parameters are optional.

ParameterTypeDescription
querystringFull-text search over event content and resolution. Accent-insensitive, stemmed, multi-word; quote a phrase to match it as a phrase. Not a substring search.
statusstringFilter by lifecycle status: open, in_progress, closed, active (open + in_progress) or needs_followup (open or in progress with no update for 7 days).
tagsstringComma-separated tag slugs. Matches events carrying ANY of them, unless match_all_tags is true.
match_all_tagsbooleanWhen true, only events carrying ALL the passed tag slugs match (intersection). Default false = ANY (union).
person_namestringOnly events linked to a person whose name contains this text (case- and accent-insensitive substring). Composes with every other filter and holds across all pages.
person_idstringOnly events linked to this exact person id (from search_persons or get_person_context) — no name ambiguity.
sincestringISO date: only events that occurred at or after this moment.
untilstringISO date: only events that occurred at or before this moment.
origin"human" | "agent"Filter by who wrote the event: human or agent.
source_typestring (<= 50)Provenance system to filter on: gmail, calendar, slack, and so on.
source_idstring (<= 500)External id in the source system. Pair with source_type to check whether an external item was already captured — the same idempotency key create_event dedupes on.
related_tostringOnly events linked to this event id.
exclude_childrenbooleanExcludes sub-events. Defaults to true; set it to false to include thread children.
days_oldnumberWith status=needs_followup, overrides the 7-day staleness cutoff.
due_afterstringDay (YYYY-MM-DD): only events with a due date on or after this day. Pair with due_before for a window.
due_beforestringDay (YYYY-MM-DD): only events with a due date strictly before this day.
due_todaybooleanWhen true, only events whose due date is the current UTC day.
follow_up_afterstringDay (YYYY-MM-DD): only events with a follow-up date on or after this day.
follow_up_beforestringDay (YYYY-MM-DD): only events with a follow-up date strictly before this day.
follow_up_todaybooleanWhen true, only events whose follow-up date is the current UTC day.
updated_sincestringISO timestamp: only events updated at or after this time — the incremental "what changed since" re-fetch.
updated_untilstringISO timestamp: only events updated at or before this time.
resolved_sincestringISO timestamp: only events resolved (closed) at or after this time.
resolved_untilstringISO timestamp: only events resolved (closed) at or before this time.
limitnumberMaximum results per page. Defaults to 20, capped at 50.
cursorstringOpaque pagination cursor from a previous response's next_cursor. Omit it for the first page.
Output

Response

Each event comes back compact: content, status, occurrence and resolution timestamps, deadlines, provenance, visibility, plus the linked persons, tags and related events in the same payload. next_cursor carries the pagination state.

Example structuredContent
{
  "events": [
    {
      "id": "6f4d1c2e-8a3b-4f6e-9d2a-1b5c7e9f0a3d",
      "content": "Quote DEV-2031 sent - follow up on Friday",
      "status": "OPEN",
      "occurred_at": "2026-07-12T09:30:00Z",
      "resolved_at": null,
      "due_date": "2026-07-24",
      "follow_up_date": null,
      "source_type": null,
      "source_id": null,
      "origin": "human",
      "visibility": "organization",
      "children_count": 0,
      "persons": [
        "Marie Dubois"
      ],
      "tags": [
        "quote"
      ],
      "related_events": []
    }
  ],
  "next_cursor": "MjAyNi0wNy0xMlQwOTozMDowMFp8NmY0ZDFjMmUt..."
}
Empty result
{
  "events": [],
  "next_cursor": null
}
outputSchema, as served by tools/list
{
  "type": "object",
  "properties": {
    "events": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "occurred_at": {
            "type": "string"
          },
          "resolved_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "due_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "follow_up_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "source_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "source_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "origin": {
            "type": "string"
          },
          "visibility": {
            "type": "string"
          },
          "children_count": {
            "type": "number"
          },
          "persons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "related_events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "content_preview": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "content_preview",
                "status"
              ],
              "additionalProperties": false
            }
          },
          "age_days": {
            "type": "number"
          }
        },
        "required": [
          "id",
          "content",
          "status",
          "occurred_at",
          "resolved_at",
          "due_date",
          "follow_up_date",
          "source_type",
          "source_id",
          "origin",
          "visibility",
          "children_count",
          "persons",
          "tags",
          "related_events"
        ],
        "additionalProperties": false
      }
    },
    "next_cursor": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "events",
    "next_cursor"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#",
  "additionalProperties": false
}
Recipes

Usage examples

01

Find an exact reference

Ask your assistant
"Find the event about quote DEV-2031."
MCP arguments
{
  "query": "\"DEV-2031\""
}
Response (abridged)
{
  "events": [
    {
      "id": "6f4d1c2e-...",
      "content": "Quote DEV-2031 sent - follow up on Friday",
      "status": "OPEN",
      "occurred_at": "2026-07-12T09:30:00Z",
      "persons": [
        "Marie Dubois"
      ],
      "tags": [
        "quote"
      ]
    }
  ],
  "next_cursor": null
}
02

Filter by person, status and period

Ask your assistant
"What is still open with Marie Dubois from May and June?"
MCP arguments
{
  "person_name": "dubois",
  "status": "open",
  "since": "2026-05-01",
  "until": "2026-06-30"
}
Response (abridged)
{
  "events": [
    {
      "id": "83a9e0b1-...",
      "content": "Called Marie Dubois about the delayed delivery",
      "status": "OPEN",
      "occurred_at": "2026-06-18T14:05:00Z",
      "persons": [
        "Marie Dubois"
      ],
      "tags": [
        "delivery"
      ]
    }
  ],
  "next_cursor": null
}
03

Deadlines between two dates

Ask your assistant
"What is due between July 20 and the end of the month?"
MCP arguments
{
  "due_after": "2026-07-20",
  "due_before": "2026-08-01"
}
Response (abridged)
{
  "events": [
    {
      "id": "6f4d1c2e-...",
      "content": "Quote DEV-2031 sent - follow up on Friday",
      "status": "OPEN",
      "occurred_at": "2026-07-12T09:30:00Z",
      "due_date": "2026-07-24",
      "persons": [
        "Marie Dubois"
      ],
      "tags": [
        "quote"
      ]
    }
  ],
  "next_cursor": null
}
04

What changed since a date

Ask your assistant
"What changed in Historis since July 15?"
MCP arguments
{
  "updated_since": "2026-07-15T00:00:00Z"
}
Response (abridged)
{
  "events": [
    {
      "id": "c47d22e8-...",
      "content": "Order #1842 picked up in store",
      "status": "CLOSED",
      "occurred_at": "2026-07-16T10:12:00Z",
      "resolved_at": "2026-07-16T10:15:00Z",
      "persons": [
        "Pierre Morel"
      ],
      "tags": [
        "order"
      ]
    }
  ],
  "next_cursor": null
}
05

What was closed over a period

Ask your assistant
"What did we resolve in June?"
MCP arguments
{
  "resolved_since": "2026-06-01T00:00:00Z",
  "resolved_until": "2026-07-01T00:00:00Z"
}
Response (abridged)
{
  "events": [
    {
      "id": "1d9b47f0-...",
      "content": "Size exchange handled for the blue coat",
      "status": "CLOSED",
      "occurred_at": "2026-06-03T16:40:00Z",
      "resolved_at": "2026-06-10T11:00:00Z",
      "persons": [
        "Julie Bernard"
      ],
      "tags": [
        "after-sales"
      ]
    }
  ],
  "next_cursor": null
}
06

Require every tag

Ask your assistant
"Show the events tagged both vip and follow-up."
MCP arguments
{
  "tags": "vip,follow-up",
  "match_all_tags": true
}
Response (abridged)
{
  "events": [
    {
      "id": "5e2fa6c3-...",
      "content": "Reserved the new collection for a fitting session",
      "status": "IN_PROGRESS",
      "occurred_at": "2026-07-08T15:20:00Z",
      "persons": [
        "Julie Bernard"
      ],
      "tags": [
        "vip",
        "follow-up"
      ]
    }
  ],
  "next_cursor": null
}
07

Fetch the next page

Ask your assistant
"Show me more of those delivery results."
MCP arguments
{
  "query": "delivery",
  "cursor": "MjAyNi0wNi0xOFQxNDowNTowMFp8ODNhOWUw..."
}
Response (abridged)
{
  "events": [
    {
      "id": "0b7c91d4-...",
      "content": "Delivery slot confirmed for the sideboard",
      "status": "OPEN",
      "occurred_at": "2026-06-02T09:00:00Z",
      "persons": [
        "Pierre Morel"
      ],
      "tags": [
        "delivery"
      ]
    }
  ],
  "next_cursor": null
}
Contract

Guarantees and limits

  • Both searches are deterministic PostgreSQL full-text search: same query, same data, same results. Nothing semantic, no vector matching — the query matches words, not meanings.
  • Visibility is resolved before matching: the server first scopes the query to the records the caller may see, and only then looks for matches.
  • A record you cannot see is indistinguishable from a record that does not exist: search never confirms the existence of hidden data.
  • Indexes are recomputed in the same transaction as every write: an entry is searchable the instant it is created, with no background indexer and no consistency window.
  • Historis runs no AI model to find results. Your agent decides what to search for and ranks or interprets what comes back; the matching itself is plain database search.
Go further

Two searches, two jobs

search_events
Searches the timeline: what happened, what is due, what changed. Composes full-text with business and time filters, keyset-paginated.
search_persons
Searches the contact records and the relationship graph: who someone is, how they are connected, which role links them.