{"apiVersion":"v1","directorySlug":"theplumbingapp-mcp-bd03f9f807","title":"The Plumbing App","description":null,"pageUrl":"https://www.mcpbundles.com/skills/theplumbingapp-mcp-bd03f9f807","connectPath":"importable","connectAction":"import_server","catalogListing":false,"bundleSlug":null,"listingKind":"remote_mcp","kind":"provider","transportUrl":"https://mcp.theplumbingapp.com/mcp","hostedMcpUrl":null,"toolCount":23,"toolInventoryStatus":"observed","refreshedAt":"2026-11-03T13:26:00.516172+00:00","registryName":"com.theplumbingapp/theplumbingapp-mcp-bd03f9f807","registryVersion":"2026.11.3","registryEligible":true,"tools":[{"name":"lookup_caller","description":"REQUIRED FIRST TOOL on every inbound call — call with empty {} if you have no phone. Identifies caller (ANI recovered server-side from the phone bridge). If is_admin=true: greet by name and ASK if they want to work on the voice AI (prompts, routing, agent setup) or a plumbing matter; use say_in_greeting. If is_admin=false: customer only — never discuss prompts/config. Also returns service_locations, service_zips, primary_service_zip, and service_area (in/out of company service area) when locatio","inputSchema":{"type":"object","properties":{"phone":{"type":"string"},"caller_id":{"type":"string"},"from_number":{"type":"string"},"caller_phone":{"type":"string"}}},"logicalName":"lookup_caller","displayName":"lookup_caller","title":"lookup_caller","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"book_job","description":"THE ONLY WAY TO BOOK. Call this (or create_appointment) after you have name, SMS phone, service address, billing same yes/no, and preferred time. Creates customer + location + contacts if new, then job + appointment. If you do not call this tool, NOTHING is saved and they are NOT booked. Never say they are booked unless this tool returns success and office_must_confirm is false.","inputSchema":{"type":"object","required":["customer_name","phone","service_address"],"properties":{"when":{"type":"string"},"phone":{"type":"string"},"customer_name":{"type":"string"},"technician_id":{"type":"integer"},"location_phone":{"type":"string"},"billing_address":{"type":"string"},"service_address":{"type":"string"},"technician_name":{"type":"string"},"location_contact_name":{"type":"string"},"billing_same_as_service":{"type":"string"},"location_phone_same_as_customer":{"type":"string"}}},"logicalName":"book_job","displayName":"book_job","title":"book_job","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"lookup_job","description":"Look up a job by phone (preferred), customer name, or job ID. Also returns customer_first_name and say_in_greeting when the phone matches a customer.","inputSchema":{"type":"object","properties":{"phone":{"type":"string"},"job_id":{"type":"integer"},"customer_name":{"type":"string"}}},"logicalName":"lookup_job","displayName":"lookup_job","title":"lookup_job","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"get_schedule","description":"Get scheduled jobs for a date (or today if omitted). Optional technician_id/name filters to that tech's busy jobs. For open slots for a requested tech use get_technician_availability instead.","inputSchema":{"type":"object","properties":{"date":{"type":"string"},"technician_id":{"type":"integer"},"technician_name":{"type":"string"}}},"logicalName":"get_schedule","displayName":"get_schedule","title":"get_schedule","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"list_technicians","description":"List bookable technicians (id + name) when a customer wants a specific plumber. Then call get_technician_availability with that tech and the chosen service_id. Work window 9:00–15:00 weekdays, next day or later; max 8 hours per tech per day; same-day = office only.","inputSchema":{"type":"object","properties":{}},"logicalName":"list_technicians","displayName":"list_technicians","title":"list_technicians","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"get_technician_availability","description":"Find open appointment slots. Pass technician_id/name if customer requested a plumber; omit tech to find days/times where ANY tech has enough contiguous free time. Pass service_id so Service.hours determines duration (capped at 8h/day). If Hours > 8, slots are full 8h days and office is notified for remaining days. Only next weekday 9:00–15:00; same-day/weekend/after 3 not offered. Offer 2–4 slots then create_appointment.","inputSchema":{"type":"object","properties":{"date":{"type":"string"},"days_ahead":{"type":"integer"},"service_id":{"type":"string"},"service_db_id":{"type":"integer"},"technician_id":{"type":"integer"},"technician_name":{"type":"string"},"duration_minutes":{"type":"integer"}}},"logicalName":"get_technician_availability","displayName":"get_technician_availability","title":"get_technician_availability","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"create_appointment","description":"Same as book_job. THE ONLY WAY TO BOOK. Creates customer, location, contacts, job, and appointment. If lookup_caller found nobody, still call this. Requires customer_name, phone (customer SMS), service_address, and billing_same_as_service. If billing differs: also billing_address plus location_phone (tenant/on-site SMS) or location_phone_same_as_customer true. Pass service_id when a pricebook item was chosen (Hours = duration). Pass when + technician_id from get_technician_availability. Auto-boo","inputSchema":{"type":"object","required":["customer_name","phone"],"properties":{"date":{"type":"string"},"when":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"service_id":{"type":"string"},"customer_name":{"type":"string"},"service_db_id":{"type":"integer"},"technician_id":{"type":"integer"},"customer_phone":{"type":"string"},"location_phone":{"type":"string"},"billing_address":{"type":"string"},"service_address":{"type":"string"},"technician_name":{"type":"string"},"duration_minutes":{"type":"integer"},"location_contact_name":{"type":"string"},"billing_same_as_service":{"type":"string"},"location_phone_same_as_customer":{"type":"string"}}},"logicalName":"create_appointment","displayName":"create_appointment","title":"create_appointment","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"search_services","description":"Search the voice-quotable pricebook by keyword. Each result includes customer_price and price_display — always quote those dollars to the caller, whether price_rule is static or dynamic. Dynamic prices are real computed base quotes, not 'no price'.","inputSchema":{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"company_id":{"type":"string"}}},"logicalName":"search_services","displayName":"search_services","title":"search_services","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"get_service_price","description":"Get the quoteable pricebook price for one service. Returns customer_price and price_display. Always speak that amount even when price_rule is dynamic.","inputSchema":{"type":"object","required":["query"],"properties":{"query":{"type":"string"},"company_id":{"type":"string"}}},"logicalName":"get_service_price","displayName":"get_service_price","title":"get_service_price","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"log_call","description":"REQUIRED near the end of every call (including admin/test calls), AFTER the caller is done — never use log_call as a reason to hang up early. Saves what was said onto the Front Desk AI summary and Call History. ALWAYS pass: (1) notes/summary = 1–3 sentence overview for the office, and (2) transcript = array of turns [{role:'caller'|'assistant', text:'...'}] covering the full conversation (what the caller asked and what you answered — prices, booking, declines, issues). Empty {} is not enough. Ph","inputSchema":{"type":"object","required":["notes"],"properties":{"notes":{"type":"string"},"phone":{"type":"string"},"job_id":{"type":"integer"},"outcome":{"type":"string"},"summary":{"type":"string"},"direction":{"type":"string"},"transcript":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string"},"text":{"type":"string"}}}},"customer_id":{"type":"integer"},"from_number":{"type":"string"},"customer_name":{"type":"string"},"transcript_text":{"type":"string"},"duration_seconds":{"type":"integer"}}},"logicalName":"log_call","displayName":"log_call","title":"log_call","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"send_appointment_confirmation","description":"Send (or re-send) an SMS appointment confirmation to the customer. create_appointment already auto-sends when SMS is enabled; use this to resend or if the customer asks for a text. Requires job_id or appointment_id.","inputSchema":{"type":"object","properties":{"force":{"type":"boolean"},"phone":{"type":"string"},"job_id":{"type":"integer"},"appointment_id":{"type":"integer"}}},"logicalName":"send_appointment_confirmation","displayName":"send_appointment_confirmation","title":"send_appointment_confirmation","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"send_tech_on_the_way","description":"Text the customer that their plumber is on the way. Usually triggered automatically when Dispatch is pressed in the app; use this tool if the customer asks for an ETA text or office wants a manual send. Requires job_id.","inputSchema":{"type":"object","required":["job_id"],"properties":{"force":{"type":"boolean"},"phone":{"type":"string"},"job_id":{"type":"integer"},"tech_name":{"type":"string"},"eta_minutes":{"type":"integer"}}},"logicalName":"send_tech_on_the_way","displayName":"send_tech_on_the_way","title":"send_tech_on_the_way","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"get_business_hours","description":"Get this company's office hours, holiday exceptions, whether open right now, and next open time. Use when the caller asks about hours, open/closed, or when to call back. Do not invent hours.","inputSchema":{"type":"object","properties":{"company_id":{"type":"integer"}}},"logicalName":"get_business_hours","displayName":"get_business_hours","title":"get_business_hours","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"leave_office_message","description":"Save a note for the office ONLY if they explicitly want a message, not a live person. If they ask to speak to someone now / a representative / transfer: call request_human instead. Never use this as a substitute for request_human.","inputSchema":{"type":"object","required":["message"],"properties":{"name":{"type":"string"},"notes":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"message":{"type":"string"},"caller_name":{"type":"string"},"callback_phone":{"type":"string"},"service_address":{"type":"string"}}},"logicalName":"leave_office_message","displayName":"leave_office_message","title":"leave_office_message","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"send_personal_message","description":"PERSONAL MITCH LINE ONLY: Text Mitch a short message on his temporary cell and save it on mitch.theplumbingapp.com. Use when the caller wants a message left for Mitch. Does NOT transfer or ring any phone. After success=true: confirm to the caller that Mitch will get the message, optional one anything-else, then polite goodbye and end call. If success=false: still acknowledge you noted it; do not claim SMS delivery; still polite goodbye. Never dial or transfer.","inputSchema":{"type":"object","required":["message"],"properties":{"name":{"type":"string"},"phone":{"type":"string"},"message":{"type":"string"},"urgency":{"type":"string"},"transcript":{"type":"string"},"caller_name":{"type":"string"},"callback_phone":{"type":"string"}}},"logicalName":"send_personal_message","displayName":"send_personal_message","title":"send_personal_message","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"check_service_area","description":"Check whether a 5-digit ZIP is in this company's service area (same list as online Book form). Call before booking if the caller gives a ZIP. If allowed=false, do not schedule; offer a message or explain out of area.","inputSchema":{"type":"object","required":["zip"],"properties":{"zip":{"type":"string"},"company_id":{"type":"integer"},"postal_code":{"type":"string"}}},"logicalName":"check_service_area","displayName":"check_service_area","title":"check_service_area","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"text_on_call_emergency","description":"After-hours plumbing emergency only: text the on-call manager and technician with caller details. Never place 911 — instruct the caller to call 911 or the gas company if life-threatening. Requires issue_summary.","inputSchema":{"type":"object","required":["issue_summary"],"properties":{"issue":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"caller_name":{"type":"string"},"caller_phone":{"type":"string"},"issue_summary":{"type":"string"},"service_address":{"type":"string"}}},"logicalName":"text_on_call_emergency","displayName":"text_on_call_emergency","title":"text_on_call_emergency","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"report_emergency","description":"Customer says it is an emergency. Treat it as an emergency — do not argue. If gas smell or flooding, tell them to call 911 first. Then call this tool to text and call the on-call roster one at a time (they call the customer back). Then offer a next-business-day appointment via book_job.","inputSchema":{"type":"object","required":["issue_summary"],"properties":{"issue":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"caller_name":{"type":"string"},"caller_phone":{"type":"string"},"issue_summary":{"type":"string"},"service_address":{"type":"string"}}},"logicalName":"report_emergency","displayName":"report_emergency","title":"report_emergency","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"request_human","description":"REQUIRED when the caller wants a live person, representative, or to be transferred. Do this instead of leave_office_message. Rings the office; if nobody takes it you are put back on the line. If office_away is true, do not call this.","inputSchema":{"type":"object","properties":{}},"logicalName":"request_human","displayName":"request_human","title":"request_human","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"request_callback","description":"Office is AWAY or CSRs unavailable: put this caller on the Front Desk callback list.","inputSchema":{"type":"object","properties":{"note":{"type":"string"}}},"logicalName":"request_callback","displayName":"request_callback","title":"request_callback","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"send_payment_link","description":"If the caller wants to pay and can_send_pay_link is true: after they agree, silently send a text with a payment link for an open invoice. Never collect card numbers. Never say Square or 'payment tool'.","inputSchema":{"type":"object","properties":{"phone":{"type":"string"},"invoice_id":{"type":"integer"}}},"logicalName":"send_payment_link","displayName":"send_payment_link","title":"send_payment_link","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"offer_spanish","description":"Call this if you hear the customer speaking Spanish. Plays 'Para español, oprima 1.' Press 1 → Spanish; no press → English.","inputSchema":{"type":"object","properties":{}},"logicalName":"offer_spanish","displayName":"offer_spanish","title":"offer_spanish","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"text_employee","description":"When the caller asks for a *named* employee and agrees to a text: send that person an SMS with the caller's name and callback number. Pass employee_name exactly as the caller said it. Only succeeds if that name uniquely matches one active employee on this company — never list staff names to the caller. If not matched, offer leave_office_message instead. This does not live-transfer the phone call.","inputSchema":{"type":"object","required":["employee_name","message"],"properties":{"note":{"type":"string"},"phone":{"type":"string"},"message":{"type":"string"},"caller_name":{"type":"string"},"caller_phone":{"type":"string"},"employee_name":{"type":"string"},"callback_phone":{"type":"string"}}},"logicalName":"text_employee","displayName":"text_employee","title":"text_employee","annotations":{"untrustedContentHint":true,"readOnlyHint":true}}],"toolSource":"directory_preview","agentAction":"both","installLinks":[{"id":"cursor","label":"Cursor","href":"cursor://anysphere.cursor-deeplink/mcp/install?name=The-Plumbing-App&config=eyJ1cmwiOiAiaHR0cHM6Ly9tY3AudGhlcGx1bWJpbmdhcHAuY29tL21jcCJ9"},{"id":"vscode","label":"VS Code","href":"vscode:mcp/install?%7B%22name%22%3A%22The-Plumbing-App%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fmcp.theplumbingapp.com%2Fmcp%22%7D"},{"id":"vscode-insiders","label":"VS Code Insiders","href":"vscode-insiders:mcp/install?%7B%22name%22%3A%22The-Plumbing-App%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fmcp.theplumbingapp.com%2Fmcp%22%7D"},{"id":"claude-web","label":"Claude.ai","href":"https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=The+Plumbing+App&connectorUrl=https%3A%2F%2Fmcp.theplumbingapp.com%2Fmcp"},{"id":"codex","label":"Codex","copyText":"codex mcp add \"The-Plumbing-App\" --url \"https://mcp.theplumbingapp.com/mcp\""},{"id":"chatgpt","label":"ChatGPT","href":"https://www.mcpbundles.com/docs/integrations/chatgpt"}],"catalogUrl":"https://www.mcpbundles.com/api/directory/v1/servers/theplumbingapp-mcp-bd03f9f807","callUrl":"https://www.mcpbundles.com/api/directory/v1/servers/theplumbingapp-mcp-bd03f9f807/tools/{tool}","mcpServerUrl":"https://mcp.theplumbingapp.com/mcp","liveCatalogUrl":"https://www.mcpbundles.com/api/directory/v1/servers/theplumbingapp-mcp-bd03f9f807?live=1"}