Asking in plain English¶
People ask an AI assistant for documents the way they would ask a colleague: "show me all our real estate notes from 2025", "every CORD note by MH in the last six months". The assistant (Claude, Microsoft Copilot, …) usually passes that whole sentence to K-Lake as the search query. A keyword search then looks for the words "last", "six" and "months" in the documents, rather than restricting the search to the last six months.
With plain-English reading on, the MCP search_content tool reads the
request first, turns the parts it understands into search filters, and searches
for the rest. It works by fixed rules, not a language model, so the same
request always reads the same way and takes microseconds. Every result says
exactly what was read, so the assistant, and the person asking, can check it
and override it.
What it understands¶
| The request says | It becomes |
|---|---|
| a relative period: "last 6 months", "past year", "last quarter", "this year", "YTD", "since March" | a document-date window, counted back from today |
| a named period: "2025", "Q3 2024", "H1 2026", "April 2026", "between March and May 2025", "before 2025" | the same window, when the request is about documents (it mentions notes, research, reports, published, written, or says "all"/"every") |
| "all", "every", "everything", a leading "list", "what have we published on…" | find-all: one result per document, paged to the end |
| "PDFs", "pdf reports", "xlsx files" | a file-type filter |
| a company name or ticker ("Cordwell Digital Infrastructure", "CORD") | a ticker filter, using the tenant's ticker aliases |
| a sector, analyst or note type that your documents carry ("real estate", "MH", "initiations", "NAV updates") | a sector, analyst or note_type filter |
Dates use each document's own date (from its folder or first page), not the date the file was copied. The fields come from the source's metadata rules. The words that name a company, sector, analyst or subject stay in the query, so ranking still uses them. Only the words of a date phrase, "all"/"every" and a leading "show me" or "can you find" are removed.
Company, sector, analyst and note-type filters are only applied to a request for a list of documents ("all real estate initiations", "CORD notes from Q3"). A question about a document ("what did the CORD note say about its results?") gets no field filter.
It needs your metadata rules and ticker aliases
Dates, find-all and file types work on any estate. The ticker, sector, analyst and note-type readings only work once the sources have metadata rules that give documents those fields, and the tenant has ticker aliases that link company names to tickers. A value is only read if it exists on a document the person asking is allowed to see.
Example prompts for broker research¶
These work well in Claude or Copilot:
- "Show me all our real estate notes from 2025.": sector
REAL ESTATE, 2025, every document. - "Every CORD note by MH in the last six months.": ticker
CORD, analystMH, the last six months, every document. - "List the investment companies initiations published since March.": sector and note type, from 1 March.
- "What have we published on Cordwell Digital Infrastructure this year?": the company's ticker, this year, every document.
- "All NAV updates on Kingsmead Property Income in Q1 2026.": ticker and note type, January to March 2026.
- "All financials research from H1 2025 as PDFs.": sector, the first half of 2025, PDF only.
Name sectors, note types and analysts the way your documents do (as they appear
in the fields of a search result). The parser does not know that "property"
means REAL ESTATE or that "banks and brokers" means FINANCIALS. Those words
still search as keywords, but they do not become a filter.
Reading interpreted_as¶
Every result of an interpreted search carries interpreted_as:
{
"original_query": "show me all our real estate sector notes from 2025",
"query": "our real estate sector notes",
"today": "2026-09-30",
"applied": {
"published_after": "2025-01-01",
"published_before": "2025-12-31",
"fields": { "sector": ["REAL ESTATE"] },
"group_by_file": true
},
"readings": [
{ "text": "from 2025", "as": "date", "applied": true,
"sets": { "published_after": "2025-01-01", "published_before": "2025-12-31" } },
{ "text": "real estate", "as": "field", "applied": true,
"sets": { "fields": { "sector": ["REAL ESTATE"] } } },
{ "text": "sector notes", "as": "field", "applied": false,
"sets": { "fields": { "note_type": ["sector note"] } },
"reason": "not applied (ambiguous): after a sector, \"sector notes\" may mean every note on that sector, not only the \"sector note\" type, so only the sector was applied. For the type alone, pass `fields: {\"note_type\": [\"sector note\"]}` or ask for the \"sector-note type\"" },
{ "text": "all", "as": "find_all", "applied": true, "sets": { "group_by_file": true } },
{ "text": "show me", "as": "framing", "applied": true }
]
}
queryis what was actually searched;original_queryis what the assistant sent.appliedis every filter that was used.readingslists each phrase that was read, what it would set, and whether it was applied. When a reading was not applied,reasonsays why, and how to ask for it explicitly.todayis the date that relative phrases ("last 6 months") counted back from.
A good assistant tells the user what it searched for. If a result looks thin,
check interpreted_as first: a filter that was not what the user meant is
the usual cause.
Overriding it¶
- Explicit filters always win. If the assistant passes
published_after,published_before,content_type,group_by_fileorfieldsitself, that value is used, and the reading it replaced is listed as not applied. interpret: falsesearches the query exactly as written, for one call.interpret: trueturns reading on for one call on an estate where it is off by default.interpret_today: "YYYY-MM-DD"sets the date relative phrases count back from, when the user's "today" is not the server's.
When reading is on for the estate, the search_content tool description tells
the assistant so, and tells it how to use interpreted_as and how to opt out.
Known limits¶
- Ambiguous phrases are reported, not applied. "Real estate sector notes"
could mean every real-estate note or only notes of the sector note type, so
only the sector is applied. To get only the type, say "real estate
sector-notes", "sector note type", or pass
fields: {"note_type": ["sector note"]}. Likewise "spreadsheets" (xlsx, xls or csv?), two date phrases that do not make one window, and a name that may continue ("Dunmore Logistics" in "Dunmore Logistics Income") are reported, not applied. - No filters on financial figures. "NAV discount above 10%" or "yield over 5%" is searched as words. Numbers in the text are not filters.
- Dates count from today. "Last six months" means the six months before the
day the search runs (UTC). Pass
interpret_todayfor a different reference date. - A year in a question about content stays in the query. In "AMD operating income in 2022", 2022 is part of the subject, not a publication date.
- Quoted phrases,
-exclusionsand file names are never read. A query that names a file searches for that file as written.
Turning it on for an estate¶
Reading is off by default. An administrator turns it on for every MCP call
on the deployment. A call can still turn it off with interpret: false.
Proof of concept (the kit's poc-up.sh), at install or upgrade:
Later upgrades keep it without the flag being repeated. The script prints
keeping plain-English search reading from the running install. To turn it
off: ./scripts/poc-up.sh --no-interpret-queries.
Helm:
helm upgrade kdbl oci://ghcr.io/kdbl-consulting/kdbl --version <release> \
--namespace kdbl --reuse-values --set search.interpretQueries=true
Or set it in your values file:
The API rolls to pick it up. Search is unaffected during the roll. Nothing is re-indexed.