Document Intelligence (PDF Search)

The Red Bricks MCP server includes four Document Intelligence tools that
search the full text extracted from project PDFs — brochures, features &
finishes sheets, incentive notices, price lists, deposit structures, and fact
sheets. Use them to answer questions that aren't in the structured project data:
appliance brand names, capped development-charge values, free-assignment terms,
finish details, and how incentives have evolved over time.

📘

These are MCP tools, invoked by an MCP client (e.g. Claude) connected to

the Red Bricks MCP server — not REST endpoints. See
Configure MCP Server for connection setup.

Availability

PlanDocument Intelligence
Sandbox / Essential❌ Not available
Pro✅ Searches the latest documents
Elite✅ Latest + historical (older-revision) documents

On plans without access, the tools return a permission error. The
include_historical option only takes effect on Elite — on Pro it is silently
ignored (latest documents only).

How matching works

The PDF tools do exact keyword + synonym matching, not natural-language
search.
Internally they run a two-stage match: a fast full-text pre-filter,
then a strict containment post-filter that drops phantom matches (and bridges
PDF-extraction encoding artifacts, so 30", 30-inch, and the mojibake 30�
all match 30 inch).

Practical implications for querying:

  • Open-ended queries ("luxury appliances", "premium finishes") won't match an
    abstract noun. Expand them into concrete terms and call the tool a few times —
    e.g. for "luxury appliances," search miele, sub-zero, wolf, thermador
    separately and merge the results.
  • Sized queries ("30 inch range") — search the size synonym (30 inch); the
    synonym groups cover hyphen/quote variants.
  • Phrase queries ("free assignment", "capped development charges") — the
    synonym groups already cover common variants, so a single call is enough.

Categories

Where a tool accepts a category, valid values are: incentives,
features-finishes, brochure, hot-list, price-list, deposit-structure,
fact-sheet, other.

Coverage metadata

Every search response carries a meta.coverage block so you can tell "nothing
matched X"
apart from "the index couldn't answer":

FieldMeaning
total_active_documentsIndexed docs in the searched scope
documents_with_textDocs that extracted successfully and are searchable
documents_with_no_textDocs that failed extraction or have no usable text
pre_filter_candidatesRows the full-text pre-filter returned before strict filtering

If total_chunks_matched is 0 after a couple of query variants, treat it as a
genuine "not mentioned" — don't speculate.


search-document-text

Citation-backed chunk search within project PDFs (one project, or all projects).

Input

FieldTypeRequiredDescription
querystringyesFree-text phrase or keywords.
project_idintegernoRestrict to a single project.
categorystringnoRestrict to a category (see Categories).
include_historicalbooleannoInclude older-revision docs (Elite only).
limitintegernoMax chunks, 125 (default 10).

Output

{
  "data": [
    {
      "chunk_id": 84213,
      "project_id": 6809,
      "project_name": "The Forest Hill Private Residences",
      "document_id": 1422,
      "document_name": "Features & Finishes.pdf",
      "category": "features-finishes",
      "page_number": 3,
      "excerpt": "...integrated Miele appliance package including a 30 inch gas cooktop...",
      "matched_term": "miele",
      "extraction_id": 5567,
      "stable_citation": {
        "document_id": 1422,
        "page_number": 3,
        "text_hash": "9f2c…"
      }
    }
  ],
  "meta": {
    "query": "miele",
    "expanded_terms": ["miele"],
    "total_chunks_matched": 4,
    "coverage": {
      "total_active_documents": 6210,
      "documents_with_text": 6151,
      "documents_with_no_text": 59,
      "pre_filter_candidates": 12
    }
  }
}

excerpt is a ~200-character window centered on the first match. Use chunk_id
with fetch-document-context to pull surrounding paragraphs.


find-projects-mentioning

Cross-project discovery — "which projects mention X?" Returns each matching
project with its match count and a sample excerpt.

Input

FieldTypeRequiredDescription
querystringyesPhrase or feature to search for across all projects.
categorystringnoRestrict to a category.
include_historicalbooleannoInclude older-revision docs (Elite only).
limitintegernoMax projects, 150 (default 25).

Output

{
  "data": [
    {
      "project_id": 6809,
      "project_name": "The Forest Hill Private Residences",
      "match_count": 7,
      "categories_matched": ["brochure", "features-finishes"],
      "best_excerpt": "...purchasers receive free assignment and one year of free maintenance..."
    }
  ],
  "meta": {
    "query": "free assignment",
    "expanded_terms": ["free assignment", "assignment fee waived"],
    "total_projects": 12,
    "coverage": {
      "total_active_documents": 6210,
      "documents_with_text": 6151,
      "documents_with_no_text": 59,
      "pre_filter_candidates": 340
    }
  }
}

Projects are ranked by match_count (then relevance). total_projects is the
full count before the limit cap.


list-project-documents

Inventory of indexed PDFs for one project — what exists, their categories, and
extraction status. Useful before drilling into search-document-text.

Input

FieldTypeRequiredDescription
project_idintegeryesProject to list documents for.
categorystringnoFilter by category.
include_historicalbooleannoInclude older-revision docs (Elite only).

Output

{
  "data": [
    {
      "document_id": 1422,
      "name": "Features & Finishes.pdf",
      "category": "features-finishes",
      "type": null,
      "indexed": true,
      "extraction_status": "completed",
      "extraction_method": "pdftotext",
      "page_count": 4,
      "raw_text_length": 8231,
      "indexed_at": "2026-05-01T12:00:00+00:00"
    }
  ],
  "meta": {
    "project_id": 6809,
    "total_documents": 12,
    "include_historical": false
  }
}

Documents that failed extraction or are still pending are included with
indexed: false and their extraction_status, so you know why they might not
surface in search.


fetch-document-context

Expand a search hit by returning the chunks immediately before and after it, in
document order — for when an excerpt is suggestive but truncated.

Input

FieldTypeRequiredDescription
chunk_idintegeryesA chunk_id returned by search-document-text.
beforeintegernoPreceding chunks to include, 05 (default 1).
afterintegernoFollowing chunks to include, 05 (default 1).

Output

{
  "data": [
    { "chunk_id": 84212, "chunk_index": 11, "page_number": 3, "is_center": false, "text": "Kitchen — All suites feature…", "stable_citation": "…" },
    { "chunk_id": 84213, "chunk_index": 12, "page_number": 3, "is_center": true,  "text": "…integrated Miele appliance package including a 30 inch gas cooktop…", "stable_citation": "…" },
    { "chunk_id": 84214, "chunk_index": 13, "page_number": 3, "is_center": false, "text": "…panel-ready dishwasher and a stacked washer/dryer.", "stable_citation": "…" }
  ],
  "meta": {
    "chunk_id": 84213,
    "document_id": 1422,
    "project_id": 6809,
    "extraction_id": 5567,
    "before_returned": 1,
    "after_returned": 1
  }
}
📘

Chunk IDs are tied to a specific extraction. If a document is re-indexed, an

old chunk_id may return "not found" — re-run search-document-text to get
fresh IDs.

A typical flow

  1. find-projects-mentioning → "which projects have Miele appliances?"
  2. search-document-text (with project_id) → exact chunks for a project.
  3. fetch-document-context (with a chunk_id) → surrounding paragraphs to
    confirm the detail before presenting it.