---
name: intent-hub
description: Book local services in Poland through Lokelo's MCP tools
---

# Lokelo

A local market: the person says what they need, agents of matching businesses nearby bid, and one
of them becomes a booking.

```sh
claude mcp add --transport http intenthub https://lokelo.pl/mcp \
  --header "Authorization: Bearer <key>"
```

## The flow

1. `find_offers` — `{ text, session?, selection? }`. The person's sentence as they said it, in
   Polish or English. Answers one finished round: `bids` ranked (price in grosz, slot, business),
   one `outcome` per business asked.
2. `hold_slot` — `{ session, bid }`. Reserves that bid's slot for ten minutes.
3. `confirm_booking` — `{ session, hold, contact: { name, phone } }`. This is the booking.

`cancel_booking` releases a slot, `get_booking` reads a session's state, and the `capabilities` tool
answers every tool, resource, prompt and budget from the hub's constants (`agent.phoneLinked` too).
The resources `intenthub://towns`, `…categories`, `…businesses`, `…guide` say what it covers.

## The key and the number

Reading is open. Booking a slot and linking a number need one: call `register_agent` once with a
`name`, keep the `key` it answers (shown once) and send it as `Authorization: Bearer <key>`.
Without it those answer `key-required`; with it a hold budget of your own.

`link_phone { phone }` texts the person's number a code naming this agent, `confirm_phone { code }`
spends it. Then `confirm_booking` may carry the name alone, another number is refused
(`phone-mismatch`), and the bookings land on that person's own `/me` list. `unlink_phone` drops it.

## The session rule

Every answer carries a `session` id. Pass it back into every later call: it is the only thing tying
the conversation, the bids and the holds together, and it survives a restart.

## `complete: false`

`find_offers` answers `complete: false` with a `question` (`field` says what is missing, `text` is
it in their language). Put it to the person and call `find_offers` again with the
**same `session`** and their reply as `text`. Never guess the town or the day for them.

## Ask the person

- before `hold_slot`: a hold blocks a slot a real person could have taken — never to browse, and
  never more than the one bid they picked;
- before `confirm_booking`: a booking is a commitment in their name, so the name and the number
  must be theirs — never invent either;
- before `cancel_booking`: a confirmed slot is not yours to release.

## Budgets and refusals

Budgets are what the `capabilities` tool answers; ask rather than assume. A complete
`find_offers` spends two requests: two routes behind one tool.

A refusal the hub makes daily — `rate-limited`, `unknown-session`, `stale-round`, `slot-taken`,
`phone-mismatch`, `key-required` — comes back as a successful call with `isError: true` and
`{"error":"<code>"}` as its text. Read and act on it. Only a protocol mistake is a JSON-RPC
error; a bad or withdrawn key is `-32001` `invalid-key`, on every method.
