MCP server connecting Claude to Hedera DeFi with 36 tools for analytics and transactions.
Aetheros is a comprehensive Model Context Protocol (MCP) server that bridges the gap between AI assistants and the Hedera DeFi ecosystem. It transforms how users interact with decentralized finance by enabling natural language conversations with AI (like Claude) to query data, analyze opportunities, and prepare transactions across multiple DeFi platforms—all without requiring deep technical knowledge or compromising security.
Aetheros provides a single, standardized interface to interact with 5 major Hedera DeFi platforms, eliminating the need to understand each platform's unique API, smart contract interface, or data format:
SaucerSwap (19 tools): Hedera's leading decentralized exchange (DEX)
Bonzo Finance (3 tools): Lending and borrowing protocol
Stader Labs (3 tools): Liquid staking protocol
HeliSwap (1 tool): Alternative DEX
Hashport (10 tools): Cross-chain bridge
Total: 36 comprehensive tools covering every aspect of Hedera DeFi operations.
Aetheros solves the critical security vs. automation dilemma through an innovative two-mode system:
Example Output:
{
"type": "prepared_transaction",
"description": "Swap 10 HBAR for minimum 1,000,000 SAUCE tokens",
"from": "0.0.123456",
"to": "0x00000000000000000000000000000000002cc9B2",
"function": "multicall(bytes[])",
"gas": 400000,
"value": "1000000000",
"unsigned": {
"contractId": "0x00000000000000000000000000000000002cc9B2",
"functionName": "multicall",
"functionParams": ["0xc04b8d59000000..."],
"payableAmount": "1000000000"
}
}
EXECUTE_TX=true) and private keyAsk questions in plain English and get instant, formatted data:
Examples:
1.0247 (staking rewards accumulated)Instead of manually constructing complex smart contract calls, simply describe what you want:
User: "I want to swap 50 HBAR for SAUCE tokens"
Aetheros:
All ready for signing with your preferred wallet.
Hashport integration enables seamless asset bridging:
Hedera's DeFi ecosystem spans multiple protocols, each with:
Solution: Aetheros abstracts all complexity into simple, natural language commands. One interface, 36 tools, 5 platforms.
DeFi traders manually:
Solution: Ask Aetheros to monitor conditions, compare rates, or identify opportunities—all through conversation.
Existing automation tools require:
Solution: Prepare-only mode generates transactions without ever accessing private keys. Sign with your hardware wallet or secure environment.
Traditional DeFi tools lack AI capabilities:
Solution: Built on MCP, enabling Claude and other AI assistants to safely interact with Hedera DeFi using your natural language.
aetheros with 1-command installation# Install globally
npm install -g aetheros
# Or use directly with npx
npx aetheros
Claude Desktop Integration (claude_desktop_config.json):
{
"mcpServers": {
"hedera-defi": {
"command": "npx",
"args": ["-y", "aetheros"]
}
}
}
Then simply chat with Claude:
Aetheros democratizes DeFi by removing technical barriers. Whether you're a:
You can now leverage Hedera's fast, low-cost DeFi ecosystem through the power of AI assistance.
Aetheros is built using a modular client-based architecture where each DeFi platform has its own dedicated client class, all exposed through a unified MCP server interface. This design enables independent platform updates without breaking other integrations.
┌─────────────────────────────────────────────────────┐
│ MCP Server (src/index.ts) │
│ - Tool registration & schema validation │
│ - Request routing & response formatting │
└─────────────────────────────────────────────────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌────▼───┐ ┌────▼───┐ ┌────▼───┐
│SaucerSwap│ │ Bonzo │ │ Stader │ ...
│ Client │ │ Client │ │ Client │
└──────────┘ └────────┘ └────────┘
│ │ │
┌────▼───────┐ ┌───▼──────┐ ┌────▼────────┐
│ REST APIs │ │Smart │ │ @hashgraph/ │
│ + Contracts│ │Contracts │ │ sdk │
└────────────┘ └──────────┘ └─────────────┘
TypeScript 5.3+ (typescript@^5.3.0)
strict: true in tsconfig.jsonNode.js 18+
"type": "module" in package.json)dotenv@^16.3.1tsx (tsx@^4.6.0)
npm run dev@modelcontextprotocol/sdk (@modelcontextprotocol/sdk@^0.5.0)
Server class for MCP server initializationStdioServerTransport for stdio-based communication with Claude Desktopimport { Server, StdioServerTransport } from "@modelcontextprotocol/sdk/server/index.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "aetheros", version: "1.0.6" },
{ capabilities: { tools: {} } }
);
// Register 36 tools with schemas
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "saucerswap_get_tokens",
description: "Get all available tokens on SaucerSwap",
inputSchema: zodToJsonSchema(GetTokensSchema)
},
// ... 35 more tools
]
}));
Zod (zod@^3.22.0) + zod-to-json-schema (zod-to-json-schema@^3.24.6)
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
// Example: SaucerSwap swap schema
const SwapHbarForTokensSchema = z.object({
accountId: z.string().describe("Hedera account ID (0.0.xxxxx)"),
tokenOut: z.string().describe("Output token address"),
amountIn: z.string().describe("HBAR amount in tinybars"),
fee: z.number().describe("Pool fee tier (500, 3000, 10000)"),
slippage: z.number().min(0).max(100).default(0.5)
});
type SwapParams = z.infer<typeof SwapHbarForTokensSchema>;
@hashgraph/sdk (@hashgraph/sdk@^2.45.0)
Client for Hedera network connections (mainnet/testnet)AccountId for Hedera address handlingPrivateKey for transaction signing in execute modeContractExecuteTransaction for smart contract interactionsContractCallQuery for read-only contract queriesimport {
Client,
AccountId,
PrivateKey,
ContractExecuteTransaction,
ContractFunctionParameters
} from "@hashgraph/sdk";
// Initialize Hedera client
const client = Client.forMainnet();
client.setOperator(
AccountId.fromString(process.env.MAINNET_HEDERA_OPERATOR_ID!),
PrivateKey.fromString(process.env.MAINNET_HEDERA_OPERATOR_KEY!)
);
// Execute contract transaction
const tx = await new ContractExecuteTransaction()
.setContractId("0.0.2917554")
.setGas(400000)
.setFunction("stake", params)
.setPayableAmount(amountInHbar)
.execute(client);
Ethers.js v6 (ethers@^6.9.0)
Interface for ABI encoding/decodingsolidityPacked for parameter encodingContract class for type-safe contract callsimport { ethers } from "ethers";
// Encode SaucerSwap multicall
const routerInterface = new ethers.Interface([
"function multicall(bytes[] calldata data) external payable returns (bytes[] memory)",
"function exactInputSingle((address,address,uint24,address,uint256,uint256,uint256)) external payable returns (uint256)"
]);
const swapParams = {
tokenIn: WHBAR_ADDRESS,
tokenOut: tokenOutAddress,
fee: feeAmount,
recipient: evmAddress,
deadline: BigInt(Math.floor(Date.now() / 1000) + 300),
amountIn: BigInt(amountIn),
amountOutMinimum: BigInt(minAmountOut)
};
const encodedSwap = routerInterface.encodeFunctionData("exactInputSingle", [swapParams]);
Axios (axios@^1.6.0)
import axios from "axios";
// SaucerSwap API with authentication
const saucerswapApi = axios.create({
baseURL: "https://api.saucerswap.finance",
headers: {
"Authorization": `Bearer ${process.env.SAUCERSWAP_API_KEY}`,
"Content-Type": "application/json"
},
timeout: 30000
});
// Bonzo Finance API (public)
const bonzoApi = axios.create({
baseURL: "https://mainnet-api.bonzo.finance/api/v1",
timeout: 15000
});
src/clients/saucerswap.ts)Challenges:
API Rate Limiting: SaucerSwap's public API has strict rate limits
V1 vs V2 Pools: Different contract interfaces for Uniswap V2 and V3 style pools
Transaction Complexity: Swaps require multicall with WHBAR wrapping/unwrapping
Key Implementation:
export class SaucerSwapClient {
private apiKey?: string;
private client?: Client;
private routerAddress: string;
private quoterAddress: string;
// 19 methods for data queries and transaction preparation
async swapHbarForTokens(params: SwapParams) {
// 1. Convert Hedera account ID to EVM address
const evmAddress = this.accountIdToEvmAddress(params.accountId);
// 2. Encode exactInputSingle call
const swapCall = this.encodeSwapCall(params, evmAddress);
// 3. Encode refundETH call (for excess HBAR)
const refundCall = routerInterface.encodeFunctionData("refundETH");
// 4. Construct multicall
const multicallData = routerInterface.encodeFunctionData("multicall", [
[swapCall, refundCall]
]);
// 5. Return unsigned transaction
return {
type: "prepared_transaction",
contractId: this.routerAddress,
functionName: "multicall",
functionParams: multicallData,
gas: 400000,
payableAmount: params.amountIn
};
}
}
src/clients/stader.ts)Challenges:
Mainnet Only: Stader contracts only deployed on mainnet
Exchange Rate Precision: HBARX rate requires high-precision decimal handling
Key Implementation:
export class StaderClient {
private stakePoolAddress = "0.0.2917554";
async stakeHbar(accountId: string, amount: string) {
// Prepare ContractExecuteTransaction
const params = new ContractFunctionParameters()
.addUint256(BigInt(amount));
return {
type: "prepared_transaction",
description: `Stake ${amount} tinybars HBAR for HBARX`,
contractId: this.stakePoolAddress,
functionName: "stake",
functionParams: params,
gas: 300000,
payableAmount: amount
};
}
}
src/clients/bonzo.ts)Challenges:
Complex Reserve Data: Multiple nested objects with protocol-specific calculations
Health Factor Calculation: Liquidation logic requires precise decimal math
Key Implementation:
export class BonzoClient {
async getReserves() {
const response = await axios.get(
"https://mainnet-api.bonzo.finance/api/v1/reserves"
);
// Transform API response to user-friendly format
return response.data.map((reserve: any) => ({
symbol: reserve.symbol,
supplyAPY: (reserve.liquidityRate / 1e27 * 100).toFixed(2),
borrowAPY: (reserve.variableBorrowRate / 1e27 * 100).toFixed(2),
utilizationRate: (reserve.utilizationRate / 1e27 * 100).toFixed(2),
totalSupplied: (BigInt(reserve.totalLiquidity) / BigInt(10 ** reserve.decimals)).toString(),
availableLiquidity: (BigInt(reserve.availableLiquidity) / BigInt(10 ** reserve.decimals)).toString()
}));
}
}
src/clients/hashport.ts)Challenges:
Multi-Network Support: 7+ different blockchain networks
Asset ID Formats: Different formats across chains (ERC20 addresses vs Hedera token IDs)
Key Implementation:
export class HashportClient {
private baseUrl = "https://mainnet.hashport.network/api/v1";
async getSupportedAssets() {
const response = await axios.get(`${this.baseUrl}/assets`);
return response.data.map((asset: any) => ({
symbol: asset.symbol,
name: asset.name,
networks: asset.supportedNetworks.map((net: any) => ({
networkId: net.networkId,
networkName: net.networkName,
assetId: net.assetId,
isNative: net.isNative
}))
}));
}
async getBridgeSteps(sourceNetwork: string, targetNetwork: string, assetId: string) {
// Query bridge contract for step-by-step instructions
// Includes: approvals, lock/burn, mint/unlock steps
}
}
const EXECUTE_TX = process.env.EXECUTE_TX === "true";
const network = process.env.HEDERA_NETWORK || "mainnet";
// Only load private key if execute mode enabled
let operatorKey: PrivateKey | undefined;
if (EXECUTE_TX) {
const keyEnvVar = network === "mainnet"
? "MAINNET_HEDERA_OPERATOR_KEY"
: "TESTNET_HEDERA_OPERATOR_KEY";
operatorKey = PrivateKey.fromString(process.env[keyEnvVar]!);
}
async function handleTransactionTool(params: any) {
const unsignedTx = await prepareTransaction(params);
if (!EXECUTE_TX) {
// Return unsigned transaction for external signing
return {
type: "prepared_transaction",
...unsignedTx,
instructions: "Sign this transaction with your wallet or dApp"
};
}
// Execute mode: sign and submit
const tx = buildTransaction(unsignedTx);
const signedTx = await tx.sign(operatorKey!);
const receipt = await signedTx.execute(client);
return {
type: "executed_transaction",
transactionId: receipt.transactionId.toString(),
status: receipt.status.toString()
};
}
{
"scripts": {
"dev": "tsx src/index.ts", // Hot reload development
"build": "tsc", // Compile TypeScript to dist/
"start": "node dist/index.js", // Run production build
"watch": "tsx watch src/index.ts", // Watch mode
"prepublishOnly": "npm run build" // Auto-build before publish
}
}
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true, // Generate .d.ts files
"declarationMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
{
"name": "aetheros",
"version": "1.0.6",
"type": "module",
"main": "dist/index.js",
"bin": {
"aetheros": "dist/index.js" // CLI command
},
"files": [
"dist/**/*", // Include compiled files
"README.md",
"LICENSE",
".env.example"
],
"engines": {
"node": ">=18.0.0" // Require Node 18+
}
}
Hedera uses account IDs (0.0.xxxxx) but smart contracts need EVM addresses (0x...). We convert by:
function accountIdToEvmAddress(accountId: string): string {
const parts = accountId.split('.');
const num = parseInt(parts[2]);
// Hedera's EVM address: 0x0000000000000000000000000000000000{accountNum in hex}
return '0x' + num.toString(16).padStart(40, '0');
}
SaucerSwap swaps require multiple steps (swap + refund). We encode them into a single multicall:
function buildMulticallSwap(params: SwapParams) {
const calls: string[] = [];
// 1. Wrap HBAR to WHBAR (if needed)
if (params.tokenIn === HBAR) {
calls.push(encodeWrapHbar(params.amountIn));
}
// 2. Execute swap
calls.push(encodeExactInputSingle(params));
// 3. Unwrap WHBAR back to HBAR (if output is HBAR)
if (params.tokenOut === HBAR) {
calls.push(encodeUnwrapWHBAR(params.amountOut));
}
// 4. Refund excess HBAR
calls.push(routerInterface.encodeFunctionData("refundETH"));
return routerInterface.encodeFunctionData("multicall", [calls]);
}
SaucerSwap API requires authentication, but we still work without it:
async getTokens() {
try {
if (this.apiKey) {
// Use authenticated endpoint (more reliable)
return await this.authenticatedApi.get('/tokens');
}
} catch (error) {
console.warn("Authenticated API failed, falling back to public endpoint");
}
// Fallback to public endpoint (rate limited)
return await this.publicApi.get('/tokens');
}
JavaScript's JSON.stringify() doesn't support BigInt, causing errors. We patch it:
// Monkey patch BigInt serialization
(BigInt.prototype as any).toJSON = function() {
return this.toString();
};
Test Coverage: 36/36 tools tested (100% success rate)
Testing Methodology:
Results: See TEST_RESULTS.md for comprehensive results including:
Immediate:
Advanced:
Long-term:

