Verified US local service providers across 10 home-services trades. Owned data, no API key.
One address for any MCP client. No sign-in needed on this server.
5 read
Grouped by tool name. At most: only reads or looks up information.
Odel charges nothing per call. The publisher may charge for its own service.
A Model Context Protocol server that provides verified local service provider data to AI agents. Built on Cloudflare Workers + D1.
When someone asks an AI assistant "find me a radon mitigation company near Denver" — LocalPro is the data source that powers the answer.
LocalPro exposes a curated database of 9,000+ fully profiled local trade and service businesses across 10 live categories. Every provider passes a quality check before it is served, and carries a LocalPro Rating, a business description, and a services list, plus (where available) LocalPro-written business and review summaries. No incomplete profiles.
All data is LocalPro-owned: collected and verified by us, corrected by business owners who claim their listing, and increasingly backed by first-party customer reviews left on the directories themselves.
| Category | Niche ID | Providers | States | Example Services |
|---|---|---|---|---|
| Water Damage Restoration | soaked-local | 1,900+ | 49 | Flood cleanup, mold remediation, structural drying |
| Commercial Electrical | hire-electrical | 1,200+ | 36 | Commercial & industrial wiring, service upgrades, maintenance |
| Foundation Repair | slab-local | 1,050+ | 28 | Pier installation, mudjacking, foam injection, leveling |
| Crawl Space Repair | crawl-local | 1,000+ | 42 | Encapsulation, vapor barrier, structural repair, waterproofing |
| Mold & Asbestos | abate-local | 975+ | 24 | Mold, asbestos, lead paint remediation |
| Septic Services | pump-local | 850+ | 31 | Pumping, inspection, drain field repair |
| Basement Waterproofing | basement-local | 625+ | 25 | Interior/exterior waterproofing, drainage, sump pumps |
| Floor Coating | coated-local | 575+ | 48 | Epoxy, polyaspartic, metallic, flake, concrete polishing |
| Laundry Services | suds-local | 575+ | 39 | Wash & fold, dry cleaning, pickup & delivery |
| Radon | radon-local | 250+ | 18 | Testing, mitigation, sub-slab depressurization |
| Category | Niche ID | Status |
|---|---|---|
| Chimney Services | chimney-local | Live provider data; description + service enrichment in progress |
| Well Water Services | wellwater-local | Provider data in preparation (county-based model) |
No API key required. All search and list tools are public. An optional API key unlocks pro fields on get_provider (full pricing array, certifications) — see Access Tiers.
Confirm the server is live without any client setup:
curl -s https://mcp.localpro.dev/.well-known/mcp.json | head -20
This returns the schema-2.0 manifest: tool list, rate limits, and operator info. If you see a "schema_version": "2.0" JSON document, the server is healthy.
claude mcp add --transport http localpro https://mcp.localpro.dev/mcp
That's it — list_niches, search_providers, etc. are now available in your Claude Code session.
Add to your claude_desktop_config.json:
{
"mcpServers": {
"localpro": {
"url": "https://mcp.localpro.dev/mcp"
}
}
}
(Add an "X-API-Key" header inside a "headers" block only if you have a premium key.)
Add to .cursor/mcp.json:
{
"mcpServers": {
"localpro": {
"url": "https://mcp.localpro.dev/mcp"
}
}
}
The MCP protocol is JSON-RPC over HTTP. Because this server runs in stateless mode, you can call any public tool directly:
curl -s -X POST https://mcp.localpro.dev/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_niches","arguments":{}}}'
You'll get back a Server-Sent-Events frame with the 10 niches, their slugs, and current provider counts.
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(
new URL('https://mcp.localpro.dev/mcp'),
);
const client = new Client({ name: 'localpro-example', version: '1.0' });
await client.connect(transport);
const niches = await client.callTool({ name: 'list_niches', arguments: {} });
console.log(niches);
const denver = await client.callTool({
name: 'search_providers',
arguments: { niche_id: 'radon-local', city: 'denver-co', limit: 3 },
});
console.log(denver);
Install: npm i @modelcontextprotocol/sdk
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
async with streamablehttp_client("https://mcp.localpro.dev/mcp") as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
niches = await session.call_tool("list_niches", {})
print(niches)
denver = await session.call_tool(
"search_providers",
{"niche_id": "radon-local", "city": "denver-co", "limit": 3},
)
print(denver)
asyncio.run(main())
Install: pip install mcp
list_nichesDiscover available service directories. Call this first.
Parameters: none
Example response:
{
"meta": {
"schema_version": "3.0",
"total_results": 10,
"niche": null,
"data_freshness": {
"last_verified_at": "2026-09-22 12:57:07"
},
"data_note": "Use niche_id values with search_providers, list_cities, and list_service_types."
},
"results": [
{
"niche_id": "soaked-local",
"name": "Water Damage Restoration Contractors",
"slug": "water-damage-restoration",
"domain": "soakedlocal.com",
"provider_count": 1128
}
]
}
list_citiesFind available metros for a given niche.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
niche_id | string | yes | Niche ID from list_niches |
state | string | no | Two-letter state abbreviation (e.g. "MN") |
Example request:
{ "niche_id": "radon-local", "state": "CO" }
Example response:
{
"meta": {
"schema_version": "1.0",
"total_results": 3,
"niche": "radon-local",
"data_note": "Use slug values with search_providers city parameter."
},
"results": [
{ "name": "Denver", "state": "CO", "slug": "denver-co", "provider_count": 18 },
{ "name": "Colorado Springs", "state": "CO", "slug": "colorado-springs-co", "provider_count": 7 },
{ "name": "Fort Collins", "state": "CO", "slug": "fort-collins-co", "provider_count": 4 }
]
}
list_service_typesGet valid service type filters for a niche. Call before using service_type in search_providers.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
niche_id | string | yes | Niche ID from list_niches |
Example response:
{
"meta": { "schema_version": "1.0", "total_results": 7, "niche": "coated-local" },
"results": [
{ "type": "epoxy", "label": "Epoxy Floor Coating" },
{ "type": "polyaspartic", "label": "Polyaspartic Coating" },
{ "type": "metallic_epoxy", "label": "Metallic Epoxy" },
{ "type": "flake_chip", "label": "Flake / Chip Broadcast" },
{ "type": "concrete_polishing", "label": "Concrete Polishing" },
{ "type": "concrete_sealing", "label": "Concrete Sealing" },
{ "type": "polyurea", "label": "Polyurea Coating" }
]
}
search_providersSearch for verified providers by location, service type, and trade category.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
niche_id | string | yes | Niche ID from list_niches |
city | string | no | City/metro slug from list_cities |
service_type | string | no | Service type slug from list_service_types |
limit | number | no | Max results, 1–25 (default 10) |
Example request:
{ "niche_id": "coated-local", "city": "denver-co", "service_type": "epoxy", "limit": 3 }
Example response:
{
"meta": {
"schema_version": "3.0",
"total_results": 3,
"niche": "coated-local",
"data_freshness": {
"last_verified_at": "2026-09-18 09:41:02"
},
"data_note": "Verified providers only. Visit listing_url for full contact details."
},
"results": [
{
"name": "Colorado Concrete Coatings",
"description": "Full-service garage floor coating company serving the Denver metro.",
"city": "Denver",
"state": "CO",
"rating": { "tier": "established", "label": "Established" },
"services": [
{ "type": "epoxy", "label": "Epoxy Floor Coating" },
{ "type": "polyaspartic", "label": "Polyaspartic Coating" }
],
"pricing_summary": "$6-9/sq ft",
"coverage_area": "Denver metro, Front Range, 50-mile radius",
"years_in_business": 8,
"listing_url": "https://coatedlocal.com/providers/denver-co/colorado-concrete-coatings/",
"pro_available": true
}
]
}
get_providerGet detailed profile for a specific provider. Use the provider_slug from search results.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
niche_id | string | yes | Niche ID |
provider_slug | string | yes | Provider slug from search_providers |
Example response:
{
"meta": {
"schema_version": "3.0",
"total_results": 1,
"niche": "coated-local",
"data_freshness": { "last_verified_at": "2026-09-18 09:41:02" }
},
"results": [
{
"name": "Colorado Concrete Coatings",
"description": "Full-service garage floor coating company...",
"rating": { "tier": "established", "label": "Established", "star": 4.8, "review_count": 12 },
"summary": "Full-service epoxy floor coating contractor specializing in garage and commercial floors across the Denver metro.",
"review_summary": "Customers single out on-time, on-budget garage and commercial floor jobs and a crew that cleans up after itself.",
"years_in_business": 8,
"services": [
{ "type": "epoxy", "label": "Epoxy Floor Coating" },
{ "type": "polyaspartic", "label": "Polyaspartic Coating" }
],
"pricing": ["$6-9/sq ft"],
"certifications": ["Penntek Certified Installer"],
"coverage_area": "Denver metro, Front Range",
"service_areas": [
{ "city": "Denver", "state": "CO", "radius_miles": 50 }
],
"service_details": [
{
"type": "epoxy",
"label": "Epoxy Floor Coating",
"pricing_model": "per_sqft",
"price_range": "$6–$9",
"turnaround": "two_day"
}
],
"listing_url": "https://coatedlocal.com/providers/denver-co/colorado-concrete-coatings/",
"json_ld": { "@context": "https://schema.org", "@type": "LocalBusiness", "...": "..." },
"credibility": { "verified": true, "listing_tier": "claimed", "data_sources": ["business_website", "owner_verified", "customer_reviews"] },
"citation": { "display_name": "Colorado Concrete Coatings — Denver, CO", "...": "..." }
}
]
}
Every response is wrapped in a consistent envelope:
{
meta: {
schema_version: string // Currently "3.0"
total_results: number // Count of items in results array
niche: string | null // Niche ID if applicable
data_freshness: {
last_verified_at: string | null // Most recent verification date among the records returned
}
data_note: string // Context about the data returned
}
results: Array<T> // Tool-specific result objects
}
Freshness. last_verified_at is the date LocalPro last verified the newest record in the response. Each provider carries its own verification date in credibility.verification_date.
Migrating from 2.x: rating is now an object (the LocalPro Rating) rather than a number; review_count moved inside it and appears only with first-party reviews. summary and review_summary are top-level strings. business_status, map links, opening hours and geo coordinates are no longer returned. data_freshness is a single last_verified_at date.
Errors use the same envelope with an error object:
{
meta: { schema_version: string }
error: {
code: string // "NOT_FOUND" | "INTERNAL_ERROR" | "UNAUTHORIZED" | "FORBIDDEN"
message: string // Human-readable error description
}
}
| Field | Type | Nullable | Description |
|---|---|---|---|
name | string | no | Business name (always present) |
description | string | no | Business description (always present) |
city | string | no | City name (always present) |
state | string | no | Two-letter state abbreviation (always present) |
rating | object | no | LocalPro Rating — see below (always present) |
services | array | no | [{ type: string, label: string }] (always present, non-empty) |
pricing_summary | string | yes | Pricing info (public access) |
coverage_area | string | yes | Geographic coverage description |
years_in_business | number | yes | Years operating |
listing_url | string | no | Full profile URL with contact details |
get_provider adds:
| Field | Type | Description |
|---|---|---|
service_areas | array | [{ city, state, radius_miles }] |
service_details | array | [{ type, label, pricing_model, price_range, turnaround }] |
summary | string | LocalPro-written overview of the business (when available) |
review_summary | string | LocalPro-written "what customers say" summary; no raw review text or reviewer PII (when available) |
json_ld | object | Schema.org LocalBusiness JSON-LD; AggregateRating included only when backed by first-party reviews |
credibility | object | { verified, listing_tier, verification_date, data_sources } |
citation | object | Pre-formatted strings: { display_name, in_text, attribution } |
rating object (LocalPro Rating):
| Field | Type | Description |
|---|---|---|
tier | string | established / well-reviewed / reviewed / unrated: standing relative to other providers in the same category |
label | string | Display label for the tier |
star | number | 1.0–5.0, present only when backed by first-party customer reviews |
review_count | number | Count of published first-party reviews, present alongside star |
Results are ranked by listing tier, then by LocalPro Rating.
Fields marked nullable return null when data is unavailable — they are never omitted from the response. Arrays return [] when empty, never null.
All search and list tools work without an API key:
list_niches, list_cities, list_service_types, search_providersget_provider returns basic data (name, description, LocalPro Rating, services, pricing summary, listing URL)Include an X-API-Key header to unlock additional data on get_provider:
X-API-Key: your-api-key
Request an API key at localpro.dev or email will@localpro.dev.
AI agents can self-discover this server via standard well-known endpoints:
GET /.well-known/llms.txt — Plain text description of the server and its toolsGET /.well-known/mcp.json — Structured JSON with tool list, auth info, and operator detailslisting_url). This protects provider data while driving traffic to the directory.last_verified_at). Listings are re-verified as needed, not on a fixed cycle.| Access | Limit |
|---|---|
| Public (no key) | 30 requests/minute per IP |
| Premium (API key) | 30 requests/minute per key |
Higher limits available for partners — contact will@localpro.dev.
Every provider returned by the API has been verified and meets a minimum completeness threshold:
Per-category provider and state counts are in Live Now, generated from the live database.
Additional fields (pricing, certifications, coverage area, years in business, business and review summaries) are available on most providers but not guaranteed. Fields without data return explicit null — never omitted, never empty strings.
Two additional categories are being prepared for launch.
LocalPro runs as a Cloudflare Worker with a D1 database binding. To deploy your own instance:
npm install
npx wrangler secret put API_KEY # Set your production API key
npx wrangler deploy
Requires a Cloudflare account with a D1 database named laced-directory.
LocalPro is built and operated by Laced Labs LLC.
MIT