Kirah Local Services
Measured conclusion: Deep-tested. L2 outcome: tools_ok.
Discover local services and availability, then create, track, reschedule, or cancel bookings.
| Author | io.github.kirubel |
|---|---|
| Access | remote |
| Publisher key required | No |
| Measured state | Deep-tested |
| L1 liveness | alive |
| L1 latency | 2683 ms |
| Last measured | 2026-10-24 |
Add to your agent
Copy this into your MCP client config:
{
"mcpServers": {
"Kirah Local Services": {
"url": "https://kirah.ai/api/mcp-registry-v1",
"transport": "streamable-http"
}
}
}
Measured tools (10)
list_servicesread-onlyReturns one published Kirah business catalog with current services, providers, timezone, prices, durations, deposit requirements, intake-question definitions and derived booking capabilities.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).
Hints: read-only yes · destructive no · idempotent not declared · open-world no
search_servicesread-onlyRanks up to five services in one published Kirah business catalog against a short free-text query. Returns catalog-grounded candidate identifiers, names, scores and match evidence.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).query(required) — string
Hints: read-only yes · destructive no · idempotent not declared · open-world no
get_availabilityread-onlyReturns current open times for one exact service and optional provider over a YYYY-MM-DD range of up to 31 days, with at most 20 rows. Approval-mode times are preferences rather than holds.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).service_id(required) — stringdate_range(required) — objectprovider_id— string
Hints: read-only yes · destructive no · idempotent not declared · open-world no
search_businessesread-onlySearches Kirah's eligible public business directory by service need or exact Kirah Agent Address, with optional coarse location, price and demo-mode filters. Demo results are explicitly labeled.
Parameters:
limit— integerquery— string — The consumer's need in plain words (e.g. 'lower back tightness', 'prenatal massage'). Matched deterministically against real service catalogs, expanded by the discovery ontology.cursor— string — Opaque next_cursor value from a previous search_businesses response with the SAME query/filters: resumes after that tenant in the stable ordering. A cursor that does not decode, or that names a tenant not present in the current ordering, is invalid_cursor.location— string — Optional place text ('City, ST', ZIP, bare city/state) OR explicit coordinates 'lat,lng'. With resolvable coordinates, radius_miles applies as real distance; otherwise matching is city/ZIP/metro-market text equality.tenant_mode— string — The authoritative eligibility filter for demo tenants. include_demos (default) returns real and demo businesses together; every demo is flagged demo:true and carries a clear notice. real_only excludes every demo business; demos_only returns ONLY demo businesses. A discovery-disabled, inactive, or otherwise ineligible tenant never appears in any mode — not even when its catalog uniquely matches the query.include_demo— boolean — Back-compat alias: true is equivalent to tenant_mode 'include_demos' and false to 'real_only'. When omitted, tenant_mode defaults to include_demos. Every demo result carries demo:true and a demo_notice. Supplying both include_demo and tenant_mode with disagreeing demo-inclusion is invalid_tenant_mode.radius_miles— integer — Radius in miles (default 25) — OPERATIVE when the location resolves to coordinates (2.6); otherwise answered with a truthful distance_note instead of a fabricated distance.agent_address— string — Exact public locator `<handle>@kirah.ai`; case-insensitive ASCII only. A locator, never authentication or owner authority. Reserved, malformed, unlisted, disabled, non-bookable, and tenant_mode-ineligible addresses do not resolve. Exact mode never fuzzy-matches a near miss.max_price_cents— integer — Only services with a parseable price at or under this amount are returned; unpriced services are excluded when this is set.
Hints: read-only yes · destructive no · idempotent not declared · open-world yes
find_available_servicesread-onlyChecks up to five top matching eligible Kirah businesses for earliest current availability within an exact ISO-8601 window of up to 14 days. Returns checked status and a partial-coverage flag.
Parameters:
query(required) — string — The consumer's service need in plain words — identical semantics to search_businesses.query.location— string — Optional place text ('City, ST', ZIP, bare city/state) OR explicit coordinates 'lat,lng' — identical semantics to search_businesses.location.tenant_mode— string — The authoritative demo eligibility filter, with the same semantics as search_businesses. include_demos is the default and returns real and demo candidates; real_only excludes demos; demos_only returns only clearly labeled demonstration candidates.include_demo— boolean — Back-compat alias: true is equivalent to tenant_mode 'include_demos' and false to 'real_only'. When omitted, tenant_mode defaults to include_demos. Every demo candidate carries demo:true and a demo_notice. Supplying both include_demo and tenant_mode with disagreeing demo-inclusion is invalid_tenant_mode.radius_miles— integer — Radius in miles (default 25) — operative when the location resolves to coordinates (2.6 semantics).earliest_after— string — Exact ISO 8601 instant the window opens (default: now). Natural-language times are rejected (invalid_earliest_after).candidate_limit— integer — How many top-matching businesses get LIVE availability checks (invalid_candidate_limit outside 1-5). This bounds the whole fan-out: businesses beyond it are never touched, and partial:true says so.earliest_before— string — Exact ISO 8601 instant the window closes (default: earliest_after + 14 days). Must be after earliest_after and at most 14 days after it (invalid_earliest_before).max_price_cents— integer — Only candidate services with a parseable price at or under this amount are considered.
Hints: read-only yes · destructive no · idempotent not declared · open-world yes
get_booking_statusread-onlyReturns the current status, time, service and provider for one grant-authorized booking reference. Client contact details and intake responses are excluded.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).booking_ref(required) — string — The reference create_booking returned (its idempotency key). Tampered, unrelated, cross-tenant or never-committed references answer one indistinguishable booking_not_found.grant— string — The booking-bound capability token returned by create_booking. It must match this tenant and booking_ref and remain unexpired and unrevoked.
Hints: read-only yes · destructive no · idempotent not declared · open-world no
get_reschedule_optionsread-onlyReturns up to five real alternate times and the current fee or approval consequences for one grant-authorized booking. It does not hold, move or cancel the appointment.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).booking_ref(required) — string — The reference create_booking returned (its idempotency key). It must be the SAME booking the supplied grant was issued for; a mismatch answers invalid_grant, indistinguishably from a forged grant.grant(required) — string — The capability token from this booking's create_booking response (confirmation.grant). Required: without it there is no way to establish that you are the agent that made this booking. Tampered, wrong-booking, wrong-tenant and revoked grants all answer invalid_grant, indistinguishably; an authentic grant past the appointment start answers expired_grant. These are the GRANT codes, not the payment page's invalid_token/expired_token — through contract 2.11 this action answered the latter, whose prose wrongly told callers their payment link was broken.limit— integer — How many options to return. Default 2, hard maximum 5; a larger value is CLAMPED to 5 rather than rejected. The ceiling is deliberate: the primary consumer is a voice agent reading options aloud, and five spoken times is more than a caller can hold in their head.latest— string — Optional exact ISO 8601 instant — the latest replacement time to consider. Default: now + 14 days. Must be after `earliest` and at most 31 days after it; anything else answers invalid_latest. Supply it explicitly whenever `earliest` is more than 14 days out.earliest— string — Optional exact ISO 8601 instant — the earliest replacement time to consider. Default: now + 2 hours (a slot the customer cannot physically reach is not an option). Natural-language times are not accepted.
Hints: read-only yes · destructive no · idempotent not declared · open-world no
reschedule_bookingdestructiveAtomically moves one grant-authorized booking to a real open time after explicit user confirmation. Reusing idempotency_key makes retries safe. Failure leaves the original booking unchanged; success returns a rotated grant.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).booking_ref(required) — string — The reference create_booking returned for the booking you want to MOVE. It must be the SAME booking the supplied grant was issued for; a mismatch answers invalid_grant, indistinguishably from a forged grant. A successful move does not change it.grant(required) — string — The capability token from this booking's create_booking response (confirmation.grant). Required: without it there is no way to establish that you are the agent that made this booking. It must carry the `booking:reschedule` scope. Tampered, wrong-booking, wrong-tenant, revoked and insufficiently-scoped grants all answer invalid_grant, indistinguishably; an authentic grant past the appointment start answers expired_grant. These are the GRANT codes, not the payment page's invalid_token/expired_token — through contract 2.11 this action answered the latter, whose prose wrongly told callers their payment link was broken.start_iso(required) — string — The exact ISO 8601 instant to move the appointment to. Natural-language times are not accepted. You may supply it DIRECTLY — calling get_reschedule_options first is optional, not required — because the instant is validated against real availability by the same slot engine create_booking uses. A time that is not genuinely open answers slot_taken with the original booking untouched; a time further ahead than this business books answers beyond_booking_horizon.idempotency_key(required) — string — REQUIRED — unlike create_booking, this action cannot derive one, because "move booking X to time T" is byte-identical whether it is a retry or a deliberate second move. Omitting it answers missing_idempotency_key. Reuse the SAME key when retrying the SAME move: the replay returns the original result with idempotent_replay:true and moves nothing. The same key with a different start_iso or provider_id answers idempotency_conflict.provider_id— string — OPTIONAL. Move the booking to a different provider. Omit it and the booking keeps the provider it is already on — the customer booked a person, not a room. An explicit provider is honored only when that provider exists in this tenant's catalog (else unknown_provider) AND performs the booked service (else provider_service_mismatch). The service and its duration never change.agent_metadata— object
Hints: read-only no · destructive yes · idempotent not declared · open-world yes
cancel_bookingdestructiveCancels one grant-authorized booking after explicit user confirmation. Reusing idempotency_key makes retries safe. Kirah refuses cancellations that could refund a charged deposit or restore a paid plan session; an allowed cancellation has no undo.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).booking_ref(required) — string — The reference create_booking returned for the booking you want to CANCEL. It must be the SAME booking the supplied grant was issued for; a mismatch answers invalid_grant, indistinguishably from a forged grant.grant(required) — string — The capability token from this booking's create_booking response (confirmation.grant). Required: without it there is no way to establish that you are the agent that made this booking. It must carry the `booking:cancel` scope. Tampered, wrong-booking, wrong-tenant, revoked and insufficiently-scoped grants all answer invalid_grant, indistinguishably; an authentic grant past the appointment start answers expired_grant.idempotency_key(required) — string — REQUIRED — unlike create_booking, this action cannot derive one, because "cancel booking X" is byte-identical whether it is a transport retry or a deliberate second call. Omitting it answers missing_idempotency_key. Reuse the SAME key when retrying the SAME cancellation: the replay returns the original result with idempotent_replay:true, cancels nothing and sends no second notice. The same key against a different booking_ref answers idempotency_conflict.agent_metadata— object
Hints: read-only no · destructive yes · idempotent not declared · open-world yes
create_bookingdestructiveCreates one guest booking for an exact service, provider and ISO-8601 start time after explicit user confirmation. Reusing idempotency_key makes retries safe. Kirah accepts no payment credentials through MCP; a deposit-required service may return a Kirah-hosted human payment continuation, but this call transfers no funds.
Parameters:
tenant(required) — string — The tenant to operate on: the provider.tenant_slug value from the tenant's /.well-known/kirah.json manifest (the tenant's full domain, e.g. <slug>.kirah.ai).service_id(required) — stringstart_iso(required) — stringclient(required) — objectprovider_id— stringagent_metadata— objectidempotency_key— stringintake_responses— object — Answers to the service's intake form (2.8), keyed by intake field id as advertised in list_services' service.intake_form.fields[].id. FLAT only: values must be a string, a boolean, or a finite number — arrays, nested objects and nulls are rejected. Unknown keys are ignored by the booking engine. Answers are validated against the LIVE form; a required plain boolean accepts an explicit true OR false, a consent boolean accepts only true, and a select must exactly match one advertised option. Omit this field entirely when the service has no intake form.
Hints: read-only no · destructive yes · idempotent not declared · open-world yes
Measured by MCPYP probing. Untested fields are omitted, never estimated. Listing is always free; MCPYP never proxies calls or stores user tokens.