---
name: mcmaster-parts
description: Use for any bought hardware in a CAD design (bearings, screws, nuts, washers, heat-set inserts, dowel and shoulder pins, standoffs and spacers, rod ends, threaded rod, grommets). Always choose a real McMaster-Carr part with a part number and place its manufacturer STEP model, normalised into a known frame, instead of drawing an envelope; record the part, its full specification table, price and mass in the project's hardware catalogue.
---

# McMaster-Carr parts

Bought hardware is a real part: a part number, its manufacturer's model, its specification. McMaster-Carr publishes
a STEP model and a full specification table (material, finish, strength class, thread, dimensions and tolerances,
load and speed ratings, temperature range, compliance) for almost everything it sells. Use them.

```mermaid
flowchart TD
    P["pick the part like an engineer<br/>category page, spec table"] --> D["download the STEP,<br/>normalise its frame"]
    D --> C["catalogue entry<br/>PN, specs, price, mass"]
    C --> K["check the model<br/>bounding box vs the page"]
    K --> Pl["place it at its seat"]
    class D,C,K here
    class P near
    class Pl out
```

The tools: `cadagent.mechanical.mcmaster` (Python) and `cad-agent mcmaster` (CLI). They read one product page at a time
in the system Chrome (Playwright), with a pause between pages. That is the same traffic as an engineer choosing parts,
and it must stay that way.

## Rules

- **Download like an engineer, not a crawler.** One part at a time, a pause between pages (default 3 s; the tool
  never goes below 2 s), only the product pages of the parts you are choosing. The tool accepts only McMaster part
  numbers (`PN_RE`, e.g. 91290A242), never a category, search or other URL. No bulk downloads, no parallel sessions.
  A part already downloaded is reused offline (no browser); download it again only when you need to (`--force`).
- **Keep the files local.** McMaster-Carr CAD is for design use; do not redistribute it. Gitignore the vendor folder
  and track only `SOURCE.txt`:

      references/vendor/**
      !references/vendor/**/
      !references/vendor/**/SOURCE.txt

- **Strong, but few parts.** Prefer one family per fastener type: for example, black-oxide alloy steel class 12.9
  socket head screws (91290A) with a minimal set of lengths; 18-8 stainless where corrosion matters; class 10 nyloc
  nuts; one washer family per size. When a computed length is not stocked, move the seat or the pilot depth so a
  stocked length fits ([Fasteners and assembly access](../../lessons/mechanical/fasteners-and-assembly-access.md)) before adding another SKU. Report the number of distinct SKUs and the total part
  count.
- **Size from the CAD, then check against the page.** The stack comes from the CAD: grip, thread depth, insert pilot
  depth. Thread engagement is length minus grip. Check the chosen length against the depth actually available, and
  check the normalised model's bounding box against the catalogue dimensions.
- **Report what McMaster does not stock**, with the closest stocked alternative (for example, a 61812-2RS is not
  stocked; 6812-2Z is), and any CAD dimension that should move to a stocked size.

## Process

1. **Pick the part like an engineer.** Open the category page (e.g. `https://www.mcmaster.com/products/ball-bearings/`),
   filter it (System of Measurement → Metric, then size, material, thread) and read the table. Choose by function
   (load, fit, material, strength class) and by the SKUs you already use. Only then open the product page
   `https://www.mcmaster.com/<PN>/`.
2. **Download and normalise.**

       cad-agent mcmaster 91290A242 --kind screw --out references/vendor/mcmaster \
           --catalog catalog/hardware.json --key screw_m5x20

   This writes `OUT/<PN>/<PN>.step` (the download, kept only if it is a STEP file), `<PN>.page.json` (title, price,
   pack quantity, every spec row, option choices), `<PN>.norm.step`, `<PN>.norm.json` (axis found, how it was
   seated, bbox, volume, mass) and an entry in `SOURCE.txt`. Kinds and their frames
   (`cadagent.mechanical.mcmaster.FRAMES`) all put the axis on +Z, through the origin (the cylinders' axis line, not the
   centre of mass); which end goes down is decided from the part's shape, not from how the vendor modelled it:
   - `bearing`, `washer`, `nut`, `insert`, `standoff`, `spacer`, `pin`, `grommet`, `rod`: the larger end (flange,
     collar, head) at z = 0 and the part on +z; when both ends are the same size, the heavier end down
     (`info["end_down"]` says which rule decided).
   - `screw`: head on +z, shank towards -z. z = 0 is the underside of the head for socket, button, pan, hex and
     flanged heads, and the top face for a countersunk (flat) head (`info["head"]`). A part with no head wider than
     its shank (set screw, stud) is refused: use `pin` or `rod`.
   - `shoulder_screw`: the underside of the head at z = 0, head on +z, shoulder and thread towards -z.
   - `rod_end`: the ball centre at the origin, ball bore along +Y, threaded shank along -Z (without a modelled ball,
     the middle of the bore).

   A part with variants (a rod end's thread direction, a choice of finish) offers its CAD only after the choice.
   Give the option text after the part numbers, one `--choose` per option, prefixed with the part it is for:

       cad-agent mcmaster 59935K53 91290A242 --choose "59935K53:Right Hand" --out references/vendor/mcmaster

   (the `PN:` prefix may be left out when there is one part number). In Python: `Session.fetch(pn, out,
   choose=["Right Hand"])`. The page data records what was offered and what was chosen.

   Playwright: `pip install playwright` into the environment that runs it, plus Google Chrome (then nothing else is
   needed; without Chrome the command stops with an install hint).

   **When McMaster asks for a login** ("Log in to view Product Detail") the tool says so (`LoginRequired`), not that
   the part number is wrong, and asks for no more pages in that run. Retry once later from a new session. Until then,
   read the part number and price off McMaster's public search page in a browser (`https://www.mcmaster.com/<trade
   number or size>/`), take ratings it leaves out (a bearing's static load) from the maker's datasheet, and record
   both sources in the catalogue entry.
3. **Record the catalogue entry.** `catalog_entry()` / `--catalog` gives: `mcmaster` (PN), `description`, `url`,
   `price_usd`, `pack_qty`, `dims_mm`, `material`, `mass_g` with `mass_basis` (McMaster's listed weight when the
   page gives one, otherwise CAD volume x density, which it says), `cad` (the normalised STEP path), `frame`, and
   `specs.raw` (label → value) with `specs.parsed` (mm, g, N, MPa, deg C). Add what only the project knows:
   `used_for`, the quantity, and notes (stack and engagement arithmetic, CAD changes needed). Fields you add are kept
   when the entry is refreshed.
4. **Check the model.** Compare `bbox_mm` with the page's dimensions (a bearing's OD and width, a screw's length below
   the head, a rod end's centre-to-end length). A mismatch means the wrong frame or the wrong part.
5. **Place it in the assembly.** Import `<PN>.norm.step` and move it to the seat: for a screw, origin on the seat face
   and +Z out of the hole; for a bearing, the bottom face on the shoulder. Run the clash and tool-access checks
   ([Fasteners and assembly access](../../lessons/mechanical/fasteners-and-assembly-access.md)) with the real heads, nuts and washers in place, not envelopes.

## Python

```python
import json

from cadagent.mechanical import mcmaster as mc

with mc.Session(delay_s=3) as s:                    # one browser, one page at a time
    step = s.fetch("5972K82", "references/vendor/mcmaster/5972K82")
norm, info = mc.normalise(step, "bearing", material="Steel")
page = json.loads((step.parent / "5972K82.page.json").read_text())
mc.update_catalog("catalog/hardware.json", "bearing_6001",
                  mc.catalog_entry(page, info, cad=str(norm)) | {"used_for": "knee", "qty": 4})
```
