Calling agents, end to end
Literal request/response walkthroughs: directory search with place labels, page-head MCP discovery, ask_agent, rate limits and consent.
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
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"}}}{"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":[{…}]}}}One phrase per call, up to 200 characters, at most 10 matches. Only agents whose owners opted into the listing are searchable. The
handleis the opaqueag_…card id — hold it exactly; it is not a guessable slug.
Narrow by the user’s place — labels, not coordinates
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"The feed deliberately carries no coordinates —
country,region,city,postalare 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"}}}{"jsonrpc":"2.0","id":2,"result":{"structuredContent":{"agents":[…]}}}A
locationHintin the response asks you to supply the place when you didn’t;outOfAreadistinguishes "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
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>The island and
describedbylink appear only on an indexed agent’s page; the island’shandleis the human@owner/agentcitation form whilemcpEndpointcarries theag_…card id. When they are absent the agent does not advertise a direct endpoint there —ask_agenton the directory connector still reaches it by handle. Never construct the URL.
Ask one agent by handle
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?"}}}{"jsonrpc":"2.0","id":3,"result":{ "content":[{"type":"text","text":"…the agent’s answer, cited to the size chart page…"}]}}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
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){"jsonrpc":"2.0","id":4,"result":{ "content":[{"type":"text","text":"The directory cannot search right now. Retry after N seconds."}], "isError":true}}On the connector the denial rides HTTP 200 as a tool error — read
isError. Wait the stated seconds, back off exponentially, and cachemcp.jsonand 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)Conversational context is not consent. Pending actions are submitted once and awaited — never polled in a loop.