> ## Documentation index
> Fetch the complete index at: /llms.txt
> Use it to discover every page before exploring further.

# AI assistants

> The same portfolio, offered to assistants that speak the Model Context Protocol: Claude, and any client that connects to an MCP server over HTTP.

## The MCP server

retrieve-IQ serves the Model Context Protocol over HTTP at one address. An assistant connected to it can list your clients, summarise a portfolio, list deadlines, find a parcel and open its detail, explain a bill line by line, and report the nightly fetch, under the same scopes and engagements as the GraphQL API. Every tool only reads; none changes a record.

```http
https://api.retrieveiq.net/mcp
```

- Authenticate with an API key as the bearer token, exactly as for GraphQL. A key with `PARCEL_READ`, `BILL_READ` and `REPORT_READ` can use every tool; each tool's entry below names the scopes it needs.
- Where retrieve-IQ has enabled it for your deployment, a person's own sign-in works too: the server publishes the discovery documents an MCP client needs to send the person through retrieve-IQ's sign-in. Until then, use a key.
- The assistant names the client it acts for by passing the engagement id `list_clients` returns to the other tools as `engagement`. A firm owns no property itself, so a tool called without one answers from an empty portfolio.

## Connecting Claude

In Claude Code, add the server once with its key:

```bash
claude mcp add --transport http retrieve-iq https://api.retrieveiq.net/mcp \
  --header "Authorization: Bearer $RETRIEVEIQ_API_KEY"
```

Or in a `.mcp.json` checked in beside a project, with the key read from the environment:

```json
{
  "mcpServers": {
    "retrieve-iq": {
      "type": "http",
      "url": "https://api.retrieveiq.net/mcp",
      "headers": { "Authorization": "Bearer ${RETRIEVEIQ_API_KEY}" }
    }
  }
}
```

Any other client that connects to a remote MCP server over HTTP takes the same address and the same header. Then ask in plain words: "what is due in the next thirty days for Grand Avenue Holdings", "why is this bill higher than last year", "which counties did not answer last night".

## Tools

What the server offers, as it lists them to a client, each with the scopes its own query needs. Every tool is read-only. A tool answers with the same figures the app shows and says when a date could not be worked out (`unevaluableReason`); `find_parcel` says when its list is cut short (`hasMore`), `parcel_detail` holds the six newest assessments and bills, and `explain_bill` looks among the twelve newest bills.

### explain_bill

`tool`, needs `BILL_READ` and `PARCEL_READ`

Breaks one tax bill into the charges the county actually levied, with the agency behind each line and its phone number where the bill prints one. Use this for "why am I being charged this" questions. The levying agency is frequently not the county, and the phone number is on the bill precisely because that agency expects to be asked about that line: pass it on rather than summarising it away. Charges describe the whole tax year and sum to totalBilled, never to one installment. Looks among the parcel's twelve newest bills.

Inputs:

- `engagement` (`string`): Engagement id from list_clients.
- `parcelId` (`string!`, required): The parcelId returned by find_parcel.
- `billKey` (`string!`, required): The billKey returned by parcel_detail.

### find_parcel

`tool`, needs `PARCEL_READ`

Search the portfolio by parcel number or address (street or city). Returns one page plus totalCount and hasMore. When hasMore is true say so rather than implying the list is complete.

Inputs:

- `engagement` (`string`): Engagement id from list_clients.
- `search` (`string`): Free text matched against parcel number and situs address.
- `limit` (`integer`): Default 20, max 50.

### ingestion_status

`tool`, needs `BILL_READ`

Which counties the nightly fetch is failing in and which answered last night, per California county this portfolio holds parcels in, plus the last nights of the feed. A county with a streak has probably changed its portal; lastOutcome says how it failed. Pass the engagement id when acting for a client.

Inputs:

- `engagement` (`string`): Engagement id from list_clients. Omit when acting for yourself.

### list_clients

`tool`, any key

Lists the clients you may act for, with the engagement id every other tool takes. Call this first when acting for a firm: a firm owns no property itself, so omitting the engagement returns an empty portfolio rather than an error. A client shown as live: false has lapsed and its data is no longer readable.

### list_deadlines

`tool`, needs `BILL_READ` and `PARCEL_READ`

Payment and appeal dates across the portfolio, soonest first. Entries the rules cannot date are returned with on: null and a plain-English unevaluableReason, rather than omitted. Report those as unknown dates and give the reason: a deadline that cannot be derived is not a deadline that does not exist, and the difference matters to a taxpayer. An entry with scope "jurisdiction" is a unit's own appeal window, which belongs to no parcel: its parcelNumber and situs are null.

Inputs:

- `engagement` (`string`): Engagement id from list_clients.
- `from` (`string`): ISO date, inclusive lower bound.
- `to` (`string`): ISO date, inclusive upper bound.

### parcel_detail

`tool`, needs `BILL_READ` and `PARCEL_READ`

Everything held for one parcel: its six newest assessments and bills, what is owed and the next payment. One call rather than several, so do not follow it with find_parcel for the same property. Use the billKey it returns with explain_bill.

Inputs:

- `engagement` (`string`): Engagement id from list_clients.
- `parcelId` (`string!`, required): The parcelId returned by find_parcel.

### portfolio_summary

`tool`, needs `BILL_READ`, `PARCEL_READ` and `REPORT_READ`

What is owed across the portfolio and where. Counties come first because the work of property tax scales with the number of counties, not the number of properties. Pass an engagement to act for a client; omit it to act for yourself. Amounts are decimal strings in major units, and null means the figure is unknown, never that it is zero. installmentsWithUnknownPayment is how incomplete the owed figure is: report it when it is above zero rather than presenting the total as complete. installmentsPaidPerRecords is how many of those the customer's own records show paid: say it beside the figure and never subtract it, since the county has not confirmed them. legalEntities is the same portfolio by owner: each entity with its parcels, their assessed value (the newest assessment of each active parcel, the rule assessedValue uses) and what is owed on their bills.

Inputs:

- `engagement` (`string`): Engagement id from list_clients. Omit when acting for yourself.

## Reading this documentation

These pages are written for assistants as well as people: [/llms.txt](/llms.txt) indexes every page, each page is available as Markdown at its address with `.md` added, and [/llms-full.txt](/llms-full.txt) holds all of it in one file. The schema itself is at [/docs/schema.graphql](/docs/schema.graphql). The **Copy page** button at the top of each page copies that Markdown, and its menu opens the page in Claude or ChatGPT.
