{"openapi":"3.1.0","info":{"title":"Charlie Obaugh Auto Group agent tools","version":"1.0.0","description":"Model Context Protocol tool surface for Charlie Obaugh Auto Group, described as OpenAPI. Every operation posts a JSON-RPC tools/call envelope to /api/ucp/mcp."},"servers":[{"url":"https://www.charlieobaugh.com/ai"}],"paths":{"/api/ucp/mcp#search_inventory":{"post":{"operationId":"search_inventory","summary":"Find specific vehicles in Charlie Obaugh Auto Group inventory by free-text query and/or structured filters, sorted howev","description":"Find specific vehicles in Charlie Obaugh Auto Group inventory by free-text query and/or structured filters, sorted however the shopper asked. Returns matching vehicles with price, specs, availability and links. Use structured filters, not a vague query string. `sort` answers the superlative questions: sort='price_asc' for 'cheapest car you have', 'price_desc' for 'most expensive', 'year_desc' for 'newest', 'mileage_asc' for 'lowest miles', 'savings_desc' for 'biggest discount off MSRP'. Never answer a superlative from list_inventory. When nothing matches, the result carries `did_you_mean` with real vehicles found by relaxing one constraint (named in `relaxed`): say plainly that we do not have what they asked for, then show those. Once a shopper settles on one vehicle, move to get_vehicle_details for the window sticker and the deal paths.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"search_inventory"},"arguments":{"type":"object","properties":{"query":{"type":"string","description":"Free text over year/make/model/trim/color/VIN"},"make":{"type":"string"},"model":{"type":"string"},"trim":{"type":"string","description":"Trim contains, e.g. LT, Elevation, EX"},"year":{"type":"integer"},"year_min":{"type":"integer"},"year_max":{"type":"integer"},"condition":{"type":"string","enum":["new","used","certified"]},"body_type":{"type":"string","description":"Body style contains, e.g. SUV, Sedan, Truck"},"drivetrain":{"type":"string","description":"AWD, 4WD, FWD, RWD"},"fuel_type":{"type":"string","description":"Gasoline, Diesel, Hybrid, Electric"},"exterior_color":{"type":"string"},"color":{"type":"string","description":"Alias of exterior_color"},"mileage_max":{"type":"number"},"min_price":{"type":"number"},"max_price":{"type":"number"},"in_transit":{"type":"boolean"},"limit":{"type":"integer","default":20},"sort":{"type":"string","enum":["price_asc","price_desc","year_desc","year_asc","mileage_asc","mileage_desc","savings_desc"],"description":"Order the results. Required for any 'cheapest', 'most expensive', 'newest', 'lowest mileage' or 'biggest discount' question."}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_vehicle":{"post":{"operationId":"get_vehicle","summary":"Get the full structured record for one vehicle by its 17-character VIN. Use when you already have a VIN and need price, ","description":"Get the full structured record for one vehicle by its 17-character VIN. Use when you already have a VIN and need price, specs, offers, photos and availability together. Do not use it to FIND a vehicle: it needs an exact VIN and will not search. Use search_inventory or match_by_budget to find one first. For a single yes-or-no on whether a car is still available, check_availability is cheaper. Fields that are absent are genuinely unknown for this vehicle, not withheld, so say so rather than estimating.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_vehicle"},"arguments":{"type":"object","properties":{"vin":{"type":"string"}},"required":["vin"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_vehicle_details":{"post":{"operationId":"get_vehicle_details","summary":"THE deep-dive tool for ONE vehicle. Returns everything we hold on that VIN in a single object: full specs, the parsed FA","description":"THE deep-dive tool for ONE vehicle. Returns everything we hold on that VIN in a single object: full specs, the parsed FACTORY WINDOW STICKER (base price, destination, itemized options with their real prices, packages), the factory VIN build record (assembly plant, GVWR, restraint systems, driver assistance), the photo gallery, EPA fuel economy, the pricing story (MSRP, discount off MSRP, any price drop), advertised manufacturer offers, and every deal path the engine will quote (finance, lease when it passes our accuracy gate, cash). Call this when a shopper asks about a specific vehicle, wants the window sticker, options, specs, or 'tell me more about that one'. The shopper sees a rich in-chat detail view. This is the one call that desks a whole deal, so it is the START of the answer, not the end: follow it in the SAME turn with get_oem_offers for that VIN, and offer estimate_trade_in, because a shopper looking at one car is a shopper ready to talk numbers.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_vehicle_details"},"arguments":{"type":"object","properties":{"vin":{"type":"string","description":"17-char VIN"},"zip":{"type":"string","description":"Shopper ZIP so tax and fees are right"},"down":{"type":"number"},"term":{"type":"integer","default":72},"credit_band":{"type":"string"},"include_payments":{"type":"boolean","default":true}},"required":["vin"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_value_props":{"post":{"operationId":"get_value_props","summary":"This dealership's OWN documented reasons to buy here: certification, inspection process, warranty coverage, guarantees, ","description":"This dealership's OWN documented reasons to buy here: certification, inspection process, warranty coverage, guarantees, upfront pricing. Returns verbatim text with the source page. Call this before you tell a shopper why to buy pre-owned here. If it returns nothing, say NOTHING about certification or warranty: never invent a program.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_value_props"},"arguments":{"type":"object","properties":{"topic":{"type":"string","description":"optional filter, e.g. 'pre-owned', 'warranty'"},"limit":{"type":"integer","default":8}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#list_inventory":{"post":{"operationId":"list_inventory","summary":"Raw pagination over the feed in load order. Use ONLY when you already need to walk the whole list page by page (offset/l","description":"Raw pagination over the feed in load order. Use ONLY when you already need to walk the whole list page by page (offset/limit crawling, an export, a sitemap). NOT for shopper questions. It is NOT an answer to 'what do you have', 'show me your inventory', 'what's on the lot' or 'what do you carry': call get_inventory_stats for those. It is NOT an answer to 'cheapest', 'newest' or 'lowest mileage' either: call search_inventory with sort=. The rows come back in feed order, so they are not ranked, not representative, and must never be presented as a selection. Minimum page size is 12.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"list_inventory"},"arguments":{"type":"object","properties":{"limit":{"type":"integer","default":50,"minimum":12,"description":"Page size, floored at 12 and capped at 200."},"offset":{"type":"integer","default":0}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_oem_offers":{"post":{"operationId":"get_oem_offers","summary":"Every incentive we can evidence on a vehicle: APR programs, lease programs, bonus cash and discount off MSRP, for one VI","description":"Every incentive we can evidence on a vehicle: APR programs, lease programs, bonus cash and discount off MSRP, for one VIN or across a make/model. CALL THIS whenever you are about to name a specific vehicle, so the shopper hears the offer alongside the price instead of the price alone. Offers sourced from the feed are advertised; offers with source 'offer_engine' are computed estimates carrying `provenance`, `program_code` and a `caveat` you must repeat. `lowest_apr` and `finance_aprs_available` answer rate questions directly. A count of 0 means we have nothing to advertise on it, not that financing is unavailable.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_oem_offers"},"arguments":{"type":"object","properties":{"vin":{"type":"string"},"make":{"type":"string"},"model":{"type":"string"},"limit":{"type":"integer","default":50}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_dealer_specials":{"post":{"operationId":"get_dealer_specials","summary":"Dealer-advertised specials from our own specials page, each with terms, expiry and a link. Call it for 'any deals right ","description":"Dealer-advertised specials from our own specials page, each with terms, expiry and a link. Call it for 'any deals right now'. Some rooftops have none ingested and return count 0: say plainly that we have no advertised specials posted, then pivot to what IS real (get_oem_offers for programs, get_inventory_stats `savings` for how many vehicles are priced below MSRP). Never invent a special to fill the gap.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_dealer_specials"},"arguments":{"type":"object","properties":{"make":{"type":"string"},"model":{"type":"string"},"limit":{"type":"integer","default":50}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#search_offers":{"post":{"operationId":"search_offers","summary":"Search every offer we hold by model, family (apr/lease/cash/special) or free text. It understands rate questions: '0 per","description":"Search every offer we hold by model, family (apr/lease/cash/special) or free text. It understands rate questions: '0 percent', 'zero percent', '0% APR' and 'no interest' all return only genuine 0.00% programs, and 'low apr' returns 2.99% or better. The result carries `lowest_apr`, `finance_aprs_available` and `matching_vehicles`. Use it for 'do you have 0% financing', 'any lease deals', 'what rebates are running'. A count of 0 means nothing matched THAT query: never conclude from it that we offer no financing, and never state a rate the tool did not return.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"search_offers"},"arguments":{"type":"object","properties":{"query":{"type":"string"},"type":{"type":"string","enum":["apr","lease","cash","special"]},"model":{"type":"string"},"limit":{"type":"integer","default":30}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_window_sticker":{"post":{"operationId":"get_window_sticker","summary":"Monroney MSRP and a fetch link for one VIN, and nothing else. PREFER get_vehicle_details: it returns the FULLY PARSED wi","description":"Monroney MSRP and a fetch link for one VIN, and nothing else. PREFER get_vehicle_details: it returns the FULLY PARSED window sticker for the same VIN (base price, destination, itemized options with their real prices, packages) plus specs, offers and every deal path, in one call. Use this thin tool only when you want the sticker link alone and nothing more.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_window_sticker"},"arguments":{"type":"object","properties":{"vin":{"type":"string"}},"required":["vin"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#decode_vin":{"post":{"operationId":"decode_vin","summary":"Decode a 17-character VIN into make, model, year, trim, body style, engine and drivetrain. Use for a VIN this dealer may","description":"Decode a 17-character VIN into make, model, year, trim, body style, engine and drivetrain. Use for a VIN this dealer may not stock, such as a shopper's own car or trade-in. Do not use it for a vehicle in this inventory: get_vehicle already returns the decode plus real price, offers and availability, so calling this instead loses all of that. Decoding describes what a VIN means; it never implies the dealer has the car.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"decode_vin"},"arguments":{"type":"object","properties":{"vin":{"type":"string"}},"required":["vin"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_dealer_info":{"post":{"operationId":"get_dealer_info","summary":"Dealership identity: name, address, geo, phone, website, franchise brands and hours. Use it for 'where are you', 'what i","description":"Dealership identity: name, address, geo, phone, website, franchise brands and hours. Use it for 'where are you', 'what is your number', 'are you open'. It is NOT the answer to 'what makes do you carry': `brands` is the franchise list, not what is on the ground today, so call get_inventory_stats and quote `by_make` with real counts. If `hours` is a placeholder rather than real hours, say we would rather have someone confirm the hours than guess, and give the phone number.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_dealer_info"},"arguments":{"type":"object","properties":{}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_inventory_stats":{"post":{"operationId":"get_inventory_stats","summary":"THE tool for any question about the lot as a whole. Call it FIRST for 'what do you have', 'show me what you have', 'show","description":"THE tool for any question about the lot as a whole. Call it FIRST for 'what do you have', 'show me what you have', 'show me your inventory', 'what's on the lot', 'what do you carry', 'what makes do you sell', 'what brands do you have', 'do you have SUVs / trucks / minivans', 'how many cars do you have', 'how big is your selection', and for any opening browse where the shopper has not named a vehicle yet. Returns the total, a ready-to-say `overview` line, counts by condition, by make (with `top_makes`), by canonical body style (`by_body_style`, already merged so one segment is not split across feed spellings), by price band, and a `savings` block counting the vehicles priced below MSRP, the ones with a price drop, and the finance programs under 2% APR. Lead an overview answer with these numbers, then the savings, then ONE narrowing question. Do NOT answer these questions with list_inventory: a page of the feed is not an overview.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_inventory_stats"},"arguments":{"type":"object","properties":{}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#compare_vehicles":{"post":{"operationId":"compare_vehicles","summary":"Compare two or more VINs side by side across price, specs and offers. Use when a shopper is choosing between specific ve","description":"Compare two or more VINs side by side across price, specs and offers. Use when a shopper is choosing between specific vehicles they have already narrowed to. Pass every VIN in one call rather than calling get_vehicle repeatedly, so the comparison is built on one consistent snapshot. Do not use it to browse: find candidates with search_inventory or match_by_budget first. Two to five VINs is the useful range; beyond that a shopper is still searching, not comparing.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"compare_vehicles"},"arguments":{"type":"object","properties":{"vins":{"type":"array","items":{"type":"string"}}},"required":["vins"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#check_availability":{"post":{"operationId":"check_availability","summary":"Live availability for one VIN: in stock, in transit, or no longer listed. Call this before telling a shopper a specific ","description":"Live availability for one VIN: in stock, in transit, or no longer listed. Call this before telling a shopper a specific car is available, and before booking or submitting a lead against it, because inventory moves faster than any cached answer. It is the cheapest tool here, so prefer it over re-fetching the whole record when availability is the only thing in question. In transit means the dealer expects it but does not have it on the lot today; say that plainly rather than calling it available.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"check_availability"},"arguments":{"type":"object","properties":{"vin":{"type":"string"}},"required":["vin"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#rag_search":{"post":{"operationId":"rag_search","summary":"Keyword/substring RAG search over the full corpus (inventory + store-page Markdown). Returns matching chunks with source","description":"Keyword/substring RAG search over the full corpus (inventory + store-page Markdown). Returns matching chunks with source links.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"rag_search"},"arguments":{"type":"object","properties":{"query":{"type":"string"},"limit":{"type":"integer","default":10}},"required":["query"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#corpus_health":{"post":{"operationId":"corpus_health","summary":"What the knowledge corpus contains, how it is composed by document type, what the admission policy refused and why, and ","description":"What the knowledge corpus contains, how it is composed by document type, what the admission policy refused and why, and which shopper topics have no document yet. Call this to judge whether a question is answerable from the corpus before answering it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"corpus_health"},"arguments":{"type":"object","properties":{}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#get_started":{"post":{"operationId":"get_started","summary":"START HERE for a shopper. Returns this assistant's capability menu and the recommended conversational flow (estimate tra","description":"START HERE for a shopper. Returns this assistant's capability menu and the recommended conversational flow (estimate trade -> capture payoff -> compute equity -> match vehicles to a monthly budget with window-sticker features -> submit a lead). Call it first so you can introduce yourself and guide the buyer.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"get_started"},"arguments":{"type":"object","properties":{}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#estimate_trade_in":{"post":{"operationId":"estimate_trade_in","summary":"Value the shopper's CURRENT / trade-in vehicle. Use this whenever they mention a car they own or want to trade in (for e","description":"Value the shopper's CURRENT / trade-in vehicle. Use this whenever they mention a car they own or want to trade in (for example a Tesla Model 3). Provide either a vin, OR year + make + model (trim optional), plus mileage (required); condition and zip optional. Returns trade_low / trade_mid / trade_high and a confidence level. ALWAYS present it as a RANGE and say it is an estimate, not a firm offer; then ask the customer if they want to proceed with this estimated value.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"estimate_trade_in"},"arguments":{"type":"object","properties":{"vin":{"type":"string","description":"17-char VIN of the trade vehicle (preferred if known)."},"year":{"type":"integer"},"make":{"type":"string"},"model":{"type":"string"},"trim":{"type":"string"},"mileage":{"type":"number","description":"Current odometer miles (required)."},"condition":{"type":"string","description":"e.g. excellent, good, fair"},"zip":{"type":"string"}},"required":["mileage"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#capture_payoff":{"post":{"operationId":"capture_payoff","summary":"Capture the loan payoff on the customer's trade so equity can be computed. Use mode='provided' with provided_amount when","description":"Capture the loan payoff on the customer's trade so equity can be computed. Use mode='provided' with provided_amount when the customer knows their payoff. Use mode='estimate' with original_amount, apr, term_months and start_date (YYYY-MM-DD) to approximate the remaining balance via amortization. Returns payoff_amount and source. Equity = trade value minus payoff.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"capture_payoff"},"arguments":{"type":"object","properties":{"mode":{"type":"string","enum":["provided","estimate"],"default":"provided"},"provided_amount":{"type":"number"},"original_amount":{"type":"number"},"apr":{"type":"number","description":"Annual percent, e.g. 6.9"},"term_months":{"type":"integer"},"start_date":{"type":"string","description":"Loan start YYYY-MM-DD"},"monthly_payment":{"type":"number","description":"Optional; improves the estimate if known."}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#calculate_payment":{"post":{"operationId":"calculate_payment","summary":"Calculate a real, penny-accurate monthly payment for a specific vehicle (by vin, preferred, or price). Optional down, te","description":"Calculate a real, penny-accurate monthly payment for a specific vehicle (by vin, preferred, or price). Optional down, term (default 72), credit_band (excellent/good/fair/poor or a score), trade_value, payoff, zip. Trade equity (trade_value minus payoff) is applied to reduce the amount financed. Returns finance {monthly_payment, apr, term, down_payment, amount_financed, sales_tax, total_of_payments, credit_tier} plus a disclaimer; set include_lease for a lease option too. Always show the disclaimer; figures are estimates on approved credit.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"calculate_payment"},"arguments":{"type":"object","properties":{"vin":{"type":"string"},"price":{"type":"number"},"down":{"type":"number"},"term":{"type":"integer","default":72},"credit_band":{"type":"string","description":"excellent | good | fair | poor, or a numeric score"},"trade_value":{"type":"number"},"payoff":{"type":"number"},"zip":{"type":"string"},"include_lease":{"type":"boolean","default":false},"payment_type":{"type":"string","description":"finance | lease | cash (deal-builder mode)"},"annual_miles":{"type":"integer","description":"Lease miles/year, e.g. 10000, 12000, 15000"},"lease_term":{"type":"integer","description":"Lease term in months, e.g. 24, 36, 39, 48"}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#match_by_budget":{"post":{"operationId":"match_by_budget","summary":"THE core shopping tool: find the best REAL in-stock vehicles for a shopper's budget, needs, and trade-in. Route broad 'w","description":"THE core shopping tool: find the best REAL in-stock vehicles for a shopper's budget, needs, and trade-in. Route broad 'which SUV / truck fits me', 'what can I afford', or 'find me a vehicle for my budget' questions here. Finds real in-stock vehicles that fit the customer's budget and computes an estimated monthly payment for each. Give target_monthly (e.g. 500) and/or target_price, plus optional down, trade_value, payoff (equity is applied), credit_band, term, and filters (body_type like 'truck', make, model, max_price, min_year, fuel_type, drivetrain, condition). Returns up to ~10 vehicles, each with a summary, price, estimated_monthly, within_budget flag, key_features pulled from specs/window sticker, a window-sticker link, photo and VDP url. Use the key_features to describe each truck to the buyer. Any question with a dollar figure and the word month, or 'what can I afford', or 'I have $X down', belongs here IMMEDIATELY: run it with what you were given and sensible defaults, then ask your one clarifying question over the top of a real list. Do not ask for the ZIP, the credit band or the body style before calling it. The exception is a trade, which must be valued with estimate_trade_in FIRST and passed in as trade_value.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"match_by_budget"},"arguments":{"type":"object","properties":{"target_monthly":{"type":"number","description":"Target monthly payment, e.g. 500"},"target_price":{"type":"number"},"down":{"type":"number","default":0},"trade_value":{"type":"number"},"payoff":{"type":"number"},"credit_band":{"type":"string"},"term":{"type":"integer","default":72},"body_type":{"type":"string","description":"e.g. truck, SUV, sedan (truck also matches pickups)"},"make":{"type":"string"},"model":{"type":"string"},"max_price":{"type":"number"},"min_year":{"type":"integer"},"fuel_type":{"type":"string","description":"Gasoline, Diesel, Hybrid, Electric"},"drivetrain":{"type":"string","description":"AWD, 4WD, FWD, RWD"},"condition":{"type":"string","enum":["new","used","certified"]},"zip":{"type":"string"},"max_results":{"type":"integer","default":10}}}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}},"/api/ucp/mcp#submit_lead":{"post":{"operationId":"submit_lead","summary":"Send the customer's info to the dealer as an ADF/XML lead so a human can follow up or schedule a visit. lead_type: 'regu","description":"Send the customer's info to the dealer as an ADF/XML lead so a human can follow up or schedule a visit. lead_type: 'regular' or 'general' (interested in an inventory vehicle), 'payment' or 'finance' (inventory vehicle + finance figures), 'lease' (inventory vehicle + lease figures: annual_mileage, money_factor, residual_value, due_at_signing in deal{}), 'trade' (customer's trade vehicle only), 'service' (service appointment on the customer's own vehicle; optional service{} with service_types[], preferred_date, preferred_time), or 'parts' (parts request). REQUIRES contact {first_name,last_name,email,phone} with at least a name and email, AND consent as an OBJECT {agreed:true, text:'...'} (not a bare boolean) -- it refuses without both. Pass the inventory vin (or vehicle{}), the deal{} payment/lease figures, and trade{} details (for 'payment'/'lease' leads, trade{} adds a SECOND vehicle to the ADF as the trade-in alongside the vehicle of interest); all payment and trade numbers are written into the ADF <comments>. Returns the generated ADF XML and a delivery confirmation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"type":["string","integer"]},"method":{"type":"string","const":"tools/call"},"params":{"type":"object","required":["name"],"properties":{"name":{"type":"string","const":"submit_lead"},"arguments":{"type":"object","properties":{"lead_type":{"type":"string","enum":["regular","general","payment","finance","lease","trade","service","parts"],"default":"regular"},"contact":{"type":"object","description":"JSON OBJECT, not a string: {\"first_name\": \"Jane\", \"last_name\": \"Doe\", \"email\": \"jane@example.com\", \"phone\": \"5405551234\"}. At least a name and an email are required.","properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"}}},"consent":{"type":"object","description":"JSON OBJECT, not a bare boolean: {\"agreed\": true, \"text\": \"Yes, have the dealer contact me\"}. Set agreed=true only after the customer actually says yes to being contacted; put their own words in text.","properties":{"agreed":{"type":"boolean","description":"true once the customer has said yes."},"text":{"type":"string","description":"What the customer said, e.g. 'Yes, have them contact me'."}}},"vin":{"type":"string","description":"Inventory VIN for regular/payment/lease leads."},"vehicle":{"type":"object","description":"Vehicle details if not resolved from vin. For service/parts leads, the customer's own vehicle."},"deal":{"type":"object","description":"Payment/lease figures: monthly_payment, term, apr, down, amount_financed, price, sales_tax, credit_band, and for lease: annual_mileage, money_factor, residual_value, due_at_signing."},"trade":{"type":"object","description":"Trade details: summary, year, make, model, trim, mileage, vin, trade_value, payoff, equity. For 'payment'/'lease' leads this adds a second ADF vehicle node; for 'trade' leads it is the whole lead."},"service":{"type":"object","description":"Only for lead_type='service': {service_types: [...], preferred_date, preferred_time}."},"comments":{"type":"string"}},"required":["contact","consent"]}}}}}}}},"responses":{"200":{"description":"JSON-RPC result","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Bearer token required for write tools"}}}}}}