From 38d863eef731cbc0760152d1dbb81b6e892f43a3 Mon Sep 17 00:00:00 2001
From: adityamishra-hydradb
<321510987+adityamishra-hydradb@users.noreply.github.com>
Date: Tue, 27 Oct 2026 23:09:32 +0000
Subject: [PATCH 1/3] docs(search): define normalized title matching (ENG-3299)
Signed-off-by: adityamishra-hydradb <321510987+adityamishra-hydradb@users.noreply.github.com>
---
api-reference/v2/endpoint/list-documents.mdx | 15 ++++++++++--
api-reference/v2/endpoint/query.mdx | 2 +-
plugins/mcp.mdx | 24 ++++++++++++++------
3 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/api-reference/v2/endpoint/list-documents.mdx b/api-reference/v2/endpoint/list-documents.mdx
index 5f9ef6dc..fe2ed2f5 100644
--- a/api-reference/v2/endpoint/list-documents.mdx
+++ b/api-reference/v2/endpoint/list-documents.mdx
@@ -80,7 +80,7 @@ curl -X POST 'https://api.hydradb.com/context/list' \
### Filters
-- `filters` accepts the three categories below. Values must match exactly, except `source_fields.title`, which matches a case-insensitive prefix.
+- `filters` accepts the three categories below. Values must match exactly, except `source_fields.title`, which matches a normalized title prefix.
- All filter pairs combine with AND. When `ids` is non-empty, filters apply only to those IDs.
- Range, contains, and OR operators are not supported. For OR behavior, run separate calls and combine the results in your application.
- A `null` filter value returns `400`.
@@ -99,10 +99,21 @@ curl -X POST 'https://api.hydradb.com/context/list' \
| --- | --- | --- |
| | Context item's schema-aligned `metadata` payload | Exact matches on database metadata fields. See [Metadata and Filters](/essentials/v2/metadata#7-list-sources-with-metadata-filters). |
| | Context item's `additional_metadata` payload | Exact matches on free-form metadata. No schema declaration is required. |
-| | Built-in and connector fields listed below | `title` matches a case-insensitive prefix. Pair external IDs with `app_provider`. Unsupported keys return `400`. |
+| | Built-in and connector fields listed below | `title` matches a normalized prefix. Pair external IDs with `app_provider`. Unsupported keys return `400`. |
Supported source fields are `type`, `title`, `description`, `url`, `timestamp`, `app_provider`, `app_kind`, `app_external_id`, and `app_parent_id`.
+Title normalization applies Unicode NFKC, removes invisible marks and decoration,
+lowercases the title, collapses spaces, and trims it. HydraDB also removes one
+final extension from `md`, `markdown`, `txt`, `pdf`, `doc`, `docx`, `rtf`, `odt`,
+`ppt`, `pptx`, `xls`, `xlsx`, `csv`, `tsv`, `json`, `html`, or `htm`, but only
+when text remains before it. Thus `Runbook.md` has the normalized prefix
+`runbook`. Unknown extensions such as `.v2` remain part of the title.
+
+Source IDs and titles are separate inputs. Use `ids` for source IDs and
+`filters.source_fields.title` for title prefixes. HydraDB never guesses from the
+input format.
+
### Field projection
When you don't need every field on every row, pass `include_fields` to keep response payloads small. Only the listed fields are populated; omitted fields should be treated as unavailable in that response. `id`, `database`, and `collection` are always returned.
diff --git a/api-reference/v2/endpoint/query.mdx b/api-reference/v2/endpoint/query.mdx
index acd4fcec..cb32be7e 100644
--- a/api-reference/v2/endpoint/query.mdx
+++ b/api-reference/v2/endpoint/query.mdx
@@ -315,7 +315,7 @@ result = client.query(
| | Single collection scope. Send the collection the content was saved in. |
| | Multi-collection scope. Send a list of collection IDs for equal weighting, or an object mapping collection ID to a positive relative weight (at most one decimal place, e.g. `{"finance": 1.5, "legal": 0.8}`) to bias ranking. Up to 100 collections. Do not combine with `collection`. |
| | Query terms or natural-language question. Cannot be empty. Maximum 5,000 words. |
-| | Exact source titles, matched case-insensitively. Matches any listed title, then intersects with `ids` if both are sent. |
+| | Exact normalized source titles. Normalization applies Unicode NFKC, removes invisible marks and decoration, lowercases, collapses spaces, and removes one final known file extension (`md`, `markdown`, `txt`, `pdf`, `doc`, `docx`, `rtf`, `odt`, `ppt`, `pptx`, `xls`, `xlsx`, `csv`, `tsv`, `json`, `html`, or `htm`) when text remains before it. Matches any listed title, then intersects with `ids` if both are sent. Use `ids` for source IDs and `titles` for titles; HydraDB never guesses from the input format. |
| | Caller identities used to filter document ACLs. Omitting `acl`, sending `[]`, or sending `["*"]` disables caller-supplied filtering. For enforced connectors, the authenticated caller is used instead; see [ACL enforcement](/essentials/v2/connectors#enforce-acl). |
| | Omit for the result object with `llm_prompt`. `"structured"` leaves out the prompt string. `"markdown"` returns the prompt string directly as `data`. |
| | What to query. `"all"` runs knowledge and memory in parallel over the same scope and merges by `relevancy_score`. (default=`"knowledge"`) |
diff --git a/plugins/mcp.mdx b/plugins/mcp.mdx
index e77d8ae5..db7885eb 100644
--- a/plugins/mcp.mdx
+++ b/plugins/mcp.mdx
@@ -456,7 +456,7 @@ See the [Glossary](/essentials/v2/glossary) for database and collection terminol
| `max_results` | number | No | Chunks to return, 1 to 50 (default: `10`) |
| `mode` | string | No | `fast` for a quick single pass, `thinking` for deeper recall with query expansion and graph traversal, or `auto` to pick per query (default: `thinking`) |
| `graph_context` | boolean | No | Include knowledge graph relations in the results (default: `true`) |
-| `titles` | string[] | No | Restrict the search to documents whose **complete** title exactly matches any value, ignoring case |
+| `titles` | string[] | No | Restrict the search to documents whose complete normalized title matches any value. See [Filtering by document title](#filtering-by-document-title). |
| `metadata_filters` | object | No | Exact-match metadata filters as `{key: value}` |
| `database` | string | No | Database (tenant) scope override for this request |
| `collection` | string | No | Collection (sub-tenant) scope override for this request |
@@ -474,15 +474,25 @@ those sources.
}
```
-- **Exact, complete titles:** `last-usage` does not match `last-usage.csv`.
-- **Case-insensitive:** `q3 roadmap.md` matches `Q3 Roadmap.md`.
-- **Several titles are ORed:** Surrounding whitespace is trimmed; punctuation such
- as commas is part of the title.
+- **One title rule:** HydraDB applies Unicode NFKC, removes invisible marks and
+ decoration, lowercases the title, collapses spaces, and trims it.
+- **Known file extensions are optional:** HydraDB removes one final extension from
+ `md`, `markdown`, `txt`, `pdf`, `doc`, `docx`, `rtf`, `odt`, `ppt`, `pptx`,
+ `xls`, `xlsx`, `csv`, `tsv`, `json`, `html`, or `htm`. Text must remain before
+ the extension. `last-usage` therefore matches `last-usage.csv`. `notes.v2` stays
+ unchanged, and `.md` stays unchanged.
+- **Exact after normalization:** `q3 roadmap.md` matches `Q3 Roadmap`, but a
+ normalized prefix alone does not match in this exact-title field.
+- **Several titles are ORed:** Punctuation such as commas remains part of the title.
- **No match returns an empty result** rather than widening to the whole corpus.
+Source IDs and titles are separate inputs. Use `ids` for source IDs and `titles`
+for titles. HydraDB never guesses from the input format.
+
-Because matching ignores case, two documents whose names differ only by case
-(`Report.md` and `report.md`) are treated as the same title and both are returned.
+Two documents with the same normalized title are treated as the same title and
+both are returned. For example, `Report.md`, `report.pdf`, and `report` share one
+normalized title.
### hydradb_ingest
From f95347a5a9e89b8ca478ca3d4f98568aaf2ad2f7 Mon Sep 17 00:00:00 2001
From: adityamishra-hydradb
<321510987+adityamishra-hydradb@users.noreply.github.com>
Date: Tue, 27 Oct 2026 23:29:47 +0000
Subject: [PATCH 2/3] docs(search): clarify normalized title rules (ENG-3299)
Signed-off-by: adityamishra-hydradb <321510987+adityamishra-hydradb@users.noreply.github.com>
---
api-reference/v2/endpoint/list-documents.mdx | 8 +++++---
api-reference/v2/endpoint/query.mdx | 2 +-
plugins/mcp.mdx | 11 +++++++----
3 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/api-reference/v2/endpoint/list-documents.mdx b/api-reference/v2/endpoint/list-documents.mdx
index fe2ed2f5..3f66ccd1 100644
--- a/api-reference/v2/endpoint/list-documents.mdx
+++ b/api-reference/v2/endpoint/list-documents.mdx
@@ -104,11 +104,13 @@ curl -X POST 'https://api.hydradb.com/context/list' \
Supported source fields are `type`, `title`, `description`, `url`, `timestamp`, `app_provider`, `app_kind`, `app_external_id`, and `app_parent_id`.
Title normalization applies Unicode NFKC, removes invisible marks and decoration,
-lowercases the title, collapses spaces, and trims it. HydraDB also removes one
-final extension from `md`, `markdown`, `txt`, `pdf`, `doc`, `docx`, `rtf`, `odt`,
+lowercases the title, collapses spaces, and trims it. HydraDB also removes all
+consecutive final extensions from `md`, `markdown`, `txt`, `pdf`, `doc`, `docx`,
+`rtf`, `odt`,
`ppt`, `pptx`, `xls`, `xlsx`, `csv`, `tsv`, `json`, `html`, or `htm`, but only
when text remains before it. Thus `Runbook.md` has the normalized prefix
-`runbook`. Unknown extensions such as `.v2` remain part of the title.
+`runbook`. `report.pdf.md` matches `report`. Unknown extensions such as `.v2`
+remain part of the title.
Source IDs and titles are separate inputs. Use `ids` for source IDs and
`filters.source_fields.title` for title prefixes. HydraDB never guesses from the
diff --git a/api-reference/v2/endpoint/query.mdx b/api-reference/v2/endpoint/query.mdx
index cb32be7e..e7bba82f 100644
--- a/api-reference/v2/endpoint/query.mdx
+++ b/api-reference/v2/endpoint/query.mdx
@@ -315,7 +315,7 @@ result = client.query(
| | Single collection scope. Send the collection the content was saved in. |
| | Multi-collection scope. Send a list of collection IDs for equal weighting, or an object mapping collection ID to a positive relative weight (at most one decimal place, e.g. `{"finance": 1.5, "legal": 0.8}`) to bias ranking. Up to 100 collections. Do not combine with `collection`. |
| | Query terms or natural-language question. Cannot be empty. Maximum 5,000 words. |
-| | Exact normalized source titles. Normalization applies Unicode NFKC, removes invisible marks and decoration, lowercases, collapses spaces, and removes one final known file extension (`md`, `markdown`, `txt`, `pdf`, `doc`, `docx`, `rtf`, `odt`, `ppt`, `pptx`, `xls`, `xlsx`, `csv`, `tsv`, `json`, `html`, or `htm`) when text remains before it. Matches any listed title, then intersects with `ids` if both are sent. Use `ids` for source IDs and `titles` for titles; HydraDB never guesses from the input format. |
+| | Exact normalized source titles. Normalization applies Unicode NFKC, removes invisible marks and decoration, lowercases, collapses spaces, and removes consecutive final known file extensions (`md`, `markdown`, `txt`, `pdf`, `doc`, `docx`, `rtf`, `odt`, `ppt`, `pptx`, `xls`, `xlsx`, `csv`, `tsv`, `json`, `html`, or `htm`) when text remains before them. Matches any listed title, then intersects with `ids` if both are sent. Use `ids` for source IDs and `titles` for titles; HydraDB never guesses from the input format. |
| | Caller identities used to filter document ACLs. Omitting `acl`, sending `[]`, or sending `["*"]` disables caller-supplied filtering. For enforced connectors, the authenticated caller is used instead; see [ACL enforcement](/essentials/v2/connectors#enforce-acl). |
| | Omit for the result object with `llm_prompt`. `"structured"` leaves out the prompt string. `"markdown"` returns the prompt string directly as `data`. |
| | What to query. `"all"` runs knowledge and memory in parallel over the same scope and merges by `relevancy_score`. (default=`"knowledge"`) |
diff --git a/plugins/mcp.mdx b/plugins/mcp.mdx
index db7885eb..547f266d 100644
--- a/plugins/mcp.mdx
+++ b/plugins/mcp.mdx
@@ -476,18 +476,21 @@ those sources.
- **One title rule:** HydraDB applies Unicode NFKC, removes invisible marks and
decoration, lowercases the title, collapses spaces, and trims it.
-- **Known file extensions are optional:** HydraDB removes one final extension from
+- **Known file extensions are optional:** HydraDB removes consecutive final
+ extensions from
`md`, `markdown`, `txt`, `pdf`, `doc`, `docx`, `rtf`, `odt`, `ppt`, `pptx`,
`xls`, `xlsx`, `csv`, `tsv`, `json`, `html`, or `htm`. Text must remain before
the extension. `last-usage` therefore matches `last-usage.csv`. `notes.v2` stays
- unchanged, and `.md` stays unchanged.
+ unchanged, `.md` stays unchanged, and `report.pdf.md` matches `report`.
- **Exact after normalization:** `q3 roadmap.md` matches `Q3 Roadmap`, but a
normalized prefix alone does not match in this exact-title field.
- **Several titles are ORed:** Punctuation such as commas remains part of the title.
- **No match returns an empty result** rather than widening to the whole corpus.
-Source IDs and titles are separate inputs. Use `ids` for source IDs and `titles`
-for titles. HydraDB never guesses from the input format.
+Source IDs and titles are separate inputs. `hydradb_query` accepts document names
+through `titles`; it does not accept source IDs. Use `hydradb_inspect` or
+`hydradb_subgraph` when you have one source ID, or `hydradb_list` with `ids` when
+you have several. HydraDB never guesses from the input format.
Two documents with the same normalized title are treated as the same title and
From bbb794527a341adf94af497281b075e74cc01421 Mon Sep 17 00:00:00 2001
From: adityamishra-hydradb
<321510987+adityamishra-hydradb@users.noreply.github.com>
Date: Tue, 27 Oct 2026 23:34:49 +0000
Subject: [PATCH 3/3] docs(search): document MCP source scopes (ENG-3299)
Signed-off-by: adityamishra-hydradb <321510987+adityamishra-hydradb@users.noreply.github.com>
---
plugins/mcp.mdx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/plugins/mcp.mdx b/plugins/mcp.mdx
index 547f266d..6fe18c93 100644
--- a/plugins/mcp.mdx
+++ b/plugins/mcp.mdx
@@ -456,6 +456,7 @@ See the [Glossary](/essentials/v2/glossary) for database and collection terminol
| `max_results` | number | No | Chunks to return, 1 to 50 (default: `10`) |
| `mode` | string | No | `fast` for a quick single pass, `thinking` for deeper recall with query expansion and graph traversal, or `auto` to pick per query (default: `thinking`) |
| `graph_context` | boolean | No | Include knowledge graph relations in the results (default: `true`) |
+| `source_ids` | string[] | No | Restrict the search to these source IDs. Intersects with `titles` when both are present. |
| `titles` | string[] | No | Restrict the search to documents whose complete normalized title matches any value. See [Filtering by document title](#filtering-by-document-title). |
| `metadata_filters` | object | No | Exact-match metadata filters as `{key: value}` |
| `database` | string | No | Database (tenant) scope override for this request |
@@ -487,10 +488,9 @@ those sources.
- **Several titles are ORed:** Punctuation such as commas remains part of the title.
- **No match returns an empty result** rather than widening to the whole corpus.
-Source IDs and titles are separate inputs. `hydradb_query` accepts document names
-through `titles`; it does not accept source IDs. Use `hydradb_inspect` or
-`hydradb_subgraph` when you have one source ID, or `hydradb_list` with `ids` when
-you have several. HydraDB never guesses from the input format.
+Source IDs and titles are separate inputs. Use `source_ids` for source IDs and
+`titles` for document names. When both are present, HydraDB intersects the two
+scopes. HydraDB never guesses from the input format.
Two documents with the same normalized title are treated as the same title and