# `search_materials` tool

Finds materials from a plain-language description of the properties and composition you want. Returns up to 50 matching rows, the constraints we understood, how many materials were eliminated, and a result_set_id that the other tools use to page, refine, rank and export the full match.

**At a glance**

| Item | Value |
| --- | --- |
| Tool | `search_materials` |
| Title | Search materials |
| Group | [Find materials](https://www.chemiadiscovery.com/docs/mcp/tools/#what-is-in-the-group-find-materials) |
| Needs one of | `professional_database` or `trial_database` |
| Charged | Yes, against the daily allowance |
| Read-only | Yes |
| Parameters | 3, of which 1 required |
| Data as of | 2026-10-04 |
| Server release | 1.5.0, read from the live server on 2026-10-04 |

## What parameters does search_materials take?

**Parameters of `search_materials`**

| Parameter | Type | Required | Default | What it does |
| --- | --- | --- | --- | --- |
| `query` | `string` | Yes | none | Plain-language description of what you want, for example "semiconductors with a band gap between 1.1 and 1.6 eV and bulk modulus above 100 GPa". It can combine property limits, element filters, a compound class, a sort such as "lowest density" and the name of a database. A language model turns it into constraints, returned in `constraints`. Give each value in the property's canonical unit (the unit on result rows): other units are converted only for the few properties whose vocabulary lists them, and are otherwise not converted. A constraint on water inertness or Pourbaix decomposition energy is evaluated against live Materials Project data and also needs the materials_project_data grant; without it the reply is a clarification question, not a silent skip. A query too vague to run returns `clarification_needed` instead of guessing. |
| `max_results` | `integer` | No | `20` | How many rows to return in this response. Values above 50 are lowered to 50 and values below 1 are raised to 1; `limit_requested`, `limit_applied` and `notice` show what happened. This does not limit the search: `total_survivors` is the full match count and get_result_set pages through the stored matches. |
| `source_id` | `string` or null | No | not set | Dataset to search, an `id` from list_material_sources. Null (the default) uses the dataset the query text names, if it names one clearly (that is not guaranteed; pass the id to be sure), and otherwise the server's default dataset. In that case an account without the professional_database grant is narrowed to the trial subset. An id that is not in the catalogue is not rejected: it falls back to the registry default, the trial subset. Asking by id for a restricted dataset your account cannot reach is refused with an error that names the missing grant. |

## Which grants does search_materials need, and is it charged?

- **Grants:** `professional_database` or `trial_database`. One of them is enough.
- **Charged:** yes, each call uses one unit of the daily allowance (as of 2026-10-04).

Grants and the allowance are explained in [Access, grants and limits](https://www.chemiadiscovery.com/docs/mcp/access/).

**Annotations the server sets on `search_materials`**

| Annotation | Value | Meaning |
| --- | --- | --- |
| `destructiveHint` | false | If true, the tool may make destructive updates. It matters only when the tool is not read-only. |
| `idempotentHint` | true | If true, calling the tool again with the same arguments has no additional effect. |
| `openWorldHint` | false | If true, the tool may interact with an open world of external entities. |
| `readOnlyHint` | true | If true, the tool does not modify its environment. |

## What does a call to search_materials look like?

A two-property search that returns ten rows.

```json Example arguments for search_materials
{
  "query": "semiconductors with a band gap between 1.1 and 1.6 eV and bulk modulus above 100 GPa",
  "max_results": 10
}
```

These arguments validate against the tool's input schema, checked when the snapshot was taken on 2026-10-04. They show the shape of a call; they are not a recorded response. [Examples](https://www.chemiadiscovery.com/docs/mcp/examples/) says where worked examples stand.

## How should I read search_materials results?

- **Convention.** There are three different counts. `total_survivors` is the exact number of matches. `results` holds at most 50 of them, and `truncated` is true when it holds fewer than the total. Up to 5000 matches are stored for get_result_set; rows beyond that were counted but never stored. A query judged to match that many or more, or a scan that runs out of time, is not answered with rows: the reply is `clarification_needed` with a size estimate and ways to narrow it, and the call is refunded.
- **Trap.** Check `source` in every response. A source_id that is misspelt or not in the catalogue raises no error: it resolves to the registry default, the small trial subset, and `requested_source` then names that default too, so only a comparison with the id you sent shows the swap. A restricted dataset that was inferred from the query text, or taken as the server default, is narrowed to the trial subset without an error when your account lacks the professional_database grant; there `requested_source` differs from `source`.
- **Gap.** A search can answer only part of a question without saying so. A condition the parser cannot map to a property it knows (for example coercivity) is dropped: it is not in the parsed `constraints`, it has no `constraint_ledger` entry, and the matches reflect only the other conditions. Its only trace is a sentence in `constraints.open_questions`, and `clarification_needed` and `notice` stay empty. Compare the parsed constraints with what you asked. A ledger entry with state not_supported is the intended signal for a condition that is parsed but cannot be checked; extending it to dropped conditions is a planned fix, not current behaviour. Today it appears only for a parsed constraint whose property is outside the vocabulary or whose kind this server does not enforce (such as a cost ceiling or a material class); it never carries a count. Entries with state no_data count materials left out only because they have no measurement of that property.

A Convention is a field or behaviour whose meaning is not obvious, a Trap looks right and is not, and a Gap is something we do not hold or do not check. [Reading results](https://www.chemiadiscovery.com/docs/mcp/reading-results/) explains the classes.

## How does the server describe search_materials?

This is the server's own description, which a client passes to the model, lightly normalised for display.

Search Chemia's materials corpus with a natural-language constraint query, for example "semiconductors with a band gap between 1.1 and 1.6 eV and bulk modulus above 100 GPa".

Returns the matching materials, the constraints parsed from the query, elimination counts, and a result_set_id that get_result_set can page through. If the query is too ambiguous to run, returns clarification_needed instead of guessing.

If a property named in the query has zero or below-threshold corpus coverage, the response carries property_offer instead: its `note` is prose written to be shown as is, naming the proxy routes that reach the property and their caveats (or, with no usable route, the irreducible verdict and what extraction would take). A ranking by such a property still returns its matches, with a property_offer saying they are not ordered by it, and `ordering` reads "cursor".

A property value carrying `suspect` is physically impossible for that property (a negative shear modulus, a density of 1,248 g/cm3): a data error in the corpus, kept with its number so it can be pointed out, and not a measurement. Real extremes (osmium's density, diamond's stiffness) are not flagged.

Every constraint is applied together in one query. `eliminations` holds that query's totals: `matched` is the number of materials meeting every constraint (equal to `total_survivors`) and `eliminated` the rest of the dataset. How many each constraint removed is in `constraint_ledger`.

Ranking by how much of an element a material contains works directly: "rank Sc compounds by Sc content" returns the highest atomic fraction first (weight fraction if the query says by weight), ranked across the whole match, with the value in each row's metadata `element_fraction`.

Rows come most stable first (lowest energy above hull, entries without one last) unless the query asks for a sort; `ordering` says which. That is an order, not a ranking; score_results ranks.

source_id picks a dataset from list_material_sources ("trial", "production") explicitly; a database named only in the query text is not guaranteed to be selected.

Compound classes are exact: "nitrides", "oxides", "sulfides", "halides" and the like mean compounds of two or more elements in which that element is the anion. So "nitrides" excludes N2 and nitrates, and "sulfides" excludes sulfates. Say "contains N" in the query to mean mere presence instead.

Searches cover real solids by default: frozen gases (N2, O2, He) and compounds of nonmetals alone (NH3, CO, H2O, organic crystals) are left out, and a `real_solids` entry in `constraint_ledger` says so. Say "including molecular solids" in the query to keep them.

`constraint_ledger` covers every constraint that is not a plain property threshold (cost ceiling, material class, operating conditions, form factor, composition, a "top N" sort). Each entry's `state` is `applied` (enforced; `count` is how many candidates it eliminated), `not_supported` (a parsed constraint that this server does not check, so no count is given: it means "not tracked", not "none match"; a condition the parser cannot map at all is dropped and shows only in `constraints.open_questions`), or `no_data` (candidates excluded from a real property check only for lacking that measurement: not a constraint failure, and not part of a same-property `applied` count). Plain thresholds are counted in `eliminations`.

max_results is capped at 50 per response; `limit_applied` and `notice` say when fewer came back than were asked for, and get_result_set pages through the rest.

## Which tools are related to search_materials?

search_materials is in the group "Find materials". The other tools in it:

- [`count_materials`](https://www.chemiadiscovery.com/docs/mcp/tools/count_materials/): Returns one exact number: how many materials meet some criteria, or how many the dataset holds when no criteria are given. Use it instead of a search whenever the question is "how many".

The [Tool reference](https://www.chemiadiscovery.com/docs/mcp/tools/) lists every tool.

---

Canonical page: https://www.chemiadiscovery.com/docs/mcp/tools/search_materials/

Data as of 2026-10-04. Server release 1.5.0, read from the live server on 2026-10-04.

Tool reference as JSON: https://www.chemiadiscovery.com/docs/mcp/tools.json

[Site FAQ](https://www.chemiadiscovery.com/faq) | [Website privacy policy](https://www.chemiadiscovery.com/privacy) | [Website terms of use](https://www.chemiadiscovery.com/terms) | [Contact support](mailto:info@chemiadiscovery.com)
