assetfare
AssetFare is a non-custodial bridge/cross-chain quote and unsigned-action planning server for USDC and other routes across Solana, Base, Arbitrum, Robinhood, Polygon, and Optimism, with v2 quote/session tools plus a legacy Solana-SOL-to-ETH workflow.
Read signed manifest, safety bundle, capabilities, live status, and the 76-route v2 route matrix.
Get fresh unranked v2 quotes (e.g. solana:USDC → base:USDC) with direct_route_summary, continuation_v3, fee components, ETA, and caller handoff data.
Generate a caller-owned 256-bit session capability locally (stdio-only helper).
Prepare an exact unsigned first action via one-shot approval, or create a session workflow with strict approval_v3 and idempotency enforcement.
Read, observe source/output transactions, and refresh actions within a v2 session; the server never signs or submits.
Use legacy v1 tools for the original Solana SOL → Base/Arbitrum ETH corridor: quote, wallet auth, session creation/read, prepare source/CCTP/destination actions, and observe receipts.
All tools are read-only or produce unsigned plans; private keys, seeds, and signed transaction payloads are refused.
Provides Solana-to-Base bridge capabilities, allowing agents to obtain quotes, prepare bridge workflows, and verify unsigned execution plans for moving SOL to ETH without custody.
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., "@assetfareGet me a Solana-to-Base quote for transferring $500 in SOL to ETH"
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.
AssetFare — non-custodial bridge and cross-chain swap for AI agents
USDC bridge API for AI agents and agent-wallet funding: Solana to Base plus 76 cross-chain routes, each with a validated ordered provider path and exact 1bp fee step. Caller approves and signs; the server never signs or submits.
Core 2.4.1 quotes also include strict continuation_v3. MCP 1.2.0 verifies the
canonical full-quote hash, route-summary hash and fingerprint claim, exact
path/providers, caller wallet-chain and event-signer requirements, base-unit
bounds, allowed mode and TTL. Every quote remains unranked_candidate; no
adapter selects it automatically, and caller_approved:true alone is not
human-approval proof.
The portable quote hash removes continuation_v3, replaces duplicated raw
base-unit numbers with the exact decimal strings in direct_route_summary,
then hashes AssetFare typed-canonical-v1 bytes. That encoding preserves JSON
type, uses exact IEEE-754 binary64 bytes for finite numbers, UTF-8 byte lengths
and byte-sorted object keys, distinguishes -0 from 0, and rejects every
non-substituted integral number outside JavaScript's safe-integer range. The required literal
quote_payload_sha256_spec appears both on continuation_v3 and in its
fingerprint claim, preventing numeric-string collisions and cross-language
precision ambiguity.
AssetFare is an agent-native, non-custodial native-USDC bridge and cross-chain route service. Solana native USDC → Base native USDC is the canonical route: an agent gets a fresh quote and, only after explicit caller approval, a bounded unsigned transaction plan the caller verifies and signs. AssetFare also provides bridge and cross-chain swap routes across six chains and eleven source endpoints, and 76 directed routes. AssetFare service fee 1bp; Circle/provider/network fees additional; quote exposes total token-path cost and live availability; server never signs/submits. Solana SOL → Base USDC and Optimism USDC → Base USDC are also supported. AssetFare never receives private keys, signs, or submits.
For economic evaluation, use USD 1,000 as the primary representative amount and always requote every candidate at the amount actually intended. The API still accepts USD 1, but USD 1 is reachability/schema smoke only, not a meaningful competitiveness test. For native-USDC routes, USD 50 is the lowest observed competitive bucket and a reasonable evaluation starting point based on dated 2026-09-23 evidence; it does not guarantee AssetFare is cheapest. SOL-input routes include a swap, so evaluate their full swap-and-bridge path at USD 1,000 or the actual intended amount. AssetFare is always one candidate, not an automatically preferred route.
Verify before trusting: public source, Ed25519-signed manifest, public key, security.txt, and on-chain execution evidence. Quotes are estimates; compare fresh executable route outputs.
Every v2 quote includes direct_route_summary, an intent-bound ordered
provider path with normalized chain:asset endpoints, exact base-unit amount
bounds as decimal strings, the single AssetFare 1bp fee step, and
server-signing/server-submission=false. direct_protocol_only means every step
uses a disclosed direct protocol. external_intent marks Across for Robinhood
ingress, where provider-internal liquidity sourcing may occur.
route_aggregator_used=false describes AssetFare's own engine and does not
claim every provider avoids internal aggregation. Circle/provider costs remain
in cost_summary.provider_fee_components; network gas is in unpriced_costs.
continuation_v3 binds the entire quote (excluding the continuation object
itself) to a process-local, maximum-60-second Core cache. A later exact
approval_v3 selects one_shot or session, may only strengthen the quote's
maximum-input/minimum-output bounds, and fails closed after expiry, restart,
path/provider drift, wallet/signer requirement drift, mode conflict or replay.
Multi-step routes are session-only. Omitting approval_v3 is explicitly
legacy_advisory; the boolean gate remains required but is not human proof.
Independent agent verifier
The dependency-free assetfare-verify CLI verifies evidence instead of
accepting an AssetFare pass, safe, score, or verdict field. From this
checkout, live verification is explicit:
node scripts/assetfare-verify.mjs --liveA package release that contains the assetfare-verify bin entry can be invoked
with npx --yes --package=assetfare-mcp assetfare-verify --live. Do not pin an
older package version that predates this command.
Live mode uses the public Ed25519 key and key id embedded in the verifier. It
fetches only the pinned manifest and its hash-bound safety bundle, rejects
redirects, unexpected MIME types, non-canonical JSON, unknown/missing schema
keys, oversized responses, expired manifests, and subjective safety claims. It
then obtains eth_chainId and exact eth_getCode bytes from two independently
pinned public RPC providers on every supported EVM chain. The raw bytes must
agree with one another and with both the bundle's SHA-256 and Ethereum
Keccak-256 evidence. These are read-only calls; the command has no signing or
transaction-submission path.
For deterministic or air-gapped checking, pass all three trust-material files explicitly:
node scripts/assetfare-verify.mjs --offline \
--manifest ./fixtures/manifest.json \
--bundle ./fixtures/safety-bundle.json \
--pubkey ./fixtures/assetfare-manifest.pubOffline mode makes no network requests. It verifies the supplied manifest
signature, the signed bundle hash, exact schemas and claims, release/build/
deployment provenance, all five EVM chains, and every embedded raw runtime-code
hash. Its successful status is offline_evidence_verified, not a live RPC
quorum result. npm run verify-selftest creates deterministic local fixtures
and exercises bad signatures, bad bundle hashes and schemas, redirects, MIME
confusion, chain/code disagreements, incomplete RPC evidence, and forbidden
subjective claims.
AssetFare is maintained by a distributed project team using one public release namespace during the pilot. Roles, release controls, and the current public owner are documented in GOVERNANCE.md and MAINTAINERS.md; this is not a claim of incorporation or independent third-party audit.
Interfaces: MCP + A2A + REST/OpenAPI.
This repository contains an optional MCP adapter. The primary remote endpoint
exposes nine current v2 tools: signed manifest, capabilities, quote, one-shot
caller-approved prepare, and the five session-lifecycle operations. The 13
unversioned legacy tools remain available at the separate /mcp/legacy
compatibility endpoint for the original Solana SOL → Base/Arbitrum ETH workflow.
The two profiles never appear together on a remote endpoint.
Agents can also evaluate any current v2 route without installing or connecting
MCP:
APIs.json:
https://assetfare.dev/apis.jsonCapabilities:
https://api.assetfare.dev/v2/capabilitiesOpenAPI v2:
https://api.assetfare.dev/v2/openapi.jsonProvider status:
https://api.assetfare.dev/v2/statusRead-only Arazzo workflow:
https://assetfare.dev/arazzo.yamlIndependent agent pilot:
https://assetfare.dev/pilot/
Safety model
AssetFare MCP never accepts a private key and never signs or submits a transaction.
Every one of the 76 routes models and collects an AssetFare service fee of exactly 1bp at one eligible successful atomic action; no route is fee-free. The 1bp is not the total cost: Circle (including any fixed CCTP forwarding fee), provider, and network fees are additional and appear in the quote's total token-path cost.
assetfare_v2_capabilitiesandassetfare_v2_quoteexpose the primary eleven-endpoint, 76-route v2 scope. Availability is live, not static: check it in capabilities/quote before preparing. Polygon and Optimism are directional native-USDC source-only origins to Base or Arbitrum USDC.assetfare_v2_prepareandassetfare_v2_session_createaccept an optional strictapproval_v3. Its selected mode is schema-bound (one_shotversussession), and session approval must use the same idempotency key. Without it, the path islegacy_advisory. Each call still requires the caller to supply literalcaller_approved:true; the adapters never insert it and never describe it as human proof. Private key/seed/signed-transaction inputs are refused.A session capability is a sensitive bearer credential, never a private key. Remote clients generate 32 random bytes locally, encode them as base64url without padding, and supply it only in
X-AssetFare-Session-Token. The server stores only its hash. The remote MCP/A2A service never generates the secret;assetfare-plankeeps it in memory by default and writes it only to an explicit new mode-0600 file. The optional local stdio helper remains offline-only.The unversioned MCP quote/status and all MCP authentication/session/action tools are isolated at
/mcp/legacyfor original-corridor compatibility only.MCP state-changing tools only create authentication/session records or prepare/verify unsigned legacy workflow actions. MCP clients should require user approval for those calls.
The caller independently verifies every returned unsigned action and signs/submits with its own wallets.
Related MCP server: agentfi-mcp-server
Remote endpoint
https://api.assetfare.dev/mcp
Official MCP Registry server: io.github.odaiin/assetfare (legacy registry
namespace; the canonical source owner is the assetfare GitHub organization).
The Registry listing is externally blocked at 0.4.11 while
namespace migration #1666
is unresolved; npm, the public source, and the hosted server are the current
1.2.0 authorities. Do not create a duplicate io.github.assetfare/* listing
to bypass the migration.
Primary MCP quote scope: 76 directed routes across eleven v2 source endpoints,
with a $1 minimum and no adapter-enforced maximum; live upstream availability
and liquidity still apply. Each route charges an AssetFare service fee of
exactly 1bp; Circle/provider/network fees are additional, and each quote
exposes total token-path cost and live availability.
Canonical examples are solana:SOL → base:USDC, solana:USDC → base:USDC,
and optimism:USDC → base:USDC. Polygon and Optimism contribute exactly four
directional native-USDC source-only routes to Base and Arbitrum USDC. The
unversioned legacy workflow remains limited to solana:SOL → base:ETH and
solana:SOL → arbitrum:ETH; it does not limit the v2 route matrix.
The USD 1 API minimum is for reachability/schema smoke only. Start native-USDC economic comparisons at USD 50 based on the dated 2026-09-23 evidence, without assuming AssetFare will be cheapest. Use USD 1,000 as the primary representative comparison amount, including for SOL-input routes whose path includes a swap, and always compare fresh executable quotes at the actual intended amount.
For a new evaluation, call assetfare_v2_capabilities and then
assetfare_v2_quote. The primary endpoint has no legacy tools to misselect.
Existing unversioned clients can connect to
https://api.assetfare.dev/mcp/legacy; new clients must not use it.
REST/OpenAPI first call
Use the public v2 quote endpoint when an agent has not explicitly connected MCP. No API key, wallet authentication, session, signature, or transaction is required for this read-only evaluation call:
curl -sS https://api.assetfare.dev/v2/quote \
-H 'content-type: application/json' \
-d '{"from_chain":"solana","from_token":"USDC","to_chain":"base","to_token":"USDC","amount_usd":1000}'From a cloned repository, the dependency-free examples are:
node examples/rest-quote.mjs 1000 solana USDC base USDC
python3 examples/rest_quote.py 1000 solana USDC base USDCFor a one-command, agent-readable evaluation that verifies the signed release manifest and remains strictly quote-only:
npx --yes --package=assetfare-mcp@1.2.0 assetfare-route-eval \
--amount 1000 --from-chain solana --from-token USDC --to-chain base --to-token USDCFrom a cloned repository, the equivalent command is npm run route-eval -- ....
For a server-enforced quote → explicit selection → unsigned-plan flow, first
save the exact fresh REST or MCP quote as quote.json. Then select a mode and
bounds offline (zero network requests):
npx --yes --package=assetfare-mcp@1.2.0 assetfare-select \
--quote quote.json --mode session \
--maximum-input-base <CONTINUATION_MAXIMUM_INPUT_BASE> \
--minimum-output-base <CONTINUATION_MINIMUM_OUTPUT_BASE> \
--output approval.json
npx --yes --package=assetfare-mcp@1.2.0 assetfare-plan \
--caller-approved --mode session \
--quote quote.json --approval approval.json \
--wallet solana=<CALLER_SOLANA_PUBLIC_KEY> \
--wallet base=<CALLER_BASE_PUBLIC_ADDRESS> \
--event-signer-public <CALLER_OWNED_SOLANA_PUBLIC_KEY> \
--session-token-output ./session-capability.jsonassetfare-select refuses expired/tampered quotes, weak bounds, one-shot on a
multi-step path, existing output files and secret material. It writes the exact
approval object with mode 0600 and never claims that selection proves human
approval. assetfare-plan validates both files and their exact hashes, makes
only the selected prepare/session POST, checks the returned path/provider/bounds
and ActionSafetyReceiptV1/raw/action/bundle hashes, and stops unsigned and
unsubmitted. Session tokens never appear in stdout or structured results. The
optional token output path must not exist and is created mode 0600; omit it only
if loss of recovery after process exit is acceptable.
The evaluator defaults to the representative USD 1,000
solana:USDC -> base:USDC request. That USDC result is one AssetFare candidate,
not a cross-provider market comparison. If solana:SOL -> base:ETH is requested
explicitly, it also requests same-input Relay and Mayan snapshots with
placeholder public addresses. Those comparison rows are not executable orders;
every provider must be requoted with the caller's real addresses and actual
intended amount before selection or signing.
Read-only framework integrations are available for Coinbase AgentKit and GOAT, plus project-reviewed (a project-authored repository review, not independent third-party assurance) SendAI Solana Agent Kit plugin and elizaOS plugin, plus quote tools for Agenti. None of these integrations exposes preparation, signing, submission, funding, swap, or bridge execution.
Dify agents can install the reviewed AssetFare Marketplace plugin. It exposes two native REST tools—live capabilities and one route quote—with no credentials, wallet, authentication, session, preparation, signing, submission, swap, or bridge execution tool.
Hugging Face smolagents users can load the reviewed
quote tool or
capabilities tool
from free Static Spaces. Hub tools execute remote code locally: inspect
tool.py, set trust_remote_code=True, and pin the documented immutable
revision. The complete source and tests are in
assetfare/smolagents-assetfare.
A2A v1 quote adapter
AssetFare also exposes a read-only A2A v1 interface for agents that discover and invoke Agent Cards without MCP:
canonical Agent Card:
https://api.assetfare.dev/.well-known/agent-card.jsonlegacy discovery alias returning the identical card:
https://api.assetfare.dev/.well-known/agent.jsonJSON-RPC v1 endpoint:
https://api.assetfare.dev/a2aprotocol: official
@a2a-js/sdkv1,A2A-Version: 1.0,Content-Type: application/json
The read-only quote skill accepts one structured DataPart containing
fromChain, fromToken, toChain, toToken, and amountUsd. It calls the
public v2 capabilities, status, and quote endpoints and returns one quote with
its passed-through caller_action_plan_handoff. amountUsd must be finite and
at least 1; the adapter imposes no maximum, while live upstream availability
and liquidity still apply. Two additional caller-approved A2A
skills mirror the MCP execution tools: a one-shot prepare operation and the full session lifecycle
(session_create, session_get, observe_source, observe_output,
refresh_action). Before calling session_create, the A2A client generates
its session token locally; the remote A2A endpoint deliberately exposes no
token-generation operation. Each execution operation requires an explicit
callerApproved:true and the caller's public wallet addresses; AssetFare never
signs or submits, and only the caller's own submitted transaction hashes are
observed.
A card fetch, registry health check, TCK request, or registry-generated
SendMessage probe is discovery/conformance traffic, not customer demand.
The public endpoint was checked with official a2aproject/a2a-tck commit
263b9cfa: all 55 applicable MUST checks passed. Five generic TCK SUT fixture
tests send fixed TextPart payloads with magic messageId prefixes and require
unrelated text/file/data artifacts. They are deliberately not implemented by
this structured non-custodial agent; the exception is disclosed rather than
presented as a full 100% pass.
Connect a remote MCP client directly—no package installation or AssetFare API key is required:
claude mcp add --transport http assetfare https://api.assetfare.dev/mcp{
"mcpServers": {
"assetfare": {
"url": "https://api.assetfare.dev/mcp"
}
}
}Codex CLI and app
Add the remote server from the CLI:
codex mcp add assetfare --url https://api.assetfare.dev/mcpOr add it to ~/.codex/config.toml or a project .codex/config.toml. The
writes approval mode prompts for tools that are not annotated read-only:
[mcp_servers.assetfare]
url = "https://api.assetfare.dev/mcp"
default_tools_approval_mode = "writes"Gemini CLI
gemini mcp add --transport http assetfare https://api.assetfare.dev/mcpEquivalent ~/.gemini/settings.json entry:
{
"mcpServers": {
"assetfare": {
"url": "https://api.assetfare.dev/mcp",
"type": "http",
"trust": false
}
}
}Cursor
Add the following server to a project .cursor/mcp.json or the global
~/.cursor/mcp.json:
{
"mcpServers": {
"assetfare": {
"url": "https://api.assetfare.dev/mcp"
}
}
}Connecting is unauthenticated. The primary endpoint uses caller-owned public wallets and, for session mode, a client-generated capability. Only the separate legacy endpoint uses the wallet-bound token produced by the old signMessage flow; never place either capability in an MCP configuration file.
Agent skill
The portable Agent Skill is skills/assetfare-route/SKILL.md.
Skills.lc-compatible clients can install it directly from this public GitHub repository.
npx --yes skills add assetfare/assetfare-mcp --skill assetfare-route -g -yPortable Agent Plugin
Clients that support the published vendor-neutral Agent Plugins 1.0 format can
install this repository from its Git URL. The current plugins CLI can install
the same MCP connection and AssetFare route-evaluation skill through the
included compatibility metadata:
npx plugins add assetfare/assetfare-mcpThe primary MCP endpoint is v2-only. Legacy wallet-auth/session tools are
isolated at /mcp/legacy. AssetFare never receives private keys, signs, or
submits, and the skill keeps REST/OpenAPI v2 as the primary evaluation path.
Circle Agent Stack and other shell-capable agents can use the same skill and
public REST/OpenAPI flow; see integrations/circle-agent-stack.
First-call evaluation
Run npm run first-call-eval to verify a fresh MCP client can discover the
primary v2 quote-only tools, validate current capabilities, and obtain a
representative USD 1,000 Solana-native-USDC to Base-native-USDC quote without
creating a wallet login, session, action, signature, or transaction. Legacy
tools are absent from the primary endpoint. Use USD 1 only for a deliberate
reachability/schema smoke test.
Use Streamable HTTP. The endpoint has no server-side API key. Read-only v2 tools never authenticate a wallet; prepare/session tools require explicit caller approval and public wallets. Legacy wallet authentication is a separate endpoint.
Local stdio
The repository also contains a stdio-compatible all-tools wrapper for self-hosting, including the local-only session-capability helper. The public Registry entry uses the lean v2-only Streamable HTTP endpoint. Package and Registry releases remain separately reviewed from remote deployment.
npm release publishing
npm releases use GitHub Actions OIDC trusted publishing through
.github/workflows/publish-npm.yml. The workflow is manually dispatched with
an existing immutable v<package-version> GitHub release tag, verifies that
the exact tag is on main and matches package.json, runs the complete package
checks and production audit, refuses an already-published version, and publishes
with short-lived OIDC credentials. No npm write token is stored in GitHub or
this repository.
The npm trusted-publisher record is pinned to GitHub organization assetfare,
repository assetfare-mcp, and workflow filename publish-npm.yml. Direct
npm publish is allowed only for that workflow. Package settings should require
2FA and disallow traditional tokens after the OIDC connection is verified.
Integration npm releases
The three unscoped integration packages use a separate, package-allowlisted release path. Their immutable tags are pinned exactly as follows:
assetfare-agentkit-action-provider-v0.1.1assetfare-elizaos-route-plugin-v0.1.1assetfare-solana-agent-kit-plugin-v0.1.1
release-integration-provenance.yml accepts only those three package choices.
It requires the corresponding lightweight tag to resolve to a commit signed by
the pinned AssetFare release key and contained in main, requires an already
published non-draft GitHub release, runs the package's locked checks, tests,
build, production audit, and pack verification, then uploads exactly the npm
tarball and its SHA-256 file and records GitHub build provenance. It never
publishes to npm.
Both workflows must be dispatched with --ref set to that package's exact tag,
never main or another branch/tag. They require GITHUB_REF to equal
refs/tags/<exact-package-tag> and GITHUB_SHA to equal the signed tag commit;
the tag itself must contain the same two workflow files and pinned signer data.
For example, after the trusted-publisher prerequisite below is complete, the
provenance phase for AgentKit is selected with
gh workflow run release-integration-provenance.yml --ref assetfare-agentkit-action-provider-v0.1.1 -f package=assetfare-agentkit-action-provider.
The publish phase uses the same --ref and package choice with
publish-integration-npm.yml only after provenance succeeds.
publish-integration-npm.yml accepts the same allowlist and version 0.1.1. It
repeats the signed-tag, release, manifest, lockfile, test, build, audit, and pack
checks; downloads only the two exact release assets; verifies GitHub's asset
digest, SHA-256 file, GitHub attestation, package identity, and byte-for-byte
reproducibility; then publishes that downloaded tarball with short-lived OIDC
credentials. An existing registry version is accepted only when its shasum
matches exactly; a conflict fails closed. The final gate requires the expected
latest tag, shasum, and npm SLSA provenance.
Do not dispatch either integration release workflow until the target npm
package's Settings → Trusted Publisher entry is configured and independently
checked with organization assetfare, repository assetfare-mcp, exact
workflow filename publish-integration-npm.yml, no environment, and direct
npm publish permission. Configure that exact entry separately for all three
packages. Do not substitute publish-npm.yml, a fork, a differently named
workflow, or an npm write token. The existing root v1.x provenance and publish
workflows remain separate and unchanged.
Trust material
Security contact:
security@assetfare.devSecurity policy and private reporting:
https://github.com/assetfare/assetfare-mcp/security/policySigned manifest:
https://api.assetfare.dev/.well-known/assetfare-manifest.jsonPublic signing key:
https://assetfare.dev/.well-known/assetfare-manifest.pubContinuously revalidated operator ownership:
https://api.assetfare.dev/.well-known/owners.jsonSix-chain source status:
https://api.assetfare.dev/v2/statusSix-chain source capabilities:
https://api.assetfare.dev/v2/capabilitiesPrimary OpenAPI v2:
https://api.assetfare.dev/v2/openapi.jsonLegacy MCP-backed v1 OpenAPI:
https://api.assetfare.dev/openapi.jsonAPIs.json:
https://assetfare.dev/apis.jsonArazzo:
https://assetfare.dev/arazzo.yamlServer card:
https://api.assetfare.dev/.well-known/mcp/server-card.jsonA2A Agent Card:
https://api.assetfare.dev/.well-known/agent-card.jsonA2A endpoint:
https://api.assetfare.dev/a2aAgent guide:
https://assetfare.dev/llms-full.txtMainnet evidence:
https://assetfare.dev/evidence/Paired route evidence:
evidence/solana-base-paired-quotes-20260916.mdAgent-payment route evidence:
evidence/solana-base-usdc-paired-quotes-20260916.mdLive same-input comparison:
https://assetfare.dev/compare/solana-to-base/Dated Solana USDC → Base USDC comparison ($250, 2026-09-23; explicit non-all-in and non-identical-lane caveats):
https://assetfare.dev/compare/solana-usdc-to-base-usdc/
Discovery
Official MCP Registry:
io.github.odaiin/assetfare(legacy namespace pending Registry migration)MCP Servers:
https://mcpservers.org/servers/assetfare/assetfare-mcpSmithery:
https://smithery.ai/servers/twotw55/assetfareGlama:
https://glama.ai/mcp/connectors/io.github.odaiin/assetfareAgent Skill:
https://www.skills.sh/assetfare/assetfare-mcp/assetfare-routeDify Marketplace:
https://marketplace.dify.ai/plugin/odaiin/assetfareHugging Face quote tool:
https://huggingface.co/spaces/odaiin/assetfare-quote(canonical reviewed revision401ecf835a3e0c95807c245a208eeda81b0d9b81)Hugging Face capabilities tool:
https://huggingface.co/spaces/odaiin/assetfare-capabilities(canonical reviewed revision995b5c5be4d88a6c94241ef22ac3a6581dfa8cdb)A2A Registry:
https://a2aregistry.org/agents/d4f9ab1a-904c-4227-8fc6-548e45749de1ARD:
https://assetfare.dev/.well-known/ard.json
The wrapper deliberately contains no AssetFare route engine, wallets, RPC credentials, or internal operations data.
Agent use case
For any supported six-chain source request, an agent first reads v2 capabilities and
requests a fresh quote through REST/OpenAPI or the read-only
assetfare_v2_quote MCP tool. Only an existing original-corridor client should
connect separately to /mcp/legacy. The caller independently signs and submits
every on-chain action; this MCP server never does.
See the first-call evaluation script, the public mainnet evidence at https://assetfare.dev/evidence/, and the end-to-end case study at https://assetfare.dev/case-studies/solana-to-base-mainnet-canary/.
Available Tools
22 toolsassetfare_create_sessionAIdempotentInspect
Lock one fresh legacy assetfare_quote into a wallet-bound v1 execution session. Use only after legacy wallet authentication for the original Solana-SOL-to-Base/Arbitrum-ETH workflow; for a v2 quote use assetfare_v2_session_create instead. Makes a network request and reserves the caller's one active legacy session slot, but creates no blockchain transaction and never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| quote_id | Yes | Fresh legacy v1 quote UUID returned by assetfare_quote. A v2 quote ID is invalid here. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. | |
| source_wallet | Yes | Caller-owned Solana public wallet address for the legacy v1 source. Public address only; never provide a seed phrase or private key. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. | |
| destination_wallet | Yes | Caller-owned Base or Arbitrum EVM destination address as 0x plus 40 hex characters. Public address only; never provide a private key. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses that the tool makes a network request, reserves the caller's single active legacy session slot, creates no blockchain transaction, and never signs or submits. This is valuable behavior context and does not contradict the readOnlyHint=false/idempotentHint=true 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?
Three sentences, each earning its place: core purpose, usage/alternative, and behavioral caveats. It is front-loaded with the most important information and contains no 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 create-style tool with five required parameters and no output schema, the description still covers the essential selection, invocation, and safety context: prerequisites, alternative, slot reservation, and the no-transaction guarantee. Nothing needed to select or invoke it correctly is missing.
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 the schema already documents all five parameters in detail. The description adds contextual expectations like the quote being 'fresh' and v1, but it does not need to carry parameter-level semantics because the schema is complete.
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 leads with a specific verb and resource: 'Lock one fresh legacy assetfare_quote into a wallet-bound v1 execution session.' It clearly defines what the tool does and explicitly distinguishes it from the v2 session tool, so an agent can differentiate it from siblings.
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 states the precondition ('Use only after legacy wallet authentication'), the intended workflow (Solana-SOL to Base/Arbitrum-ETH), and names the alternative for v2 quotes (assetfare_v2_session_create). This gives explicit when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_finish_wallet_authAInspect
Verify the caller's signature over the exact legacy login challenge and return a sensitive wallet-bound access token. Use only after assetfare_start_wallet_auth; do not use for a v2 session, transaction signature, or arbitrary message. Makes a network request and consumes login-challenge state, but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| signature | Yes | Caller-produced Solana signature for the exact indicated legacy message or transaction. Never provide a seed phrase, private key, or signed transaction payload. | |
| challenge_id | Yes | Short-lived legacy wallet-login challenge UUID returned by assetfare_start_wallet_auth. | |
| source_wallet | Yes | Caller-owned Solana public wallet address for the legacy v1 source. Public address only; never provide a seed phrase or private key. | |
| terms_version | Yes | Exact terms version supplied in the legacy wallet-login challenge; copy it unchanged from that challenge. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=false, and destructiveHint=false, so the description's statement 'Makes a network request and consumes login-challenge state, but never signs or submits' adds valuable context beyond the annotations—specifically clarifying non-idempotency and non-destructive behavior. It also flags the output as 'sensitive', which is not in the annotations. This is strong added value, though it doesn't detail error or token-expiry behavior.
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 with zero waste: the first sentence states purpose and output, the second provides usage constraints and side effects. It is front-loaded with the core action and uses phrasing that directly guides the agent without 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?
Despite having no output schema, the description mentions the returned output ('sensitive wallet-bound access token'), the network request, state consumption, and the exact conditions for use. For a four-parameter authentication tool with clear annotations and schema coverage, nothing essential an agent needs to call it correctly is missing.
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?
With 100% schema coverage, all four parameters (signature, challenge_id, source_wallet, terms_version) are already well-documented in the schema with type, constraints, and guidance. The description adds no additional parameter semantics beyond restating the legacy context; it does not compensate for any schema gaps because there are none. Baseline 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 'Verify the caller's signature over the exact legacy login challenge and return a sensitive wallet-bound access token,' which specifies a specific verb, resource, and outcome. It further differentiates itself from siblings by explicitly naming the prerequisite (assetfare_start_wallet_auth) and excluding v2 sessions, transaction signatures, and arbitrary messages.
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 explicitly commands 'Use only after assetfare_start_wallet_auth' and lists what not to use it for ('v2 session, transaction signature, or arbitrary message'), providing clear positive and negative use cases. This leaves no ambiguity for an agent choosing between this and the many sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_manifestARead-onlyIdempotentInspect
Read the Ed25519-signed release manifest and safety-bundle binding before preparing an action. Example: call this once to verify the current release and contract pins; it never creates state, signs, or submits.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| service | Yes | |
| execution | Yes | |
| signature | Yes | |
| safety_bundle | Yes | |
| release_commit | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false, covering the safety profile. The description reinforces this by stating it never creates state, signs, or submits, and adds that it reads an Ed25519-signed manifest and safety-bundle binding, plus the 'call once' guidance which implies idempotency. This adds value beyond the annotations without contradicting them.
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 followed by a concrete usage example. Every sentence contributes meaningful information without redundancy, and the structure is clean and scannable.
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 simple read-only tool with no parameters and an existing output schema, the description is complete. It explains what the tool reads, when to call it, and its safety guarantees. The presence of an output schema means the description need not detail return values, and the guidance covers the essential usage context.
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 tool has zero parameters, so the input schema is trivially covered (100%). The description provides no parameter details because none exist, and per the baseline for 0-parameter tools, this is appropriate. No further explanation is needed.
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 reads an Ed25519-signed release manifest and safety-bundle binding, which is a specific verb-resource pair. It distinguishes itself from siblings by emphasizing it's a verification step before preparation, and explicitly notes it never creates state, signs, or submits. However, it does not name any sibling tool to contrast with, so differentiation is implicit rather than explicit.
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 gives clear context: call this before preparing an action and once to verify current release and contract pins. It implies the tool is a prerequisite step and safe to use repeatedly, but it does not explicitly state when to avoid using it or mention alternative tools. The guidance is useful but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_observe_cctpAIdempotentInspect
Verify Circle attestation and the forwarded Base or Arbitrum USDC mint for a caller-submitted legacy v1 burn, then advance the session record. Use only after the CCTP burn is submitted; use assetfare_read_session for inspection without advancement and a v2 session observe tool for v2 routes. Makes a network request but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Legacy v1 session UUID returned by assetfare_create_session. Use only with the unversioned legacy workflow; do not pass a v2 session ID. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. | |
| burn_signature | Yes | Finalized Solana burn signature already submitted by the caller for this legacy CCTP step. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, destructiveHint=false, and idempotentHint=true. The description adds valuable context beyond annotations by stating 'Makes a network request but never signs or submits' and 'advance the session record', clarifying the mutation nature and the non-signing/submitting behavior. This is useful supplementary detail, though not exhaustive (e.g., no mention of error handling or side effects).
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 concise sentences with zero waste. The purpose is front-loaded, followed by usage guidance and a behavioral note. Every sentence earns its place, and the structure is immediately scannable.
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 tool with no output schema, the description covers the core purpose, usage constraints, and behavioral transparency. It does not explicitly describe return values or error conditions, but given the tool's role (verify and advance session), the description is sufficient for an agent to call it correctly. Minor gap is the lack of mention of what happens on verification failure, but this is not critical.
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 all four parameters are already well-documented in the schema. The description does not add significant meaning beyond what the schema provides; it merely refers to 'caller-submitted legacy v1 burn' which aligns with burn_signature. Per the baseline for high coverage, a 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 states a specific verb ('Verify' and 'advance') with a clear resource ('Circle attestation and the forwarded Base or Arbitrum USDC mint for a caller-submitted legacy v1 burn'). It explicitly distinguishes itself from sibling tools by naming assetfare_read_session for inspection without advancement and a v2 observe tool for v2 routes, so an agent can easily tell them apart.
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?
Provides explicit when-to-use ('Use only after the CCTP burn is submitted') and names alternatives with their conditions ('use assetfare_read_session for inspection without advancement and a v2 session observe tool for v2 routes'). This leaves no ambiguity about when to invoke this tool versus siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_observe_destinationAIdempotentInspect
Verify an already-submitted destination UserOperation receipt and finalize the legacy v1 workflow record. Use only after the caller independently submits assetfare_prepare_destination_action; for v2 output observation use assetfare_v2_session_observe_output instead. Makes a network request and advances session state, but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Legacy v1 session UUID returned by assetfare_create_session. Use only with the unversioned legacy workflow; do not pass a v2 session ID. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. | |
| transaction_hash | Yes | Destination EVM transaction hash already submitted by the caller, formatted as 0x plus 64 hex characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses meaningful side effects beyond the annotations: 'Makes a network request and advances session state, but never signs or submits.' This tells an agent exactly what state impact to expect and what side effects are excluded. It is consistent with the annotations, and nothing in the description contradicts them.
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?
Three sentences with distinct jobs: first states purpose, second states usage and alternatives, third states behavioral side effects. There is no filler, and the most decision-relevant information is front-loaded.
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 definition covers purpose, sequencing, alternatives, side effects, and parameter semantics comprehensively. The only minor gap is that it does not indicate what the verification result or finalization output looks like, and with no output schema present the description could carry that burden more fully.
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 the baseline is 3. The description does not add parameter-level detail beyond the schema, but the schema already documents formats, sensitivities, and version constraints for all four parameters, so no compensation is needed.
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 a specific verb and resource: 'Verify an already-submitted destination UserOperation receipt and finalize the legacy v1 workflow record.' It clearly identifies the operation's scope and workflow version, and explicitly names the sibling tool it is not, assetfare_v2_session_observe_output, making differentiation immediate.
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 gives an explicit sequencing precondition: 'Use only after the caller independently submits assetfare_prepare_destination_action.' It also names the v2 alternative explicitly, and the schema reinforces that the session_id and access_token are legacy-v1-only. This is unambiguous when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_prepare_cctp_actionAIdempotentInspect
Prepare the unsigned CCTP burn for the current legacy v1 session using a caller-owned event signer public key. Use only when the legacy workflow reports this as the next action; for v2 routes use assetfare_v2_prepare or assetfare_v2_session_create instead. Requires caller approval and advances preparation state, but never receives the event signer private key, signs, or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Legacy v1 session UUID returned by assetfare_create_session. Use only with the unversioned legacy workflow; do not pass a v2 session ID. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. | |
| event_signer_public | Yes | Fresh caller-generated ephemeral Solana event signer public key for the legacy CCTP burn. Keep the matching private key client-side; never send it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false. The description adds meaningful behavioral context beyond those annotations: it requires caller approval, advances preparation state, and explicitly does not receive the private key, sign, or submit. This is useful for an agent deciding whether this is the right mutation step. It does not describe the response shape, but no output schema exists and the core behavioral traits are well covered.
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 compact and front-loaded: it states the core action first, then usage constraints, then exclusions. Every sentence earns its place, and the sibling differentiation is woven in without 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?
For a 4-parameter tool with no output schema, the description covers the action, the workflow context, the v2 alternative, the caller-approval requirement, and the non-goals (no private key, no signing, no submission). The only minor gap is that it does not describe what the response contains or how to detect success, but the description is otherwise complete enough for an agent to invoke it 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?
Schema description coverage is 100%, so the schema already documents all four parameters. The description adds value by clarifying the event_signer_public is caller-generated and ephemeral, and by reinforcing that the private key must never be sent. It also clarifies the access_token is legacy v1 wallet-bound and not a v2 capability. This goes beyond the schema's field descriptions.
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 states a specific verb ('prepare'), a specific resource ('unsigned CCTP burn'), and the exact context ('current legacy v1 session using a caller-owned event signer public key'). It also explicitly distinguishes itself from v2 sibling tools, so an agent can tell it apart from assetfare_v2_prepare and assetfare_v2_session_create without opening schemas.
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 gives explicit when-to-use guidance: 'Use only when the legacy workflow reports this as the next action' and explicitly names alternatives for v2 routes. It also states what the tool does not do (never receives the private key, signs, or submits), which helps an agent avoid misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_prepare_destination_actionAIdempotentInspect
Prepare the exact-cap permit and unsigned ERC-4337 destination settlement plan for the current legacy v1 session. Use only when the legacy workflow reports the destination step and after caller approval; v2 sessions expose their current action through assetfare_v2_session_get. Makes a network request and advances preparation state, but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Legacy v1 session UUID returned by assetfare_create_session. Use only with the unversioned legacy workflow; do not pass a v2 session ID. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description explains that calling this tool 'Makes a network request and advances preparation state, but never signs or submits.' This is valuable safety-relevant context for a settlement tool. It doesn't contradict the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=false), though it could say more about the exact state changes.
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?
Three short sentences pack the action, the exact trigger condition, the v2 alternative, and the network/state/signing boundary with zero fluff. The most important information is front-loaded in the first sentence.
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 complex state-advancing tool, the description covers when to call it, the alternative, the scope, and the safety boundary, while annotations plus 100% schema coverage handle idempotency and parameters. It does not explicitly describe the return value, which is a small gap given there is no output schema.
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 all three parameters are fully documented in the schema. The tool description does not need to add param-level meaning; it correctly relies on the schema and provides no additional parameter semantics beyond it.
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 names a specific verb-resource pair: 'Prepare the exact-cap permit and unsigned ERC-4337 destination settlement plan' for the legacy v1 session. It is explicitly scoped to the destination step and distinguishes from v2 by naming v2 sessions' current action exposure, so an agent can disambiguate among the sibling tools.
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 gives an explicit condition: 'Use only when the legacy workflow reports the destination step and after caller approval.' It also names the alternative for v2 sessions (assetfare_v2_session_get), giving clear routing guidance and an exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_prepare_source_actionAIdempotentInspect
Prepare the bounded unsigned Solana source action for the current legacy v1 session step. Use only after assetfare_create_session and explicit caller approval; for a v2 route use assetfare_v2_prepare or assetfare_v2_session_create instead. Makes a network request and advances preparation state, but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Legacy v1 session UUID returned by assetfare_create_session. Use only with the unversioned legacy workflow; do not pass a v2 session ID. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate it is not read-only, not destructive, and idempotent. The description adds that it 'makes a network request and advances preparation state, but never signs or submits,' which clarifies the side-effect profile and the non-submission guarantee. This adds value beyond annotations, though it doesn't cover error behavior or return details.
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 with no redundancy. The main purpose is front-loaded, followed by usage constraints and behavioral notes. 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 description covers prerequisites, alternatives, side effects, and what it does not do (sign/submit). The only gap is that it does not describe the return value or output format, which is notable since there is no output schema. Still, for a state-advancing step in a flow, the description 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?
Schema coverage is 100% and both parameters have detailed descriptions in the schema itself. The tool description does not add parameter-specific meaning, but the schema already does the heavy lifting, so a 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 states a specific verb ('Prepare') and a specific resource ('bounded unsigned Solana source action'), and scopes it to the legacy v1 session step. It clearly distinguishes itself from v2 siblings by naming them, so an agent can tell it apart without opening other schemas.
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 explicitly states when to use it ('after assetfare_create_session and explicit caller approval') and when not to use it ('for a v2 route use assetfare_v2_prepare or assetfare_v2_session_create instead'). This is exactly the when/when-not/alternative guidance expected.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_quoteARead-onlyIdempotentInspect
Legacy v1 original-corridor quote: get Solana SOL to Base or Arbitrum ETH pricing. Use only with the unversioned legacy wallet-auth/session tools; for every new or six-chain evaluation use assetfare_v2_quote instead. Read-only; makes a network request and never authenticates, creates a session, prepares an action, signs, or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| amount_usd | Yes | Whole-dollar input value for the legacy Solana SOL route, minimum 1. Use assetfare_v2_quote for fractional amounts or any v2 route. | |
| destination_chain | No | Legacy destination chain for SOL-to-ETH only: base or arbitrum. Use a v2 route tool for any other destination or token. | base |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds specifics beyond annotations: it makes a network request and never authenticates, creates a session, prepares an action, signs, or submits. This aligns with annotations and provides richer behavioral context.
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 tightly packed sentences with zero filler. The core purpose is front-loaded, and the usage guidance and behavioral disclosure follow efficiently. 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 simple legacy quote tool with only 2 parameters, full schema coverage, and clear annotations, the description provides all necessary context: legacy status, exact corridor, and explicit routing to the v2 alternative. Nothing an agent needs to call it correctly is missing.
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 both parameters are fully documented in the schema. The description itself doesn't add parameter-level details beyond the route context, which is already clear from the purpose. Baseline 3 is appropriate since schema does 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 states a specific verb ('get'), resource ('Solana SOL to Base or Arbitrum ETH pricing'), and clearly identifies it as the legacy v1 original-corridor quote. It explicitly differentiates from the v2 sibling tool, 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?
Explicitly instructs when to use ('with the unversioned legacy wallet-auth/session tools') and when not to ('for every new or six-chain evaluation use assetfare_v2_quote instead'). Names the alternative directly, leaving no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_read_sessionARead-onlyIdempotentInspect
Read a legacy v1 session summary, workflow state, receipt, or current unsigned action. Use to inspect or resume a session created by assetfare_create_session; for a v2 session use assetfare_v2_session_get instead and do not use this call to advance state. Read-only and makes a network request; never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | Legacy read projection: session summary, workflow state, receipt, or next_action. This selection never advances the workflow. | session |
| session_id | Yes | Legacy v1 session UUID returned by assetfare_create_session. Use only with the unversioned legacy workflow; do not pass a v2 session ID. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false. The description adds useful behavioral context beyond those annotations: it 'makes a network request; never signs or submits' and states that the view selection 'never advances the workflow.' No contradiction with the annotations exists.
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 with no filler. It front-loads the primary action, then adds the key routing instruction and safety caveat. 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 simple read-only tool with 3 fully described parameters and no side effects, the description is nearly complete. It covers purpose, usage, legacy vs v2 routing, and behavioral guarantees. It could go slightly further by describing the shape of the returned data, but the absence of an output schema is mitigated by the description stating exactly which projections can be read.
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 the baseline is 3. The description does not add much parameter-level meaning; the schema already documents view projections, the legacy session UUID, and the sensitive access token. The phrase 'current unsigned action' slightly reinforces the next_action enum, but the schema already explains this.
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 a specific verb and resource: 'Read a legacy v1 session summary, workflow state, receipt, or current unsigned action.' It clearly identifies the legacy v1 scope and distinguishes it from v2 tools by naming the exact alternative (assetfare_v2_session_get).
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 explicitly says when to use the tool ('inspect or resume a session created by assetfare_create_session'), when not to use it ('for a v2 session use assetfare_v2_session_get instead'), and what to avoid ('do not use this call to advance state'). This fully routes an agent to the correct sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_start_wallet_authAInspect
Create a short-lived, non-transactional Solana signMessage challenge for the legacy v1 workflow. Use only after selecting a fresh legacy assetfare_quote and obtaining caller approval; v2 quote and session tools do not use wallet authentication. Makes a network request and creates login-challenge state, but cannot move funds, sign, or submit.
| Name | Required | Description | Default |
|---|---|---|---|
| source_wallet | Yes | Caller-owned Solana public wallet address for the legacy v1 source. Public address only; never provide a seed phrase or private key. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false, which could imply a mutating operation, but the description clarifies the actual scope: 'Makes a network request and creates login-challenge state, but cannot move funds, sign, or submit.' This meaningfully contextualizes the non-read-only hint and prevents the agent from assuming the tool can execute transactions. No contradiction with 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?
Three sentences with zero waste: the first fronts the core purpose with key qualifiers, the second provides usage conditions and exclusion, the third discloses behavioral limits. Every sentence earns its place and the most decision-relevant information appears first.
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 single-parameter tool with no output schema, the description covers purpose, preconditions, exclusions, and behavioral safety limits comprehensively. The only minor gap is that it doesn't name the natural follow-up step (e.g., assetfare_finish_wallet_auth) or hint at the response shape, but the sibling naming and 'login-challenge state' mention make this a small omission rather than a blocking one.
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% — the sole parameter 'source_wallet' is already well documented in the schema as a caller-owned public address with an explicit warning against seed phrases/private keys. The tool description adds only indirect context (the fresh quote precondition), so the schema carries the heavy lifting and 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 states a specific verb ('Create') and a specific resource ('short-lived, non-transactional Solana signMessage challenge'), scoped precisely to the legacy v1 workflow. It also distinguishes itself from the sibling family by explicitly noting that v2 quote and session tools do not use wallet authentication, so an agent can route correctly without opening schemas.
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 gives explicit preconditions ('Use only after selecting a fresh legacy assetfare_quote and obtaining caller approval') and an explicit exclusion ('v2 quote and session tools do not use wallet authentication'). This tells the agent both when to invoke this tool and when not to, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_statusARead-onlyIdempotentInspect
Read legacy v1 compatibility status and original-corridor safety gates. Use only before the unversioned Solana-SOL-to-Base/Arbitrum-ETH workflow; for every six-chain v2 route use assetfare_v2_capabilities instead. Read-only; makes a network request and never authenticates, signs, submits, or advances a session.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint, so the bar is lower. The description adds value beyond them by disclosing 'makes a network request' (latency/connectivity implications) and 'never authenticates, signs, submits, or advances a session' — exclusions that matter given session- and auth-oriented siblings. The leading 'Read-only' slightly echoes readOnlyHint, but the rest is genuinely additive.
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?
Three sentences with zero waste: purpose, usage routing, and behavioral caveats. The main purpose is front-loaded, and each sentence earns its place. The only redundancy is the word 'Read-only' echoing readOnlyHint, which is negligible given the new information packed into the same sentence.
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 0-parameter read-only status tool with rich annotations, this is nearly complete: purpose, workflow placement, and behavioral exclusions are all covered. The return format is not specified (no output schema exists), but the output is strongly implied by the stated purpose — compatibility status and safety gates — so this is a minor gap rather than a serious one.
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?
Tool has 0 parameters with an empty schema (additionalProperties: false), so the baseline is 4 and there is nothing for the description to document. No parameter semantics are needed or expected here.
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?
Description opens with a specific verb+resource: 'Read legacy v1 compatibility status and original-corridor safety gates.' It explicitly names what it is not by routing v2 workflows to assetfare_v2_capabilities, which distinguishes it from the closest sibling without opening any schema.
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?
Gives an explicit positive condition ('Use only before the unversioned Solana-SOL-to-Base/Arbitrum-ETH workflow') and an explicit exclusion with the named alternative ('for every six-chain v2 route use assetfare_v2_capabilities instead'). This is textbook when/when-not guidance with a specific sibling fallback.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_capabilitiesARead-onlyIdempotentInspect
Read the 76-route matrix, live availability, direct_route_summary, and continuation_v3 contracts before quoting. continuation_v3 is restart-fail-closed and binds the full quote payload, exact path, wallet chains, signer requirement, bounds, and explicit one_shot/session choice. Example: inspect this before requesting solana:USDC to base:USDC. Read-only; creates no wallet login, session, or action.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| status | Yes | |
| server_signing | Yes | |
| asset_endpoints | Yes | |
| continuation_v3 | Yes | |
| server_submission | Yes | |
| public_api_enabled | Yes | |
| source_only_routes | Yes | |
| direct_route_summary | Yes | |
| execution_availability | No | |
| execution_ready_routes | Yes | |
| phase_b_blocked_routes | Yes | |
| blocked_source_only_routes | Yes | |
| directed_conversion_routes | Yes | |
| unsigned_route_plans_ready | Yes | |
| source_only_asset_endpoints | Yes | |
| execution_implemented_routes | No | |
| currently_prepare_ready_routes | No | |
| temporarily_unavailable_routes | No | |
| temporarily_unavailable_route_count | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnly, idempotent, non-destructive hints. Description adds important context about continuation_v3 being restart-fail-closed and binding the full payload, which is behavioral detail not in annotations. Also clarifies no login/session creation, reinforcing safety.
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?
Three sentences, front-loaded with the key instruction. Example is useful but slightly verbose; still efficient for the complexity. No wasted words.
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?
Tool has zero parameters and output schema exists, so return values are covered. The description explains prerequisites, safety, and how it relates to quoting. Complete for an agent to call correctly without further context.
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 has zero parameters and 100% coverage, but description adds meaning by explaining the tool's role in reading contracts. With no params, the description explains what the tool does with its environment, compensating for lack of schema detail.
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?
States specific verb 'Read' + resource (multiple contracts), clearly distinguishing from siblings. It names the exact artifacts to inspect and gives a concrete example usage, making 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?
Explicitly says to inspect before quoting, names a specific example scenario, and states when it applies. Does not name alternatives but context signals indicate it is a prerequisite for quote tools, which is clearly implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_new_session_capabilityARead-onlyInspect
Local stdio only: generate one caller-owned 256-bit session capability without a network call. Remote MCP/A2A servers deliberately do not expose this helper; remote clients generate 32 random bytes locally, encode them as 43-character base64url without padding, and pass the result to assetfare_v2_session_create and every lifecycle call. The token is a sensitive bearer capability, never a private key.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| usage | Yes | Handling and tool-use instructions for the capability. |
| token_bits | Yes | Entropy size of the generated CSPRNG token in bits. |
| sensitivity | Yes | Classification showing that the token is a sensitive bearer capability. |
| token_length | Yes | Length of the unpadded base64url token in characters. |
| session_token | Yes | New 256-bit, URL-safe caller-owned bearer capability. Treat as sensitive and never log, share, or persist it in plaintext. |
| is_private_key | Yes | Always false: this capability is not a wallet private key and cannot sign transactions. |
| server_signing | Yes | Always false: AssetFare never signs caller transactions. |
| server_submission | Yes | Always false: AssetFare never submits caller transactions. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only and non-destructive, so the safety profile is covered. The description adds useful behavioral context beyond annotations: no network call is made, the output is a sensitive bearer capability, and it is never a private key. This is meaningful additional transparency without contradicting 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 compact and front-loaded with the most important constraint ('Local stdio only'). Each sentence adds distinct value: scope, generation mechanics, and security classification. There is no fluff or redundant restatement of the tool name.
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 zero parameters and an output schema present, the description covers everything an agent needs to know: when to use it, how remote clients should behave instead, where the result should be passed, and the security sensitivity of the value. Nothing critical is missing.
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 tool has zero parameters and the schema is empty, so the baseline is 4. The description compensates by clarifying the semantic nature of the generated value and how it is encoded, which is the only parameter-like information an agent needs.
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 states a specific verb ('generate') and a specific resource ('one caller-owned 256-bit session capability') without a network call. It also clearly distinguishes the local stdio context from remote MCP/A2A servers, so an agent can differentiate this from the many session-related siblings.
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 explicitly says this helper is local stdio only and that remote clients should generate the capability themselves by producing 32 random bytes and base64url-encoding them. It also instructs that the result should be passed to assetfare_v2_session_create and every lifecycle call, giving concrete usage direction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_prepareAInspect
Return the exact validated first unsigned bundle. For server-enforced binding, explicitly pass caller_approved=true plus an approval_v3 selected as one_shot from the exact quote; multi-step quotes reject one_shot. Example: use the approval file produced by assetfare-select for a one-step quote. Omitting approval_v3 uses legacy_advisory only, and caller_approved:true is not human proof. No field is auto-inserted; AssetFare never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| wallets | Yes | Map each chain needed by this route to the caller's public wallet address. Include public addresses only; one to six entries, never private keys or seed phrases. | |
| to_chain | Yes | Destination chain for the v2 route: Solana, Base, Arbitrum, or Robinhood Chain. Polygon and Optimism are not destinations. | |
| to_token | Yes | Output token symbol on to_chain. The chain-token pair must appear in current v2 capabilities. | |
| amount_usd | Yes | Requested input value in USD, minimum 1. USD 1 is reachability/schema smoke only; USD 50 is the native-USDC economic-comparison start based on dated 2026-09-23 evidence, not a cheapest guarantee; USD 1,000 is the primary representative amount. SOL input includes a swap. Always quote the actual intended amount. | |
| from_chain | Yes | Source chain for the v2 route. Polygon and Optimism are source-only and cannot be used as to_chain. | |
| from_token | Yes | Input token symbol on from_chain. The chain-token pair must appear in current v2 capabilities. | |
| approval_v3 | No | Optional strict Core 2.4.1 one_shot quote-bound selection. Omit only for the explicitly legacy_advisory path. | |
| caller_approved | Yes | Legacy caller assertion that MUST be supplied explicitly. It is not human-proof and is never auto-inserted; approval_v3 adds server-enforced quote binding. | |
| event_signer_public | No | Solana CCTP only: caller-generated ephemeral public key. Keep the matching private key client-side and use it to co-sign the returned unsigned event-account transaction; never send the private key. |
Output Schema
| Name | Required | Description |
|---|---|---|
| signed | Yes | |
| version | Yes | |
| action_id | Yes | |
| submitted | Yes | |
| expires_at | Yes | |
| step_index | Yes | |
| workflow_id | Yes | |
| payload_sha256 | Yes | sha256(UTF-8 JSON with sorted keys and compact separators, excluding payload_sha256 itself) |
| server_signing | Yes | |
| unsigned_action | Yes | |
| server_submission | Yes | |
| payload_sha256_spec | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses critical behavior: no field is auto-inserted, AssetFare never signs or submits, caller_approved:true is not human-proof, and multi-step quotes reject one_shot. These are exactly the non-obvious traits an agent needs to avoid unsafe or invalid calls. No contradiction with 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 compact and front-loaded with the core purpose, followed by binding mode, example, fallback, and safety warnings. Every sentence carries distinct information and none is filler. The structure moves from what it returns to how to invoke it correctly.
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?
Despite having 9 parameters, nested objects, and open-world hint true, the description covers the essential workflow and safety semantics: binding mode, fallback behavior, no-auto-insertion, and no signing/submission. The output schema exists and can carry return-value details, so nothing critical is missing for correct invocation.
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, but the description adds meaningful parameter context: it links approval_v3 to server-enforced quote binding, explains that omission falls back to legacy_advisory, and clarifies caller_approved is a required explicit assertion. That raises the score above baseline without repeating schema text.
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 a specific verb and resource: 'Return the exact validated first unsigned bundle.' This clearly distinguishes prepare from quote and session tools: it returns a bundle, not a quote or a session handle. The word 'first' and 'unsigned' add precise scoping.
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 gives explicit when-to-use guidance: for server-enforced binding, pass caller_approved=true plus an approval_v3 selected as one_shot from the exact quote. It also states a when-not condition ('multi-step quotes reject one_shot') and the alternative fallback ('Omitting approval_v3 uses legacy_advisory only'). This leaves little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_quoteARead-onlyInspect
Get one unranked fresh candidate with direct_route_summary and continuation_v3. The adapter verifies the canonical full-quote hash, route-summary hash, fingerprint claim, wallet/signer requirements, path, bounds, modes, and TTL. It never auto-selects or treats caller_approved:true as human proof. Example: quote solana USDC to Base USDC at USD 1000. Read-only; never authenticates, prepares, signs, or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| to_chain | Yes | Destination chain for the v2 route: Solana, Base, Arbitrum, or Robinhood Chain. Polygon and Optimism are not destinations. | |
| to_token | Yes | Output token symbol on to_chain. The chain-token pair must appear in current v2 capabilities. | |
| amount_usd | Yes | Requested input value in USD, minimum 1. USD 1 is reachability/schema smoke only; USD 50 is the native-USDC economic-comparison start based on dated 2026-09-23 evidence, not a cheapest guarantee; USD 1,000 is the primary representative amount. SOL input includes a swap. Always quote the actual intended amount. | |
| from_chain | Yes | Source chain for the v2 route. Polygon and Optimism are source-only and cannot be used as to_chain. | |
| from_token | Yes | Input token symbol on from_chain. The chain-token pair must appear in current v2 capabilities. |
Output Schema
| Name | Required | Description |
|---|---|---|
| eta | Yes | |
| risk | Yes | |
| as_of | Yes | |
| offer | Yes | |
| route | Yes | |
| intent | Yes | |
| status | Yes | |
| quote_id | Yes | |
| execution | Yes | |
| ttl_seconds | Yes | |
| cost_summary | Yes | |
| continuation_v3 | Yes | |
| direct_route_summary | Yes | |
| caller_action_plan_handoff | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond the readOnly/destructive annotations by enumerating exactly what the adapter verifies (hashes, fingerprint, wallet/signer requirements, path, bounds, modes, TTL) and what it refuses to do (auto-select, treat caller_approved as human proof, authenticate/prepare/sign/submit). No annotation 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?
Every sentence carries distinct information: purpose, verification behavior, non-behaviors, an example, and the read-only boundary. It is front-loaded with the core action and remains dense without fluff.
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 tool with an output schema and rich annotations, the description covers behavior, safety, and verification comprehensively. It does not explicitly link to sibling tools (e.g., when to hand off to prepare), but the available output schema and parameter descriptions fill most remaining operational 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 description coverage is 100%, so the schema already documents all five parameters thoroughly. The description's example ('quote solana USDC to Base USDC at USD 1000') is illustrative but adds no new parameter semantics beyond the schema.
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 verb 'Get' plus the resource 'one unranked fresh candidate' states precisely what the tool returns, and the qualifiers 'unranked', 'direct_route_summary', and 'continuation_v3' distinguish it from prepare/session siblings. The closing 'read-only; never authenticates, prepares, signs, or submits' reinforces the scope.
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 gives clear context for use: request a fresh quote candidate and do not treat caller_approved as proof or auto-select. The negative statements implicitly exclude prepare/session tools, though it never names an alternative or says 'use X when you need Y'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_session_createAIdempotentInspect
Create one receipt-driven workflow. For server-enforced binding, explicitly pass caller_approved=true, the exact approval_v3 selected as session, the same idempotency_key, and a caller-local session token. Example: select session for any multi-step quote. Omitting approval_v3 uses legacy_advisory only. AssetFare never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| wallets | Yes | Map each chain needed by this route to the caller's public wallet address. Include public addresses only; one to six entries, never private keys or seed phrases. | |
| to_chain | Yes | Destination chain for the v2 route: Solana, Base, Arbitrum, or Robinhood Chain. Polygon and Optimism are not destinations. | |
| to_token | Yes | Output token symbol on to_chain. The chain-token pair must appear in current v2 capabilities. | |
| amount_usd | Yes | Requested input value in USD, minimum 1. USD 1 is reachability/schema smoke only; USD 50 is the native-USDC economic-comparison start based on dated 2026-09-23 evidence, not a cheapest guarantee; USD 1,000 is the primary representative amount. SOL input includes a swap. Always quote the actual intended amount. | |
| from_chain | Yes | Source chain for the v2 route. Polygon and Optimism are source-only and cannot be used as to_chain. | |
| from_token | Yes | Input token symbol on from_chain. The chain-token pair must appear in current v2 capabilities. | |
| approval_v3 | No | Optional strict Core 2.4.1 session quote-bound selection. Omit only for legacy_advisory. | |
| session_token | Yes | Sensitive caller-generated v2 session capability: at least 32 CSPRNG bytes encoded as 43-128 URL-safe base64 characters. Generate it locally; never log it or substitute a private key or legacy access token. | |
| caller_approved | Yes | Legacy caller assertion that MUST be supplied explicitly. It is not human-proof and is never auto-inserted; approval_v3 adds server-enforced quote binding. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. | |
| event_signer_public | No | Solana CCTP only: caller-generated ephemeral public key. Keep the matching private key client-side and use it to co-sign the returned unsigned event-account transaction; never send the private key. |
Output Schema
| Name | Required | Description |
|---|---|---|
| signed | Yes | |
| status | Yes | |
| submitted | Yes | |
| session_id | Yes | |
| quote_binding | Yes | |
| current_action | Yes | |
| server_signing | Yes | |
| action_available | Yes | |
| server_submission | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It discloses that 'AssetFare never signs or submits', a critical safety behavior beyond the annotations' mutability and idempotency hints. It also reveals the two operational modes (server-enforced binding vs legacy_advisory) based on approval_v3 presence. It does not cover failure modes or authorization scope, but the annotations already carry the core safety profile.
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 compact and front-loaded with the action, then gives binding-specific guidance, then a safety note. Each sentence serves a purpose; the 'Example:' phrasing is slightly informal but not wasteful.
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 an 11-parameter tool with nested objects, the description provides key invocation directives but leaves the surrounding workflow implicit, such as how the caller obtains the approval_v3 and when to use this tool versus quote/prepare/get siblings. The output schema covers return values, so that gap is acceptable, but the process context is thin.
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, but the description adds cross-parameter meaning: caller_approved, approval_v3, idempotency_key, and session_token must be coordinated for server-enforced binding. It also clarifies the effect of omitting approval_v3, which is not fully evident from the schema alone.
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 states a specific action, 'Create one receipt-driven workflow', and ties it to session selection for multi-step quotes, which helps distinguish it from get/observe siblings. However, 'receipt-driven workflow' is jargon and the description does not explicitly name sibling tools to reinforce differentiation.
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 gives concrete conditions: pass caller_approved=true, the exact approval_v3 selected as session, the same idempotency_key, and a caller-local session token for server-enforced binding. It also specifies that omitting approval_v3 uses legacy_advisory only, offering a clear alternative mode. It stops short of explicitly routing the agent to quote/prepare first or excluding sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_session_getARead-onlyIdempotentInspect
Read an existing v2 workflow and current unsigned action without advancing it. Example: pass the session_id and its caller-owned session_token after a restart. Read-only; never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | V2 workflow session UUID returned by assetfare_v2_session_create. Use only with assetfare_v2_session_* tools; do not pass a legacy session ID. | |
| session_token | Yes | Sensitive caller-generated v2 session capability: at least 32 CSPRNG bytes encoded as 43-128 URL-safe base64 characters. Generate it locally; never log it or substitute a private key or legacy access token. |
Output Schema
| Name | Required | Description |
|---|---|---|
| signed | Yes | |
| status | Yes | |
| submitted | Yes | |
| session_id | Yes | |
| quote_binding | Yes | |
| current_action | Yes | |
| server_signing | Yes | |
| action_available | Yes | |
| server_submission | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false. The description adds valuable behavioral guarantees beyond those: 'without advancing it' and 'never signs or submits,' which clarify the state effects. No contradiction with 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?
Two sentences with no filler: the first states purpose and scope, the second gives an example and reiterates read-only behavior. 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?
With rich schema descriptions, full annotations, and an output schema present, the description fully covers what the tool does, when to use it, and its non-mutating behavior. Nothing essential is missing for correct invocation.
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%, with detailed parameter descriptions for session_id and session_token covering origin, usage, sensitivity, and format. The description itself adds no new parameter semantics beyond restating 'caller-owned session_token,' so the 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 uses a specific verb ('Read') and resource ('existing v2 workflow and current unsigned action') and immediately clarifies the non-advancing, read-only nature. This distinguishes it from action-oriented siblings like assetfare_v2_session_refresh_action and signing/submitting tools.
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 gives a concrete use case ('after a restart') and states the tool does not advance, sign, or submit. It does not explicitly name alternatives or say when not to use it, but the context is clear enough for an agent to select it for inspection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_session_observe_outputAIdempotentInspect
Record an already-produced bridge or destination output, then advance the workflow. Example: transaction_hash='' with idempotency_key='output-0001'. AssetFare observes but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | V2 workflow session UUID returned by assetfare_v2_session_create. Use only with assetfare_v2_session_* tools; do not pass a legacy session ID. | |
| session_token | Yes | Sensitive caller-generated v2 session capability: at least 32 CSPRNG bytes encoded as 43-128 URL-safe base64 characters. Generate it locally; never log it or substitute a private key or legacy access token. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. | |
| transaction_hash | No | Optional bridge or destination transaction hash already produced outside AssetFare. Omit only when the provider output can be observed without a hash. |
Output Schema
| Name | Required | Description |
|---|---|---|
| signed | Yes | |
| status | Yes | |
| submitted | Yes | |
| session_id | Yes | |
| quote_binding | Yes | |
| current_action | Yes | |
| server_signing | Yes | |
| action_available | Yes | |
| server_submission | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds genuinely useful behavior beyond annotations: 'advance the workflow' clarifies this is a state-mutating step (consistent with readOnlyHint=false), while 'AssetFare observes but never signs or submits' prevents an agent from mistaking this for a transaction-submission tool. The example further discloses that transaction_hash comes from an external producer.
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?
Three short, front-loaded elements — core action, a concrete example, and the key safety constraint — with no filler. Every sentence earns its place and the most important directive ('record output, advance workflow') appears first.
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 an output schema present, the description need not explain return values, and the annotations already cover idempotency and destructiveness. The description covers the essential call semantics (what to record, when it exists, what happens next); the only notable gap is explicit error/prerequisite context, but the 100%-coverage schema and rich annotations carry that weight.
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 the baseline is 3 even with no param detail in the description. The example (transaction_hash='<caller-or-provider-output-hash>' with idempotency_key='output-0001') adds mild connective value showing how the two optional/required params combine, but it does not materially compensate beyond the already-rich schema.
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 states a specific verb ('Record') and resource ('already-produced bridge or destination output'), and adds the workflow-advancing consequence. It distinguishes itself from the sibling observe_source tool via the 'destination output' phrasing, but never names the sibling explicitly, leaving the contrast partly implicit.
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?
'Already-produced' implies this tool is for outputs created outside AssetFare, and 'advance the workflow' signals the follow-on effect — that is usable context. However, no sibling alternative (notably assetfare_v2_session_observe_source) is named, and there is no explicit when-not-to-use or exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_session_observe_sourceAIdempotentInspect
Record source hashes the caller already signed and submitted, then advance the workflow. Example: transaction_hashes=[''] with idempotency_key='source-0001'. Never pass an unsigned hash; AssetFare observes but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | V2 workflow session UUID returned by assetfare_v2_session_create. Use only with assetfare_v2_session_* tools; do not pass a legacy session ID. | |
| session_token | Yes | Sensitive caller-generated v2 session capability: at least 32 CSPRNG bytes encoded as 43-128 URL-safe base64 characters. Generate it locally; never log it or substitute a private key or legacy access token. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. | |
| transaction_hashes | Yes | One to eight hashes for source transactions the caller already signed and submitted. Do not provide unsigned payloads or destination hashes. |
Output Schema
| Name | Required | Description |
|---|---|---|
| signed | Yes | |
| status | Yes | |
| submitted | Yes | |
| session_id | Yes | |
| quote_binding | Yes | |
| current_action | Yes | |
| server_signing | Yes | |
| action_available | Yes | |
| server_submission | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false, so the mutation and idempotency are covered. The description adds valuable behavioral context: it observes but never signs or submits, and it advances the workflow. It also warns about idempotency_key reuse semantics, which is beyond the schema. The only minor gap is not describing what the response contains, but the output schema exists and the description's behavioral notes are strong.
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 plus an example, with no wasted words. The core action is front-loaded, the example is immediately useful, and the critical warning ('Never pass an unsigned hash') is placed at the end for emphasis. 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 mutation tool with an output schema and 100% schema coverage, the description is nearly complete. It covers the action, the example, the idempotency semantics, and the critical constraint. The only thing missing is an explicit statement of what 'advance the workflow' means in terms of state transitions, but the sibling tools and output schema likely cover that. This is a strong, complete description for the tool's 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?
Schema description coverage is 100%, so the schema already documents all four parameters thoroughly. The description adds value by explaining the relationship between transaction_hashes and the workflow ('already signed and submitted'), and by giving a concrete example. It also reinforces the idempotency_key semantics. This is above the baseline 3 because the description clarifies the intended usage pattern beyond the schema's field-level descriptions.
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 states a specific verb ('Record source hashes... then advance the workflow') and resource ('source hashes the caller already signed and submitted'), and it distinguishes itself from the sibling assetfare_v2_session_observe_output by focusing on source hashes and workflow advancement. The example and explicit warning ('Never pass an unsigned hash') make the tool's purpose unmistakable.
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 gives explicit when-to-use guidance: record already-signed source hashes and advance the workflow. It also provides a concrete example with transaction_hashes and idempotency_key, and it explicitly warns against passing unsigned hashes. The sibling context (observe_output) further clarifies the alternative, though the description itself doesn't name it; the example and warning are strong usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_v2_session_refresh_actionAIdempotentInspect
Refresh an expired action only while it remains unsubmitted. Example: pass the existing session_id, session_token, and idempotency_key='refresh-0001'. Never refresh a submitted step; AssetFare never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | V2 workflow session UUID returned by assetfare_v2_session_create. Use only with assetfare_v2_session_* tools; do not pass a legacy session ID. | |
| session_token | Yes | Sensitive caller-generated v2 session capability: at least 32 CSPRNG bytes encoded as 43-128 URL-safe base64 characters. Generate it locally; never log it or substitute a private key or legacy access token. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. |
Output Schema
| Name | Required | Description |
|---|---|---|
| signed | Yes | |
| status | Yes | |
| submitted | Yes | |
| session_id | Yes | |
| quote_binding | Yes | |
| current_action | Yes | |
| server_signing | Yes | |
| action_available | Yes | |
| server_submission | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false. The description adds value beyond those by gating the operation on session state (expired but unsubmitted) and by disclosing the standing guarantee that 'AssetFare never signs or submits.' No contradiction with annotations; readOnlyHint=false is consistent with a refresh mutation.
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?
Three compact sentences, front-loaded with the core purpose, followed by a concrete example and then a safety constraint. Every sentence earns its place with zero filler or repetition of schema details.
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?
Given an output schema exists and all three parameters are simple required strings fully documented, the description covers the one non-obvious behavioral requirement: the unsubmitted-state gate. A minor gap is the lack of error behavior when a refresh is attempted on a submitted step, but the prohibition is stated clearly enough for correct invocation.
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 the baseline of 3 applies; the schema already fully documents all three parameters. The example adds mild usage color ('pass the existing session_id...', idempotency_key='refresh-0001') but no substantive semantic meaning beyond the schema.
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?
'Refresh an expired action' states a specific verb plus resource, and the qualifier 'only while it remains unsubmitted' narrows the scope precisely. The explicit 'Never refresh a submitted step' differentiates it from the session_* observation tools without needing their schemas.
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 gives a clear when-condition (expired, still unsubmitted) and an explicit when-not ('Never refresh a submitted step'). However, it does not name an alternative tool to use for the submitted-step case, leaving the fallback path to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
assetfare_verify_source_receiptAIdempotentInspect
Verify a finalized Solana source signature already submitted by the caller and advance the legacy v1 workflow. Use only after the caller independently submits assetfare_prepare_source_action; for a v2 session use assetfare_v2_session_observe_source instead. Requires caller approval and makes a network request, but never signs or submits.
| Name | Required | Description | Default |
|---|---|---|---|
| signature | Yes | Caller-produced Solana signature for the exact indicated legacy message or transaction. Never provide a seed phrase, private key, or signed transaction payload. | |
| session_id | Yes | Legacy v1 session UUID returned by assetfare_create_session. Use only with the unversioned legacy workflow; do not pass a v2 session ID. | |
| access_token | Yes | Sensitive legacy v1 wallet-bound bearer token returned by assetfare_finish_wallet_auth. Use only with unversioned legacy session tools; never log or use it as a v2 session capability. | |
| idempotency_key | Yes | Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=false, idempotentHint=true, and destructiveHint=false. The description adds valuable behavioral context: it requires caller approval, makes a network request, never signs or submits, and advances a stateful workflow. This goes beyond schema/annotations without contradicting them, though it could say a bit more about failure behavior.
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?
Three sentences, each carrying distinct value: purpose, usage/alternative, and behavioral caveat. The most important scoping information is front-loaded, and there is no repeated or filler content.
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 stateful v1 workflow step with no output schema, the description adequately covers ordering, v1/v2 routing, and safety profile. It could be slightly more explicit about what 'advances the workflow' means for subsequent steps or response interpretation, but the essential invocation context is present.
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%, and each parameter has a clear, detailed description (e.g., signature format and security warning, session_id scope, access_token sensitivity, idempotency_key reuse rule). The tool description itself adds workflow context but does not need to repeat parameter details; the baseline 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 a specific verb ('Verify'), names the exact resource ('finalized Solana source signature already submitted by the caller'), and states the workflow effect ('advance the legacy v1 workflow'). It also explicitly distinguishes this tool from the v2 sibling assetfare_v2_session_observe_source, so an agent can select it correctly without opening schemas.
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 gives an explicit precondition: use only after the caller independently submits assetfare_prepare_source_action. It also states the alternative for v2 sessions, making the when-to-use and when-not-to-use boundaries clear. The added note about caller approval and network behavior further clarifies prerequisites.
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.
14 tool updates
v1.2.0- Changed
assetfare_create_session1 field changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern."
- Changed
assetfare_observe_cctp1 field changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern."
- Changed
assetfare_observe_destination1 field changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern."
- Changed
assetfare_prepare_cctp_action1 field changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern."
- Changed
assetfare_prepare_destination_action1 field changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern."
- Changed
assetfare_v2_capabilities3 fields changed- added
Output schema / properties / continuation_v3Added value: +{ + "additionalProperties": false, + "properties": { + "automatic_selection_forbidden": { + "const": true, + "type": "boolean" + }, + "cache_scope": { + "const": "bounded_process_local_ttl_restart_fails_closed", + "type": "string" + }, + "caller_approved_boolean_is_not_human_proof": { + "const": true, + "type": "boolean" + }, + "enforcement": { + "const": "server_enforced_quote_binding", + "type": "string" + }, + "future_actions_requote_and_enforce_original_step_minimums": { + "const": true, + "type": "boolean" + }, + "maximum_cache_records": { + "const": 2048, + "type": "number" + }, + "maximum_ttl_seconds": { + "const": 60, + "type": "number" + }, + "multistep_allowed_modes": { + "items": [ + { + "const": "session", + "type": "string" + } + ], + "maxItems": 1, + "minItems": 1, + "type": "array" + }, + "one_step_allowed_modes": { + "items": [ + { + "const": "one_shot", + "type": "string" + }, + { + "const": "session", + "type": "string" + } + ], + "maxItems": 2, + "minItems": 2, + "type": "array" + }, + "quote_payload_sha256_spec": { + "const": "sha256(AssetFare typed-canonical-v1 bytes of the quote without continuation_v3 after exact base-unit substitution: n=null; t/f=boolean; d=<IEEE-754 binary64 big-endian 16 lowercase hex> for each finite JSON number; s=<UTF-8 byte length>:<Unicode scalar text with lone surrogates forbidden>; a=<count>:[items]; o=<count>:{UTF-8-byte-sorted string-key/value pairs}; every non-substituted integral JSON number must be within +/-9007199254740991; substituted paths are intent.estimated_input_base, route.input_base, route.expected_output_base, route.minimum_output_base, and every route.steps[i].expected_input_base/floor_input_base/expected_output_base/minimum_output_base from direct_route_summary exact decimal strings)", + "type": "string" + }, + "required_on_every_quote": { + "const": true, + "type": "boolean" + }, + "selection_status": { + "const": "unranked_candidate", + "type": "string" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "session_owner_binding": { + "const": "sha256_of_caller_generated_session_token_raw_token_never_stored", + "type": "string" + }, + "version": { + "const": "assetfare-quote-bound-continuation-v3", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": true, + "type": "boolean" + } + }, + "required": [ + "version", + "required_on_every_quote", + "enforcement", + "selection_status", + "automatic_selection_forbidden", + "caller_approved_boolean_is_not_human_proof", + "cache_scope", + "maximum_ttl_seconds", + "maximum_cache_records", + "multistep_allowed_modes", + "one_step_allowed_modes", + "session_owner_binding", + "whole_session_path_and_bounds_enforced", + "future_actions_requote_and_enforce_original_step_minimums", + "quote_payload_sha256_spec", + "server_signing", + "server_submission" + ], + "type": "object" +} - added
Output schema / properties / direct_route_summaryAdded value: +{ + "additionalProperties": false, + "properties": { + "assetfare_fee_step_bound": { + "const": true, + "type": "boolean" + }, + "base_unit_amounts_are_decimal_strings": { + "const": true, + "type": "boolean" + }, + "classification_values": { + "items": [ + { + "const": "direct_protocol_only", + "type": "string" + }, + { + "const": "external_intent", + "type": "string" + } + ], + "maxItems": 2, + "minItems": 2, + "type": "array" + }, + "external_intent": { + "const": "Across only for Robinhood ingress; provider-internal liquidity sourcing or aggregation remains possible", + "type": "string" + }, + "normalized_chain_asset_endpoints": { + "const": true, + "type": "boolean" + }, + "ordered_provider_path": { + "const": true, + "type": "boolean" + }, + "required_on_every_quote": { + "const": true, + "type": "boolean" + }, + "route_aggregator_used_scope": { + "const": "assetfare_engine_only", + "type": "string" + }, + "route_count": { + "const": 76, + "type": "number" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "step_count": { + "const": 168, + "type": "number" + }, + "version": { + "const": "assetfare-direct-route-summary-v1", + "type": "string" + } + }, + "required": [ + "version", + "required_on_every_quote", + "route_count", + "step_count", + "ordered_provider_path", + "normalized_chain_asset_endpoints", + "base_unit_amounts_are_decimal_strings", + "assetfare_fee_step_bound", + "classification_values", + "route_aggregator_used_scope", + "external_intent", + "server_signing", + "server_submission" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "status", - "public_api_enabled", - "asset_endpoints", - "source_only_asset_endpoints", - "source_only_routes", - "directed_conversion_routes", - "unsigned_route_plans_ready", - "execution_ready_routes", - "phase_b_blocked_routes", - "blocked_source_only_routes", - "server_signing", - "server_submission" -]New value: +[ + "status", + "public_api_enabled", + "asset_endpoints", + "source_only_asset_endpoints", + "source_only_routes", + "directed_conversion_routes", + "unsigned_route_plans_ready", + "execution_ready_routes", + "direct_route_summary", + "continuation_v3", + "phase_b_blocked_routes", + "blocked_source_only_routes", + "server_signing", + "server_submission" +]
- Changed
assetfare_v2_prepare2 fields changed- added
Input schema / properties / approval_v3Added value: +{ + "additionalProperties": false, + "description": "Optional strict Core 2.4.1 one_shot quote-bound selection. Omit only for the explicitly legacy_advisory path.", + "properties": { + "direct_route_summary_sha256": { + "$ref": "#/properties/approval_v3/properties/quote_fingerprint" + }, + "idempotency_key": { + "pattern": "^[A-Za-z0-9._:-]{8,128}$", + "type": "string" + }, + "maximum_input_base": { + "pattern": "^[1-9][0-9]*$", + "type": "string" + }, + "minimum_output_base": { + "$ref": "#/properties/approval_v3/properties/maximum_input_base" + }, + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "selected_mode": { + "const": "one_shot", + "type": "string" + }, + "selection_status": { + "const": "selected", + "type": "string" + }, + "version": { + "const": "assetfare-quote-bound-approval-v3", + "type": "string" + } + }, + "required": [ + "version", + "quote_id", + "quote_fingerprint", + "selection_status", + "selected_mode", + "maximum_input_base", + "minimum_output_base", + "direct_route_summary_sha256", + "idempotency_key" + ], + "type": "object" +} - changed
Input schema / properties / caller_approved / descriptionPrevious value: -"Explicit confirmation that the caller approved this state-changing preparation or session creation. A quote alone is not approval."New value: +"Legacy caller assertion that MUST be supplied explicitly. It is not human-proof and is never auto-inserted; approval_v3 adds server-enforced quote binding."
- Changed
assetfare_v2_quote3 fields changed- added
Output schema / properties / continuation_v3Added value: +{ + "additionalProperties": false, + "properties": { + "allowed_modes": { + "items": { + "enum": [ + "one_shot", + "session" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 1, + "type": "array" + }, + "approval_v3_required_fields": { + "items": [ + { + "const": "direct_route_summary_sha256", + "type": "string" + }, + { + "const": "idempotency_key", + "type": "string" + }, + { + "const": "maximum_input_base", + "type": "string" + }, + { + "const": "minimum_output_base", + "type": "string" + }, + { + "const": "quote_fingerprint", + "type": "string" + }, + { + "const": "quote_id", + "type": "string" + }, + { + "const": "selected_mode", + "type": "string" + }, + { + "const": "selection_status", + "type": "string" + }, + { + "const": "version", + "type": "string" + } + ], + "maxItems": 9, + "minItems": 9, + "type": "array" + }, + "automatic_selection_forbidden": { + "const": true, + "type": "boolean" + }, + "caller_approved_boolean_is_not_human_proof": { + "const": true, + "type": "boolean" + }, + "direct_route_summary_sha256": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint" + }, + "enforcement": { + "const": "server_enforced_quote_binding", + "type": "string" + }, + "event_signer_public_required": { + "type": "boolean" + }, + "expires_at": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/issued_at" + }, + "idempotency": { + "additionalProperties": false, + "properties": { + "field": { + "const": "idempotency_key", + "type": "string" + }, + "pattern": { + "const": "^[A-Za-z0-9._:-]{8,128}$", + "type": "string" + }, + "required": { + "const": true, + "type": "boolean" + }, + "scope": { + "const": "quote_and_selected_mode", + "type": "string" + } + }, + "required": [ + "required", + "field", + "pattern", + "scope" + ], + "type": "object" + }, + "input_base_bounds": { + "additionalProperties": false, + "properties": { + "maximum": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + }, + "minimum": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + } + }, + "required": [ + "minimum", + "maximum" + ], + "type": "object" + }, + "intent": { + "additionalProperties": true, + "properties": { + "amount_usd": { + "type": "number" + }, + "estimated_input_base": { + "exclusiveMinimum": 0, + "type": "integer" + }, + "from": { + "minLength": 1, + "type": "string" + }, + "to": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "from", + "to", + "amount_usd", + "estimated_input_base" + ], + "type": "object" + }, + "issued_at": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/issued_at" + }, + "legacy_handoff_enforcement": { + "const": "legacy_advisory", + "type": "string" + }, + "minimum_output_base": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + }, + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_fingerprint_claim": { + "additionalProperties": false, + "properties": { + "allowed_modes": { + "items": { + "enum": [ + "one_shot", + "session" + ], + "type": "string" + }, + "maxItems": 2, + "minItems": 1, + "type": "array" + }, + "direct_route_summary_sha256": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint" + }, + "event_signer_public_required": { + "type": "boolean" + }, + "expires_at": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/issued_at" + }, + "input_base_bounds": { + "additionalProperties": false, + "properties": { + "maximum": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + }, + "minimum": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + } + }, + "required": [ + "minimum", + "maximum" + ], + "type": "object" + }, + "intent": { + "additionalProperties": false, + "properties": { + "amount_usd_decimal": { + "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$", + "type": "string" + }, + "estimated_input_base": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + }, + "from": { + "minLength": 1, + "type": "string" + }, + "to": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "from", + "to", + "amount_usd_decimal", + "estimated_input_base" + ], + "type": "object" + }, + "issued_at": { + "format": "date-time", + "type": "string" + }, + "minimum_output_base": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + }, + "quote_id": { + "$ref": "#/properties/continuation_v3/properties/quote_id" + }, + "quote_payload_sha256": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint" + }, + "quote_payload_sha256_spec": { + "const": "sha256(AssetFare typed-canonical-v1 bytes of the quote without continuation_v3 after exact base-unit substitution: n=null; t/f=boolean; d=<IEEE-754 binary64 big-endian 16 lowercase hex> for each finite JSON number; s=<UTF-8 byte length>:<Unicode scalar text with lone surrogates forbidden>; a=<count>:[items]; o=<count>:{UTF-8-byte-sorted string-key/value pairs}; every non-substituted integral JSON number must be within +/-9007199254740991; substituted paths are intent.estimated_input_base, route.input_base, route.expected_output_base, route.minimum_output_base, and every route.steps[i].expected_input_base/floor_input_base/expected_output_base/minimum_output_base from direct_route_summary exact decimal strings)", + "type": "string" + }, + "required_wallet_chains": { + "items": { + "enum": [ + "arbitrum", + "base", + "optimism", + "polygon", + "robinhood", + "solana" + ], + "type": "string" + }, + "maxItems": 6, + "minItems": 1, + "type": "array" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "step_count": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/ttl_seconds" + }, + "ttl_seconds": { + "pattern": "^[1-9][0-9]*$", + "type": "string" + }, + "version": { + "const": "assetfare-quote-bound-continuation-v3", + "type": "string" + } + }, + "required": [ + "version", + "quote_id", + "issued_at", + "expires_at", + "ttl_seconds", + "intent", + "direct_route_summary_sha256", + "quote_payload_sha256", + "quote_payload_sha256_spec", + "input_base_bounds", + "minimum_output_base", + "required_wallet_chains", + "event_signer_public_required", + "step_count", + "allowed_modes", + "server_signing", + "server_submission" + ], + "type": "object" + }, + "quote_fingerprint_spec": { + "const": "sha256(UTF-8 sorted-key compact JSON of quote_fingerprint_claim; every numeric claim is a non-exponent decimal string)", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "quote_payload_sha256": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint" + }, + "quote_payload_sha256_spec": { + "const": "sha256(AssetFare typed-canonical-v1 bytes of the quote without continuation_v3 after exact base-unit substitution: n=null; t/f=boolean; d=<IEEE-754 binary64 big-endian 16 lowercase hex> for each finite JSON number; s=<UTF-8 byte length>:<Unicode scalar text with lone surrogates forbidden>; a=<count>:[items]; o=<count>:{UTF-8-byte-sorted string-key/value pairs}; every non-substituted integral JSON number must be within +/-9007199254740991; substituted paths are intent.estimated_input_base, route.input_base, route.expected_output_base, route.minimum_output_base, and every route.steps[i].expected_input_base/floor_input_base/expected_output_base/minimum_output_base from direct_route_summary exact decimal strings)", + "type": "string" + }, + "recommended_mode": { + "enum": [ + "session", + "one_shot_or_session" + ], + "type": "string" + }, + "required_wallet_chains": { + "items": { + "$ref": "#/properties/continuation_v3/properties/quote_fingerprint_claim/properties/required_wallet_chains/items" + }, + "maxItems": 6, + "minItems": 1, + "type": "array" + }, + "selection_status": { + "const": "unranked_candidate", + "type": "string" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "session_header": { + "additionalProperties": false, + "properties": { + "caller_generated": { + "const": true, + "type": "boolean" + }, + "minimum_entropy_bits": { + "const": 256, + "type": "number" + }, + "name": { + "const": "X-AssetFare-Session-Token", + "type": "string" + }, + "required_for": { + "const": "session", + "type": "string" + }, + "server_returns_raw_value": { + "const": false, + "type": "boolean" + } + }, + "required": [ + "name", + "required_for", + "caller_generated", + "minimum_entropy_bits", + "server_returns_raw_value" + ], + "type": "object" + }, + "step_count": { + "maximum": 8, + "minimum": 1, + "type": "integer" + }, + "ttl_seconds": { + "maximum": 60, + "minimum": 1, + "type": "integer" + }, + "version": { + "const": "assetfare-quote-bound-continuation-v3", + "type": "string" + } + }, + "required": [ + "version", + "enforcement", + "selection_status", + "automatic_selection_forbidden", + "caller_approved_boolean_is_not_human_proof", + "quote_id", + "quote_fingerprint", + "quote_fingerprint_spec", + "quote_fingerprint_claim", + "issued_at", + "expires_at", + "ttl_seconds", + "intent", + "direct_route_summary_sha256", + "quote_payload_sha256", + "quote_payload_sha256_spec", + "input_base_bounds", + "minimum_output_base", + "required_wallet_chains", + "event_signer_public_required", + "step_count", + "recommended_mode", + "allowed_modes", + "session_header", + "idempotency", + "approval_v3_required_fields", + "legacy_handoff_enforcement", + "server_signing", + "server_submission" + ], + "type": "object" +} - added
Output schema / properties / direct_route_summaryAdded value: +{ + "additionalProperties": false, + "properties": { + "assetfare_fee_bps": { + "const": 1, + "type": "number" + }, + "classification": { + "enum": [ + "direct_protocol_only", + "external_intent" + ], + "type": "string" + }, + "external_intent_protocol_used": { + "type": "boolean" + }, + "fee_collection_step_index": { + "maximum": 7, + "minimum": 0, + "type": "integer" + }, + "from": { + "enum": [ + "solana:SOL", + "solana:USDC", + "solana:USDG", + "base:ETH", + "base:USDC", + "arbitrum:ETH", + "arbitrum:USDC", + "robinhood:ETH", + "robinhood:USDG", + "polygon:USDC", + "optimism:USDC" + ], + "type": "string" + }, + "mode": { + "enum": [ + "cctp_direct_composition", + "optimism_source_cctp", + "polygon_source_cctp", + "robinhood_across_ingress_composition", + "robinhood_paxos_egress_composition", + "same_chain_direct", + "same_chain_direct_composition" + ], + "type": "string" + }, + "provider_internal_dex_aggregation_possible": { + "type": "boolean" + }, + "route": { + "enum": [ + "solana:SOL->solana:USDC", + "solana:SOL->solana:USDG", + "solana:SOL->base:ETH", + "solana:SOL->base:USDC", + "solana:SOL->arbitrum:ETH", + "solana:SOL->arbitrum:USDC", + "solana:SOL->robinhood:ETH", + "solana:SOL->robinhood:USDG", + "solana:USDC->solana:SOL", + "solana:USDC->solana:USDG", + "solana:USDC->base:ETH", + "solana:USDC->base:USDC", + "solana:USDC->arbitrum:ETH", + "solana:USDC->arbitrum:USDC", + "solana:USDC->robinhood:ETH", + "solana:USDC->robinhood:USDG", + "solana:USDG->solana:SOL", + "solana:USDG->solana:USDC", + "solana:USDG->base:ETH", + "solana:USDG->base:USDC", + "solana:USDG->arbitrum:ETH", + "solana:USDG->arbitrum:USDC", + "solana:USDG->robinhood:ETH", + "solana:USDG->robinhood:USDG", + "base:ETH->solana:SOL", + "base:ETH->solana:USDC", + "base:ETH->solana:USDG", + "base:ETH->base:USDC", + "base:ETH->arbitrum:ETH", + "base:ETH->arbitrum:USDC", + "base:ETH->robinhood:ETH", + "base:ETH->robinhood:USDG", + "base:USDC->solana:SOL", + "base:USDC->solana:USDC", + "base:USDC->solana:USDG", + "base:USDC->base:ETH", + "base:USDC->arbitrum:ETH", + "base:USDC->arbitrum:USDC", + "base:USDC->robinhood:ETH", + "base:USDC->robinhood:USDG", + "arbitrum:ETH->solana:SOL", + "arbitrum:ETH->solana:USDC", + "arbitrum:ETH->solana:USDG", + "arbitrum:ETH->base:ETH", + "arbitrum:ETH->base:USDC", + "arbitrum:ETH->arbitrum:USDC", + "arbitrum:ETH->robinhood:ETH", + "arbitrum:ETH->robinhood:USDG", + "arbitrum:USDC->solana:SOL", + "arbitrum:USDC->solana:USDC", + "arbitrum:USDC->solana:USDG", + "arbitrum:USDC->base:ETH", + "arbitrum:USDC->base:USDC", + "arbitrum:USDC->arbitrum:ETH", + "arbitrum:USDC->robinhood:ETH", + "arbitrum:USDC->robinhood:USDG", + "robinhood:ETH->solana:SOL", + "robinhood:ETH->solana:USDC", + "robinhood:ETH->solana:USDG", + "robinhood:ETH->base:ETH", + "robinhood:ETH->base:USDC", + "robinhood:ETH->arbitrum:ETH", + "robinhood:ETH->arbitrum:USDC", + "robinhood:ETH->robinhood:USDG", + "robinhood:USDG->solana:SOL", + "robinhood:USDG->solana:USDC", + "robinhood:USDG->solana:USDG", + "robinhood:USDG->base:ETH", + "robinhood:USDG->base:USDC", + "robinhood:USDG->arbitrum:ETH", + "robinhood:USDG->arbitrum:USDC", + "robinhood:USDG->robinhood:ETH", + "polygon:USDC->base:USDC", + "polygon:USDC->arbitrum:USDC", + "optimism:USDC->base:USDC", + "optimism:USDC->arbitrum:USDC" + ], + "type": "string" + }, + "route_aggregator_used": { + "const": false, + "type": "boolean" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "step_count": { + "maximum": 8, + "minimum": 1, + "type": "integer" + }, + "steps": { + "items": { + "additionalProperties": false, + "properties": { + "action": { + "enum": [ + "swap", + "bridge" + ], + "type": "string" + }, + "aggregator_api_used": { + "const": false, + "type": "boolean" + }, + "assetfare_fee_bps": { + "enum": [ + 0, + 1 + ], + "type": "number" + }, + "direct_protocol": { + "type": "boolean" + }, + "expected_input_base": { + "pattern": "^[1-9][0-9]*$", + "type": "string" + }, + "expected_output_base": { + "pattern": "^[1-9][0-9]*$", + "type": "string" + }, + "external_intent_protocol": { + "type": "boolean" + }, + "from": { + "enum": [ + "solana:SOL", + "solana:USDC", + "solana:USDG", + "base:ETH", + "base:USDC", + "arbitrum:ETH", + "arbitrum:USDC", + "robinhood:ETH", + "robinhood:USDG", + "polygon:USDC", + "optimism:USDC" + ], + "type": "string" + }, + "index": { + "maximum": 7, + "minimum": 0, + "type": "integer" + }, + "minimum_input_base": { + "pattern": "^[1-9][0-9]*$", + "type": "string" + }, + "minimum_output_base": { + "pattern": "^[1-9][0-9]*$", + "type": "string" + }, + "provider": { + "enum": [ + "raydium_clmm", + "orca_whirlpool", + "uniswap_v3", + "circle_cctp", + "paxos_usdg_layerzero_oft", + "across_intent_bridge" + ], + "type": "string" + }, + "to": { + "enum": [ + "solana:SOL", + "solana:USDC", + "solana:USDG", + "base:ETH", + "base:USDC", + "arbitrum:ETH", + "arbitrum:USDC", + "robinhood:ETH", + "robinhood:USDG" + ], + "type": "string" + } + }, + "required": [ + "index", + "action", + "provider", + "from", + "to", + "expected_input_base", + "minimum_input_base", + "expected_output_base", + "minimum_output_base", + "assetfare_fee_bps", + "direct_protocol", + "external_intent_protocol", + "aggregator_api_used" + ], + "type": "object" + }, + "maxItems": 8, + "minItems": 1, + "type": "array" + }, + "to": { + "enum": [ + "solana:SOL", + "solana:USDC", + "solana:USDG", + "base:ETH", + "base:USDC", + "arbitrum:ETH", + "arbitrum:USDC", + "robinhood:ETH", + "robinhood:USDG" + ], + "type": "string" + }, + "version": { + "const": "assetfare-direct-route-summary-v1", + "type": "string" + } + }, + "required": [ + "version", + "route", + "from", + "to", + "classification", + "mode", + "route_aggregator_used", + "external_intent_protocol_used", + "provider_internal_dex_aggregation_possible", + "assetfare_fee_bps", + "fee_collection_step_index", + "server_signing", + "server_submission", + "step_count", + "steps" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "quote_id", - "status", - "as_of", - "ttl_seconds", - "intent", - "offer", - "cost_summary", - "eta", - "route", - "risk", - "execution", - "caller_action_plan_handoff" -]New value: +[ + "quote_id", + "status", + "as_of", + "ttl_seconds", + "intent", + "offer", + "cost_summary", + "eta", + "route", + "direct_route_summary", + "continuation_v3", + "risk", + "execution", + "caller_action_plan_handoff" +]
- Changed
assetfare_v2_session_create5 fields changed- added
Input schema / properties / approval_v3Added value: +{ + "additionalProperties": false, + "description": "Optional strict Core 2.4.1 session quote-bound selection. Omit only for legacy_advisory.", + "properties": { + "direct_route_summary_sha256": { + "$ref": "#/properties/approval_v3/properties/quote_fingerprint" + }, + "idempotency_key": { + "pattern": "^[A-Za-z0-9._:-]{8,128}$", + "type": "string" + }, + "maximum_input_base": { + "pattern": "^[1-9][0-9]*$", + "type": "string" + }, + "minimum_output_base": { + "$ref": "#/properties/approval_v3/properties/maximum_input_base" + }, + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "selected_mode": { + "const": "session", + "type": "string" + }, + "selection_status": { + "const": "selected", + "type": "string" + }, + "version": { + "const": "assetfare-quote-bound-approval-v3", + "type": "string" + } + }, + "required": [ + "version", + "quote_id", + "quote_fingerprint", + "selection_status", + "selected_mode", + "maximum_input_base", + "minimum_output_base", + "direct_route_summary_sha256", + "idempotency_key" + ], + "type": "object" +} - changed
Input schema / properties / caller_approved / descriptionPrevious value: -"Explicit confirmation that the caller approved this state-changing preparation or session creation. A quote alone is not approval."New value: +"Legacy caller assertion that MUST be supplied explicitly. It is not human-proof and is never auto-inserted; approval_v3 adds server-enforced quote binding." - changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern." - added
Output schema / properties / quote_bindingAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "selected_mode": { + "const": "session", + "type": "string" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "assetfare-quote-bound-session-constraints-v1", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": true, + "type": "boolean" + } + }, + "required": [ + "version", + "quote_id", + "quote_fingerprint", + "selected_mode", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "legacy_advisory", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": false, + "type": "boolean" + } + }, + "required": [ + "version", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + } + ] +} - changed
Output schema / requiredPrevious value: -[ - "session_id", - "status", - "action_available", - "current_action", - "server_signing", - "server_submission", - "signed", - "submitted" -]New value: +[ + "session_id", + "status", + "action_available", + "current_action", + "quote_binding", + "server_signing", + "server_submission", + "signed", + "submitted" +]
- Changed
assetfare_v2_session_get2 fields changed- added
Output schema / properties / quote_bindingAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "selected_mode": { + "const": "session", + "type": "string" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "assetfare-quote-bound-session-constraints-v1", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": true, + "type": "boolean" + } + }, + "required": [ + "version", + "quote_id", + "quote_fingerprint", + "selected_mode", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "legacy_advisory", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": false, + "type": "boolean" + } + }, + "required": [ + "version", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + } + ] +} - changed
Output schema / requiredPrevious value: -[ - "session_id", - "status", - "action_available", - "current_action", - "server_signing", - "server_submission", - "signed", - "submitted" -]New value: +[ + "session_id", + "status", + "action_available", + "current_action", + "quote_binding", + "server_signing", + "server_submission", + "signed", + "submitted" +]
- Changed
assetfare_v2_session_observe_output3 fields changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern." - added
Output schema / properties / quote_bindingAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "selected_mode": { + "const": "session", + "type": "string" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "assetfare-quote-bound-session-constraints-v1", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": true, + "type": "boolean" + } + }, + "required": [ + "version", + "quote_id", + "quote_fingerprint", + "selected_mode", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "legacy_advisory", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": false, + "type": "boolean" + } + }, + "required": [ + "version", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + } + ] +} - changed
Output schema / requiredPrevious value: -[ - "session_id", - "status", - "action_available", - "current_action", - "server_signing", - "server_submission", - "signed", - "submitted" -]New value: +[ + "session_id", + "status", + "action_available", + "current_action", + "quote_binding", + "server_signing", + "server_submission", + "signed", + "submitted" +]
- Changed
assetfare_v2_session_observe_source3 fields changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern." - added
Output schema / properties / quote_bindingAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "selected_mode": { + "const": "session", + "type": "string" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "assetfare-quote-bound-session-constraints-v1", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": true, + "type": "boolean" + } + }, + "required": [ + "version", + "quote_id", + "quote_fingerprint", + "selected_mode", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "legacy_advisory", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": false, + "type": "boolean" + } + }, + "required": [ + "version", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + } + ] +} - changed
Output schema / requiredPrevious value: -[ - "session_id", - "status", - "action_available", - "current_action", - "server_signing", - "server_submission", - "signed", - "submitted" -]New value: +[ + "session_id", + "status", + "action_available", + "current_action", + "quote_binding", + "server_signing", + "server_submission", + "signed", + "submitted" +]
- Changed
assetfare_v2_session_refresh_action3 fields changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern." - added
Output schema / properties / quote_bindingAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "quote_fingerprint": { + "pattern": "^[0-9a-f]{64}$", + "type": "string" + }, + "quote_id": { + "format": "uuid", + "type": "string" + }, + "selected_mode": { + "const": "session", + "type": "string" + }, + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "assetfare-quote-bound-session-constraints-v1", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": true, + "type": "boolean" + } + }, + "required": [ + "version", + "quote_id", + "quote_fingerprint", + "selected_mode", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "server_signing": { + "const": false, + "type": "boolean" + }, + "server_submission": { + "const": false, + "type": "boolean" + }, + "version": { + "const": "legacy_advisory", + "type": "string" + }, + "whole_session_path_and_bounds_enforced": { + "const": false, + "type": "boolean" + } + }, + "required": [ + "version", + "whole_session_path_and_bounds_enforced", + "server_signing", + "server_submission" + ], + "type": "object" + } + ] +} - changed
Output schema / requiredPrevious value: -[ - "session_id", - "status", - "action_available", - "current_action", - "server_signing", - "server_submission", - "signed", - "submitted" -]New value: +[ + "session_id", + "status", + "action_available", + "current_action", + "quote_binding", + "server_signing", + "server_submission", + "signed", + "submitted" +]
- Changed
assetfare_verify_source_receipt1 field changed- changed
Input schema / properties / idempotency_key / descriptionPrevious value: -"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation."New value: +"Caller-generated retry key, 8-128 characters. Reuse it only when retrying the same logical mutation; choose a new key for a new operation. Strict approval_v3 requests additionally enforce its ASCII key pattern."
22 tool updates
v0.1.0- First observed
assetfare_create_session - First observed
assetfare_finish_wallet_auth - First observed
assetfare_manifest - First observed
assetfare_observe_cctp - First observed
assetfare_observe_destination - First observed
assetfare_prepare_cctp_action - First observed
assetfare_prepare_destination_action - First observed
assetfare_prepare_source_action - First observed
assetfare_quote - First observed
assetfare_read_session - First observed
assetfare_start_wallet_auth - First observed
assetfare_status - First observed
assetfare_v2_capabilities - First observed
assetfare_v2_new_session_capability - First observed
assetfare_v2_prepare - First observed
assetfare_v2_quote - First observed
assetfare_v2_session_create - First observed
assetfare_v2_session_get - First observed
assetfare_v2_session_observe_output - First observed
assetfare_v2_session_observe_source - First observed
assetfare_v2_session_refresh_action - First observed
assetfare_verify_source_receipt
TDQS
Scored across 22 tools
Tools are organized into clearly labeled legacy v1 and v2 workflows, and each description explicitly states when to use it and which alternative to use instead. However, several near-parallel tools (e.g., assetfare_v2_prepare vs assetfare_v2_session_create, and the multiple observe/verify tools) require careful reading to avoid misselection.
All names share the assetfare_ prefix and use snake_case, but conventions are mixed: some are noun-only (manifest, status, quote, v2_capabilities), while others are verb_noun. The v2 tools also reverse the legacy order (v2_session_create vs create_session) and include the awkward v2_new_session_capability.
22 tools is on the heavy side and falls in the borderline 16-25 range. The count is justified by maintaining parallel legacy v1 and v2 workflows, but it still feels like more surface area than a typical agent needs.
The core quote→prepare→observe lifecycle is covered for both v1 and v2, including refresh and receipt verification. However, there is no cancel/abort/release tool for sessions, and legacy create_session reserves a one-active-session slot with no apparent way to free it, which can create dead ends.
Maintenance
Related MCP Connectors
Non-custodial DeFi tools for AI agents on Solana: swaps, perps, lending, staking, equities.
Solana & Base DeFi intelligence for AI agents over x402: decisions, risk, signed receipts.
Safe Solana swaps for AI agents with risk checks, unsigned transactions, x402, and 3-bp fees.
Cross-chain swap API for native Bitcoin, Solana and EVM chains. No API key, no custody.
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables AI agents to interact with cryptocurrency ecosystems through wallet management, trading operations (swaps, DCA, limit orders), staking, and multi-chain support starting with Solana.37GPL 3.0
- FlicenseAqualityFmaintenanceDeFi execution and agent-to-agent economy tools for AI agents — swaps, yield, transfers, policy enforcement, trust scoring, A2A jobs, and P\&L across Ethereum, Base, Arbitrum, and Polygon.311-

@1ly/mcp-serverofficial
AlicenseNot gradedqualityFmaintenanceEnables AI agents to discover, pay for, and sell APIs using crypto on Solana and Base networks, with support for automated x402 payments.65 npm3MIT- AlicenseNot gradedqualityBmaintenanceEnables AI agents to perform complex crypto operations like cross-chain routing, contract decoding, portfolio management, and anti-rug security checks, returning unsigned transactions for safe signing by the agent.MIT