MCP server + TypeScript SDK that lets any AI agent spend from a Eunomia treasury on Stellar — inside an owner-set on-chain budget, blocked by the contract when out of policy, with x402 payment requirements and owner-approved exceptions.
eunomia-mcp demonstrates solid tool design with clear, domain-specific naming (check_budget, pay, request_exception) and comprehensive descriptions (avg 180 chars, well above 34-char baseline). All 6 tools have input schemas with typed parameters and descriptions. However, output schemas are not documented in the source code provided, and parameter descriptions lack explicit format constraints (e.g., 'Amount in the treasury's token (7 decimals)' is stated but not formalized as a regex or pattern). Error handling is present (errorReporting=true) but recovery guidance is minimal. Tool composition is excellent, each tool has a single responsibility and output from one (e.g., check_payee returning is_payee) chains naturally into others (pay). No security issues detected; no credentials exposed as parameters.
What this agent may spend from its Eunomia treasury right now: per-payment cap, rolling 24h limit, Leash session cap and expiry, pause state, free balance — all in the treasury's token, named in `unit` (e.g. "USDC"). Pass `amount` (e.g. "2.5") to pre-flight a specific payment and get the contract's rejection reasons before paying.
Status of an exception request: pending (waiting for owner approval), approved (ready to retry the payment), or closed (expired or used up). Pass the exception ID returned by request_exception.
Exact on-chain answer to "will the treasury pay this address?" (is_payee). Use it before paying anyone not returned by list_allowed_payees.
Addresses this treasury will pay: the owner-approved whitelist (each address re-verified on-chain) plus the reputation gate if one is set. Anything not allowed is refused by the contract, not by this server.
Spend from the treasury: sign and submit a payment transaction. The agent's Leash key signs it. Returns the transaction hash, ledger, and whether it paid or was refused by the contract (with reasons). Payments are atomic: either the full amount reaches the payee or nothing does.
Output schemas not documented. Tools return results but the response structure (fields, types, pagination) is not visible in source. LLMs cannot plan downstream calls or extract chaining IDs without documented output.
Parameter format constraints not formalized. 'Amount in the treasury's token (7 decimals)' is stated in description but not enforced via regex pattern or JSON Schema format. LLMs may pass invalid amounts.
Error recovery guidance minimal. Tools report errors (errorReporting=true) but descriptions lack 'what to do next' guidance. E.g., if pay() fails due to insufficient budget, should the agent call check_budget() first?
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 68 | 2025-06-18+ | v2 |
Ask the owner to approve a payment that the policy refused. The agent signs the request with its Leash key; the owner approves it in the dashboard. Once approved, the agent can retry the payment and it will go through (until the exception expires). Returns the exception ID and a link to the dashboard.
No dry-run or confirmation step for irreversible pay() operation. Agents can invoke pay() directly without a pre-flight confirmation, risking accidental treasury depletion.
Stellar address format not validated in descriptions. 'Stellar G… or C… address' is informal; should specify regex pattern (e.g., '^G[A-Z0-9]{55}$|^C[A-Z0-9]{55}$') so LLMs and validators know exact format.