Skip to content

Commit 2c96c31

Browse files
author
azeth-sync[bot]
committed
v0.2.23: sync from monorepo 2026-07-02
1 parent c6ad5ba commit 2c96c31

15 files changed

Lines changed: 1418 additions & 25 deletions

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@azeth/mcp-server",
3-
"version": "0.2.22",
3+
"version": "0.2.23",
44
"mcpName": "io.github.azeth-protocol/mcp-server",
55
"type": "module",
66
"description": "MCP server for the Azeth trust infrastructure — smart accounts, payments, reputation, and discovery tools for AI agents",
@@ -41,8 +41,8 @@
4141
"clean": "rm -rf dist"
4242
},
4343
"dependencies": {
44-
"@azeth/common": "^0.2.22",
45-
"@azeth/sdk": "^0.2.22",
44+
"@azeth/common": "^0.2.23",
45+
"@azeth/sdk": "^0.2.23",
4646
"@modelcontextprotocol/sdk": "^1.0.0",
4747
"dotenv": "^16.4.0",
4848
"viem": "^2.21.0",

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { registerPaymentTools } from './tools/payments.js';
77
import { registerAgreementTools } from './tools/agreements.js';
88
import { registerRegistryTools } from './tools/registry.js';
99
import { registerReputationTools } from './tools/reputation.js';
10+
import { registerCrosschainTools } from './tools/crosschain.js';
1011
import { registerMessagingTools } from './tools/messaging.js';
1112
import { registerGuardianTools } from './tools/guardian.js';
1213
import { registerGuardianApprovalTools } from './tools/guardian-approval.js';
@@ -38,6 +39,7 @@ function createServer(): McpServer {
3839
registerAgreementTools(rateLimitedServer);
3940
registerRegistryTools(rateLimitedServer);
4041
registerReputationTools(rateLimitedServer);
42+
registerCrosschainTools(rateLimitedServer);
4143
registerMessagingTools(rateLimitedServer);
4244
registerGuardianTools(rateLimitedServer);
4345
registerGuardianApprovalTools(rateLimitedServer);

src/tools/account.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ export function registerAccountTools(server: McpServer): void {
5555
'',
5656
'Returns: The deployed smart account address, trust registry token ID, and transaction hash.',
5757
'',
58-
'Gas is automatically sponsored — no ETH required. The SDK uses a gasless relay (EIP-712 signature)',
59-
'so the account can be created without any pre-funding. On testnet, USDC is also auto-funded.',
58+
'Gas: when the Azeth server relay is reachable, creation is sponsored (EIP-712 gasless relay —',
59+
'no ETH required, and testnet USDC is auto-dripped). When the relay is unreachable, creation',
60+
'FALLS BACK to a direct transaction paid by your EOA (requires ETH for gas). The response\'s',
61+
'"creationPath" field reports which path was used ("gasless-relay" or "direct").',
6062
'',
6163
'Guardian: By default, the guardian is derived from AZETH_GUARDIAN_KEY env var. If not set, falls back to self-guardian (owner address).',
6264
'For production, always use a separate guardian key. Set AZETH_GUARDIAN_KEY in your .env file.',
@@ -182,6 +184,12 @@ export function registerAccountTools(server: McpServer): void {
182184
account: result.account,
183185
tokenId: tokenIdStr,
184186
txHash: result.txHash,
187+
...(result.creationPath ? {
188+
creationPath: result.creationPath,
189+
...(result.creationPath === 'direct' ? {
190+
creationPathNote: 'The gasless relay was unreachable — creation was paid by your EOA as a direct transaction.',
191+
} : {}),
192+
} : {}),
185193
guardian: guardianAddress,
186194
guardianSource,
187195
emergencyWithdrawTo: emergencyAddress,
@@ -638,9 +646,10 @@ export function registerAccountTools(server: McpServer): void {
638646
'',
639647
'Returns: Transaction hash confirming the whitelist update.',
640648
'',
641-
'Note: Only the account owner can update their own whitelist. If a guardian is configured,',
642-
'whitelisting a token is a guardrail change that requires guardian co-signature — the call',
643-
'returns a GUARDIAN_COSIGN_REQUIRED error with guidance until the guardian signs.',
649+
'Note: Only the account owner can update their own whitelist. Whitelisting a token is a',
650+
'guardrail change that requires guardian co-signature. Self-guardian accounts (guardian ==',
651+
'owner) co-sign automatically; with a distinct guardian the call returns a',
652+
'GUARDIAN_COSIGN_REQUIRED error with guidance until the guardian signs.',
644653
'',
645654
'Example: { "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", "allowed": true }',
646655
].join('\n'),

src/tools/agreements.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { TOKENS, type SupportedChainName } from '@azeth/common';
66
import { PaymentAgreementModuleAbi } from '@azeth/common/abis';
77
import { createClient, resolveChain } from '../utils/client.js';
88
import { resolveAddress, resolveSmartAccount } from '../utils/resolve.js';
9-
import { success, error, handleError, formatUSD, guardianRequiredError } from '../utils/response.js';
9+
import { success, error, handleError, formatUSD, guardianRequiredError, safeIso } from '../utils/response.js';
1010

1111
// ──────────────────────────────────────────────
1212
// Shared formatting utilities
@@ -481,8 +481,6 @@ export function registerAgreementTools(server: McpServer): void {
481481
const chain = resolveChain(args.chain);
482482

483483
// Resolve to the caller's OWN smart account (not arbitrary addresses).
484-
// Only the payer can cancel their own agreements — resolveSmartAccount
485-
// restricts resolution to accounts owned by the caller's private key.
486484
let account: `0x${string}`;
487485
if (args.smartAccount) {
488486
try {
@@ -499,6 +497,19 @@ export function registerAgreementTools(server: McpServer): void {
499497
account = await client.resolveSmartAccount();
500498
}
501499

500+
// OWNERSHIP GATE: resolveSmartAccount passes raw addresses through unchecked,
501+
// so a foreign account address would reach the signing path and die with a
502+
// misleading guardian-co-signature error (the chain rejects it regardless —
503+
// this check exists for error quality, not security). Only the payer can cancel.
504+
const ownedAccounts = await client.getSmartAccounts();
505+
if (!ownedAccounts.some((a) => a.toLowerCase() === account.toLowerCase())) {
506+
return error(
507+
'UNAUTHORIZED',
508+
`Smart account ${account} is not owned by your key — only the payer (agreement creator) can cancel an agreement.`,
509+
'Use azeth_accounts to list your own accounts. To stop receiving payments as a payee, contact the payer or simply stop providing the service.',
510+
);
511+
}
512+
502513
const agreementId = BigInt(args.agreementId);
503514

504515
// Pre-flight: check agreement exists and is active
@@ -620,7 +631,7 @@ export function registerAgreementTools(server: McpServer): void {
620631
// schedules from creation), so lastExecuted is never 0n even before any execution.
621632
const lastExecutedAt = agreement.executionCount === 0n
622633
? null
623-
: new Date(Number(agreement.lastExecuted) * 1000).toISOString();
634+
: safeIso(agreement.lastExecuted);
624635

625636
let nextExecutionTime: string;
626637
let nextExecutionIn: string;
@@ -632,7 +643,9 @@ export function registerAgreementTools(server: McpServer): void {
632643
nextExecutionIn = `N/A (${status})`;
633644
isDue = false;
634645
} else {
635-
nextExecutionTime = new Date(Number(nextExecTime) * 1000).toISOString();
646+
// safeIso: read path of ON-CHAIN data — an agreement created by a non-MCP client
647+
// can hold a uint256 timestamp beyond the JS Date range; reporting must not throw.
648+
nextExecutionTime = safeIso(nextExecTime);
636649
const nowSecs = Math.floor(Date.now() / 1000);
637650
const diff = Number(nextExecTime) - nowSecs;
638651
if (diff <= 0) {
@@ -697,7 +710,7 @@ export function registerAgreementTools(server: McpServer): void {
697710
lastExecutedAt,
698711
nextExecutionTime,
699712
nextExecutionIn,
700-
expiresAt: agreement.endTime === 0n ? 'never' : new Date(Number(agreement.endTime) * 1000).toISOString(),
713+
expiresAt: agreement.endTime === 0n ? 'never' : safeIso(agreement.endTime),
701714
// Checks
702715
isDue,
703716
canExecute,

0 commit comments

Comments
 (0)