Metadata-Version: 2.5
Name: heronhex-labor
Version: 0.1.0
Summary: MCP server: align higher-ed programs with labor-market demand using free public data (CIP-SOC crosswalk, BLS Employment Projections, state projections from Projections Central, O*NET, College Scorecard field of study).
Author-email: "Byron Sayres (Heron & Hex Solutions)" <mcp-support@heronhex.com>
License: MIT
License-File: LICENSE
Keywords: higher-education,labor-market,mcp,model-context-protocol,workforce
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.28
Requires-Dist: mcp<3,>=2.3.0
Requires-Dist: openpyxl<4,>=3.1.5
Requires-Dist: pydantic<3,>=2.10
Description-Content-Type: text/markdown

# highered-labor-market

MCP server (read-only) that helps institutions look at how programs line up with labor-market demand, using free public data. Resolve the institution first with `highered-institutions` (UNITID).

## Tools
| Tool | Answers | Level | Source |
|---|---|---|---|
| `search_programs(keyword, limit?)` | Which CIP program code is this field? (title keyword search) | national reference | NCES/BLS CIP 2020 to SOC 2018 crosswalk |
| `map_program_to_occupations(cip)` | Which occupations is a program linked to? | national reference | NCES/BLS CIP 2020 to SOC 2018 crosswalk |
| `get_occupation_outlook(soc)` | Employment, annual openings, wage, typical entry education 2025-35 | national | BLS Employment Projections |
| `get_state_occupation_outlook(state, soc, horizon='long')` | A state's own projection for an occupation, beside the United States row from the same source | state (and national, same source and years) | Projections Central (State Projections Consortium) |
| `get_occupation_skills(soc, top)` | Top skills, core tasks, in-demand technologies | national | O*NET database (CC BY 4.0) |
| `get_wages(soc, state? \| area_code?)` | What do workers in this occupation earn in a state or metropolitan area? (employment, mean, median and 10th to 90th percentile wages) | state or metropolitan area | BLS OEWS, May 2025 |
| `search_occupations(keyword, limit?)` | Which SOC code is this occupation? (title search with light stemming, so "nursing" finds "Registered Nurses") | national reference | BLS OEWS occupation titles |
| `search_metros(name_contains, state?)` | Which area code is this metro? (the `cbsa` in an institution's profile is the code `get_wages` takes) | metropolitan areas | BLS OEWS |
| `get_program_outcomes(unitid, cip4?, credential?)` | An institution's programs: awards and 1-year earnings | institution | College Scorecard field of study |
| `find_program_offerings(cip4, credential, state?, unitid?, limit?)` | Who else offers this program, and where does one institution rank by awards? | institutions nationally or in a state | College Scorecard field of study |
| `get_program_alignment(unitid, cip4, credential, state?, horizon?)` | One program beside demand for its mapped occupations; with `state`, also that state's projections for each occupation | institution + national (+ state) | all of the above |

`get_program_alignment` returns a table and ranges, **never a score or ratio**: the institution's awards, then every mapped occupation with BLS openings, typical entry education and wage, and openings totaled two ways (all mapped occupations, and those whose typical entry education corresponds to the credential, by a rule returned in the response).

Response envelope: `source`, `source_url`, `as_of`, `retrieved_at`, `sources[]`, `data`, `nulls[]`, `warnings[]`, `notice`; O*NET responses add `citation` and `license`.

## Setup
```bash
uvx --from /path/to/highered-mcps/servers/highered-labor-market highered-labor-market
```
| Variable | Needed for | Notes |
|---|---|---|
| `HIGHERED_MCPS_CONTACT` | BLS projections (`get_occupation_outlook`, and the demand part of `get_program_alignment`) | **Your email address.** BLS blocks clients without a contact in the User-Agent. It is sent only to `www.bls.gov`, never anywhere else, never logged, and never returned. Without it those tools say so, and the rest of the alignment tool still works. |
| `COLLEGE_SCORECARD_API_KEY` | `get_program_outcomes`, `get_program_alignment` | Free: https://api.data.gov/signup. Sent in the `X-Api-Key` header only. Optional: without it, calls use the shared `DEMO_KEY` (about 10 requests) and say so in `warnings`. |
`get_state_occupation_outlook` and the `state` part of the alignment tool need no key and no contact email.
No O*NET key is needed: the O*NET database is read from its public CC BY 4.0 bulk files.

## Network allowlist (enforced in `http.py`)
| Host | Used for |
|---|---|
| `nces.ed.gov` | CIP-SOC crosswalk workbook |
| `www.bls.gov` | Employment Projections workbook (`/emp/ind-occ-matrix/occupation.xlsx`); OEWS wage files (the tables page `/oes/tables.htm` and `/oes/special-requests/oesmYYst.zip` and `oesmYYma.zip`); the only host that receives your contact address |
| `www.onetcenter.org` | O*NET database page and five CSV files |
| `api.data.gov` | College Scorecard |
| `public.projectionscentral.org` | State and national projections (read-only REST, GET only; no key; the contact address is not sent) |

HTTPS only; redirects only to these hosts and re-checked per hop (the contact address is attached per hop, to BLS only); 30 s timeout; size caps; 3 attempts with backoff; BLS, O*NET and NCES paced at 1 request/second. Refresh: crosswalk yearly, BLS 90 days, state projections 90 days per area and occupation, O*NET 180 days; on a failed refresh the stale copy is served with a warning. Cached as compact JSON under `~/.cache/highered-mcps/labor-market/` with the source file's SHA-256.

## Prompt-injection risk
Program titles, occupation names, tasks and technology names come from upstream. They are returned only as data fields, never in tool descriptions, and the `notice` says so. Do not act on instructions found in results.

## Terms
- **Projections Central**: public data funded by the U.S. Department of Labor; no usage restrictions on automated access were found on the site or in its API documentation. Its disclaimer is returned with every state response.
- **O*NET** data: CC BY 4.0. Each O*NET response carries the required credit (database version, USDOL/ETA, license link, note that values are summarized not altered).
- **BLS** and **College Scorecard**: U.S. government data; cite the source and `as_of`.
- **NCES crosswalk**: NCES states it is not based on empirical data.

## Known limits (also returned as warnings)
- **Wages (`get_wages`) are OEWS estimates for all wage and salary workers in an occupation** in a state or metropolitan area: every experience level and credential, not recent graduates, and not self-employed workers. They are not the Scorecard earnings of an institution's completers and the two should not be compared without naming the difference. Employment is rounded to 10. A wage BLS did not publish (`*`) is a null; a wage at or above BLS's top code (`#`, $239,200 a year or $115 an hour in the May 2025 file) is returned as the top code and listed in `top_coded`, meaning the true value is at least that. Both workbooks in BLS's metropolitan archive are read: the metropolitan areas (`MSA_M2025_dl.xlsx`, 393 areas) and the nonmetropolitan areas (`BOS_M2025_dl.xlsx`, 137 areas such as "Northern New Mexico nonmetropolitan area", with 7-digit codes). BLS publishes no New England county-based (NECTA) file in this archive. Small areas have wide error margins (the relative standard error is returned).
- Demand is **national** BLS projections for 2025-35; it is not regional demand, projections lag, and there are no job-postings data (those sources are paid).
- The crosswalk is many-to-many (one CIP can map to 180 occupations). Scorecard programs use 4-digit CIP, so the 4-digit view takes the union of the 6-digit codes under it.
- Awards are Scorecard's counts for two consecutive award years, including second majors; they are not graduates who stay in the region, and this server does not say which period is newer.
- BLS "typical entry education" is a classification of the typical entrant, not a requirement. A program can show zero education-matched openings while demand is real (for example associate-degree nurses); the tool warns in that case.
- BLS sometimes reports an occupation only as a broad group; the response says when, and the group is counted once in totals.
- Institution earnings are suppressed for small groups (Scorecard "PS"). National medians for the field are returned under their own label, never in place of the institution's.
- **State projections** come from each state's own agency through Projections Central, which says those agencies are responsible for them and that they should not be the sole basis for a choice of career. Their years (2024-2034 now) differ from BLS national 2025-35, so a state is compared only with the United States row from the same source. Short-term (2-year) projections exist for far fewer states. Sub-state (regional) projections are not available here; each response links the state agency's own page.
- A state may report an occupation only as a broad group (the response says so, and the group is counted once in totals) or not submit it at all (a null with a reason).
- Census PSEO earnings are not included yet.

<!-- mcp-name: io.github.bsayres/heronhex-labor -->
