Skip to main content
Glama

ASPERN: counterparty checks for agents

Weigh one action against a named policy

evaluate_action
Read-onlyIdempotent

Call this when you are about to DO something and need one answer you can act on: pay an address, connect to an MCP server, call a tool, or put capital into a vault. The answer depends on the AMOUNT, the ACTION, the POLICY you name and how much we actually read — so the same address can be allow for $5 and abstain for $5,000. Four decisions. allow means nothing we could check objects, up to maxAmountUsd, and is NOT a statement that the action is safe: nothing here sees what it is for or what you agreed. review means something we READ does not match, and reasons names which rule. abstain means we did not read enough to have an opinion — our gap, never approval. unsupported means the policy has no rule for this action, and inventing one would be worse than declining. A policy judges the risk LEVEL as well as whether it could be read: conservative will not allocate into a band worse than moderate, nor where control is thin, and returns review for that rather than abstain. A failed rule carries detail (observed, accepted, failedCondition); read it, and rules, before suspecting an error. Every rule id in reasons is published in full at the policies tool, including to the party being evaluated. Free.

Input Schema

NameRequiredDescriptionDefault
chainNoThe chain the action settles on, e.g. base, polygon, solana.
actionYesWhat you are about to do.
policyNoA policy version or slug. Defaults to conservative-v1. An unknown name is REFUSED rather than silently replaced with the default.
subjectYesWhat you are about to do it to: an address to pay, an endpoint URL to connect to, or a vault slug.
resourceNoThe http(s) endpoint being bought or connected to, where that differs from `subject`. This is what reaches the seller’s own catalogue entry, carrying their price and their payee.
amountUsdNoWhat you are about to commit, in US dollars. Leave it out and the amount rules report that they did not run, rather than passing.
requiredChecksNoRule ids YOU will not act without, e.g. ["quoted-payee-matches-proposal","live-price-matches-proposal"]. The policy is OUR view of what matters; this is yours. Any one of them that does not reach a verdict — because we could not read it, or because it never applied to what you sent — turns the answer into ABSTAIN instead of ALLOW. It can only ever make the answer more conservative: a required check that passes changes nothing, and a real objection stays a REVIEW rather than being buried as an abstain. An id we do not hold is NAMED in `required.unknownIds` rather than ignored, because a caller whose requirement was never looked at must not read `allow` as it having been met. `list_policies` has every id.

Output Schema

NameRequiredDescriptionDefault
metaNoHow current this answer is and what it was read from: `freshness` and the ages behind it. Present on every answer from this server, whatever the tool.
saysYesThe decision in one sentence, naming the rules that drove it. Written to be shown to whoever authorises the action.
rulesNoEvery rule considered: `id`, `state` (pass, fail or unknown), `checks` and `says`. THE TWO SENTENCES ARE DIFFERENT THINGS and the distinction is the audit trail. `checks` is the QUESTION the rule asks and never moves; `says` is WHAT WE FOUND and follows the state, so a failing rule reads as a failure. Until 2026-10-13 `says` carried the question in every state, which meant a `fail` arrived beside the claim it had just refuted — a model reading the prose rather than the state got the opposite of the decision. Read `state` to decide and `says` to explain; they can no longer disagree. A FAILED RULE CARRIES `detail` WHERE IT CAN: `observed` is what we read in the rule’s own vocabulary, `accepted` is what the policy would have taken, and `failedCondition` is the sentence replacing the generic one. On `controller-risk-within-policy` that matters more than anywhere: a vault can read `controller.level: low` in vault_check and still fail here, because the LEVEL says how dangerous the arrangement is and the BAND says what it is; a timelock with no guardian is `thin`, conservative accepts `checked` only, and both readings are right. The detail says so rather than leaving a reader to find a computational error that is not there. SINCE 2026-10-11 A POLICY JUDGES THE RISK LEVEL, NOT ONLY ITS TRUSTWORTHINESS. `risk-band-is-supported` asks whether the band survives what we could not read; `risk-band-within-policy` and `controller-risk-within-policy` ask whether the band and the control we DID read are ones this policy will commit capital against. Conservative will not allocate into a band worse than moderate, nor where control is `thin` (one party able to move the money), and returns `review` rather than `abstain`, because a band we read as high is a finding about the vault and not a gap in our reading. Permissive declares neither threshold and is unchanged. This closed a real defect: a vault our own vault_check called high risk with 0.5% withdrawable used to come back `allow`, because every rule about the AVAILABILITY of risk data passed.
byAreaNoThe same coverage, PER QUESTION: counterparty, payment-intent, service, capital. Read this rather than the single `coverage` when the action moves money. The denominator is the rules the policy holds for that area, NOT the ones that happened to apply — so an area where nothing could be checked reports `none`, which is the fact, instead of reporting high coverage of nothing.
limitsNoWhat a decision here is and is not. `allow` means no rule objected under this policy at this coverage, which is not a statement that the action is safe.
policyNoThe policy applied: its intent, its ceiling and the coverage floor below which it abstains.
checkedNoWHICH ACCEPTANCE QUESTIONS THIS POLICY PUT AT ALL: `riskBand`, `controller`, `exitRecord`, `amount`, as booleans. READ THIS BEFORE ACTING ON `decision`. FALSE is the dangerous value and the reason the field exists: it means the question was never put, which is NOT a question that passed. `permissive` returns `allow` on a vault that lost 92.8% of its value because it declares no risk ceiling, and a client reading only `decision` cannot see that. `exitRecord` is whether the policy weighed HOW OFTEN THE EXIT HAS BEEN SHUT over the days we watched, as against how it reads at the last reading: 20 vaults holding $190.8M read as open today and were shut on more than a tenth of the days we have watched them, so a policy that never asked has not cleared them. Derived from what the POLICY declares and never from how the subject turned out, so a refusal and a clean pass under one policy carry identical flags.
reasonsYesRule ids that decided. Look them up in the policy to see the sentence each one checks.
coverageYesHow much of what the policy wanted was actually there. Below the policy floor the decision is `abstain` rather than `allow`.
decisionYes`allow` is not “safe” and `abstain` is not “nothing found”. Read `decisions` in the answer for what each one means.
proposalNoWhat you asked about, read back, so a typo is visible before you act on the answer.
requiredNoPresent only where you sent `requiredChecks`. `met`, `unmet` and `unknownIds`, with a sentence. An `unmet` entry is why the decision is ABSTAIN.
warningsNoAnything the server wants a caller to know about THIS answer before acting on it. Empty is the normal case and is not a guarantee.
decisionsNoWhat each decision word means, so a caller never has to guess. Read it before treating `allow` as approval or `abstain` as a clean result.
maxAmountUsdNoThe most this policy permits for this proposal. Null where the action moves no money, and null on anything but an `allow`, because a limit printed beside a `review` reads as permission.
policyIntentNoWhat the policy is FOR. `risk-and-evidence` puts questions about the level AND about what we could read. `evidence-availability` asks only whether we could read enough — which is what `permissive` is: an availability-of-evidence policy rather than an investment risk policy. An `allow` from one is not an `allow` from the other.
notApplicableNoRules this PROPOSAL does not raise, each with `why` and what to send to have it checked. Distinct from `missingEvidence`, which is a gap in our record: a payment naming no `resource` has no listing to be found in, so those rules do not apply and do not lower coverage. Send `resource` and two more checks run, both decisive.
paymentIntentNoWhether this payment was checked against WHAT IT IS BUYING, in one field. `not-verified` means the policy holds such rules and none of them ran, which on a payment is almost always a missing `resource`: the counterparty may have an excellent record and nothing has compared this amount to this service. `verified` means at least one reached a verdict. `not-applicable` means the policy asks nothing about it, or the action is not a payment.
policyVersionYesCarried so an answer given today can be reproduced after the rules change.
missingEvidenceNoRule ids whose evidence we do not hold. These lower `coverage` and are NEVER counted as objections.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedOutput schema / properties / rules / description
      Previous value: -"Every rule considered: `id`, `state` (pass, fail or unknown), `checks` and `says`. THE TWO SENTENCES ARE DIFFERENT THINGS and the distinction is the audit trail. `checks` is the QUESTION the rule asks and never moves; `says` is WHAT WE FOUND and follows the state, so a failing rule reads as a failure. Until 2026-10-13 `says` carried the question in every state, which meant a `fail` arrived beside the claim it had just refuted — a model reading the prose rather than the state got the opposite of the decision. Read `state` to decide and `says` to explain; they can no longer disagree."New value: +"Every rule considered: `id`, `state` (pass, fail or unknown), `checks` and `says`. THE TWO SENTENCES ARE DIFFERENT THINGS and the distinction is the audit trail. `checks` is the QUESTION the rule asks and never moves; `says` is WHAT WE FOUND and follows the state, so a failing rule reads as a failure. Until 2026-10-13 `says` carried the question in every state, which meant a `fail` arrived beside the claim it had just refuted — a model reading the prose rather than the state got the opposite of the decision. Read `state` to decide and `says` to explain; they can no longer disagree. A FAILED RULE CARRIES `detail` WHERE IT CAN: `observed` is what we read in the rule’s own vocabulary, `accepted` is what the policy would have taken, and `failedCondition` is the sentence replacing the generic one. On `controller-risk-within-policy` that matters more than anywhere: a vault can read `controller.level: low` in vault_check and still fail here, because the LEVEL says how dangerous the arrangement is and the BAND says what it is; a timelock with no guardian is `thin`, conservative accepts `checked` only, and both readings are right. The detail says so rather than leaving a reader to find a computational error that is not there. SINCE 2026-10-11 A POLICY JUDGES THE RISK LEVEL, NOT ONLY ITS TRUSTWORTHINESS. `risk-band-is-supported` asks whether the band survives what we could not read; `risk-band-within-policy` and `controller-risk-within-policy` ask whether the band and the control we DID read are ones this policy will commit capital against. Conservative will not allocate into a band worse than moderate, nor where control is `thin` (one party able to move the money), and returns `review` rather than `abstain`, because a band we read as high is a finding about the vault and not a gap in our reading. Permissive declares neither threshold and is unchanged. This closed a real defect: a vault our own vault_check called high risk with 0.5% withdrawable used to come back `allow`, because every rule about the AVAILABILITY of risk data passed."
  2. Changed1 schema field changed
    • changedOutput schema / properties / checked / description
      Previous value: -"WHICH ACCEPTANCE QUESTIONS THIS POLICY PUT AT ALL: `riskBand`, `controller`, `amount`, as booleans. READ THIS BEFORE ACTING ON `decision`. FALSE is the dangerous value and the reason the field exists: it means the question was never put, which is NOT a question that passed. `permissive` returns `allow` on a vault that lost 92.8% of its value because it declares no risk ceiling, and a client reading only `decision` cannot see that. Derived from what the POLICY declares and never from how the subject turned out, so a refusal and a clean pass under one policy carry identical flags."New value: +"WHICH ACCEPTANCE QUESTIONS THIS POLICY PUT AT ALL: `riskBand`, `controller`, `exitRecord`, `amount`, as booleans. READ THIS BEFORE ACTING ON `decision`. FALSE is the dangerous value and the reason the field exists: it means the question was never put, which is NOT a question that passed. `permissive` returns `allow` on a vault that lost 92.8% of its value because it declares no risk ceiling, and a client reading only `decision` cannot see that. `exitRecord` is whether the policy weighed HOW OFTEN THE EXIT HAS BEEN SHUT over the days we watched, as against how it reads at the last reading: 20 vaults holding $190.8M read as open today and were shut on more than a tenth of the days we have watched them, so a policy that never asked has not cleared them. Derived from what the POLICY declares and never from how the subject turned out, so a refusal and a clean pass under one policy carry identical flags."
  3. Changed2 schema fields changed
    • addedOutput schema / properties / meta
      Added value: +{
      +  "description": "How current this answer is and what it was read from: `freshness` and the ages behind it. Present on every answer from this server, whatever the tool.",
      +  "type": "object"
      +}
    • addedOutput schema / properties / warnings
      Added value: +{
      +  "description": "Anything the server wants a caller to know about THIS answer before acting on it. Empty is the normal case and is not a guarantee.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
  4. Changed2 schema fields changed
    • addedOutput schema / properties / checked
      Added value: +{
      +  "description": "WHICH ACCEPTANCE QUESTIONS THIS POLICY PUT AT ALL: `riskBand`, `controller`, `amount`, as booleans. READ THIS BEFORE ACTING ON `decision`. FALSE is the dangerous value and the reason the field exists: it means the question was never put, which is NOT a question that passed. `permissive` returns `allow` on a vault that lost 92.8% of its value because it declares no risk ceiling, and a client reading only `decision` cannot see that. Derived from what the POLICY declares and never from how the subject turned out, so a refusal and a clean pass under one policy carry identical flags.",
      +  "type": "object"
      +}
    • addedOutput schema / properties / policyIntent
      Added value: +{
      +  "description": "What the policy is FOR. `risk-and-evidence` puts questions about the level AND about what we could read. `evidence-availability` asks only whether we could read enough — which is what `permissive` is: an availability-of-evidence policy rather than an investment risk policy. An `allow` from one is not an `allow` from the other.",
      +  "enum": [
      +    "risk-and-evidence",
      +    "evidence-availability"
      +  ],
      +  "type": "string"
      +}
  5. Changed1 schema field changed
    • changedOutput schema / properties / rules / description
      Previous value: -"Every rule considered, each pass, fail or unknown. The audit trail for the decision."New value: +"Every rule considered: `id`, `state` (pass, fail or unknown), `checks` and `says`. THE TWO SENTENCES ARE DIFFERENT THINGS and the distinction is the audit trail. `checks` is the QUESTION the rule asks and never moves; `says` is WHAT WE FOUND and follows the state, so a failing rule reads as a failure. Until 2026-10-13 `says` carried the question in every state, which meant a `fail` arrived beside the claim it had just refuted — a model reading the prose rather than the state got the opposite of the decision. Read `state` to decide and `says` to explain; they can no longer disagree."
  6. Changed4 schema fields changed
    • addedInput schema / properties / requiredChecks
      Added value: +{
      +  "description": "Rule ids YOU will not act without, e.g. [\"quoted-payee-matches-proposal\",\"live-price-matches-proposal\"]. The policy is OUR view of what matters; this is yours. Any one of them that does not reach a verdict — because we could not read it, or because it never applied to what you sent — turns the answer into ABSTAIN instead of ALLOW. It can only ever make the answer more conservative: a required check that passes changes nothing, and a real objection stays a REVIEW rather than being buried as an abstain. An id we do not hold is NAMED in `required.unknownIds` rather than ignored, because a caller whose requirement was never looked at must not read `allow` as it having been met. `list_policies` has every id.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / byArea
      Added value: +{
      +  "description": "The same coverage, PER QUESTION: counterparty, payment-intent, service, capital. Read this rather than the single `coverage` when the action moves money. The denominator is the rules the policy holds for that area, NOT the ones that happened to apply — so an area where nothing could be checked reports `none`, which is the fact, instead of reporting high coverage of nothing.",
      +  "items": {
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / paymentIntent
      Added value: +{
      +  "description": "Whether this payment was checked against WHAT IT IS BUYING, in one field. `not-verified` means the policy holds such rules and none of them ran, which on a payment is almost always a missing `resource`: the counterparty may have an excellent record and nothing has compared this amount to this service. `verified` means at least one reached a verdict. `not-applicable` means the policy asks nothing about it, or the action is not a payment.",
      +  "type": "object"
      +}
    • addedOutput schema / properties / required
      Added value: +{
      +  "description": "Present only where you sent `requiredChecks`. `met`, `unmet` and `unknownIds`, with a sentence. An `unmet` entry is why the decision is ABSTAIN.",
      +  "type": "object"
      +}
  7. Changed1 schema field changed
    • addedOutput schema / properties / notApplicable
      Added value: +{
      +  "description": "Rules this PROPOSAL does not raise, each with `why` and what to send to have it checked. Distinct from `missingEvidence`, which is a gap in our record: a payment naming no `resource` has no listing to be found in, so those rules do not apply and do not lower coverage. Send `resource` and two more checks run, both decisive.",
      +  "items": {
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
  8. Changed2 schema fields changed
    • addedOutput schema / properties / limits / description
      Added value: +"What a decision here is and is not. `allow` means no rule objected under this policy at this coverage, which is not a statement that the action is safe."
    • addedOutput schema / properties / says / description
      Added value: +"The decision in one sentence, naming the rules that drove it. Written to be shown to whoever authorises the action."
  9. Changed4 schema fields changed
    • addedOutput schema / properties / decisions
      Added value: +{
      +  "description": "What each decision word means, so a caller never has to guess. Read it before treating `allow` as approval or `abstain` as a clean result.",
      +  "type": "object"
      +}
    • addedOutput schema / properties / limits
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / policy
      Added value: +{
      +  "description": "The policy applied: its intent, its ceiling and the coverage floor below which it abstains.",
      +  "type": "object"
      +}
    • addedOutput schema / properties / proposal
      Added value: +{
      +  "description": "What you asked about, read back, so a typo is visible before you act on the answer.",
      +  "type": "object"
      +}
  10. Added

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint already declaring this is a safe read, the description goes well beyond: it defines all four outcome values, warns that `allow` is not a safety endorsement, explains that `abstain` is a gap rather than approval, and notes amount-dependence so the same address can differ by order size. That is exactly the decision-interpretation context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The usage trigger is front-loaded and the decision glossary is useful, but the prose is dense and backtick-heavy, with parenthetical asides and rhetorical framing ('inventing one would be worse than declining') that inflate length without adding callable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only evaluator with an output schema and 7 parameters, the description covers what it returns (four verdicts plus reasons/detail), how to read a failed rule, and the conservative-policy behavior on risk bands — nothing an agent needs to interpret a verdict is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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 real meaning: `amountUsd` omitted makes amount rules report as not-run rather than pass, and `requiredChecks` can only make the answer more conservative and unknown ids surface in `required.unknownIds`. Those behavioral consequences are not restated in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a concrete verb and resource — weigh one prospective action against a named policy and return a decision — and enumerates the four action types (pay, connect_mcp, call_tool, allocate_capital). This is clearly separable from sibling read tools like list_policies or check_action.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit trigger ('call this when you are about to DO something') and names the situations that qualify. It doesn't explicitly say when to prefer check_action or preflight_payment over this tool, so routing among the many sibling tools is left partly to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources