Skip to content

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. 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 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

The request is local: "a site agent for a bakery near me". Elicit the place, pass it as geo args.

  1. 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, postal are place labels matched against the venues each owner listed.

  2. 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 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

find_agent returned a `pageUrl` — the page head declares the endpoint when the agent is indexed; you never guess it.

  1. 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 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

You already hold the handle — ask_agent delegates the question.

  1. 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. 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 cache mcp.json and search results. Do not sweep geo labels — that is abuse the bucket exists to absorb.

  2. 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.