What happens when an AI agent asks about your business

This one’s for the technically curious: a walkthrough of a single agent request to a CoreLoop business, from the wire to the log line. Business owners are welcome, but you’ll never need any of this; that’s the deal.
Say an assistant wants to know what a business offers. It speaks the Model Context
Protocol, so it connects to the business’s endpoint, coreloop.so/api/mcp/{slug}, over
Streamable HTTP, and calls a tool. Here’s what happens, in order, every time.
The gate chain
Resolve the business. The slug maps to exactly one profile. If the business renamed its link, the old slug returns a 301 to the new one, agents update themselves.
Check the publishing status, first. Only published profiles are served, ever. Draft, unpublished, and suspended profiles return an error, and they do it before rate limiting. That ordering is deliberate: if unpublished slugs behaved differently under load, you could enumerate them by timing. They don’t, so you can’t.
Check the owner’s switches. Every channel obeys a per-channel kill switch, and unpublishing is the master switch above them all. Off means off, immediately, no cache grace period.
Rate limit. Per business, per hour, sized by plan: 100 on Free, 1,000 on Starter, 10,000 on Pro and Agency. Past the limit you get a 429 with a Retry-After header, not a degraded answer.
Execute the tool. Six tools exist, generated from the profile automatically:
get_info, get_services, check_availability (static hours today, honestly labelled),
get_reviews, compare_services (appears when a category has two or more services), and
send_inquiry. Five are strictly read-only. send_inquiry is the sole write path in the
whole surface, and it’s fenced accordingly: 3 messages per day per agent per business, 50
per day per business, 2,000 characters, HTML stripped, and the limits are shared with the
web form so the two doors can’t be stacked.
Answer, with metadata. Responses are bounded — at most 50 services per answer — and
every one carries locale, translation_status, available_locales,
last_updated, verified, and data_source. An agent doesn’t just get an answer; it
gets the provenance to decide how much to trust it.
Locale, resolved per request
?locale= beats Accept-Language beats the profile’s original language, with Vary set
so caches don’t cross-contaminate. Only completed translations are served; anything
pending falls back to the original language rather than shipping a half-translated
business.
The log line
Every invocation is recorded: tool, protocol, detected agent platform, discovery source, response status and time, and a hashed agent identifier. No silent requests, and no raw identifiers at rest; IP addresses are never stored in full anywhere in the pipeline. The owner sees the aggregate in their analytics; the raw stream stays internal.
Why this shape
Public, unauthenticated, read-only-with-one-exception is an unusual API posture, and it’s chosen, not inherited. Agents won’t pre-register for API keys to ask a local business its opening hours; a public endpoint with hard gates, bounded responses, and full logging is what actually gets used and stays defensible. The same discipline applies across the other surfaces, A2A, llms.txt, WebMCP, which are all projections of the same profile through the same gates.
Full reference, including the cross-business directory endpoint, in the MCP doc.


