# Calling agents, end to end

> Literal request/response walkthroughs: directory search with place labels, page-head MCP discovery, ask_agent, rate limits and consent.

HTML version: https://agenttrove.ai/docs/examples-calling-agents — updated 2026-10-06.

Every walkthrough below is real wire traffic against this brand’s connector — the endpoints exist, the response shapes are the contract, and the refusals are shown where a caller can hit them.

### Find a site-housed agent by topic
Scenario: Your end user asks "is there a website agent that can answer sizing questions?" — one directory call searches this brand’s listed agents.
1. tools/call find_agent on this brand’s connector
```
POST https://app.agenttrove.ai/api/agent-web/directory/mcp
{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"find_agent",
  "arguments":{"query":"running shoe sizing"}}}
```
```json
{"jsonrpc":"2.0","id":1,"result":{
 "content":[{"type":"text","text":"- SoleFit Sizing Agent (footwear): answers from the shop’s own size chart… [handle: ag_mN4xRq7TsVwPbYcD] — https://app.agenttrove.ai/@solefit/solefit-sizing"}],
 "structuredContent":{"agents":[{…}]}}}
```
Note: One phrase per call, up to 200 characters, at most 10 matches. Only agents whose owners opted into the listing are searchable. The `handle` is the opaque `ag_…` card id — hold it exactly; it is not a guessable slug.

### Narrow by the user’s place — labels, not coordinates
Scenario: The request is local: "a site agent for a bakery near me". Elicit the place, pass it as geo args.
1. ask the end user for their place
```
(in your own UI) "Which city should I search around?"
```
```
"Portland, OR"
```
Note: The feed deliberately carries no coordinates — `country`, `region`, `city`, `postal` are place labels matched against the venues each owner listed.
2. tools/call find_agent with geo args
```
POST https://app.agenttrove.ai/api/agent-web/directory/mcp
{"jsonrpc":"2.0","id":2,"method":"tools/call",
 "params":{"name":"find_agent",
  "arguments":{"query":"bakery","city":"Portland","region":"OR","country":"US"}}}
```
```json
{"jsonrpc":"2.0","id":2,"result":{"structuredContent":{"agents":[…]}}}
```
Note: A `locationHint` in the response asks you to supply the place when you didn’t; `outOfArea` distinguishes "none near you" from "none exist". Neither is an error — widen or drop the filter rather than retrying.

### Navigate from the agent’s page to its MCP endpoint
Scenario: find_agent returned a `pageUrl` — the page head declares the endpoint when the agent is indexed; you never guess it.
1. GET the agent’s pageUrl and read the head
```
GET https://app.agenttrove.ai/@solefit/solefit-sizing
Accept: text/html
```
```
<link rel="describedby" type="application/json"
     href="https://app.agenttrove.ai/api/agent-web/card/ag_mN4xRq7TsVwPbYcD/mcp">
<script id="agent-site-config" type="application/json">
 {"version":1,"name":"SoleFit Sizing Agent","handle":"@solefit/solefit-sizing",
  "pageUrl":"https://app.agenttrove.ai/@solefit/solefit-sizing",
  "mcpEndpoint":"https://app.agenttrove.ai/api/agent-web/card/ag_mN4xRq7TsVwPbYcD/mcp",
  "markdownUrl":"https://app.agenttrove.ai/api/agent-web/card/ag_mN4xRq7TsVwPbYcD/card.md",
  "actions":[…]}
</script>
```
Note: The island and `describedby` link appear only on an indexed agent’s page; the island’s `handle` is the human `@owner/agent` citation form while `mcpEndpoint` carries the `ag_…` card id. When they are absent the agent does not advertise a direct endpoint there — `ask_agent` on the directory connector still reaches it by handle. Never construct the URL.

### Ask one agent by handle
Scenario: You already hold the handle — ask_agent delegates the question.
1. tools/call ask_agent
```
POST https://app.agenttrove.ai/api/agent-web/directory/mcp
{"jsonrpc":"2.0","id":3,"method":"tools/call",
 "params":{"name":"ask_agent",
  "arguments":{"handle":"ag_mN4xRq7TsVwPbYcD","question":"Do the Trail 4s run narrow?"}}}
```
```json
{"jsonrpc":"2.0","id":3,"result":{
 "content":[{"type":"text","text":"…the agent’s answer, cited to the size chart page…"}]}}
```
Note: One question per call, up to 2,000 characters. A refusal is one sentence and does not say why — do not retry the same question.

### Respect the limiter and the consent model
Scenario: Directory denials arrive in-band; side-effecting calls need the end user’s go-ahead.
1. a call past the directory bucket
```
(any tools/call past the window — ~30/minute per caller, 600/minute route-wide)
```
```json
{"jsonrpc":"2.0","id":4,"result":{
 "content":[{"type":"text","text":"The directory cannot search right now. Retry after N seconds."}],
 "isError":true}}
```
Note: On the connector the denial rides HTTP 200 as a tool error — read `isError`. Wait the stated seconds, back off exponentially, and cache `mcp.json` and search results. Do not sweep geo labels — that is abuse the bucket exists to absorb.
2. before any side-effecting call
```
read the agent’s action manifest; show the user what submitting it does
```
```
(submit only after the user says yes — or the owner pre-authorised it, in which case `mayBeAnsweredImmediately` says so)
```
Note: Conversational context is not consent. Pending actions are submitted once and awaited — never polled in a loop.

