Per-card MCP server for spending card management and payments. Provides tools for card status, USDC payments, contract execution, sub-card issuance, and fiat payments via Visa. Stateless architecture with per-request card-scoped tool lists and typed refusals.
GlassPay MCP server demonstrates solid tool design with clear naming, comprehensive descriptions, and well-structured schemas. All 10 tools have verb-noun names (card, pay, execute, etc.) and descriptions ranging 100-280 chars. Input schemas are present and typed with Zod validation. Tool annotations (destructiveHint/readOnlyHint) are correctly applied. Key strengths: idempotency support (pay tool), typed refusal errors, and clear capability scoping per card. Weaknesses: output schemas are not explicitly documented in the code; error handling relies on structured JSON but lacks recovery guidance in descriptions; some parameter descriptions could be more prescriptive about constraints (e.g., address format validation is in schema but not emphasized in description text).
Your spending card's terms and live state: remaining budget this period, lifetime remaining, expiry, recent charges, sub-cards. Call this first to learn what you can spend.
Reveal the linked test Visa card details. Only available on fiat-linked cards.
Call an allowlisted contract within the card's contract terms. The contract must be in the card's scope and the call must respect all caveats (per-call limits, allowlists, etc.).
Buy over Visa rails (simulated, test mode) from the same budget. Only available on fiat-linked cards.
Mint a narrower child card for a sub-agent and return its connection URL (treat it as a secret). The sub-card inherits the parent's caveats and can be further restricted.
Fetch an HTTP resource and pay its 402 Payment Required challenge automatically using this card.
Output schemas not documented in code. While input schemas are well-defined with Zod, return types are not explicitly declared. LLMs cannot plan downstream tool calls without knowing what fields to expect (e.g., does card() return remaining_budget as string or number?).
Error recovery guidance missing from descriptions. Tools return typed refusals (over_period_limit, merchant_not_allowed) but descriptions do not explain what the LLM should do when refused (e.g., 'If refused with over_period_limit, check card() for remaining budget and retry with a smaller amount').
Parameter constraints not emphasized in descriptions. The 'to' parameter in pay() has a regex pattern (^0x[0-9a-fA-F]{40}$) in schema but description only says 'recipient address', LLMs may not parse the pattern and could pass invalid formats.
Inferred effective spec: 2026-07-28+.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | A | 81 | 2026-07-28+ | v2 |
Send USDC on Base to a recipient address, within this card's limits. Blocks until the payment confirms on-chain (seconds). Refusals are typed (over_period_limit, merchant_not_allowed, ...) — relay them honestly to your user. Use idempotency_key to make retries safe.
Kill a child card and its descendants instantly. The card becomes frozen and all pending operations are cancelled.
Purchase a product from the Stripe catalog using the linked Visa card.
List the Stripe product catalog available for purchase.
execute() function signature parameter is underspecified. Description says 'function signature, e.g. transfer(address,uint256)' but does not clarify whether this is a selector, ABI string, or canonical form. The code uses canonicalSelector() internally but this is not exposed to the LLM.
issue_subcard() 'terms' parameter lacks structure documentation. Accepts an object but does not specify required fields, valid keys, or constraints. LLMs cannot construct valid terms without examples or a schema reference.