Back to Claude Scientific Skills

Materials Project API: bounded queries, provenance, and computed-data limits

skills/pymatgen/references/materials_project_api.md

2.55.012.9 KB
Original Source

Materials Project API: bounded queries, provenance, and computed-data limits

This reference targets mp-api==0.46.4 (released 2026-06-15) with pymatgen==2026.5.4 and pymatgen-core==2026.7.16. mp-api requires Python 3.11+ and depends on pymatgen>2024.2.20.

Use the separate official client:

python
from mp_api.client import MPRester

Do not use a legacy Materials Project client import from older pymatgen examples.

Installation

Pin the tested client and materials stack:

bash
uv add "pymatgen==2026.5.4" "pymatgen-core==2026.7.16" "mp-api==0.46.4"
uv lock
uv sync --frozen

The 0.46.4 package metadata declares direct dependencies including pymatgen>2024.2.20, monty>=2024.12.10, emmet-core>=0.87.1, requests>=2.23.0, orjson>=3.10,<4, pyarrow>=20, and deltalake>=1.4,<1.6, plus boto3 and typing extensions. A lockfile is needed to freeze transitive artifacts.

Authentication: one named secret

An API key is required and is available from the logged-in Materials Project dashboard.

The approved pattern is:

python
from mp_api.client import MPRester

# MPRester reads only the already-injected MP_API_KEY.
with MPRester() as rester:
    pass

Operational rules:

  • use only the environment variable MP_API_KEY
  • inject it through the user's shell/session secret manager
  • never accept it as a command-line argument
  • never embed it in code, notebooks, URLs, cache files, or manifests
  • never traverse dot-env files or dump the environment
  • never print the key or unredacted exceptions that might contain it
  • do not send it anywhere except the official Materials Project API endpoint

The bundled query CLI follows these rules and reads the variable only after --execute.

Query contract before network

Before any request, disclose:

  1. endpoint and mp-api version
  2. all filters
  3. exact response fields
  4. num_chunks, chunk_size, and maximum serialized bytes
  5. cache reads/writes
  6. output path and no-overwrite behavior
  7. API-key source by name, never value
  8. data license, citation, provenance, and scientific limitations

The dry-run planner:

bash
python scripts/mp_query.py \
  --chemsys Li-Fe-O \
  --energy-above-hull 0 0.05 \
  --fields formula_pretty,energy_above_hull,band_gap,origins \
  --limit 25

Only an explicit execution permits the disclosed network workflow:

bash
python scripts/mp_query.py \
  --material-id mp-149 \
  --fields formula_pretty,structure,origins,last_updated \
  --limit 1 --output mp-149.json --execute

The CLI has no implicit result cache. The explicit bounded JSON output is the reusable artifact. MPRester initialization performs compatibility and heartbeat/database-version metadata requests before the bounded summary search. The CLI discloses those requests, disables the platform-detail user agent and local database-version notification log, and records the server's database version.

Summary searches

The official docs identify summary data as the main property overview for a material:

python
from mp_api.client import MPRester

with MPRester() as rester:
    docs = rester.materials.summary.search(
        material_ids=["mp-149", "mp-13"],
        fields=[
            "material_id",
            "formula_pretty",
            "energy_above_hull",
            "band_gap",
            "origins",
            "last_updated",
        ],
        all_fields=False,
        num_chunks=1,
        chunk_size=25,
    )

material_ids accepts one ID or a list in the current signature. The result is a list of SummaryDoc model objects by default.

Property filters

Verified public SummaryRester.search parameters include:

python
with MPRester() as rester:
    docs = rester.materials.summary.search(
        chemsys="Li-Fe-O",
        elements=["Li", "O"],
        exclude_elements=["F"],
        energy_above_hull=(0.0, 0.05),
        band_gap=(0.5, 3.0),
        is_stable=None,
        fields=["material_id", "formula_pretty", "energy_above_hull", "band_gap"],
        all_fields=False,
        num_chunks=1,
        chunk_size=25,
    )

Other current filters include formula, crystal system, density, deprecation, dielectric ranges, elastic ranges, metal/direct-gap flags, property availability, magnetic ordering, element/site counts, space group, theoretical status, energy ranges, volume, and surface-property ranges. Consult the exact installed signature instead of passing guessed keywords.

exclude_elements is a list of element symbols; it is not a Boolean flag.

available_fields lists fields the endpoint can return. It does not mean every field is a valid filter:

python
with MPRester() as rester:
    returnable_fields = rester.materials.summary.available_fields

Requesting all fields is the documented default and can be expensive. Always pass a short fields list and bound chunks.

Serialization

Use the public Pydantic model interface:

python
payload = [document.model_dump(mode="json") for document in docs]

Then write strict JSON with allow_nan=False, a byte bound, and a new output path. Include query, fields, retrieval time, endpoint, client versions, and license/citation. Do not use deprecated generic dictionary shims, pickle, or a general object decoder on untrusted cached data.

Structures

python
from mp_api.client import MPRester

with MPRester() as rester:
    structure = rester.get_structure_by_material_id(
        "mp-149",
        final=True,
        conventional_unit_cell=False,
    )

Alternatively request structure as an explicit summary field. Preserve:

  • material ID
  • whether the final/initial and conventional/primitive representation was requested
  • origins and task IDs
  • retrieval and database release
  • parser/API warnings

Validate the returned structure locally. A Materials Project structure is a computed relaxed representation, not necessarily the experimental setting, lattice parameters, disorder, temperature, or composition model.

Entries and phase diagrams

python
from mp_api.client import MPRester

with MPRester() as rester:
    entries = rester.get_entries_in_chemsys(
        "Li-Fe-O",
        compatible_only=True,
        conventional_unit_cell=False,
    )

The current method also accepts use_gibbs, property_data, and additional_criteria. The official query guide shows filtering thermo types through:

python
with MPRester() as rester:
    entries = rester.get_entries_in_chemsys(
        "Co-N",
        additional_criteria={
            "thermo_types": ["GGA_GGA+U", "GGA_GGA+U_R2SCAN", "R2SCAN"]
        },
    )

Do not mix thermo types or correction schemes casually. Record all arguments, entry IDs, correction data, origins, and database release. Preserve the retrieved entries locally and build the hull offline.

Band structures and DOS

Official convenience methods include:

python
with MPRester() as rester:
    bands = rester.get_bandstructure_by_material_id("mp-149")
    dos = rester.get_dos_by_material_id("mp-149")

These can return None when data is unavailable. Their values are computed and method-dependent. Preserve calculation/task origins, spin/SOC, path/mesh, functional, and database release. Do not treat an absent object as a zero gap or zero DOS.

Provenance with origins

The official query guide recommends requesting origins to connect a summary property to a calculation task:

python
with MPRester() as rester:
    summaries = rester.materials.summary.search(
        material_ids=["mp-149"],
        fields=["material_id", "structure", "origins"],
        all_fields=False,
        num_chunks=1,
        chunk_size=1,
    )

An origin can identify the task used for a property. A corresponding thermo document's run_type distinguishes categories such as GGA, GGA+U, or r2SCAN. Do not assume all properties on one summary document came from one calculation or functional.

Other routes

The client exposes endpoint-specific resters under rester.materials, with routes documented for thermo, electronic structure, elasticity, dielectric, magnetism, phonons, surfaces, XAS, synthesis-related data, and others. Signatures and document models vary. Inspect the current route documentation and request only supported fields.

Do not copy old endpoint examples or invent filter names. Endpoint availability and schema can evolve independently of the Python wrapper.

Errors, retries, and rate handling

Use the current exception:

python
from mp_api.client.core.exceptions import MPRestError

try:
    with MPRester() as rester:
        docs = rester.materials.summary.search(
            material_ids=["mp-149"],
            fields=["material_id"],
            all_fields=False,
            num_chunks=1,
            chunk_size=1,
        )
except MPRestError:
    # Report a bounded, credential-redacted failure.
    raise

Official 0.46.4 client source configures retries for HTTP 429, 502, and 504 and respects Retry-After. It wraps request failures as MPRestError and advises smaller requests on connection timeout.

Safety rules:

  • rely on the pinned client's bounded retry behavior
  • do not add an unbounded retry loop
  • do not claim a numeric service quota unless current official documentation publishes one
  • reduce fields/chunk size on timeout or oversized responses
  • stop after a persistent authorization, schema, or validation error
  • redact MP_API_KEY from any exception text

Cache policy

Caching can improve reproducibility but creates a data-governance obligation. Before using a cache, disclose:

  • exact path, schema, size limit, and retention
  • cache key: endpoint, filters, fields, client version, and database release
  • whether stale data is acceptable
  • license/citation metadata
  • whether structures or contributed data are stored

Never cache credentials. Never treat a cache as current without checking its retrieval time and database version. mp-api exposes a local full-dataset cache path for bulk/delta-table workflows; the bundled summary-query CLI does not request those downloads and intentionally uses no hidden result cache.

License, attribution, and citation

Materials Project states that its data is licensed under CC BY 4.0 and that contributed data is owned by its respective contributors.

The official FAQ says citations are appropriate wherever Materials Project data, methods, or output are used. Preserve:

  • canonical Materials Project citation
  • property/tool-specific citations from the material/citation page
  • database release citation
  • material IDs and task/property origins
  • retrieval date and query

See How to Cite and Database Versions.

Computed-data limitations

Materials Project documents that:

  • core properties are calculated in-house using simulation methods
  • typical/systematic errors must be assessed from property publications
  • PBE lattice parameters often show systematic overestimation, with larger interlayer errors where van der Waals interactions are poorly described
  • PBE band gaps are systematically underestimated
  • summary/aggregated values can change as calculations and database releases are updated
  • space groups depend on symprec; the MP pipeline commonly uses 0.1 Å

Therefore:

  • computed stability is not experimental stability or synthesizability
  • predicted structures are not proof of existence
  • missing data is not zero
  • a material ID does not guarantee one immutable property record
  • cite the database version and property methodology

Minimal provenance envelope

json
{
  "retrieved_at_utc": "2026-07-23T00:00:00Z",
  "endpoint": "https://api.materialsproject.org/materials/summary/",
  "filters": {"material_ids": ["mp-149"]},
  "fields": ["material_id", "formula_pretty", "origins", "last_updated"],
  "limit": 1,
  "client": {
    "mp-api": "0.46.4",
    "pymatgen": "2026.5.4",
    "pymatgen-core": "2026.7.16"
  },
  "database_version": "record from current MP release metadata",
  "license": "CC BY 4.0",
  "citation": "https://materialsproject.org/about/cite"
}

Do not include the API key.

Sources (verified 2026-07-23)