angi-mcp
# angi-mcp
MCP server for [Angi](https://www.angi.com) (formerly Angie's List) — find
home-service pros by trade and city, and read their ratings, profiles and
reviews.
Angi serves its pages only to a real browser, so requests route through the
user's own `angi.com` tab via the [ContextMint Bridge](https://github.com/nullnet-app/contextmint-bridge)
browser extension ([fetchproxy](https://github.com/chrischall/fetchproxy) protocol), reusing their existing session. The trade/city taxonomy is
read directly from Angi's public sitemaps and needs no browser at all.
**No Angi account or credentials are required.** Everything this server reads
is public.
> This project was developed and is maintained by AI (Claude). Use at your own
> discretion.
## Install
```sh
npm install -g @chrischall/angi-mcp
```
Register it with your MCP host:
```json
{
"mcpServers": {
"angi": { "command": "angi-mcp" }
}
}
```
You also need the **ContextMint Bridge** browser extension, with an open
`angi.com` tab and its site access allowing `angi.com`. Install it from the
[ContextMint Bridge releases](https://github.com/nullnet-app/contextmint-bridge/releases):
unzip the Chrome build and load it via `chrome://extensions` → *Load
unpacked*. Safari isn't available yet (it will ship inside the ContextMint app,
which has no public download), so use Chrome for now. On the first request the
extension shows a pairing code to approve; the trust then persists.
ContextMint Bridge is the fetchproxy browser extension under its new name, from
the same maintainer — fetchproxy's own README
(https://github.com/chrischall/fetchproxy#extension) points to it. Its source is
public at https://github.com/nullnet-app/contextmint-bridge: build it yourself,
or check a release zip against the `.sha256` file published beside it
(`shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256`).
Run `angi_healthcheck` to confirm the bridge is connected.
## Tools
| Tool | What it does |
| --- | --- |
| `angi_search_pros` | Pros for a trade in a US city, with ratings, review counts, years in business, service area, amenities. 10 per page. |
| `angi_get_pro` | One pro's full profile and ratings breakdown. |
| `angi_get_reviews` | Reviews on a pro's profile — rating, text, reported cost, date, categories, the pro's response. Filterable by rating. |
| `angi_list_trades` | Every trade slug Angi publishes (~312). No bridge needed. |
| `angi_list_cities` | Cities Angi publishes pages for, per trade. No bridge needed. |
| `angi_healthcheck` | Bridge connection state. |
Signed-in tools (need the browser tab signed in to Angi):
| Tool | What it does |
| --- | --- |
| `angi_get_account` | Your name, email and open/closed project counts. |
| `angi_list_my_projects` | Your Angi projects, open and closed. |
| `angi_list_my_reviews` | Reviews you've written, plus pros awaiting a rating. |
Searches take **slugs**, not free text — resolve them first:
```
angi_list_trades { contains: "duct" } -> "air-duct-cleaning"
angi_list_cities { trade: "plumbing", state: "nc", contains: "char" }
angi_search_pros { trade: "plumbing", state: "nc", city: "charlotte" }
```
`angi_search_pros`, `angi_get_pro` and `angi_get_reviews` answer in the slim
`view: "compact"` projection by default; pass `view: "full"` for Angi's whole
~1KB records. (The old `compact` boolean still works as a deprecated alias and
will be removed in a later release.)
### Ratings
Each pro carries two overall ratings and they differ on purpose:
- `rating` (`averageRatings.OVERALL`) — unrounded. **Rank on this.**
- `displayRating` (`averageOverallRating`) — the rounded value Angi shows.
Per-dimension ratings (quality, value, punctuality, professionalism,
responsiveness) come through in the full record.
`isSponsored: true` marks paid placement, not a quality signal.
## Limits
- **No zip-code filtering.** Angi's `?zip=` parameter is inert — a Charlotte URL
returns Charlotte pros regardless. Location comes from the city slug.
- **Account record shapes are unverified.** The account used to map
`my.angi.com` held zero projects and zero reviews, so only the *envelopes*
were observed. `angi_list_my_projects` and `angi_list_my_reviews` return
records raw and set `recordFieldsVerified: false` rather than projecting onto
field names nobody has seen. See `docs/ANGI-API.md`.
- **The inbox is not readable.** Angi's messages run on the Twilio
Conversations SDK; the proxy endpoints reject the session cookie alone (401),
so messages need the Twilio client rather than an HTTP GET.
- **Cannot be hosted remotely.** Like every browser-bridge server in this fleet,
it needs a signed-in tab on the machine it runs on, so it cannot be served to
claude.ai from mcp-host.
## Without the MCP
`skills/angi-fpx/` is a shell-out skill that reads the same data with the `fpx`
CLI and no running server — useful in scripts or on a machine where the MCP
isn't installed.
## Development
```sh
npm install
npm run build # tsc --noEmit + esbuild bundle
npm test
```
`docs/ANGI-API.md` records the live-captured request/response shapes, including
the verified negative results. Read it before changing `src/parse.ts`.
## License
MIT
TDQS
Scored across 9 tools
Each tool targets a distinct resource+action: list_trades/list_cities resolve slugs, search_pros finds pros, get_pro/get_reviews read one pro, list_my_reviews/list_my_projects read the signed-in user's data, get_account reads identity, and healthcheck diagnoses hops. The potentially confusable pair (list_my_reviews vs get_reviews) is clearly separated by 'signed-in user's own reviews' vs 'reviews on a pro's page'. No two tools appear to do the same thing.
Uniform angi_ prefix with consistent snake_case verb_noun structure (list_, get_, search_) throughout. The one-word healthcheck is a trivial deviation and still fits the prefix pattern.
Nine tools is well-scoped for a read-oriented Angi browsing server, with each tool earning its place (slug resolvers, search/get pairs, user data, diagnostics). No redundant or filler tools.
Covers the core read surface (search pros, pro detail, reviews, trades, cities, account, projects) but has notable gaps: no way to read the messages whose unread count is reported, and no create/submit operation for service requests or projects despite listing them. Read-only design is coherent, but the lifecycle is incomplete.