# You need one clause out of an eighty-page contract

> Search the result instead of reading it: excerpts come back with the page they fall on, and reading the pages around them is free.

Canonical HTML version: https://mcpbelt.com/problems/find-one-clause-in-a-long-contract

## The problem

Somebody asks what the termination terms are. The contract is eighty pages, the answer is two paragraphs, and nobody knows which page they are on.

The two ways to get there are both bad. Read the whole thing into the conversation and you have spent about twenty thousand tokens to use two hundred words, and the other seventy-nine pages stay in context degrading everything that follows. Guess a page range and you are betting on where a clause lives in a document you have not read.

What you want is the search you would do in a PDF viewer: type the word, get the hits with their page numbers, read around the ones that matter. That is the operation, and it is missing from every naive pipeline.

## Why it fails locally

On a digital PDF, text search works and is not the hard part. On a scanned contract it finds nothing, because there is no text to search: the pages are pictures, and the empty result looks exactly like a document that does not mention termination. That is the wrong answer arriving with confidence.

Even once the characters are recognised, extraction hands back one flat string. **The page numbers are gone.** You can find the word and still not be able to say where it is, and a clause without a page reference is not something anyone can check against the paper copy.

So the local path either searches nothing, or searches something that has lost the one piece of metadata that makes the answer usable. And the workaround, reading everything so the model can find it, is precisely the cost you were trying to avoid.

## The code

Read once, then search the result. `find` is a case-insensitive text search and returns excerpts with the page each one falls on. Every `result` call is free.

```
upload(filename="contract.pdf", content_type="application/pdf")
  -> key, upload_url

curl -T contract.pdf "<upload_url>"

read(key="<key>")
  -> handle, engine, structure, tokens_if_inlined

result(handle="<handle>", find="termination")
  -> matches, match_count, matches_omitted

result(handle="<handle>", pages="12-14")
  -> the pages around the match, in full

result(handle="<handle>", find="notice period")
  -> another search, same handle, still free
```

## What it costs

You pay once, for the read. `balanced` costs 0.007 EUR per page, about 0.56 EUR for eighty pages, and nothing at all when the PDF already carries its own text and can be extracted locally. `exact` costs 0.016 EUR per page and goes straight to an engine, which is what you want on a scan of a signed copy.

Searching is free and so is paging. Ten searches and four page ranges cost the same as one: `result` is never charged, because the work was already paid for when the document was read.

Reading the same contract twice costs once. The file is recognised by its contents rather than its name, so the second call returns the first result and charges nothing, even if somebody renamed it in the meantime.

## What this does not do

- `find` is a text search, case-insensitive and literal. It matches words, not meanings: a clause that never uses the word you searched for will not come back.
- A search that hits hundreds of times returns the first excerpts and reports the rest in `matches_omitted`, rather than flooding your context. Narrow the term or read the pages.
- Page numbers are the pages of the file. If the printed document is numbered differently, the two will not agree.
- Email files (EML, MSG) and ebooks (EPUB) are read by no engine. Extract the text or convert to PDF first.
