# LifeClaw

> Call you, a person, or a business; find places, book or inquire by phone, and return the answer.

- name: ai.agentese.lifeclaw/lifeclaw
- version: 1.0.0
- connection class: R2 (oauth_consent_once)
- trust: 80/100 flags: no-repository
- quality: 78/100 (good)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/ai.agentese.lifeclaw%2Flifeclaw
- tools: https://api.protogrid.dev/v1/servers/ai.agentese.lifeclaw%2Flifeclaw/tools

**An agent can connect after a one-time OAuth consent by a human.** Remote endpoint behind OAuth 2. Tokens stay with the agent; the registry only exposes the authorization metadata.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "lifeclaw": {
      "type": "http",
      "url": "https://api-v2.lifeclaw.agentese.ai/mcp",
      "headers": {
        "Authorization": "Bearer ${LIFECLAW_TOKEN}"
      }
    }
  }
}
```

Placeholders to fill: `${LIFECLAW_TOKEN}`.

## Trust

- hygiene: 80
- liveness: 100
- freshness: 100
- provenance: 45
- drivers: +dns-namespace +reachable +uptime-100% +updated-7d-ago -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 78/100 (good)

### protocol: n/a (weight 25)

- n/a `protocol.modern`, `protocol.stateless`, `protocol.transport`, `protocol.list_ttl`: no remote answered a protocol handshake (not probed yet, unreachable, or local-only)

### authorization: 83 (weight 15)

- pass `auth.prm`: Protected Resource Metadata (RFC 9728) published
- pass `auth.as_metadata`: authorization server metadata reachable
- warn `auth.cimd`: only Dynamic Client Registration, deprecated in 2026-07-28 in favour of CIMD
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 64 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 3 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- fail `tools.annotations`: no tool declares readOnlyHint or destructiveHint, so clients cannot tell safe calls from risky ones
- fail `tools.directory_hints`: no tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: search_places (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); get_place (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); call_business (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); …
- pass `tools.token_cost`: about 3,844 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 100 (weight 15)

- pass `stability.changes`: no tool changes in 30 days
- pass `stability.rug_pull`: no tool changed its meaning under the same name

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 16, about 3,844 tokens to load them all
- tool set hash: 533426eb471df7466187c3b55f2d6156
- badge: [![protogrid quality](https://protogrid.dev/badge/ai.agentese.lifeclaw/lifeclaw.svg)](https://protogrid.dev/servers/ai.agentese.lifeclaw/lifeclaw)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

_No tool definition changes recorded._

## Remotes

- https://api-v2.lifeclaw.agentese.ai/mcp (streamable-http, auth oauth2, reachable true, uptime30d 1)

## Packages

_none_

## Tools (16)

- `account_status`: Points balance, display name, and the selected receiving
number for call_me (masked). Use receiving_phone_status for setup and
caller_id_status for outbound display and
outbound-display state. 300 points ≈ one minute of calling.
- `call_business`: Phone a business and wait for the outcome.

`action="book"`: reserve. Required: merchant_name, date (YYYY-MM-DD),
time_ (HH:MM, 24h), party_size, name; recommended: contact_phone (E.164).
Both are the MERCHANT's local time.
`action="inquiry"`: ask something — put the question in `purpose`; the
answer comes back in `result.summary`.

`reply_language` is the language of the result fields (the call itself
is spoken in the merchant's language). `idempotency_key`: reuse the same
key to recover this attempt; after a terminal no-answer or busy result,
a deliberate new call needs a new key. Do not redial a `failed` result:
its cause may be unknown. Without a key, the same arguments derive the
same key for the UTC day and return the original task.

For personal accounts, a verified and enabled Caller ID is shown to the
business when the route permits it. Otherwise a LifeClaw number is used.
Caller ID setup is optional for business calls.

Returns the flat result (`result.status` is confirmed / rejected /
pending / no_answer / busy / unclear / timeout / failed, plus summary,
details, conditions, transcript) or `status: in_progress` with a task_id
for wait_for_call.
Costs 300 points per minute, minimum one minute, nothing on no answer.

- `call_contact`: Call a saved private contact without passing their full number.

First list_contacts and confirm the chosen name, masked number and exact
spoken message with the user. Pass that contact_ref and user_confirmed=true.
If the contact changes before dialing, re-list and confirm again. This
uses call_person's screening, verified Caller ID, daily cap and strict
no-platform-number-fallback policy. Check caller_id_status first. Its
no-answer retry decision and idempotency rules are the same as call_person.

- `caller_id_status`: Check the owner's outbound Caller ID. Verified plus enabled display
enables call_person. call_me uses a separate receiving number.
If setup is needed, direct the user to `setup_url`: Settings → Caller ID,
bind their own phone, answer Twilio's verification call and enter its code.
Then check again. Business calls do not need this setup.
- `call_me`: Ring the user's own phone, read them `message`, and bring back what
they say.

A phone call interrupts the user. Follow their explicit instructions about
whether and when to call, including an immediate call or a call when a job
finishes. Otherwise prefer chat for routine updates; call for a time-sensitive
decision only they can make after chat has no explicit answer, or for a
still-active important event after the workflow's chosen wait if nobody has
acknowledged it. There is no fixed waiting period: use the user's timing
when given, otherwise choose one appropriate to the task. For monitoring,
your workflow must watch the event, wait for acknowledgment, and decide
when to invoke this tool; LifeClaw cannot do those things or schedule a
future call. An explicit request to call regardless of event status takes
priority over the default active-and-unacknowledged condition.
Consider local time and do not repeatedly ring after a missed call. A
terminal no-answer is for your workflow to assess; LifeClaw will not
redial it automatically. Do not redial a `failed` result because contact
may have occurred. A deliberate later call needs a new
idempotency_key, and only a workflow that can wait and resume can promise
one. Reuse the original key to recover an uncertain request instead.

Examples: (1) a deployment is blocked on a rollback decision and chat
has no explicit answer; ask that one question and use `result.reply`.
(2) An external monitor confirms a critical incident is still active
and unacknowledged; call with that incident ID as `idempotency_key`.
(3) The user asked for a call when a job finishes; call once when your
workflow observes completion. Do not call for an ordinary completion
the user did not ask to hear by phone.

`wait_for_reply=True`: the assistant asks, listens, reads the answer
back, and returns it in `result.reply`. `wait_for_reply=False`: deliver
and hang up. `agent_name` ("Claude Code", "Codex") is how the assistant
introduces itself. `language` is spoken on the call and used for the
result; set it to the user's language. Write the message as speech:
short sentences, no markdown. Do NOT greet or introduce yourself inside
`message` — the call already opens with "I'm your assistant from
{agent_name}" / "我是来自 {agent_name} 的 AI 助手"; a message that starts
with "Hi, this is Claude Code" gets introduced twice. Start with the
content ("Hotpot or sushi tonight?").
`keywords` (optional, up to 20 short terms): the words the user is likely
to say back — the options you offered ("火锅", "日料"), a ticket or PR
number, a product name. They steer the speech-to-text toward those
spellings so `result.reply` and the transcript come back right; phone
audio otherwise mishears short words (火锅 → 哥哥 on a real call). Give
them whenever the answer is a choice between named things.

Needs the account's voice-verified receiving number. Outbound Caller ID
is separate. If this returns `error: receiving_phone_required`, send the
user to the returned setup_url to select a number, answer the voice
verification call, and enter its code.
Capped at 4 calls per account per 10 minutes and 30 per 24 hours. Billed
per minute like any call. For monitoring, pass a stable event ID as
idempotency_key; a new event needs a new key.

- `call_person`: Call one private person and relay one message from the user.

Ask the user to confirm the recipient, E.164 number and exact spoken
message first, then set user_confirmed=true. `original_message` is the
user's unedited request; `message` is the faithful sentence spoken aloud.
Both are screened. The AI identifies itself and passes on the message;
this tool is not an open-ended conversation or a broadcast tool.

Requires the user's verified, enabled outbound Caller ID. Call
caller_id_status for readiness and setup link. Verification means answering
a call and entering a code; call_me uses a separately selected receiving number.
Never substitute call_business for a private recipient. If the Caller ID
is refused by the carrier, the call fails without a platform-number retry.
Up to 10 private calls per account per rolling 24h. Billed per minute.
Reuse the same idempotency_key to recover this attempt; wait_for_call if
in_progress. Only after a terminal no-answer or busy result with no contact
should your workflow consider another call, using a new key and respecting
the user's instructions and the recipient's local time. Do not redial a
`failed` result because it does not establish that nobody was reached.

- `delete_contact`: Delete a saved contact by exact name after the user confirms deletion.
- `get_place`: Full details for one place from search_places: phone, hours, rating,
website, booking link. Pass the same `location` you searched with.

`phone_ref` is the handle call_business needs; when it is null the place
cannot be called and `phone_ref_unavailable_reason` says why — show the
user `detail.phone` / `detail.booking_url` instead. Costs 15 points.

- `list_bookings`: The account's bookings (confirmed, cancelled, answered inquiries).
`status` filters: "confirmed", "cancelled", "answered", or "" for all.
- `list_contacts`: List the token owner's saved contacts with masked phone numbers.

Each contact_ref pins the current name and number for call_contact. If two
names could match a request, ask the user to choose one exact name.
Never repeat a full contact number in chat.

- `modify_booking`: Phone the venue to cancel or reschedule a confirmed booking from
list_bookings. `action` is "cancel" or "reschedule"; reschedule needs
new_date and/or new_time (merchant local). When the venue confirms, the
booking record is updated for you. Same waiting and idempotency rules as
call_business.

- `receiving_phone_status`: Check where call_me would ring (masked). A number must be explicitly
selected and verified by voice; SMS login alone does not qualify. The user
can set it in the web app without enabling outbound Caller ID. Direct them
to setup_url if no receiving number is ready.
- `save_contact`: Add or update one contact after confirming name and number with the user.

phone_number must be E.164, e.g. +85291234567. This updates the same
address book used by the web app. The result masks the number; do not echo
the full number in a chat reply. Set user_confirmed only after agreement.

- `search_places`: Search businesses (restaurants, salons, clinics, hotels…) by free text.

`location` is REQUIRED and decides which country is searched — a city or
country name ("Tokyo", "Singapore"). Returns up to `limit` places with a
`cid` to pass to get_place. Costs 5 points.

- `update_contact`: Edit a saved contact's name and/or E.164 phone number atomically.

Confirm the existing contact and proposed change with the user first.
A name conflict refuses instead of overwriting another person. Return
values mask the number; do not repeat a full number in chat.

- `wait_for_call`: Keep waiting for a call that call_business / modify_booking / call_person / call_me
reported as in_progress. Returns the flat result once the call ends, or
in_progress again — just call it again.
