whodoicallfor-mcp
MCP server that helps users identify which trade to call during home emergencies by analyzing natural-language problem descriptions and providing ranked matches with costs, sources, and dispatch lines.
README
whodoicallfor-mcp
An MCP server that answers the question people actually have during a home emergency: which trade do I call?
Not "find me a plumber." The prior question — is this even a plumber?
The problem
I called a plumber, who told me to call an appliance tech. I called an appliance tech, who told me to call a plumber.
That is the normal experience of a household emergency, and it is expensive. Two trip charges, half a day gone, and the water is still coming through the ceiling. The trades are specialized and their boundaries are invisible from the outside: a stain on your ceiling is a roofer if it tracks the weather, an HVAC tech if it tracks the air conditioning, and a plumber if it tracks the shower upstairs. Water damage after the leak stops is a fourth trade — a mitigation crew — and a plumber will tell you so after you have paid the callout.
This server gives an assistant the routing table. Describe the problem in plain words; get back who to call, in what order, what not to call them for, what it typically costs with a dated source, and — where one exists — a 24/7 dispatch line.
Content comes from the public JSON API at whodoicallfor.com. No auth, no API key, no configuration.
Install
Claude Code
claude mcp add whodoicallfor -- npx -y whodoicallfor-mcp
Cursor — add to ~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"whodoicallfor": {
"command": "npx",
"args": ["-y", "whodoicallfor-mcp"]
}
}
}
Same shape works for Claude Desktop (claude_desktop_config.json), Windsurf, Zed, and anything else that speaks stdio MCP.
Or don't run anything. A hosted instance of this server is live:
https://whodoicallfor.com/api/mcp/
It speaks streamable HTTP, is stateless, and needs no credentials. The trailing slash is required — the slashless URL answers with a 308 redirect, and several MCP clients will not follow a redirect on a POST.
claude mcp add --transport http whodoicallfor https://whodoicallfor.com/api/mcp/
Running it directly
npx whodoicallfor-mcp # stdio (default)
npx whodoicallfor-mcp --http # streamable HTTP on http://localhost:3000/mcp
npx whodoicallfor-mcp --http 8080 # ...on a port you pick
Requires Node 20.19 or newer.
Tools
All three are read-only, idempotent, and touch nothing outside the public API.
| Tool | Arguments | Returns |
|---|---|---|
route_emergency |
problem (required), state (optional) |
Up to 3 ranked situations, best first |
get_scenario |
category, slug |
One situation in full |
list_scenarios |
— | Every published situation with canonical URLs |
route_emergency
Plain-language problem in, ranked situations out. Pass a US state code or name ("FL", "Florida") to filter dispatch numbers down to lines that actually cover that state.
Input
{ "problem": "water coming through my ceiling" }
Output (abridged — the real response carries three matches with full costs, faq, and sources arrays)
{
"matches": [
{
"title": "Water Leaking From the Ceiling — Who Do I Call?",
"category": "water",
"vertical": "water-damage",
"tldr": "What's directly above matters less than timing. Appears or worsens when it rains → roofer. Appears when the AC runs, or only in cooling season → HVAC condensate line. Neither, and it tracks water use upstairs → plumber. If water is still coming, shut the main valve, keep it clear of lights and outlets, and photograph everything before any repair. Renting? The landlord's emergency line comes before any of this.",
"who_to_call": [
{
"who": "Emergency plumber",
"when": "Water is actively dripping or flowing and you can't stop it at the source",
"not_for": "The leak has stopped — a plumber fixes pipes, not soaked drywall"
},
{
"who": "Roofer",
"when": "The stain appears or worsens when it rains and stays quiet in dry weather — usually failed flashing",
"not_for": "The stain tracks showers, washes, or flushes rather than the weather"
}
],
"costs": [
{
"item": "Water-damaged ceiling repair",
"range": "$200–$1,500",
"source": "Fixr",
"source_url": "https://www.fixr.com/costs/ceiling-repair"
}
],
"updated": "2026-08-12",
"url": "https://whodoicallfor.com/water/ceiling-leaking/",
"recommended_call": null,
"match_score": 12
}
],
"state": null
}
The not_for field is the part that saves the wasted trip charge.
When nothing scores high enough, you get an empty matches array plus a note, the category index, and a link to guided triage — rather than a confidently wrong answer.
get_scenario
Fetch one situation in full using category and slug from route_emergency or list_scenarios.
{ "category": "water", "slug": "ceiling-leaking" }
Returns the same structured object, plus body_markdown (the complete step-by-step guide) when the upstream API supplies it.
list_scenarios
No arguments. Returns { site, count, scenarios[] } — every published situation with its title, description, category, slug, updated date, canonical URL, and JSON URL.
How matching works
route_emergency ranks by weighted token overlap between your problem and four fields of each situation: title ×3, description ×2, tldr ×1, and the who/when of each who_to_call step ×1. Tokens are lowercased, stripped of punctuation, filtered against a stopword list, and suffix-folded, so "leaking" matches "leak" and "pipes" matches "pipe". Anything scoring below 3 is discarded; at most three matches come back.
tldr and who_to_call live on the per-page documents rather than the index, so the first route_emergency call warms a full in-memory cache (bounded concurrency, ~2s cold). Subsequent calls are single-digit milliseconds. The index is cached for 10 minutes and page bodies for an hour, so the server never hammers the site.
There is no fuzzy matching, no embedding model, and no network call to anything but whodoicallfor.com. It is a small deterministic function you can read in one sitting: src/match.ts.
Disclosure
Two things worth being plain about.
recommended_call entries are sponsored. They are paid pay-per-call lines, and each one is labeled "sponsored": true in the payload. When a situation carries one, that is the commercial engine behind the site. Treat it as an ad with a phone number, and surface it to users as such — the flag is in the data precisely so you can.
Life-safety numbers are never sponsored. 911, poison control, and gas utility emergency lines carry no recommended_call at all — there is a hard server-side guard that strips it for gas scenarios and for any situation without a commercial vertical. If someone smells gas, the answer is "get out and call the utility from outside," and nobody has paid for that placement. That guard is not a policy preference; it is code, upstream, and this client cannot override it.
Cost figures are cited to a named source with an access date. Verify anything you are about to act on.
Development
npm install
npm run typecheck
npm run build
npm start # stdio
npm run start:http # http on :3000
src/index.ts entry point: tool definitions, stdio + streamable HTTP transports
src/client.ts cached fetches against the public JSON endpoints
src/match.ts token-overlap ranking
Coverage
US-focused. Around 40 situations across water and flooding, gas and carbon monoxide, power and electrical, heating and cooling, appliances, pests and wildlife, lockouts, car trouble, and disputes with landlords and contractors. list_scenarios always reflects what is actually published.
License
MIT © Daniel Widmonte
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.