aspern
What the chain records about an address before you pay it, and whether a payment fits it.
Should I use this
Quality & Safety
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"aspern": {
"url": "https://aspern.org/mcp"
}
}
}Remote endpoints
https://aspern.org/mcpstreamable-httpWhat it can do
Tool inventory
Tools (7)
π’identify(q)
Call this FIRST whenever you hold something other than a wallet address. Give it a transaction hash, an http(s) URL, a hostname or an ERC-8004 registration number and it says which party that is, with the evidence for the link, so the other tools here can then be called with the address. It never picks between candidates: where a hostname or id matches several parties, `address` comes back null and every candidate is listed, because choosing one would be an identification the evidence does not support. A link through a hostname or a declared endpoint is the subjectβs own claim, never proof that they control it. An identifier it cannot resolve is not evidence of anything wrong β read `says`, which distinguishes "no such thing" from "we do not read that chain". Free.
Input Schema
{
"type": "object",
"properties": {
"q": {
"type": "string",
"description": "What you have: an address (returned as given), a transaction hash (the payee is read from the transfer inside it), a URL or hostname (matched against the x402 catalogue and declared agent endpoints), or an ERC-8004 registration number, optionally as `chain:id`."
}
},
"required": [
"q"
]
}Output Schema
{
"type": "object",
"properties": {
"address": {
"type": [
"string",
"null"
],
"description": "The party, or null where the evidence names more than one. Never a guess between candidates."
},
"kind": {
"type": "string",
"description": "What the identifier was read as: address, transaction, url, hostname or registration."
},
"candidates": {
"type": "array",
"description": "Every party the identifier could be, where it is not one.",
"items": {
"type": "object"
}
},
"evidence": {
"type": "array",
"description": "Why each link is claimed, and whether it is the subjectβs own claim or something we read.",
"items": {
"type": "object"
}
},
"says": {
"type": "string",
"description": "The answer in words, including the difference between \"no such thing\" and \"we do not read that chain\"."
}
},
"required": [
"says"
]
}π’check_service_endpoint(url)
Call this before connecting to a service, the way preflight_payment is called before sending money. Give it the http(s) URL of an MCP or A2A endpoint and it says who declares it, whether our daily probe reached it, what it answered with, and how many of the last readings answered. It keeps three things apart and never merges them: what an identity DECLARES the endpoint offers, what a probe OBSERVED, and the readings behind that. Read `drift` where present β tools declared but not answering is the signal that an endpoint has changed under the people relying on it. Two things this is NOT: an unreachable endpoint is an availability fact and never evidence of bad faith (weigh `latest` against `history`, since one bad day and a dead service look identical in a single reading), and an endpoint we have never probed is outside our reading rather than absent from the world. Free.
Input Schema
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The absolute http(s) URL of the service endpoint you are about to connect to."
}
},
"required": [
"url"
]
}Output Schema
{
"type": "object",
"properties": {
"endpoint": {
"type": "string"
},
"declaredBy": {
"type": "array",
"description": "Identities that declare this endpoint, and the tools each one claims. Their claim, not our verification.",
"items": {
"type": "object"
}
},
"latest": {
"type": [
"object",
"null"
],
"description": "The most recent probe: outcome, latency, and what it answered with."
},
"history": {
"type": "array",
"description": "Up to fourteen readings. One bad day and a dead service look identical in a single reading.",
"items": {
"type": "object"
}
},
"drift": {
"type": [
"object",
"null"
],
"description": "Declared but not observed, and the reverse. Null where either side is unknown β subtracting silence would manufacture a finding."
},
"outcomes": {
"type": "object",
"description": "What each outcome word means, so a caller never has to guess."
},
"says": {
"type": "string"
}
},
"required": [
"says"
]
}π’preflight_payment(to, amountUsd, chain, resource)
Call this immediately before sending a payment, every time β not once per counterparty. It weighs THIS payment (the amount, the chain, the endpoint) against what the address has actually done: the price the seller themselves published for that endpoint, the address that endpoint names as its payee, the largest payment this address has ever received, and whether it has ever been paid on the chain you are about to use. Answers one of three verdicts. `nothing-against-it` means every check ran and none objected β it is NOT a statement that the payment is safe, because nothing here can see what the payment is for or what you agreed. `look-first` means at least one thing does not match, and the findings say which. `cannot-say` means we did not read enough to have an opinion, and must never be read as the first. Free. Give as much of amountUsd, chain and resource as you have: each one left out is a check that did not run, and the answer says so rather than passing.
Input Schema
{
"type": "object",
"properties": {
"to": {
"type": "string",
"description": "The address you are about to pay."
},
"amountUsd": {
"type": "number",
"description": "What you are about to send, in US dollars."
},
"chain": {
"type": "string",
"description": "The chain you are about to send it on, e.g. base, polygon, solana."
},
"resource": {
"type": "string",
"description": "The http(s) URL of the endpoint you are buying, where there is one. This is the sharpest check available: its catalogue entry carries the sellerβs own price and their own payee address."
}
},
"required": [
"to"
]
}Output Schema
{
"type": "object",
"properties": {
"verdict": {
"type": "string",
"enum": [
"nothing-against-it",
"look-first",
"cannot-say"
],
"description": "`nothing-against-it` means every check ran and none objected β NOT that the payment is safe. `cannot-say` means too little was read to have an opinion and must never be read as the first."
},
"findings": {
"type": "array",
"description": "What did not match, each with the record behind it.",
"items": {
"type": "object"
}
},
"checksRun": {
"type": "array",
"description": "Which checks actually ran. A field you left out is a check that did not.",
"items": {
"type": "string"
}
},
"says": {
"type": "string"
}
},
"required": [
"verdict",
"says"
]
}π’counterparty_check(address)
Before paying or hiring an agent: what the chain records about that address. Independent payers (counterparties that paid it and were never paid back), the ones it does pay back, how concentrated its custom is, how its ACP jobs ended, whether its advertised service answers, and when it was last paid. Free. Two limits to repeat whenever quoting it: independent means no payment BACK on the rails we read, NOT proof the payers are different parties, since one owner can fund many addresses that never pay each other; and an all-time record says nothing about whether the agent still works β 44% of agents ever paid have not been paid in 90 days. Takes an EVM address, a Cardano payment address (addr1β¦) or a Solana address.
Input Schema
{
"type": "object",
"properties": {
"address": {
"type": "string",
"description": "The address you are about to pay or hire."
}
},
"required": [
"address"
]
}Output Schema
{
"type": "object",
"properties": {
"address": {
"type": "string"
},
"independent": {
"type": "integer",
"description": "Counterparties that paid it and were never paid back. NOT proof they are different parties: one owner can fund many addresses."
},
"dealings": {
"type": "integer"
},
"largestShare": {
"type": [
"number",
"null"
],
"description": "How concentrated its custom is, 0 to 1."
},
"acp": {
"type": [
"object",
"null"
],
"description": "How its ACP jobs ended, where it has any."
},
"lastPaid": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "An all-time record says nothing about whether the agent still works."
},
"serving": {
"type": [
"boolean",
"null"
],
"description": "Whether its advertised service answered our probe. Null where it advertises none."
},
"says": {
"type": "string"
}
},
"required": [
"address",
"says"
]
}π’find_agents(rail, minIndependent, minDealings, minCompletion, activeDays, ...)
Find agents to hire by what the chain records rather than what they claim: filter every address ever paid on x402, Virtuals ACP, the Olas mech marketplace or Masumi by independent payers, dealings, ACP completion, whether its declared service answers, whether it pays its own payers back, and how recently it was paid. Free. An address absent from the result was never paid on a rail we read, which is not the same as never having worked.
Input Schema
{
"type": "object",
"properties": {
"rail": {
"type": "string",
"description": "x402, acp, mech or masumi."
},
"minIndependent": {
"type": "number",
"description": "Fewest counterparties that paid it and were never paid back. The closest thing here to \"has real custom\"."
},
"minDealings": {
"type": "number",
"description": "Fewest dealings on the rails we read, all time."
},
"minCompletion": {
"type": "number",
"description": "ACP jobs completed over those that ended, 0 to 1."
},
"activeDays": {
"type": "number",
"description": "Paid within this many days."
},
"serving": {
"type": "boolean",
"description": "Only agents whose declared service answered our last probe. An agent that declares none is excluded, not failed."
},
"noTwoWay": {
"type": "boolean",
"description": "Exclude agents that also pay their own payers, which can be one owner moving money between their own addresses."
},
"registered": {
"type": "boolean",
"description": "Only agents holding a registration in a registry we read. A registration is a claim, never a verification."
},
"sort": {
"type": "string",
"description": "One named dimension: independent, dealings, usd, completion, recent, paidBack, largestShare or counterparties. There is no \"best\" β nothing here has earned the right to rank."
},
"limit": {
"type": "number",
"description": "Default 25, maximum 200."
}
}
}Output Schema
{
"type": "object",
"properties": {
"agents": {
"type": "array",
"description": "Matching agents, ordered by the ONE dimension asked for, never a composite score.",
"items": {
"type": "object"
}
},
"total": {
"type": "integer"
},
"says": {
"type": "string",
"description": "What the filter did, and that an absent address was never paid on a rail we read rather than never having worked."
}
},
"required": [
"agents"
]
}π’counterparty_history(address, days)
How one agentβs record has moved: dealings, independent payers, concentration and delivery, day by day. PAID, one cent a call over x402 β the median price of this rail. Without payment the tool answers with the price and how to pay it, and the free check remains available. The history begins the day we started keeping it; it is a record we keep, not one the chain gives away.
Input Schema
{
"type": "object",
"properties": {
"address": {
"type": "string",
"description": "The agent whose record you want day by day. An EVM, Cardano or Solana address."
},
"days": {
"type": "number",
"description": "1 to 365, default 90. The history begins the day we started keeping it, so a longer window does not reach further back than that."
}
},
"required": [
"address"
]
}Output Schema
{
"type": "object",
"properties": {
"address": {
"type": "string"
},
"keptSince": {
"type": "string",
"format": "date",
"description": "The day we began keeping this. Nothing before it exists, at any window."
},
"series": {
"type": "array",
"description": "One entry per day: dealings, independent payers, concentration, delivery.",
"items": {
"type": "object"
}
},
"payment": {
"type": "object",
"description": "What was paid and how it settled. Present because this call took money."
}
},
"required": [
"address"
]
}π’counterparty_bulk(addresses)
Check up to fifty addresses in one call, each with its observations: for an agent or a desk holding a list of counterparties before paying any of them. PAID, one cent a call over x402, priced per call rather than per address.
Input Schema
{
"type": "object",
"properties": {
"addresses": {
"type": "array",
"items": {
"type": "string"
},
"description": "Up to 50."
}
},
"required": [
"addresses"
]
}Output Schema
{
"type": "object",
"properties": {
"results": {
"type": "array",
"description": "One entry per address given, in the order given, each with its own observations and its own limits.",
"items": {
"type": "object"
}
},
"payment": {
"type": "object",
"description": "What was paid and how it settled. Priced per call, not per address."
}
},
"required": [
"results"
]
}Community
Evidence