MCP server
Connect an AI agent to ContractorsNearMe's contractor directory over the Model Context Protocol.
ContractorsNearMe runs a remote MCP server. Through it, an agent can search the contractor directory, read profiles, reviews and availability, and find public invitations to bid. With an API key, it can also send leads and reviews, or manage a contractor’s own leads and profile.
| Endpoint | https://contractorsnearme.ai/api/mcp |
| Transport | Streamable HTTP, stateless, JSON responses (POST only; GET returns 405) |
| Server | contractors-near-me 1.3.0, protocol 2025-06-18 |
| Auth | None for read tools. Write tools need an x-api-key header. |
Connect
Claude Code
claude mcp add contractors-near-me --transport http https://contractorsnearme.ai/api/mcpOpenCode
{ "$schema": "https://opencode.ai/config.json", "mcp": { "contractors-near-me": { "type": "remote", "url": "https://contractorsnearme.ai/api/mcp", "enabled": true } }}Other MCP clients (Cursor, Claude Desktop and others)
{ "mcpServers": { "contractors-near-me": { "url": "https://contractorsnearme.ai/api/mcp" } }}To use write tools, add "headers": { "x-api-key": "<your key>" } to the server entry. Use your client’s environment-variable syntax instead of pasting the key into a shared file.
There is no npm package for this server. Older pages that mention npx @contractorsnearme/mcp-server are wrong: use the remote URL above.
Test it with curl
The server requires an Accept header that allows both JSON and event streams. Without it, every call fails with JSON-RPC error -32000 (“Not Acceptable”).
curl -sS -X POST https://contractorsnearme.ai/api/mcp \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{ "name":"search_contractors", "arguments":{"trade":"roofing","city":"Austin","state":"TX","limit":2}}}'The tool result is JSON inside result.content[0].text:
{ "contractors": [ { "contractor_id": "…", "company_name": "…", "slug": "…", "city": "Austin", "state_code": "TX", "avg_rating": 5, "is_verified": false, "primary_trade": { "name": "Roofers", "slug": "roofing" }, "profile_url": "https://contractorsnearme.ai/tx/austin/…" } ], "count": 2}Tools
Read tools (no key)
| Tool | Arguments | Returns |
|---|---|---|
search_contractors | trade, state (2 letters), city, q (name or keywords), lat + lng, radius_miles (1-200, default 25), limit (1-50, default 20). Give at least one of trade, state, city, q, or lat+lng. | contractors[], count |
get_contractor | slug (required) | Full profile: about text, phone, website, rating, is_verified, primary trade, profile_url |
get_reviews | contractor_slug (required), limit (1-50, default 10) | Newest reviews: rating, text, reviewer name, title, dates |
list_trades | none | All trades with slug. Use these slugs for trade. |
get_availability | slug (required) | Published availability (days, start, end, timezone, note), or null with “No availability published” |
search_itbs | query, city, state_code, limit (1-50) | Open public invitations to bid: title, description, budget range, city, status |
get_itb | itb_id (UUID, required) | One invitation to bid in full |
list_marketplace_requests | q, limit | Public marketplace requests (currently returns none) |
get_marketplace_request | id_or_slug (required), state_code, city_slug | One marketplace request |
Write tools (API key)
| Tool | Arguments | Effect |
|---|---|---|
submit_lead | name, email, message (10+ characters) required; phone, contractor_slug, trade_slug | Sends a lead to a contractor (or a trade). Limit 10 per hour per key. |
submit_review | contractor_slug, rating (1-5), description (20+ characters), reviewer_name required; title and sub-ratings for cleanliness, communication, quality, timeliness, value | Submits a review. It’s held for moderation before it appears. Limit 5 per hour per key. |
get_my_leads | status, limit (1-100) | The key owner’s leads. Needs a contractor key on a paid plan. |
respond_to_lead | lead_id (required), status (new, contacted, qualified, converted, lost), note (up to 2,000 characters) | Updates one of the key owner’s leads. Paid plan. |
update_my_profile | Any of company_name, dba, phone, email, website, about_text, quote, license_number, year_established, company_size | Edits the key owner’s directory profile. Paid plan. |
Leads sent through the MCP server go to the contractor’s ContractorsNearMe profile. They don’t appear in the contractor’s MyBuildX Leads list.
API keys
Keys look like cnm_… and are tied to one contractor profile. They’re issued by BuildX support to contractors with an active Contractor ID subscription; there’s no self-serve key page yet. To ask for one, file a ticket. A key is shown once; store it as a secret.
Errors and limits
- Tool errors don’t use HTTP status codes. The call returns
200with"isError": trueand a message incontent[0].text, for exampleInvalid trade slugorAPI key required to view leads. - Rate limits: 100 requests a minute per IP without a key, 1,000 a minute with a key, plus the per-tool write limits above. Over the limit you get HTTP
429withRetry-After. Limits are approximate and can reset when the service redeploys, so don’t design around exact numbers. - Browser calls are allowed only from contractorsnearme.ai, claude.ai and chatgpt.com; other web origins get
403. Server-side calls (noOriginheader) always work. get_contractorcan include a contractor’s email address. Don’t repeat it to users unless they ask for contact details; link theprofile_urlinstead.

