Metadata-Version: 2.4
Name: wagefinder
Version: 0.1.0
Summary: Command-line client and MCP server for US prevailing-wage data from the WageFinder API
Keywords: prevailing wage,davis-bacon,construction,mcp,cli,agents
Classifier: Programming Language :: Python :: 3
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# wagefinder

Command-line client and MCP server for [WageFinder](https://wagefinder.org), an API of US prevailing-wage determinations. One install gives you a `wagefinder` command for your terminal and a Model Context Protocol server, so AI agents can look up what a trade must be paid on a public works job and cite the government document it came from.

- **Coverage:** about 1.9 million wage records. Federal Davis-Bacon determinations (SAM.gov) for all 50 states, DC and the territories, plus state sources (California, Illinois, New Jersey, New York, Ohio, Washington) and the City of Houston.
- **Every record links to its source:** the `url` field points at the SAM.gov page or the agency PDF the rate was read from.
- **No dependencies:** standard-library Python 3.9+. Nothing else to install.

## Install

```bash
pipx install wagefinder      # or: pip install wagefinder
uvx wagefinder --help        # or run it without installing, using uv
```

From a checkout of this repository: `pip install .`, or `python -m wagefinder` with no install at all.

## API key

Every command except `health` needs an API key. Get one at [wagefinder.org/developers](https://wagefinder.org/developers), then put it in your environment:

```bash
export WF_API_KEY="your_key"                 # macOS / Linux
$env:WF_API_KEY = "your_key"                 # PowerShell, current session
setx WF_API_KEY "your_key"                   # Windows, future sessions
```

`--api-key` works too, but anything typed on a command line ends up in shell history, so prefer the environment variable. A key may be limited to certain states; `wagefinder states` shows which ones yours can read.

## Use it from the terminal

```bash
# Find a record by free text, then fetch its rates
wagefinder search "electrician cook county"
wagefinder wage <taxonomy_slug>

# Browse: states -> counties -> wages
wagefinder states
wagefinder counties "new york"
wagefinder wages --state "new york" --county Albany --classification carpenter

# Narrow further
wagefinder wages --state ohio --county Franklin --union-status union --construction-type Building
wagefinder wages --state california --zip-code 94103 --limit 100 --offset 100

# Historical rates
wagefinder versions --state california
wagefinder wages --state california --county Alameda --version 2025-1

# Lookups
wagefinder classifications --state washington --county King
wagefinder construction-types
wagefinder zip-codes --state "new jersey" --county Bergen
wagefinder usage --days 30
```

`wagefinder <command> --help` documents every option. Output is JSON on stdout, so it pipes straight into `jq`:

```bash
wagefinder wages --state "new york" --county Albany --classification electrician \
  | jq -r '.data[] | [.name, .wage_rate, .fringe_rate, .effective_date] | @tsv'
```

### Commands

| Command | What it returns |
| --- | --- |
| `health` | API status and record count (no key needed) |
| `states` | States your key can query |
| `counties STATE` | Counties with data in a state |
| `construction-types` | Construction-type buckets (Building, Heavy, Highway, ...) |
| `zip-codes --state S [--county C]` | ZIP codes covered |
| `classifications [filters]` | Distinct trade/classification names, paginated |
| `wages [filters]` | Wage records with rates; needs at least two filters |
| `wage SLUG` | One record in full, including the fringe breakdown and determination details |
| `search QUERY` | Free-text hits (no rates); use `wage` on a hit's slug |
| `versions [--state S]` | Historical versions available per state and source |
| `usage [--days N]` | Your recent request counts and remaining quota |

### Output and exit codes

- Success: the API's JSON response on stdout, exit code `0`.
- API or network error: a one-line JSON object on stderr, exit code `1`, for example `{"error": "Invalid API key.", "status": 403}`. On a rate limit (`429`) it also carries `retry_after_seconds`.
- Bad command-line usage: argparse's message on stderr, exit code `2`.

## Use it from an AI agent

### Any agent with a shell

Agents that can run commands (Claude Code, Codex, Cursor's agent, Aider, ...) can use the CLI directly. Set `WF_API_KEY` in the agent's environment and tell it the tool exists, for example in `CLAUDE.md` or `AGENTS.md`:

```markdown
Prevailing wages: run `wagefinder --help`. Typical flow: `wagefinder search "<trade> <county>"`,
then `wagefinder wage <taxonomy_slug>`. Output is JSON. Cite each record's `url`.
```

### As an MCP server

`wagefinder mcp` runs a Model Context Protocol server on stdio, with one tool per command (`search`, `wage`, `wages`, `states`, `counties`, `classifications`, `construction_types`, `zip_codes`, `versions`, `usage`, `health`). All tools are read-only.

**Claude Code:**

```bash
claude mcp add wagefinder --env WF_API_KEY=your_key -- uvx wagefinder mcp
```

**Claude Desktop, Cursor, Windsurf and other clients** take the usual JSON config (Claude Desktop: `claude_desktop_config.json`; Cursor: `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "wagefinder": {
      "command": "uvx",
      "args": ["wagefinder", "mcp"],
      "env": { "WF_API_KEY": "your_key" }
    }
  }
}
```

If you installed with pip or pipx instead of using uv, set `"command": "wagefinder"` and `"args": ["mcp"]`.

Then ask things like *"What's the prevailing wage for a union electrician in Cook County, Illinois, and where does that number come from?"*

## Configuration

| Variable | Default | Purpose |
| --- | --- | --- |
| `WF_API_KEY` | none | Your API key |
| `WF_BASE_URL` | `https://wagefinder-api.up.railway.app` | API base URL (point it at a local or staging API) |

## Development

```bash
python -m unittest discover -s tests
```

The tests run the CLI and the MCP server against a local stub API, so they need no key and no network.

## Data notice

Prevailing-wage rates are published by federal, state and city agencies and change often. WageFinder normalizes them but is not the issuing authority: before relying on a rate for payroll or a bid, check the source document linked in the record's `url`.
