Full-Text Search
How entry content is indexed and ranked, and how to search it with the MCP search_query tool.
Overview
Airogel CMS keeps a full-text search index of every entry in your account. The index uses English-language stemming and ranks results by relevance. Today the only way to search it is the search_query tool on the MCP server, so you can search from an AI assistant or an MCP client.
Where search is available
| Surface | Full-text search? |
|---|---|
MCP tool search_query | Yes |
REST API (api.airogelcms.com/v1) | No. There is no search endpoint. GET …/entries can only filter by handle and published. |
| Liquid templates and your public site | No. There is no search tag, filter or public endpoint, so you can't build a visitor-facing search box with built-in features. |
| Dashboard quick search | Matches titles, handles and file names only. It does not use the full-text index. |
What gets indexed
Each entry is indexed as one block of text made up of:
- Title
- Handle, with hyphens treated as spaces (so
spring-salematches "spring sale") - Text fields
- Rich Text fields, with HTML tags removed
- Raw HTML fields, with HTML tags removed
All of these count equally. A match in the title doesn't rank higher than the same match in the body. Other field types (Markdown, enumerate, entity, number, date, image and so on) are not indexed.
The index updates automatically when an entry is created, when its title or handle changes, and when any indexed field is saved or cleared. If you clear a field, its old text stops matching.
How matching works
- Stemming. Words are reduced to their English root, so "programming" matches "program" and "programs".
- Every word must match.
annual budget reportonly returns entries that contain all three words (after stemming), in any order and anywhere in the entry. - No query syntax. Punctuation is removed before searching, so quotes,
OR,-excludeand wildcards have no special meaning. Search for plain words only. - Ranking. Results are sorted by relevance, which depends on how often and how close together the terms appear.
- English only. There is no fuzzy matching or typo tolerance, and results don't include highlighted snippets.
The search_query tool
This tool needs the entries:read scope (or the full mcp scope).
| Parameter | Type | Description |
|---|---|---|
account_id | string | Required. The account's acct_… ID, which you can get from accounts_list. |
query | string | Required. The words to search for. |
collection_handle | string | Optional. Only search one collection. |
published | boolean | Optional. true returns published entries only, false returns drafts only, and omitting it returns both. |
page | integer | Optional. Page number, starting at 1 (default 1). |
per_page | integer | Optional. Results per page (default 25, max 100). |
If you leave out published, drafts are included in the results. Pass published: true when you only want content that is live.
Example
{
"account_id": "acct_XXXXXXXX",
"query": "volunteer training",
"collection_handle": "posts",
"published": true,
"per_page": 10
}
Response
{
"page": 1,
"per_page": 10,
"total": 2,
"total_pages": 1,
"items": [
{
"id": "cnety_XXXXXXXX",
"title": "Volunteer Training Dates",
"handle": "volunteer-training-dates",
"collection_handle": "posts",
"published": true,
"published_at": "2026-09-01T14:00:00Z",
"content_path": "/blog/volunteer-training-dates"
}
]
}
content_path is the entry's path on your site. To get the full URL, add your site's domain in front of it.
Related
- MCP Integration: connecting an AI assistant or MCP client
- Field Types Reference: which field types hold text
- Entries API: listing and filtering entries over REST