Appointment Booking
Find real businesses and book appointments. Books via Cal.com; imports 12 platforms.
Open source Repository Open in the app JSON README (API)
About
Find real businesses and book appointments. Books via Cal.com; imports 12 platforms.
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- dev.hatchloop
- Origin
- official
- Category
- ferramentas
- Transport
- http
- Version
- 0.2.13
- Stars
- 1
- Forks
- 1
- Open pull requests
- 1
- Last push
- 2026-09-07T19:22:25Z
- Repository state
- ativo
- Language
- Python
- License
- MIT
- Added
- 2026-08-29 13:00:29
- Updated
- 2026-09-07 16:01:11
- Origin id
dev.hatchloop/appointment-booking
README
# Agent Broker - SMB Transaction & Communication MCP Server
> **An agent-callable MCP server** that lets autonomous AI agents find, verify, message, schedule with, and transact with small and mid-sized businesses (SMBs) through a single compliance-enforced tool surface.
[](https://smithery.ai/servers/lordbasil147/agent-broker)
[](https://hatchloop.dev/mcp/agent-broker)
[](LICENSE)
[](https://www.python.org/)
[](./edge)
[](https://github.com/modelcontextprotocol/servers)
<!-- NO STATIC TEST BADGE. A shields.io badge is a literal in a
URL: it rendered "103/103 passing" in green whether or not
the suite passed, and the real count is over a thousand. A
badge that cannot fail is decoration pretending to be
evidence. The CI run on the commit is the evidence. -->
[](https://github.com/basilalshukaili/agentbroker/actions/workflows/ci.yml)
**Live endpoint:** `https://hatchloop.dev/mcp/agent-broker` (streamable-http, always-on Cloudflare edge)
---
## Why this exists
There are tens of millions of long-tail small businesses in the US - barbers, plumbers, accountants, home cleaners - and they have **no API surface**. AI agents that need to schedule a haircut, get a quote, or send a confirmation today must either drive a browser, cold-call by voice, or give up.
This server is the missing middle layer. Agents call us; we route to the right SMB through whichever channel reaches them fastest - Cal.com -> WhatsApp -> SMS -> voice AI -> email - with full TCPA / GDPR / CASL / 10DLC compliance enforced as a non-bypassable gate.
---
## Current status (honest)
| Capability | Status |
|---|---|
| MCP endpoint (streamable-http) | **Live** - `https://hatchloop.dev/mcp/agent-broker` |
| 23 MCP tools | **Live** (callable today) |
| Compliance gate (TCPA/GDPR/CASL) | **Live** |
| REST + A2A + OpenAI/Anthropic tool surfaces | **Live** |
| SMB supply network | **Demo** - 20+ seed SMBs; demo bookings return `demo_smb_no_live_booking` |
| Billing | **Live** - 12 utility tools free (no key, unmetered). Premium data tools (company verification, sanctions, trade screening): free up to a daily limit (500/day with a free key, 100/day anonymous), then $0.02/call via credits. Write tools: free email-verified key (100 ops/day) at hatchloop.dev/agent-broker; credit packages from $9/1,000 credits at hatchloop.dev/pricing;. |
| x402 payment rail | **Offered, opt-in.** Enabled on the service since the founder lifted the crypto restriction on 2026-08-29. A caller attaches a payment in `params._meta["x402/payment"]` and the call is served without a key (USDC on Base, proven once on mainnet, tx 0x38a0d9ec). Callers who do not attach one fall through to credits and the free quota, so nothing is gated behind it. `/.well-known/x402` is still a 404 - discovery is via `/.well-known/mcp.json`, which lists the rail. |
| Production SMB onboarding | **Planned** - real businesses not yet enrolled |
> The MCP server is live and callable right now. Bookings hit demo data. 12 utility tools are free (no key, unmetered). Premium data tools (verify_company_record, screen_sanctions, map_trade_restriction) are free up to a daily limit; beyond that, $0.02/call via credits. Write tools require a free email-verified key (100 ops/day) - get one at https://hatchloop.dev/agent-broker. Credit packages from $9/1,000 credits at https://hatchloop.dev/pricing.
---
## 23 MCP Tools
All tools are callable via MCP, REST, OpenAI function calling, Anthropic tool_use, or A2A protocol.
| # | Tool | What it does | Auth |
|---|---|---|---|
| 1 | `find_business` | Search SMBs by vertical, location, and capability | **free** |
| 2 | `verify_business` | Confirm an SMB is real, operating, and capable of the requested service | **free** |
| 3 | `get_status` | Poll the current state of an async operation | **free** |
| 4 | `get_outcome` | Retrieve the final `OutcomeReceipt` (with cost and reason codes) | **free** |
| 5 | `preview_cost` | Estimate cost, latency, and success probability before committing | **free** |
| 6 | `self_test` | Verify service health and all claimed capabilities are responding | **free** |
| 7 | `check_quota` | Inspect your remaining daily quota and tier without consuming any ops - call at session start or after a rate_limited error | **free** |
| 8 | `check_booking_link` | Classify a URL and confirm import_booking_url will accept it - sub-100ms pre-flight | **free** |
| 9 | `check_compliance` | Preview TCPA/GDPR/CASL/10DLC gate result before spending a paid send | **free** |
| 10 | `verify_company_record` | Live GLEIF LEI registry + SEC EDGAR lookup - official legal name, status, jurisdiction, address | **free up to daily limit** |
| 11 | `screen_sanctions` | Check a name or entity against OFAC SDN, the EU Consolidated list and the UK Sanctions List | **free up to daily limit** |
| 12 | `map_trade_restriction` | OFAC country embargoes + export-control Entity List + sanctioned-party screening for a proposed shipment | **free up to daily limit** |
| 13 | `get_conversation` | Read a two-way thread you started: state, full transcript, reply count | **free** |
| 14 | `lookup_us_contracts` | Search US federal contract awards by company name via USASpending.gov - awardee, agency, amount, NAICS, period | **free** |
| 15 | `send_message` | Send WhatsApp, SMS, email, or voice with compliance pre-check enforced | key |
| 16 | `capture_lead` | Structured intake of a prospect into the SMB's AgentBroker lead store (not the business's own CRM), deduplicated | key |
| 17 | `schedule_appointment` | Book, reschedule, or cancel via the direct booking API (Cal.com); SMBs reachable only through async channels fail honestly until a background worker is deployed | key |
| 18 | `send_transactional_confirmation` | TCPA-exempt OTPs, booking confirmations, receipts | key |
| 19 | `handle_inbound` | Classify inbound messages: booking / cancel / opt-out / question / complaint | key |
| 20 | `escalate_to_human` | Hand off a stuck or ambiguous task to a human operator with full context | key |
| 21 | `import_booking_url` | Turn any Cal.com, Calendly, Doctolib, Booksy, OpenTable, Square, Acuity, or Fresha URL into a bookable SMB record | key |
| 22 | `call_business` | Place a conversational voice-AI phone call to a business on behalf of a consumer | key |
| 23 | `mint_key` | Issue a free-tier agent identity key via HMAC proof - no email required, no human in the loop | **free** |
Free key (100 write ops/day + 500 premium data calls/day): https://hatchloop.dev/agent-broker - Credits from $9/1,000 ops: https://hatchloop.dev/pricing - Premium data beyond quota: $0.02/call
---
## Verifiable compliance receipts
`screen_sanctions` and `check_compliance` attach a **compliance receipt**: a
hash-bound record of which list copies were screened (and how fresh they were),
which ruleset decided, what inputs it was given, and what it returned. It is
signed with **Ed25519** and verifiable **offline** - months later, with no call
back to us. It asserts facts about *our system's actions only*; it never claims
"this party is clean."
Verify one in ~12 lines (pin the public key from
[hatchloop.dev/agents.md](https://hatchloop.dev/agents.md)):
```python
import json, hashlib
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
PINNED_KEY_HEX = "<hex public key from hatchloop.dev/agents.md>"
receipt = json.load(open("receipt.json")) # the compliance_receipt object
payload, integrity = receipt["payload"], receipt["integrity"]
canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"),
ensure_ascii=True, allow_nan=False).encode()
assert integrity["payload_sha256"] == "sha256:" + hashlib.sha256(canonical).hexdigest()
Ed25519PublicKey.from_public_bytes(bytes.fromhex(PINNED_KEY_HEX)).verify(
bytes.fromhex(integrity["signature"]), canonical) # raises if tampered
```
If no signing key is configured on the server, the receipt says
`signature_status: "unsigned"` with the reason - it never claims a signature it
does not have.
---
## Quick start
### Connect via MCP (Claude Desktop, Cursor, Cline, Continue, etc.)
```json
{
"mcpServers": {
"agent-broker": {
"url": "https://hatchloop.dev/mcp/agent-broker"
}
}
}
```
**15 tools require no key.** 12 are always free (find_business, verify_business, check_booking_link, check_compliance, get_conversation, get_status, get_outcome, preview_cost, self_test, check_quota, mint_key, lookup_us_contracts) and 3 more are free within a daily quota (verify_company_record, screen_sanctions, map_trade_restriction).
**Write tools** require an `X-Agent-Identity` bearer token:
- Free email-verified key (100 ops/day): https://hatchloop.dev/agent-broker
- **Machine-mintable key (no email, agent self-serve):** `POST https://api.hatchloop.dev/keys/mint` - see [Machine-mintable keys](#machine-mintable-keys) below.
- Credits from $9/1,000 ops: https://hatchloop.dev/pricing
Add your key to the config once you have one:
```json
{
"mcpServers": {
"agent-broker": {
"url": "https://hatchloop.dev/mcp/agent-broker",
"headers": {
"X-Agent-Identity": "Bearer YOUR_KEY_HERE"
}
}
}
}
```
### Or via npx (stdio transport)
```bash
npx agentbroker-mcp
```
With a key:
```bash
AGENT_BROKER_KEY=your_key npx agentbroker-mcp
```
### Discover tools (JSON-RPC)
```bash
curl -X POST https://hatchloop.dev/mcp/agent-broker \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```
### Call a tool (JSON-RPC)
```bash
curl -X POST https://hatchloop.dev/mcp/agent-broker \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "find_business",
"arguments": {
"vertical": "personal_services",
"location": {"zip_or_city": "30309"},
"capability": "haircut"
}
}
}'
```
### OpenAI function calling
```python
import httpx, openai
tools = httpx.get(
"https://hatchloop.dev/.well-known/openai-tools.json"
).json()["tools"]
client = openai.OpenAI()
resp = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Book a haircut in Atlanta Saturday under $50"}],
tools=tools,
)
```
### Anthropic tool use
```python
import httpx, anthropic
tools = httpx.get(
"https://hatchloop.dev/.well-known/anthropic-tools.json"
).json()["tools"]
client = anthropic.Anthropic()
msg = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Book a haircut in Atlanta Saturday under $50"}],
)
```
### Plain REST
```bash
curl -X POST https://hatchloop.dev/ops/find_business \
-H "Content-Type: application/json" \
-d '{"vertical":"personal_services","location":{"zip_or_city":"30309"},"capability":"haircut"}'
```
---
## Machine-mintable keys
AI agents that cannot receive email can self-provision a free-tier API key (100 gated ops/day) by proving identity via HMAC-SHA256.
### How it works
1. Obtain the `MACHINE_MINT_SECRET` from [hatchloop.dev/docs/#machine-mint](https://hatchloop.dev/docs/#machine-mint).
2. Compute the signature:
```
signature = HMAC-SHA256(agent_id + str(timestamp) + nonce, MACHINE_MINT_SECRET)
```
The HMAC input is the **raw concatenation** of the three fields (no separators). Digest must be lowercase hex.
3. POST to `https://api.hatchloop.dev/keys/mint`:
```json
{
"agent_id": "my-agent-abc123",
"timestamp": 1725100000,
"nonce": "4f8a2c1d9e2b7c6a",
"signature": "<lowercase-hex-hmac>"
}
```
### Response
```json
{
"ok": true,
"key": "<JWT - use as X-Agent-Identity header>",
"key_id": "free_machine_<hash>",
"expires_at": "2026-11-28",
"tier": "free",
"daily_limit": 100,
"usage": "Send as the X-Agent-Identity header on every call to https://hatchloop.dev/mcp/agent-broker"
}
```
### Constraints
- `timestamp` must be within **60 seconds** of server time (prevents replay attacks).
- Use a fresh `nonce` on every call (UUID or random hex).
- `agent_id` is a stable identifier for your agent; the issued key is tied to its SHA-256 hash.
- Returns `401 {error: "invalid_request"}` on bad signature or stale timestamp.
- Returns `503 {error: "not_configured"}` if the server secret has not been set (contact hello@hatchloop.dev).
---
## Discovery surfaces
| Surface | URL |
|---|---|
| **MCP (streamable-http)** | `https://hatchloop.dev/mcp/agent-broker` |
| MCP descriptor | `https://hatchloop.dev/.well-known/mcp.json` |
| OpenAI function tools | `https://hatchloop.dev/.well-known/openai-tools.json` |
| Anthropic tool_use | `https://hatchloop.dev/.well-known/anthropic-tools.json` |
| A2A (Agent-to-Agent) | `https://hatchloop.dev/.well-known/agents.json` |
| OpenAI ChatGPT plugin | `https://hatchloop.dev/.well-known/ai-plugin.json` |
| llms.txt | `https://hatchloop.dev/llms.txt` |
| OpenAPI 3.1 | `https://hatchloop.dev/openapi.yaml` |
| npm shim (stdio) | `npx agentbroker-mcp` |
| Glama MCP Registry | Listed via [`glama.json`](./glama.json) |
| MCP Registry | Listed via [`server.json`](./server.json) |
---
## Architecture
```
AI agent
|
v MCP / REST / A2A
Cloudflare Worker edge (hatchloop.dev)
| 300+ PoPs globally -- discovery served from edge bundle in 40-70 ms
|
+-- GET /.well-known/* /manifest /llms.txt --> embedded snapshot (40-70 ms)
+-- POST /mcp initialize / tools/list --> embedded snapshot (40-65 ms)
+-- POST /mcp tools/call /ops/* --> proxy to origin (170-190 ms)
|
v
Python FastAPI (api.hatchloop.dev)
| Cron keep-alive every 2 min (eliminates Render cold starts)
|
+-- 23 operation handlers (core/)
+-- Compliance gate (compliance/pre_check)
+-- Channel adapters (channels/ -- Twilio, Cal.com, Vapi, SendGrid)
+-- Billing + outcome store
+-- All .well-known / MCP endpoints (also served from edge bundle)
```
The edge worker can outlive the origin: discovery still works even if the origin is down. Idempotency is keyed by `(agent_id, operation, idempotency_key)` with 24h TTL. Async operations return `pending_async`; poll with `get_status` / `get_outcome`.
---
## Compliance
Every outbound communication passes through `compliance/pre_check()`:
1. **Content classification** - blocks restricted categories (gambling, adult, cannabis, spam)
2. **Opt-out check** - TCPA STOP keyword, GDPR right-to-be-forgotten, CASL
3. **Consent check** - TCPA written consent, GDPR opt-in, CASL implied/express
4. **10DLC registry check** - US SMS campaign compliance
5. **Two-party recording consent** - CA, FL, IL, MD, MA, MT, NV, NH, PA, WA
6. **Audit log** - PII stored as SHA-256 hash, never plaintext
Violations surface as `ComplianceViolationError` and are never silently bypassed.
---
## Repo layout
```
agentbroker/
+-- core/ # 23 operation handlers + shared Pydantic models
+-- channels/ # Twilio, SendGrid, Vapi, Bland, Cal.com, Playwright
+-- compliance/ # pre_check, jurisdiction_rules, consent_store, audit_log
+-- reliability/ # retry, circuit_breaker, channel_fallback, async_runner
+-- billing/ # meter, budget_guard, receipt_signer, pricing_tiers
+-- telemetry/ # tracer, log_redactor, metrics_emitter
+-- storage/ # outcome_store, idempotency_store
+-- supply/ # smb_directory (20+ seed/demo SMBs)
+-- onboarding/ # self_serve, verification_flow, channel_capture
+-- feedback/ # failure_classifier, attribution_engine, outcome_evaluator
+-- optimizer/ # ab_router, selection_analytics, weekly_report
+-- agent_interface/ # manifest_server, mcp_server, well_known, identity, webhooks
+-- manifest/ # manifest.json, mcp_tools.json, openapi.yaml
+-- api/ # errors.md, identity.md, async.md
+-- docs/ # mission, architecture, compliance, ADRs
+-- edge/ # Cloudflare Worker (TypeScript/Hono)
+-- deploy/ # Dockerfile, docker-compose.yml
+-- tests/ # unit, contract, compliance, fault_injection, agent_sim
+-- main.py # FastAPI entry point
+-- config.py # Centralized config from env
+-- requirements.txt
```
---
## Local development
```bash
# Install dependencies
pip install -r requirements.txt
# Run tests (1173 passing at the time of writing)
python -m pytest tests/ -q
# Start the API
python main.py
# --> http://localhost:8000/docs (Swagger UI)
# --> http://localhost:8000/mcp (MCP endpoint)
# --> http://localhost:8000/manifest (capability manifest)
# Run the agent simulation harness
python -m tests.agent_sim.harness
# Self-test
python -c "import asyncio; from agent_interface.self_test import run_self_test; print(asyncio.run(run_self_test()).all_passed)"
```
Or with Docker:
```bash
docker compose -f deploy/docker-compose.yml up
```
---
## Documentation
- [Architecture](./docs/architecture.md) - module map, data flow, fallback chains
- [Compliance](./docs/compliance.md) - full jurisdiction matrix, pre-check sequence
- [Agent integration guide](./docs/AGENT_INTEGRATION_GUIDE.md) - copy-paste examples for every protocol
- [API errors](./api/errors.md) - 16 error codes with retry semantics
- [API identity](./api/identity.md) - Agent-Identity JWT spec
- [API async](./api/async.md) - execution profiles, polling rules, webhook contract
- [Benchmarks](./docs/BENCHMARKS.md) - measured WinRate, latency, cost vs alternatives
- [Mission](./docs/mission.md) - north-star metric and scope
---
## Contributing
Licensed under MIT. Issues and discussion are welcome - open a GitHub issue to report bugs or suggest features. For substantial changes, please open an issue first to discuss direction. Note: this repo is the open-source server; the hosted service at hatchloop.dev (supply index, billing rails) is operated by Hatchloop.
---
## License
MIT - see [LICENSE](LICENSE). The hosted service and its supply/billing data are operated separately by Hatchloop.
---
*Built by [Basil Al-Shukaili](https://github.com/basilalshukaili). Listed on the [MCP Registry](https://github.com/modelcontextprotocol/servers) and [Glama](https://glama.ai/mcp/servers).*