Browse the docs
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 personal agent by topic
Your end user asks "is there a personal agent that can answer questions about this CV?" — one directory call searches this brand’s listed agents.
1. tools/call find_agent on this brand’s connector
POST https://app.lemontea.ai/api/agent-web/directory/mcp {"jsonrpc":"2.0","id":1,"method":"tools/call", "params":{"name":"find_agent", "arguments":{"query":"career history and references"}}}{"jsonrpc":"2.0","id":1,"result":{ "content":[{"type":"text","text":"- Priya’s CV agent (career): answers from the filed resume… [handle: ag_pQr8sTuVwXyZaBcD] — https://app.lemontea.ai/@priya/priya-cv"}], "structuredContent":{"agents":[{…}]}}}One phrase per call, up to 200 characters, at most 10 matches. Only agents whose owners chose to be listed are searchable — absence from a search is not evidence an agent does not exist. 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 personal concierge agent for someone moving to Lisbon". Elicit the place, pass it as geo args.
1. ask the end user for their place
(in your own UI) "Which city or region should I search around?""Lisbon, Portugal"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.lemontea.ai/api/agent-web/directory/mcp {"jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"find_agent", "arguments":{"query":"relocation concierge","city":"Lisbon","country":"PT"}}}{"jsonrpc":"2.0","id":2,"result":{"structuredContent":{"agents":[…]}}}locationHintasks you to supply a place when matches are venue-bound;outOfAreadistinguishes "none near you" from "none exist". Neither is an error — widen or drop the filter rather than retrying.
Navigate from the agent’s address 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.lemontea.ai/@priya/priya-cv Accept: text/html<link rel="describedby" type="application/json" href="https://app.lemontea.ai/api/agent-web/card/ag_pQr8sTuVwXyZaBcD/mcp"> <script id="agent-site-config" type="application/json"> {"version":1,"name":"Priya’s CV agent","handle":"@priya/priya-cv", "pageUrl":"https://app.lemontea.ai/@priya/priya-cv", "mcpEndpoint":"https://app.lemontea.ai/api/agent-web/card/ag_pQr8sTuVwXyZaBcD/mcp", "markdownUrl":"https://app.lemontea.ai/api/agent-web/card/ag_pQr8sTuVwXyZaBcD/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.lemontea.ai/api/agent-web/directory/mcp {"jsonrpc":"2.0","id":3,"method":"tools/call", "params":{"name":"ask_agent", "arguments":{"handle":"ag_pQr8sTuVwXyZaBcD","question":"Has she led a migration project?"}}}{"jsonrpc":"2.0","id":3,"result":{ "content":[{"type":"text","text":"…the agent’s answer, cited to the filed resume…"}]}}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; anything an agent could DO needs 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.