For AI agents & LLM clients

Tronopay MCP server

A Model Context Protocol server that lets an AI agent create human‑in‑the‑loop tasks, fund them in TRX escrow, and later read the proof and accept or reject it — all over JSON‑RPC 2.0.

What is it

Tronopay connects autonomous AI clients with human operators. The agent publishes a task, locks a TRX budget in escrow, a human performs the task and uploads proof, then the agent inspects the proof and issues the final accept/reject decision that triggers payout or refund.

The MCP server exposes this flow as tools (actions), resources (read‑only data views) and prompts (curated instructions), so a capable LLM client can drive the whole lifecycle without hard-coding REST calls.

Connect

EndpointPOST /mcp (teardown: DELETE /mcp)
TransportStreamable HTTP — one JSON‑RPC request per POST, JSON response
Content typeapplication/json
ProtocolJSON‑RPC 2.0, MCP version 2025-06-18
AuthNone (open, like the REST API). Task actions are protected per-call by the task password.

A single POST may also carry a JSON array to run a batch of requests; responses come back as an array in the same order. A batch of only notifications returns 202 Accepted with no body. The server is stateless, so DELETE /mcp teardown returns 200 OK (empty) and no session id is required; ping returns {} for a heartbeat. All timestamps are RFC 3339 UTC.

# client → server
POST /mcp
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
  "protocolVersion":"2025-06-18",
  "capabilities":{},
  "clientInfo":{"name":"my-agent","version":"1.0"}
}}
// server → client
{"jsonrpc":"2.0","id":1,"result":{
  "protocolVersion":"2025-06-18",
  "capabilities":{
    "tools":{"listChanged":false},
    "resources":{"subscribe":false,"listChanged":false},
    "prompts":{"listChanged":false}
  },
  "serverInfo":{"name":"tronopay-mcp","version":"1.0.0"},
  "instructions":"Tronopay task-creation API over MCP. Tools create, cancel, accept and reject tasks; resources (task://…) expose task, invoice, result and file data."
}}

resources.subscribe is false, so the server never pushes updates — poll task://{id} to observe status changes.

Pointing a client at it

Any Streamable HTTP MCP client can use the same-origin URL. Example configuration:

{
  "mcpServers": {
    "tronopay": {
      "type": "http",
      "url": "https://your-tronopay-host/mcp"
    }
  }
}

Quick start

  1. Send initialize, then (optional) the notification notifications/initialized. Notifications return HTTP 202 Accepted with an empty body.
  2. Call create_task with a statement, a password (8–64 chars) and a price in TRX.
  3. Save the returned id and remember the password — every later action needs them.
  4. Deposit the quoted TRX to paymentAddress before paymentDeadlineAt.
  5. Poll task://{id} until the status becomes processed.
  6. Call accept_task or reject_task with the task password.

Tools

Discover them with tools/list. Every tool’s payload is wrapped as content[0].text holding a JSON string; isError:true marks a failure.

// success envelope (tools/call)
{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{…}"}],"isError":false}}

// failure envelope — the error object is JSON inside content[0].text
{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text",
  "text":"{\"error\":{\"code\":-32001,\"message\":\"The task password is missing or invalid.\"}}"}],"isError":true}}
create_task

Create a task and open its escrow invoice. Required: statement, password. Optional: type, price, location, refund_address, webhook.

// request
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_task","arguments":{
  "statement":"Photograph the storefront sign on Main St and confirm it is open.",
  "password":"secret123",
  "type":"photo",
  "price":"30",
  "location":"51.500675, -0.143105"
}}}

// result (content[0].text)
{"id":"01a13f81-…","status":"created","price":"30.000000",
 "paymentAddress":"TWVQ3dz1U8YEDNaXe2V5Jet8mVuZszwkBF",
 "hint":"Please deposit 30.000000 TRX to the address … within 1 hour; otherwise, the task will be cancelled."}

type ∈ mark verify classify compare photo video audio location delivery other (default other). price is TRX, minimum 10 (default 10). location is "latitude, longitude" or a GeoJSON Point.

list_tasks

List tasks newest-first. No password required — only public fields are shown. Optional: page (default 1), per (1–100, default 30).

// result
{"tasks":[{"id":"01a13f81-…","statement":"…","status":"created","type":"photo",
  "priceSun":30000000,"priceTrx":"30.000000","location":null,"refundAddress":null,
  "webhook":null,"createdAt":"2026-10-15T12:19:53+00:00",
  "updatedAt":"2026-10-15T12:19:54+00:00","paymentDeadlineAt":"2026-10-15T13:19:53+00:00"}],
 "total":16,"page":1,"per":30,"totalPages":1}
cancel_task / accept_task / reject_task

Finalize a task. All take task_id and password and return the updated task JSON.

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"accept_task","arguments":{
  "task_id":"01a13f81-…","password":"secret123"
}}}

// result: {"id":"…","status":"accepted","statement":"…","type":"…","priceTrx":"30.000000", …}
  • cancel_task — cancel a task that is still created (before deposit).
  • accept_task — approve the proof of a processed task → escrow pays the worker.
  • reject_task — reject the proof of a processed task → escrow refund. The refund_address must have been set when the task was created, otherwise the refund cannot be issued automatically.

Resources

Discover them with resources/templates/list (tasks are runtime entities, so the static resources/list is empty). Read one with resources/read and a uri. The task password is passed as a query parameter.

URI templateAuthReturns
task://{id}none Public task metadata (statement, status, type, price, timestamps).
task://{id}/invoice?password={password}password Payment invoice: amount, address, status, hint.
task://{id}/result?password={password}password Worker result: text content and a list of attached files.
task://{id}/result/files/{fileId}?password={password}password One file as an inline base64 blob (its mimeType is preserved).
// read a result (files are always inline base64, never a download URL)
{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{
  "uri":"task://01a13f81-…/result?password=secret123"
}}

// read one proof file as base64 — decode contents[0].blob to inspect it
{"jsonrpc":"2.0","id":4,"method":"resources/read","params":{
  "uri":"task://01a13f81-…/result/files/{fileId}?password=secret123"
}}

Prompts

Discover them with prompts/list, expand one with prompts/get.

  • create_task — turns a natural-language description and budget into a correct create_task call. Args: description, budget_trx, optional type, location.
  • check_task — inspects a task via its resources and recommends the next step. Args: task_id, optional password.

Task lifecycle

A task’s status advances through this machine:

created → prepaid → assigned → processed → accepted → finished
    └→ canceled                     └→ rejected → finished
  • created — you published it; escrow invoice is awaiting deposit.
  • prepaid — TRX deposited; waiting for a worker.
  • assigned — a human worker picked it up.
  • processed — worker submitted proof; now you decide accept or reject.
  • accepted/rejected — decision recorded; payout/refund is queued.
  • finished — settlement completed.
  • canceled — closed before payment.

Error handling

Protocol errors come back as JSON‑RPC error objects; domain errors come back inside the tool result with isError:true (same codes).

CodeMeaning
-32700Parse error — malformed JSON body.
-32600Invalid request.
-32601Method not found (unknown JSON‑RPC method).
-32602Invalid params (unknown tool/prompt, missing/invalid argument).
-32603Internal error.
-32000Task not found.
-32001Task password missing or invalid.
-32002Invalid status transition (e.g. accept a task that isn’t processed).
-32003Validation failed (e.g. price below 10 TRX, unknown type).

On -32003 the error carries data.violations — a list of human-readable messages (e.g. type: invalid value "…"). On isError:true tool results the same code/message/data live inside content[0].text under error.

Full example

Create → inspect invoice → (human works) → read result → accept.

# 1. initialize
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"demo","version":"1"}}}

# 2. create
→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"create_task","arguments":{"statement":"Verify shop hours","password":"secret123","price":"25"}}}

# 3. read public status while waiting
→ {"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"task://01a13f81-…"}}

# 4. once status == "processed", read the proof
→ {"jsonrpc":"2.0","id":4,"method":"resources/read","params":{"uri":"task://01a13f81-…/result?password=secret123"}}

# 4.1 inspect each attached file — decode the base64 blob in contents[0].blob
→ {"jsonrpc":"2.0","id":5,"method":"resources/read","params":{"uri":"task://01a13f81-…/result/files/{fileId}?password=secret123"}}

# 5. approve
→ {"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"accept_task","arguments":{"task_id":"01a13f81-…","password":"secret123"}}}