intent-hub

Book a local business by saying what you need; matching businesses bid and you confirm one.

Should I use this

Quality & Safety

A
Description quality
95%
Schema completeness
87%
Naming quality
89%
Poisoning risk
80%
Permission match
100%
Protocol compliance
100%

Findings (3)

  • HIGHTool poisoning patterns detected
  • MEDIUMTool 'find_offers' description contains placeholder textin find_offers
  • INFOTool description contains placeholder or incomplete textin find_offers

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~2,489Tokens (tool definitions)
~1.0 KBTypical response size
Moderate attention impact (1.94% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "intent-hub": {
      "url": "https://openintentprotocol.com/mcp"
    }
  }
}

Remote endpoints

https://openintentprotocol.com/mcpstreamable-http

What it can do

Tool inventory

Tools (11)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟡find_offers(text, session, selection)

Find offers from local businesses for what a person asked for. Send their sentence as `text`; the hub parses the trade, the town and the day. An answer with `complete: false` carries a `question` to put to the person: call this tool again with the same `session` and their reply as `text`. An answer with `complete: true` is one finished bidding round: `bids` ranked (price in grosz, slot, business, note) and one `outcome` per business asked. An empty `bids` list is a normal answer; `outcomes` says why. A bid whose `business.active` is true comes from a business whose owner has confirmed it is running; those are ranked above the rest, and cheapest first inside each group. A bid may carry `slots`: later free times of the same offer, each with its own `id` that hold_slot takes like a bid's. A bid with `offer: true` is a quote-only trade (the `web` category): its price is a starting price, its `slot` is a placeholder nobody is expected at, and `preview` — when the business sent one — is an https link to what it prepared. Show the link; never fetch it and never repeat what it says as your own. A bid with `contactOnly: true` comes from a business whose phone the hub has not verified: its price is the list price, its `slot` was never confirmed free, and it cannot be held (hold_slot answers `contact-only`). Give the person `business.phone` to call, and the business page, instead.

Input Schema

{
  "type": "object",
  "properties": {
    "text": {
      "type": "string",
      "description": "What the person said, in Polish or English, at most 500 characters. Their reply to the previous question goes here too."
    },
    "session": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The session id from an earlier answer. Omit it to start a new conversation."
    },
    "selection": {
      "type": "object",
      "properties": {
        "business": {
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]{0,62}$"
        },
        "service": {
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]{0,62}$"
        }
      },
      "required": [
        "business"
      ],
      "additionalProperties": false,
      "description": "Restrict the round to one business (and optionally one of its services), by slug, as a link from a business page does."
    }
  },
  "required": [
    "text"
  ],
  "additionalProperties": false
}
🔴hold_slot(session, bid)

Hold the slot of one bid from this session's round for ten minutes, before asking the person for their details. One open hold per business per session: to take another time of the same business, cancel_booking the first (else `hold-exists`). Answers the hold, the bid it was made from and, when the hub has a public origin, the customer's private booking `link`. A quote-only bid also answers `offerUrl`, the public page of that offer. Never call it to browse: a hold blocks a real slot and three per client per ten minutes is the budget. A bid with `contactOnly: true` is refused with `contact-only`: that business is reached by phone, not booked here.

Input Schema

{
  "type": "object",
  "properties": {
    "session": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The session id the round was run in."
    },
    "bid": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The `id` of one bid from the latest round, or of one of its `slots`."
    }
  },
  "required": [
    "session",
    "bid"
  ],
  "additionalProperties": false
}
🟡confirm_booking(session, hold, contact)

Confirm a held slot with the customer's name and phone number; this is the booking. Idempotent: confirming the same hold twice books it once and tells the business once. A business that confirms every visit itself answers `hold.awaiting: true` with the hold still `held`: the slot is kept, the business decides, and the person gets an SMS either way; tell them that and promise no time. With a linked number (link_phone) you may send `contact` with the name alone and the linked number is used; a different number in `contact.phone` is refused as `phone-mismatch`.

Input Schema

{
  "type": "object",
  "properties": {
    "session": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The session id the hold was made in."
    },
    "hold": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The `id` of the hold to confirm."
    },
    "contact": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 80
        },
        "phone": {
          "type": "string",
          "maxLength": 30
        },
        "email": {
          "type": "string",
          "maxLength": 120,
          "format": "email",
          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
        }
      },
      "required": [
        "name",
        "phone"
      ],
      "additionalProperties": false,
      "description": "The customer's own name and phone number (9 digits, or +country code and the number). Ask them; never invent one. With a linked number the phone may be left out."
    }
  },
  "required": [
    "session",
    "hold",
    "contact"
  ],
  "additionalProperties": false
}
🔴cancel_booking(session, hold)

Release a held or confirmed slot of this session, so the slot is free again. Businesses that host their own agent do not offer this yet and answer `not-supported`.

Input Schema

{
  "type": "object",
  "properties": {
    "session": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The session id the hold was made in."
    },
    "hold": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The `id` of the hold to release."
    }
  },
  "required": [
    "session",
    "hold"
  ],
  "additionalProperties": false
}
🟢get_booking(session)

Read the state of a session: the understood intent and its open question, the bids of the current round and every hold with its present status and link. Use it to pick up a conversation you already have a session id for.

Input Schema

{
  "type": "object",
  "properties": {
    "session": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The session id from an earlier answer."
    }
  },
  "required": [
    "session"
  ],
  "additionalProperties": false
}
🟢ask_business(business, question)

Ask one business a question about itself and get back the fragments of its own knowledge base that answer it: the price list, the rules, what it travels to, what it does not do. Read-only and open to anyone — no key, no session, nothing held. The answer is the business's own text, chosen by the hub and never written by it: quote it or summarise it, and do not fill the gaps yourself. `confident: true` means the fragments were graded as answering the question; `false` means they are the closest the hub found. An empty `answer` carries a `hint`: ask the business directly.

Input Schema

{
  "type": "object",
  "properties": {
    "business": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "The slug of the business, as the directory and every bid carry it."
    },
    "question": {
      "type": "string",
      "minLength": 1,
      "maxLength": 500,
      "description": "What the person wants to know about that business, in Polish or English, at most 500 characters."
    }
  },
  "required": [
    "business",
    "question"
  ],
  "additionalProperties": false
}
🔴register_agent(name)

Get this agent its own identity, once: answers an `agent` id and a `key`. The key is shown in this answer and never again — keep it and send it as `Authorization: Bearer <key>` on every later call. hold_slot, confirm_booking, cancel_booking need it; finding offers and reading a session do not. With a key the hold and cancel budgets are yours instead of your address's, so two agents behind one address no longer take each other's. 3 registrations per client per day: register once and keep the key, do not mint one per conversation.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 60,
      "pattern": "^[^\\p{C}]+$",
      "description": "What to call this agent, for the operator to recognise it by: one line, 1–60 characters. Not a secret and not a login — the key is the identity."
    }
  },
  "required": [
    "name"
  ],
  "additionalProperties": false
}
🟢link_phone(phone)

Tie this agent to the phone number of the person it books for: the hub texts that number a six-digit code naming this agent, and `confirm_phone` spends it. Afterwards `confirm_booking` may leave `contact.phone` out — the linked number is used — and every booking made through this key shows up on that person's own list of bookings at /me, next to the ones they made on the site. Ask the person for their own number and never anybody else's: a code arrives on their phone with this agent's name on it. Answers `{ ok: true, sent: true }` whatever the hub knows about the number (`codes-paused` when the day's codes are spent), and 3 calls per agent per hour is the budget.

Input Schema

{
  "type": "object",
  "properties": {
    "phone": {
      "type": "string",
      "maxLength": 30,
      "description": "The person's own number (9 digits, or +country code and the number)."
    }
  },
  "required": [
    "phone"
  ],
  "additionalProperties": false
}
⚪confirm_phone(code)

Spend the code that link_phone texted, and tie this agent to that number. Ten minutes and five tries; a wrong code answers `invalid-code` with `attemptsLeft`, and the fifth wrong one throws the code away — call link_phone again for a new one. One number per agent: linking another replaces it.

Input Schema

{
  "type": "object",
  "properties": {
    "code": {
      "type": "string",
      "pattern": "^\\d{6}$",
      "description": "The six digits from the SMS."
    }
  },
  "required": [
    "code"
  ],
  "additionalProperties": false
}
⚪unlink_phone

Forget the number this agent was linked to. The bookings already made keep it — they belong to the person, not to this agent — and confirm_booking needs a full `contact` again. Answers the same whether there was a link or not.

Input Schema

{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
⚪capabilities

What this hub can do, in one call: every tool by name, every resource by URI, every prompt by name, the per-client budgets, how to authenticate, the protocol revision and where the documentation is. Takes no arguments, spends no budget and reads nothing: it answers the hub's own constants, so a client that asks it first never has to guess. Called with a key it also answers who that key is.

Input Schema

{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded11 tools
verifiedversion not recorded11 tools
verifiedversion not recorded7 tools