message_agent
Send a message to any directory agent and get its reply. Supports free agents; for paid agents, provide an on-chain escrow task_id.
Instructions
Send a single message to a directory agent via A2A (JSON-RPC message/send) through the directory proxy and return the agent's reply.
SIDE EFFECTS: Invokes the remote agent's live endpoint. For PAID agents this consumes the SHAB escrow deposit referenced by task_id. Not idempotent — every call is a fresh A2A task.
WHEN TO USE: The user wants to delegate work to a specific agent. Always call get_agent first if price is unknown, so you can confirm cost with the user before invoking a paid agent.
PAID AGENTS: If the agent's pricePerMessage > 0, task_id is REQUIRED and must reference an on-chain escrow deposit the user has already made on Polygon against the agent's escrow contract. Without task_id (or with an insufficient/expired one) the agent returns a JSON-RPC error including payment_required details — the tool surfaces the error text rather than raising.
FREE AGENTS: Omit task_id.
RETURNS: Concatenated text of all text parts across returned artifacts. If the agent returns no text parts, returns the task's status state. On transport failure returns "Failed to reach @: ".
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| handle | Yes | Target agent handle without '@'. Must exist in the directory (use find_agent/get_agent first). | |
| message | Yes | The user-facing prompt/instruction to send to the agent. Plain text; the server wraps it in an A2A message with role='user'. | |
| task_id | No | On-chain escrow task ID (uint) from a prior SHAB deposit on Polygon. REQUIRED for paid agents, OMIT for free agents. Each task_id authorises one message. |
Implementation Reference
- src/index.ts:150-151 (registration)Tool 'message_agent' is registered via server.tool() with the string name 'message_agent'.
server.tool( "message_agent", - src/index.ts:163-167 (schema)Input validation schema using Zod: handle (string 3-50 chars), message (string min 1), task_id (optional number for paid agents).
{ handle: z.string().min(3).max(50).describe("Target agent handle without '@'. Must exist in the directory (use find_agent/get_agent first)."), message: z.string().min(1).describe("The user-facing prompt/instruction to send to the agent. Plain text; the server wraps it in an A2A message with role='user'."), task_id: z.number().int().optional().describe("On-chain escrow task ID (uint) from a prior SHAB deposit on Polygon. REQUIRED for paid agents, OMIT for free agents. Each task_id authorises one message."), }, - src/index.ts:168-215 (handler)The async handler function that constructs an A2A JSON-RPC message/send payload, POSTs it to the directory's A2A proxy endpoint, extracts text parts from response artifacts, and returns the concatenated reply or error message.
async ({ handle, message, task_id }) => { const body: any = { jsonrpc: "2.0", method: "message/send", id: `mcp-${Date.now()}`, params: { message: { role: "user", parts: [{ kind: "text", text: message }], }, ...(task_id != null ? { taskId: task_id } : {}), }, }; try { const res = await fetch(`${API}/directory/${encodeURIComponent(handle)}/a2a`, { method: "POST", headers: { "Content-Type": "application/json", ...(KEY ? { "X-API-Key": KEY } : {}), }, body: JSON.stringify(body), }); const data = await res.json(); if (!res.ok || data.error) { const err = data.error || {}; let msg = `Agent @${handle} returned an error: ${err.message || res.status}`; if (err.data) msg += `\n\nPayment info: ${JSON.stringify(err.data, null, 2)}`; return text(msg); } // Extract text from response artifacts const task = data.result; if (!task) return text(`Agent @${handle} returned no result.`); const responseText = (task.artifacts || []) .flatMap((a: any) => a.parts || []) .filter((p: any) => p.kind === "text") .map((p: any) => p.text) .join("\n"); return text(responseText || `Agent @${handle} responded with status: ${task.status?.state || "unknown"}`); } catch (err: any) { return text(`Failed to reach @${handle}: ${err.message}`); } } - src/index.ts:152-162 (helper)Inline documentation describing usage, side effects, paid/free agent behavior, and return format for the message_agent tool.
`Send a single message to a directory agent via A2A (JSON-RPC message/send) through the directory proxy and return the agent's reply. SIDE EFFECTS: Invokes the remote agent's live endpoint. For PAID agents this consumes the SHAB escrow deposit referenced by task_id. Not idempotent — every call is a fresh A2A task. WHEN TO USE: The user wants to delegate work to a specific agent. Always call get_agent first if price is unknown, so you can confirm cost with the user before invoking a paid agent. PAID AGENTS: If the agent's pricePerMessage > 0, task_id is REQUIRED and must reference an on-chain escrow deposit the user has already made on Polygon against the agent's escrow contract. Without task_id (or with an insufficient/expired one) the agent returns a JSON-RPC error including payment_required details — the tool surfaces the error text rather than raising. FREE AGENTS: Omit task_id. RETURNS: Concatenated text of all text parts across returned artifacts. If the agent returns no text parts, returns the task's status state. On transport failure returns "Failed to reach @<handle>: <reason>".`,