ripar-skills
This server provides an agent-interoperability layer for the Ripar platform on Algorand TestNet, enabling read-only access to on-chain registries and composition of unsigned blockchain transactions. Key capabilities include:
Agent Search and Lookup: List or search agents by domain, ID, or address (
ripar_search_agents); fetch a single agent's details, optionally with reputation and jobs (ripar_get_agent).Reputation and Settlements: Read an agent's on-chain score, credited payments, USDC volume, and validator verdicts (
ripar_get_reputation); audit actual USDC transfers versus counted payments (ripar_settlements).Job Listing: Browse jobs on the ValidationRegistry by status, agent, or job ID, viewing budget and escrow amounts (
ripar_list_jobs).x402 Endpoint Interaction: Obtain price quotes from paid endpoints without paying (
ripar_quote_endpoint); call an endpoint and receive 402 payment challenges when required (ripar_call_endpoint).Compose Unsigned Transactions: Build unsigned transactions for posting a job (
ripar_post_job), funding escrow via a two-transaction group (ripar_fund_job), and releasing or refunding escrow (ripar_settle_escrow). All transactions are returned as base64 msgpack for external signing—the server never signs or broadcasts.A2A Agent Cards and On-Chain Verification: Publish and discover agent capabilities and contact information, verifiable on-chain.
MCP Resources and Prompts: Expose registry data (agent lists, job lists) as MCP resources and support guided workflows like vetting agents, posting/funding jobs, and settling escrow.
All data is read directly from live TestNet registries, ensuring current escrow and reputation information.
Provides tools for interacting with Ripar's agent and reputation registries deployed on the Algorand TestNet, enabling agent lookup, reputation checks, job listing, settlement auditing via the Algorand indexer, and composition of post-job transactions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ripar-skillsSearch for registered agents and tell me which ones have been paid."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@ripar/skills
Ripar's agent-interoperability layer.
Two protocols, one package:
an MCP server so Claude (or any MCP client) can drive Ripar — agent to tool
an A2A agent card so other agents can find Ripar without a human wiring anything up — agent to agent
Everything it reads comes off three registries that are live on Algorand TestNet. Nothing here signs anything: a write comes back as an unsigned transaction for a human or a wallet to approve.
IdentityRegistry 769444119 who an agent is
ReputationRegistry 769444120 what payments have been credited to it
ValidationRegistry 769444121 what work is open, how it was judged, and what is escrowedYou can check those on the explorer right now: https://testnet.explorer.perawallet.app/application/769444119
A job carries two money numbers and they are not the same thing. The budget is what the client says the work is worth. The escrow is what they have actually handed to the contract. A job showing budget 1.0 and escrow 0 is unfunded — and that is the single most useful thing an agent can know before bidding on it. Every job this package returns reports both.
Quick start
git clone <this repo> && cd ripar-skills
npm install
npm run build
npm test # 192 tests, 13 of which hit the real chainTry it without an MCP client at all:
printf '%s\n%s\n%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"ripar_get_reputation","arguments":{"agentId":1}}}' \
| node dist/bin/mcp-stdio.js 2>/dev/nullThat returns agent 1's real score, read out of box sc_ on app 769444120 while you wait.
Related MCP server: Agent Directory MCP Server
Connecting it to Claude
Open your Claude Desktop config:
macOS
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows
%APPDATA%\Claude\claude_desktop_config.json
Create the file if it isn't there, and add this block. Replace the path with the absolute path to your clone — Claude Desktop does not expand ~ or resolve relative paths.
{
"mcpServers": {
"ripar": {
"command": "node",
"args": ["/absolute/path/to/ripar-skills/dist/bin/mcp-stdio.js"],
"env": {
"RIPAR_NETWORK": "testnet"
}
}
}
}If you already have other servers in mcpServers, add "ripar" alongside them rather than replacing the object.
Then quit Claude Desktop completely and reopen it — it only reads the config at launch. You should see the tools appear under the tools icon. Ask it something like "Search Ripar for registered agents and tell me which ones have actually been paid."
Once this is published to npm, the same block without a build step:
{
"mcpServers": {
"ripar": {
"command": "npx",
"args": ["-y", "@ripar/skills"]
}
}
}If the server doesn't show up: Claude Desktop logs to ~/Library/Logs/Claude/mcp-server-ripar.log on macOS. The usual causes are a relative path in args, a missing npm run build, or a node that isn't on Claude's PATH (use the absolute path from which node if so).
Other MCP clients
Anything that speaks MCP over stdio works — the command is the same:
node /absolute/path/to/ripar-skills/dist/bin/mcp-stdio.js# Claude Code
claude mcp add ripar -- node /absolute/path/to/ripar-skills/dist/bin/mcp-stdio.jsThe tools
Tool | What it does | Reads or writes |
| List or search the IdentityRegistry by domain, id, or address | read |
| One agent record, optionally with its score and jobs | read |
| Settled payments, USDC volume, validator verdicts | read |
| Jobs on the ValidationRegistry — budget and escrow both | read |
| Real USDC transfers, next to the score the chain actually holds | read |
| Ask a paid endpoint what it costs, without paying | read |
| Call an endpoint; returns the 402 challenge if it charges | can spend |
| Compose a | returns a transaction |
| Compose the two-transaction group that puts money in escrow | returns a group |
| Compose a | returns a transaction |
The four that aren't reads
ripar_post_job returns base64 msgpack plus a plain-language summary:
{
"signed": false,
"unsignedTxnBase64": "iqRhcGFhlMQE6xJnHsQiACBdanwFPa6OATBBTNfKO3sHnSiP…",
"txId": "IM2SP7CUFPBNC5BSJJEKG2FDCLPXPSKZKY53IZHTOAVERKEOMMUA",
"method": "post_job(byte[],uint64,uint64)uint64",
"summary": "Open job #3 on ValidationRegistry 769444121 with a budget of 2.500000 USDC, committing to spec hash 5d6a7c…, to be judged by agent 1. Signing this makes UBB4… the job's client.",
"boxes": ["jb_3"],
"nextSteps": ["…", "Sign it with the wallet that holds `sender`; this package holds no key and cannot sign.", "…"]
}ripar_fund_job returns two transactions, because fund_job is a group and only works as one:
{
"signed": false,
"groupId": "<base64 of the 32-byte group id BOTH transactions carry>",
"method": "fund_job(axfer,uint64)uint64",
"summary": "Move 1.000000 of asset 10458941 into escrow for job 3 … the money leaves KBDR… and is held by the contract at EJHY… until the work passes (release_escrow pays the assignee) or fails (refund_escrow returns it here).",
"transactions": [
{ "index": 0, "kind": "axfer", "summary": "Transfer 1.000000 of asset 10458941 from KBDR… to the app account EJHY…" },
{ "index": 1, "kind": "appl", "boxes": ["jb_3", "es_3"], "summary": "Call fund_job(axfer,uint64) … which reads the amount off transaction 0" }
],
"nextSteps": ["Sign BOTH transactions … a group is invalid if any member is missing or moved.", "…"]
}The contract reads the escrow amount off transaction 0, not from an argument — so the number it records is one the AVM has already validated. That is the same rule that stopped reputation being minted from bytes, and it is why this is a group rather than a call with a number in it.
ripar_settle_escrow composes the other end. release pays the assignee and is legal only on a passing verdict: the client may sign immediately, and anyone at all may sign once the dispute window has closed — because a validator who never comes back would otherwise freeze the worker's money for good. refund returns the escrow to the client on a failed verdict or a cancelled job, and anyone may sign that too, since the destination is read off the job rather than off the sender.
Both refuse, before a fee is spent, anything the chain would reject anyway: the wrong sender, the wrong status, or an escrow that is already 0.
ripar_call_endpoint forwards an X-PAYMENT header you supply, and never invents one. If the endpoint answers 402 and you gave it nothing, you get the challenge back with an explanation, not a silent charge.
Why: an MCP server is driven by a model. A model that can both decide to spend and sign for the spend has no meaningful approval step. Splitting compose from sign puts a human in the middle, and the base64 blob is exactly what a wallet expects, so the split costs you one paste.
There is no mnemonic parameter, no key file, and no signTransaction import anywhere in this package. grep -rn "signTransaction\|mnemonic" src/ returns two lines, both of them the prose in src/unsigned.ts promising the code is not there.
Resources
The registries are also readable as MCP resources — documents a client can attach to a conversation without anyone deciding to call a tool:
URI | What it holds |
| The three app ids, and the escrow terms read off the contract's own global state |
| Every agent, with the URL its A2A card should be at |
| One agent, its score, and the jobs it is on |
| Every job, budget and escrow side by side |
| One job, plus when its escrow becomes releasable by anyone |
The two templates enumerate: resources/list returns one entry per agent and one per job, with
the real domain or the real budget in the title, so a picker shows the roster rather than a URI
pattern you are expected to fill in yourself. Every read hits the chain at the moment it is read —
there is no cache, because a cached escrow figure is how an agent ends up doing unpaid work.
Prompts
Three guided flows, each of which is mostly about the order the tools have to be used in:
Prompt | What it walks through |
| Resolve → reputation → settlements → job history → quote, ending in a recommendation that is allowed to be "no" |
| Compose |
| Read the status, pick release or refund from it, name who is about to be paid, and say who may sign and when |
Every tool a prompt names exists — PROMPTS_REFERENCE_TOOLS is asserted against TOOL_NAMES in the
tests. A prompt that sends a model after a tool that isn't there gets improvisation instead of a
chain read, and for "has this agent been paid" that means an invented track record.
Skills
A skill is the smallest thing an agent can advertise and be paid for: a stable id, a description, an input schema, and a price. That triple is what each protocol needs — A2A publishes the id and description so a peer can find it, MCP publishes the schema so a client can call it, and x402 publishes the price so the caller knows the cost before committing.
Four ship, all backed by the registries:
Skill | Price | Backed by |
| free |
|
| $0.01 |
|
| $0.02 |
|
| $0.05 |
|
Reads that cost nothing to serve are priced at zero rather than given a token price. Charging for a public box read would be theatre.
import { SKILLS, skillsManifest } from "@ripar/skills";
console.log(skillsManifest("testnet"));
// { asset: { id: 10458941, symbol: "USDC", decimals: 6 }, skills: [ … ] }ripar.settlement.audit is the one worth looking at. It reads USDC transfers from the indexer and reports them next to the score the ReputationRegistry actually holds, so a claimed track record can be checked against money that demonstrably moved.
What it deliberately does not report is a per-transfer "already credited" flag. The registry used to keep a pd_ box per counted payment and this skill joined against it; that ledger is gone, because keying it on the txid was circular — the box name depends on the txid, which depends on the group id, which depends on the app call, which must declare the box — and unnecessary, since the payment is now a transaction in the same group and consensus rejects a duplicate. Leaving the join in place would have marked every real payment uncredited: a lie in the shape of an answer.
A2A: publishing and discovering
Publish your card
RIPAR_AGENT_ID=1 \
RIPAR_PAY_TO=UBB4PNTT7CI3IQS25ZMQR4DGVYYCBORNSBLU4WKUGX4BAZ3KN4O2KATPAU \
RIPAR_AGENT_URL=https://your-agent.example \
npm run cardServes the card at both /.well-known/agent.json and /.well-known/agent-card.json. Or drop it into an app you already have:
import { riparAgentCard, createCardHandler } from "@ripar/skills/a2a";
const card = riparAgentCard({
name: "My Ripar Agent",
description: "Does a specific useful thing",
url: "https://your-agent.example",
agentId: 1, // your IdentityRegistry id
payTo: "UBB4…", // where x402 payments land
});
const handleCard = createCardHandler(card);
// returns true if it answered, false if the path wasn't a card — so it
// sits in front of your existing routes rather than taking them overDiscover someone else's
import { discoverAgent } from "@ripar/skills/a2a";
const result = await discoverAgent("agent-1785821796525.ripar.io");
result.endpoint // where to talk to it
result.skills // what it says it can do
result.x402.prices // what each skill costs
result.mcp.tools // which MCP tools it exposes
result.verification // whether the chain agrees with the card
result.warnings // things worth knowing before you payverification is the part that matters. An agent card is a self-published document — anyone can write "agentId": 1 on theirs. discoverAgent reads that id out of the IdentityRegistry and compares the domain the contract holds against the host that actually served the card. Disagreement means verified: false with a reason that says "impersonating", never a quiet downgrade to "probably fine".
A2MCP: why these two protocols belong in one package
They're perpendicular, which is exactly why they compose.
MCP is agent-to-tool. A client already knows about a server and calls its tools. It answers how do I invoke this? — and has no discovery story at all. Someone has to put the server in a config file first.
A2A is agent-to-agent. An agent publishes a card at a well-known URL. It answers who is out there and what can they do? — and has no invocation story for tools. A card describes skills, not function signatures.
Stack them and each fills the other's hole. A Ripar card carries an MCP extension naming the exact server the agent exposes and the tools on it:
{
"capabilities": {
"extensions": [
{
"uri": "https://ripar.io/a2a/ext/mcp/v1",
"params": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@ripar/skills"],
"tools": ["ripar_search_agents", "ripar_get_agent", "…"]
}
}
]
}
}So the whole path is:
GET https://them.example/.well-known/agent.json ← A2A discovery
→ read capabilities.extensions[".../mcp/v1"] ← which tools exist
→ connect to that MCP server ← MCP invocation
→ call the tool ← work happensDiscovery and invocation end up one hop apart. An agent that has never heard of another agent can go from a bare domain to a live tool call without a human editing a config.
The third leg is payment. The x402 extension states what each skill costs and where to pay; the registry extension states which on-chain agent id backs the claim. So the caller can check reputation before it spends. Price, track record, and the call itself all come off one document.
Extension data rides in capabilities.extensions[] — the A2A spec's own escape hatch — rather than in invented top-level fields, so a strict A2A reader that has never heard of Ripar still parses the card and just ignores the parts it doesn't know.
A note on card paths and versions
The current A2A spec puts the card at /.well-known/agent-card.json and models transports as supportedInterfaces[]. The older, widely deployed shape used /.well-known/agent.json with flat url + preferredTransport + protocolVersion.
This package writes both — one document that satisfies either reader — and parses both, normalising to one internal shape. You don't have to know which generation a peer speaks.
Reading the chain yourself
No API key, CORS open, nothing to sign up for:
import { RiparRegistry } from "@ripar/skills";
const registry = new RiparRegistry(); // TestNet by default
await registry.totalAgents(); // global state agent_count
await registry.listAgents(); // every ag_ box, decoded
await registry.resolveByDomain("agent-….ripar.io"); // dm_ index → agent id
await registry.getScore(1); // sc_ box
await registry.listJobs({ status: "assigned" }); // jb_ boxes
await registry.listJobsWithEscrow({}); // jb_ boxes ⋈ es_ boxes
await registry.getEscrow(2); // es_ box, 0 when unfunded
await registry.escrowTerms(); // asset, window, app account
await registry.settlements({ agentId: 1 }); // indexer, plus the score boxIf the chain is unreachable these throw. There is no cache, no seed data, and no fallback — an agent acting on a fabricated reputation score is worse than one that knows it couldn't check.
About the box encoding
Box values are ARC-4 encoded structs, so they're decoded with ABIType.from(...) using the layout from the ARC-56 JSON, never by slicing at hand-counted offsets. AgentInfo has five fields but a 58-byte head — the domain lives in a tail addressed by a 2-byte offset. Guess that wrong and you read an agent's domain out of the middle of its address.
Box names are raw AVM bytes, which is a different rule:
ag_ + 8 raw big-endian bytes uint64 agent id
dm_ + the domain's UTF-8 bytes no ARC-4 length prefix
ad_ + the 32-byte public key not the 58-character address string
sc_ + 8 raw big-endian bytes uint64 agent id
jb_ + 8 raw big-endian bytes uint64 job id
es_ + 8 raw big-endian bytes uint64 job id — value is a bare uint64, not a structBoth rules are pinned by tests against real captured bytes.
es_ has one more rule worth stating: an absent box is zero. The contract never creates one for
a job nobody funded, and it deletes the box before it sends the money out, which is what makes
paying an escrow twice impossible. So escrow 0 on a finished job means it was settled, not that it
never existed.
Configuration
Everything defaults to TestNet and public endpoints. Environment variables, all optional:
Variable | Default | Notes |
|
| The registries only exist on TestNet today |
|
| |
|
|
Asking for mainnet without supplying app ids fails loudly rather than reading app 0 and reporting an empty registry.
Tests
npm test # 192 tests, including live TestNet reads
RIPAR_SKIP_LIVE=1 npm test # offline: skips the 13 live tests
npx tsc --noEmit # typecheckFile | Covers |
| ARC-4 box decoding and box-name encoding, against bytes captured from the live chain |
| A2A card emitting, parsing, warnings, and impersonation detection |
| Tool schemas and annotations, plus the real server over an in-memory transport |
| Reading |
| Resources and prompts over the real MCP protocol, including that prompts name real tools |
| The four skills, their prices, and their input guards |
| 402 challenge parsing and the never-invent-a-payment rule |
| Real reads against TestNet — shape invariants, not fixed values |
The fixtures aren't invented. Every base64 blob in decoders.test.ts was captured with a curl that's quoted in the file, so a decoder that drifts from what the deployed contracts write fails offline instead of returning confident nonsense at runtime.
The escrow transactions were checked against the real AVM before any of them shipped, by running the composed groups through algod's simulate endpoint — which needs no key and spends no fee, and which reports a missing box or foreign app as unavailable App … and a short inner-transaction budget as group fee … too small, both of them long before the contract's own asserts are reached. Dropping the identity app from release_escrow produces exactly the first; dropping the extra fee produces exactly the second.
The tests are mutation-checked: each new assertion was verified by breaking the line it covers and confirming the suite goes red. 45 mutations, 45 killed — including grouping the funding transactions the wrong way round, paying a refund to the sender instead of the client, measuring the dispute window from the wrong timestamp, and pointing a prompt at a tool that does not exist.
Layout
src/
config.ts app ids, endpoints, USDC, job statuses, box prefixes
abi.ts ARC-4 box decoders and box-name encoders
registry.ts the read side — algod, indexer, escrow, and the settlement join
unsigned.ts the write side — composes, never signs
x402.ts 402 challenge parsing, quote vs call
skills.ts the four skills
a2a/
card.ts build and parse agent cards (both generations)
discover.ts discoverAgent() + on-chain verification
server.ts Ripar's own card, and a handler that serves it
mcp/
tools.ts the ten tools, defined as data
resources.ts ripar:// documents, including the two that enumerate
prompts.ts three guided flows, each naming only tools that exist
server.ts McpServer wiring
bin/
mcp-stdio.ts the stdio entry point
serve-card.ts the card serverKnown gaps
Things that are true about the deployed system today, written down because finding them in production is worse.
1. Escrow is denominated in a test asset, not in circulating USDC. The live
ValidationRegistry is bootstrapped against ASA 768547363 (rUSDC), a six-decimal token minted for
this deployment because the TestNet USDC faucet is login-gated. escrowTerms() reports that id
rather than assuming it. Read the assetId a composer gives you; do not assume "USDC" because the
amounts are formatted with six decimals. Moving to circulating USDC (10458941) means a redeploy —
bootstrap is one-shot — and an older registry still answers with the old asset forever.
2. The volume on TestNet is a proof, not traction. Agent 1's score box currently reports one
credited payment of 0.010000 and two passing validations. Those are real — the payment is an
Algorand transfer that the contract read out of its own group, and the verdicts were written by the
ValidationRegistry through record_validation — but they were produced by deploy-v2.mjs
exercising the contracts, not by anyone buying anything. Do not quote them as usage.
3. Box listings are capped at 100 pages of 1000. listBoxNames paginates with algod's
next-token and throws rather than returning a partial list, so it is correct up to 100,000 boxes
per prefix and loud after that. listJobs still reads every jb_ box before filtering, so a
registry with many thousands of jobs will issue that many concurrent box reads and get rate-limited.
4. npx tsc --noEmit does not typecheck test/. tsconfig.json excludes it. Four type errors
in test/x402.test.ts are invisible to the typecheck command; vitest transpiles without checking,
so the suite passes anyway.
License
MIT
Available Tools
8 toolsripar_call_endpointCall an endpoint (x402-aware)A
Call an endpoint and return its response. If it answers 402, you get the payment challenge back instead of a result — this server holds no private key and CANNOT pay. To complete a paid call, have a wallet sign the payment and pass the resulting header as paymentHeader; it is forwarded untouched as X-PAYMENT.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Full URL of the endpoint to call | |
| body | No | JSON body, for POST | |
| method | No | HTTP method | GET |
| headers | No | Extra request headers | |
| paymentHeader | No | A pre-signed x402 payment header. Sending this spends money. This server cannot create one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate readOnlyHint=false, destructiveHint=false, etc., but the description adds valuable behavioral details: the server cannot pay (no private key), 402 responses yield a payment challenge, and paymentHeader is forwarded untouched as X-PAYMENT. This goes beyond the schema and annotations, informing the agent of important limitations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the primary action, then concise conditions and payment guidance. No filler or redundancy. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a generic endpoint caller with 5 params, nested objects, and no output schema, the description covers the essential behavioral context: success returns the response, 402 returns a payment challenge, and the server's inability to pay. This is sufficient given the tool's open-ended nature.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds semantic value by explaining that paymentHeader is forwarded as X-PAYMENT and clarifying the 402 flow, which is not fully captured in the schema's parameter descriptions. This enriches understanding of how the paymentHeader parameter functions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Call an endpoint and return its response' with a specific verb and resource. It distinguishes this from sibling tools (agent search, reputation, jobs, settlements) by focusing on generic endpoint invocation with x402 payment handling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides clear context for use: call any endpoint, with special handling for 402 payment challenges. While it doesn't explicitly mention alternatives or when-not-to-use, the purpose is self-evident given sibling tools are domain-specific. The payment guidance adds practical usage direction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ripar_get_agentGet one Ripar agentARead-only
Fetch a single agent record from the IdentityRegistry by id, domain, or Algorand address. Returns found:false with the reason when the registry has no such agent — the contract's 'not found' value is a literal 0, so an absent agent is a real answer, not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | Exact domain, e.g. agent-123.ripar.io | |
| address | No | Algorand address, 58 characters | |
| agentId | No | Registry id | |
| includeJobs | No | Also list jobs this agent is involved in | |
| includeReputation | No | Also read the agent's score box |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds valuable insight about the 'not found' behavior: returns found:false with reason, and the literal 0 representation. This goes beyond annotations and correctly explains absence is not an error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the main purpose and immediately followed by a crucial edge-case explanation. No unnecessary words or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the core fetch behavior and not-found semantics, but leaves ambiguity about optional identifier precedence (e.g., if multiple identifiers are passed) and response shape affected by includeJobs/includeReputation. Still, schema descriptions fill some gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptive text for each parameter. The description references id/domain/address but does not add new parameter-level meaning beyond schema descriptions. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool fetches a single agent record from the IdentityRegistry by id, domain, or Algorand address. The verb 'Fetch' combined with 'single' distinguishes it from sibling search tool ripar_search_agents.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description indicates usage for retrieving one specific agent via unique identifiers, contrasting with search. It does not explicitly name alternatives or state when not to use, but the context is clear enough for selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ripar_get_reputationGet an agent's reputationARead-only
Read an agent's score from the ReputationRegistry (Algorand TestNet app 768559198): payments credited to it, total USDC volume, and validator verdicts. Each credit is keyed to a payment transaction id and the contract refuses to count the same id twice, but it does NOT verify that the id names a real transfer — so treat a score as a claim recorded on chain, not one proven by it, and call ripar_settlements to check it against the indexer before trusting a number. An agent with no score box has never been credited at all, which is different from having been paid and scored zero.
| Name | Required | Description | Default |
|---|---|---|---|
| agentId | Yes | Registry id of the agent |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, but the description adds crucial behavioral context: credits are keyed to payment IDs and the contract refuses duplicates but does not verify real transfers, so scores are claims not proofs. It also explains the 'never credited' vs 'scored zero' distinction, going well beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single paragraph but packs vital caveats and usage guidance without fluff. It could be split for readability, but every sentence contributes meaning, making it appropriately concise for the complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully describes what the read operation returns (payments credited, total USDC volume, validator verdicts), covers limitations (no real transfer verification), and explains edge cases (no score box). It provides all necessary context for an agent to invoke and interpret the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already provides 100% coverage for the single parameter with a clear description ('Registry id of the agent'). The tool description does not add further semantic detail about the parameter, so the baseline of 3 is appropriate since the schema carries the explanation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Read') and names the exact resource ('ReputationRegistry' app 768559198) and the data returned (payments, USDC volume, verdicts). It distinguishes itself from siblings by explicitly contrasting with ripar_settlements, making its purpose clear and unique.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use the tool ('Read an agent's score') and when not to trust it blindly, instructing the agent to call ripar_settlements to verify against the indexer before relying on the number. It also clarifies the meaning of a missing score box, giving clear guidance on interpreting results.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ripar_list_jobsList validated jobsARead-only
List jobs on the ValidationRegistry (Algorand TestNet app 768547172), newest first, optionally filtered by status or by the agent serving or validating them. Each job commits to its spec by hash; the spec and the result themselves stay offchain.
| Name | Required | Description | Default |
|---|---|---|---|
| jobId | No | Fetch exactly one job | |
| limit | No | Maximum jobs to return | |
| status | No | Filter by lifecycle state. 'disputed' is a validator's failing verdict. | |
| agentId | No | Only jobs where this agent is the server or the validator |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint, which already conveys safety. The description adds context about the specific Algorand TestNet app, the newest-first ordering, and that specs/results stay offchain. This goes beyond annotations without contradicting them, though it doesn't describe return formatting or pagination.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences: the first front-loads the action and filters, the second adds useful context about offchain storage. No fluff or redundancy; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is a simple list operation with no output schema, and the description does not specify the structure of returned job objects. While it gives useful context (app ID, hash commitment, offchain storage), the absence of return-format details leaves the description not fully complete for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema descriptions cover 100% of parameters with meaningful details (e.g., status enum and the 'disputed' clarification, agentId scope). The tool description's mention of filtering is redundant with the schema, adding no new parameter-level meaning, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the specific verb 'List' and clearly identifies the resource ('jobs on the ValidationRegistry'), including ordering ('newest first') and filter options. It differentiates from siblings like ripar_post_job (create) and ripar_search_agents (search agents) by focusing on job listing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use this tool: to list jobs with optional filters by status or agent. It does not explicitly mention alternatives or exclusions, but the verb and resource make the use case unambiguous, so it misses the explicit 'when-not' guidance that would earn a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ripar_post_jobCompose a post-job transaction (unsigned)AIdempotent
Compose a ValidationRegistry post_job call and return it UNSIGNED as base64 msgpack, with a plain-language summary of what signing it would do. Nothing is submitted and no key is used or held: a human or wallet signs and broadcasts. The spec is committed by hash so it cannot be changed after the job is open.
| Name | Required | Description | Default |
|---|---|---|---|
| sender | Yes | Address that will sign, pay the fee, and become the job's client | |
| specHash | Yes | Hex of the 32-byte sha256 digest of the job spec. The spec stays offchain. | |
| budgetMicro | Yes | Budget in USDC base units — 2500000 is $2.50. The contract rejects zero. | |
| validatorAgentId | No | Registry id of the judging agent, or 0 to leave it unset |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (readOnlyHint: false, destructiveHint: false, idempotentHint: true), the description discloses concrete behavioral details: the output is unsigned base64 msgpack, no key is used/held, nothing is submitted, and the spec is committed by hash to prevent changes. This adds significant context beyond the annotations alone and contains no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loads the primary action and output, and every sentence adds meaningful detail (output format, signing authority, immutability). There is no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a transaction composer with no output schema and no nested objects, the description adequately covers what the tool returns (unsigned base64 msgpack plus plain-language summary), the safety model (no submission/key), and the commitment property of specHash. It is complete for this level of complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% parameter descriptions, so the baseline is 3. The description adds a contextual note that 'the spec is committed by hash' which reinforces the role of specHash, but does not add new format or syntax details for the parameters. Thus it does not exceed the schema's coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Compose a ValidationRegistry post_job call and return it UNSIGNED as base64 msgpack', naming a specific verb (compose), resource (ValidationRegistry post_job), and distinguishing output format. This clearly differentiates it from sibling tools like ripar_search_agents or ripar_get_agent, which are read-only queries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states that 'Nothing is submitted and no key is used or held: a human or wallet signs and broadcasts,' which tells the agent when to use this tool (to prepare an unsigned transaction) and what it will not do (submit). It does not explicitly name alternative tools, but the sibling list contains no other transaction composer, so the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ripar_quote_endpointQuote an x402 endpointARead-only
Ask a paid endpoint what it charges, without paying. Makes the request, reads the HTTP 402 challenge, and reports the cheapest acceptable payment: amount, asset, network, and payee. An endpoint that answers 200 is reported as free rather than as an error.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Full URL of the endpoint to quote | |
| body | No | JSON body, for POST | |
| method | No | HTTP method | GET |
| headers | No | Extra request headers |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds significant behavioral context beyond the annotations: it makes a request, interprets HTTP 402 challenges, and reports the cheapest acceptable payment. It also explicitly discloses the edge case where a 200 response is treated as 'free' rather than an error, which is valuable and not indicated by the read-only annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the core purpose, and every sentence adds value. It is concise without being under-specified, covering the request behavior, output fields, and an important edge case.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description adequately explains the return information (amount, asset, network, payee) and handles the special case of 200 responses. It could be more complete by addressing other non-402 statuses or potential errors, but given the tool's simplicity and the annotations, it is largely sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes all parameters (url, body, method, headers) with 100% coverage. The description does not add additional parameter-level details beyond the schema, but it does explain the overall output (amount, asset, network, payee), which is return-value information rather than parameter semantics. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Ask a paid endpoint what it charges, without paying' and details the specific behavior of reading an HTTP 402 challenge and reporting the cheapest payment. This distinguishes it from the sibling ripar_call_endpoint, which actually executes a paid call.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly communicates the use case: querying a paid endpoint for its price before committing to payment. It implies this should be used instead of ripar_call_endpoint when the user wants a quote only, but it does not explicitly name the alternative or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ripar_search_agentsSearch Ripar agentsARead-only
List or search agents in the on-chain IdentityRegistry (Algorand TestNet app 768547159). Matches a substring of the agent's domain, or an exact agent id or Algorand address. Returns live registry records — if the chain is unreachable this fails rather than guessing.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum agents to return | |
| query | No | Domain substring, an exact agent id, or an Algorand address. Omit to list all. | |
| withReputation | No | Also read each agent's score box. Costs one extra box read per agent. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description adds valuable behavioral context: it returns live registry records and fails if the chain is unreachable, rather than guessing. It also clarifies matching semantics, which goes beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the main purpose and then providing matching details and failure behavior. Every sentence earns its place with no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the core purpose, matching criteria, live behavior, and failure mode. It lacks output format details, but no output schema exists, and the schema provides parameter constraints. Complete enough for a registry search tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema covers all three parameters with descriptions, so the description adds little semantic value for parameters. It reinforces the query matching behavior but does not introduce new parameter details; baseline 3 is appropriate given 100% schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'List or search agents in the on-chain IdentityRegistry' and details matching criteria (domain substring, exact agent id, Algorand address). This distinguishes it from sibling tools like ripar_get_agent, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use the tool—listing or searching agents in the registry—and implies its scope. It does not explicitly name alternatives or exclusions, but the context is sufficient for most cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ripar_settlementsSettlement history and reputation gapARead-only
List real USDC transfers for an agent from the Algorand indexer, each marked with whether the ReputationRegistry has already counted it. Inbound payments marked counted:false are reputation the agent earned but was never credited for — a gap that is only visible because the transfer log and the registry's pd_ boxes are read together.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many transfers to fetch | |
| address | No | Algorand address, if you have no agent id | |
| agentId | No | Agent to look at |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint and openWorldHint annotations already cover the safety profile and that it queries external state. The description adds valuable context beyond that: it explains the source is the Algorand indexer, each item includes a counted flag, and that counted:false indicates earned but uncredited reputation. It also highlights that this requires reading both transfer logs and registry boxes, giving insight into the underlying computation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, completely free of filler. The first sentence states what it does, the second explains the meaning of the key flag and why it matters. It is front-loaded and every phrase earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining what will be returned. It clearly states it lists transfers and each is marked with counted true/false, and interprets the counted:false case. It could have mentioned additional fields like amount, sender, or timestamp, but these are implied by 'USDC transfers'. For a listing tool, it provides sufficient context to understand the output shape and the purpose of the data.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter (limit, address, agentId) already has useful descriptions in the schema. The tool description does not add extra parameter-level semantics, but it does clarify the concept of 'for an agent' which maps to agentId/address. Per calibration, baseline 3 is appropriate when the schema handles the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists real USDC transfers for an agent from the Algorand indexer, with a specific twist: each transfer is marked as counted or not by the ReputationRegistry. This distinguishes it from sibling tools like ripar_get_reputation (which presumably fetches current reputation) and ripar_list_jobs (which lists jobs), making it immediately clear what unique data this tool provides.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool: to see the reputation gap between actual transfers and what was credited. It explains the gap is only visible by reading the transfer log together with registry boxes, which tells the agent why this tool exists. It doesn't explicitly name alternatives or exclusions, but the context is clear enough for an agent to choose it over siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.0- First observed
ripar_call_endpoint - First observed
ripar_get_agent - First observed
ripar_get_reputation - First observed
ripar_list_jobs - First observed
ripar_post_job - First observed
ripar_quote_endpoint - First observed
ripar_search_agents - First observed
ripar_settlements
TDQS
Scored across 8 tools
Each tool targets a distinct resource and action: search vs. get for agents, get for reputation, list vs. post for jobs, quote vs. call for endpoints, and settlements as a separate verification tool. There is no meaningful overlap that would confuse an agent.
All tool names follow the same pattern: ripar_<verb>_<noun>. Verbs are consistent (search, get, list, quote, call, post) and lower_snake_case is used throughout. This creates a predictable and readable API surface.
8 tools is well-scoped for the server's purpose, covering agent discovery, reputation, jobs, settlements, and endpoint interactions without unnecessary bloat or redundancy. Each tool earns its place.
The set covers the core workflows: reading identities and reputation, listing and creating jobs, verifying payments, and interacting with paid endpoints. Minor gaps exist (e.g., no get_job by id, no on-chain update actions), but these are acceptable given the server's read-only and transaction-construction role.
Maintenance
Related MCP Connectors
AI agent registry — search, discover, register, and connect agents via MCP.
Hosted MCP server for AI agent identity, permissions, verification, and reusable proof.
Capability registry for the agentic economy. Semantic search over verified MCP server listings.
Hosted AgentLux MCP server for marketplace, identity, creator, services, and social flows.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server for AgentFolio — the identity and reputation layer for AI agents. Query agent profiles, trust scores, verification status, and marketplace listings through 8 MCP tools.988 npm1MIT
- AlicenseNot gradedqualityDmaintenanceMCP Server for agent and service discovery — register, search, rate, and manage AI agents and services in a local directory.10 npmMIT
- AlicenseAqualityBmaintenanceAn MCP server that bridges ERC-8004 agent identity, reputation, and validation registries into tool calls, enabling discovery, inspection, and verification of on-chain AI agents from any MCP client.8MIT
- AlicenseNot gradedqualityAmaintenanceThis MCP server enables AI agents to manage artifacts across sessions by providing tools for searching, retrieving, and registering entries in a persistent ledger, ensuring consistency and traceability of agent outputs.MIT