Skip to content

Commit 554ac8c

Browse files
committed
feat: enhance prompt content and structure for token transfers, transaction diagnosis, and wallet analysis
1 parent 796245b commit 554ac8c

1 file changed

Lines changed: 41 additions & 22 deletions

File tree

src/core/tools.ts

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { z } from "zod";
33
import { getSupportedNetworks, getRpcUrl } from "./chains.js";
44
import * as services from "./services/index.js";
55
import { type Address, type Hex, type Hash } from 'viem';
6-
import { normalize } from 'viem/ens';
76
import { privateKeyToAccount } from 'viem/accounts';
7+
import { normalize } from 'viem/ens';
88

99
/**
1010
* Register all EVM-related tools with the MCP server
@@ -19,13 +19,26 @@ import { privateKeyToAccount } from 'viem/accounts';
1919
* @param server The MCP server instance
2020
*/
2121
export function registerEVMTools(server: McpServer) {
22-
// Helper to get the configured wallet from environment
23-
const getConfiguredWallet = () => {
22+
// Helper to get the configured private key from environment
23+
const getConfiguredPrivateKey = (): Hex => {
2424
const privateKey = process.env.EVM_PRIVATE_KEY;
2525
if (!privateKey) {
2626
throw new Error("EVM_PRIVATE_KEY environment variable is not set. Configure it to enable write operations.");
2727
}
28-
return privateKeyToAccount(privateKey as Hex);
28+
// Ensure 0x prefix
29+
return (privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`) as Hex;
30+
};
31+
32+
// Helper to get wallet address from private key
33+
const getWalletAddressFromKey = (): Address => {
34+
const privateKey = getConfiguredPrivateKey();
35+
const account = privateKeyToAccount(privateKey);
36+
return account.address;
37+
};
38+
39+
// Helper to get configured wallet object
40+
const getConfiguredWallet = (): { address: Address } => {
41+
return { address: getWalletAddressFromKey() };
2942
};
3043

3144
// ============================================================================
@@ -47,12 +60,12 @@ export function registerEVMTools(server: McpServer) {
4760
},
4861
async () => {
4962
try {
50-
const wallet = getConfiguredWallet();
63+
const address = getWalletAddressFromKey();
5164
return {
5265
content: [{
5366
type: "text",
5467
text: JSON.stringify({
55-
address: wallet.address,
68+
address,
5669
message: "This is the wallet that will be used for all transactions"
5770
}, null, 2)
5871
}]
@@ -606,10 +619,10 @@ export function registerEVMTools(server: McpServer) {
606619
server.registerTool(
607620
"get_contract_abi",
608621
{
609-
description: "Fetch a contract's ABI from a block explorer (Etherscan, Polygonscan, etc.). Requires ETHERSCAN_API_KEY environment variable.",
622+
description: "Fetch a contract's full ABI from Etherscan/block explorers. Use this to understand verified contracts before interacting. Requires ETHERSCAN_API_KEY. Supports 30+ EVM networks. Works best with verified contracts on block explorers.",
610623
inputSchema: {
611624
contractAddress: z.string().describe("The contract address (0x...)"),
612-
network: z.string().optional().describe("Network name. Defaults to Ethereum mainnet. Supported: ethereum, polygon, arbitrum, optimism, base, avalanche, etc.")
625+
network: z.string().optional().describe("Network name or chain ID. Defaults to ethereum. Supported: ethereum, polygon, arbitrum, optimism, base, avalanche, gnosis, fantom, bsc, celo, scroll, linea, zksync, manta, blast, and testnets (sepolia, mumbai, arbitrum-sepolia, optimism-sepolia, base-sepolia, avalanche-fuji)")
613626
},
614627
annotations: {
615628
title: "Get Contract ABI",
@@ -650,12 +663,12 @@ export function registerEVMTools(server: McpServer) {
650663
server.registerTool(
651664
"read_contract",
652665
{
653-
description: "Read data from a smart contract (read-only call). Can auto-fetch verified contract ABIs or use common function signatures.",
666+
description: "Call read-only functions on a smart contract. Automatically fetches ABI from block explorer if not provided (requires ETHERSCAN_API_KEY). Falls back to common functions if contract is not verified. Use this to query contract state and data.",
654667
inputSchema: {
655668
contractAddress: z.string().describe("The contract address"),
656-
functionName: z.string().describe("Function name (e.g., 'name', 'symbol', 'balanceOf', 'totalSupply')"),
657-
args: z.array(z.string()).optional().describe("Function arguments as strings"),
658-
abiJson: z.string().optional().describe("Full contract ABI as JSON string (optional - will try to auto-fetch if not provided)"),
669+
functionName: z.string().describe("Function name (e.g., 'name', 'symbol', 'balanceOf', 'totalSupply', 'owner')"),
670+
args: z.array(z.string()).optional().describe("Function arguments as strings (e.g., ['0xAddress'] for balanceOf)"),
671+
abiJson: z.string().optional().describe("Full contract ABI as JSON string (optional - will auto-fetch verified contract ABI if not provided)"),
659672
network: z.string().optional().describe("Network name or chain ID. Defaults to Ethereum mainnet.")
660673
},
661674
annotations: {
@@ -775,14 +788,15 @@ export function registerEVMTools(server: McpServer) {
775788
},
776789
async ({ to, amount, network = "ethereum" }) => {
777790
try {
778-
const wallet = getConfiguredWallet();
779-
const txHash = await services.transferETH(wallet, to as Address, amount, network);
791+
const privateKey = getConfiguredPrivateKey();
792+
const senderAddress = getWalletAddressFromKey();
793+
const txHash = await services.transferETH(privateKey, to as Address, amount, network);
780794
return {
781795
content: [{
782796
type: "text",
783797
text: JSON.stringify({
784798
network,
785-
from: wallet.address,
799+
from: senderAddress,
786800
to,
787801
amount,
788802
txHash,
@@ -819,18 +833,21 @@ export function registerEVMTools(server: McpServer) {
819833
},
820834
async ({ tokenAddress, to, amount, network = "ethereum" }) => {
821835
try {
822-
const wallet = getConfiguredWallet();
823-
const txHash = await services.transferERC20(wallet, tokenAddress as Address, to as Address, amount, network);
836+
const privateKey = getConfiguredPrivateKey();
837+
const senderAddress = getWalletAddressFromKey();
838+
const result = await services.transferERC20(tokenAddress as Address, to as Address, amount, privateKey, network);
824839
return {
825840
content: [{
826841
type: "text",
827842
text: JSON.stringify({
828843
network,
829844
tokenAddress,
830-
from: wallet.address,
845+
from: senderAddress,
831846
to,
832-
amount,
833-
txHash,
847+
amount: result.amount.formatted,
848+
symbol: result.token.symbol,
849+
decimals: result.token.decimals,
850+
txHash: result.txHash,
834851
message: "Transaction sent. Use get_transaction_receipt to check confirmation."
835852
}, null, 2)
836853
}]
@@ -864,14 +881,16 @@ export function registerEVMTools(server: McpServer) {
864881
},
865882
async ({ tokenAddress, spenderAddress, amount, network = "ethereum" }) => {
866883
try {
867-
const wallet = getConfiguredWallet();
868-
const txHash = await services.approveERC20(wallet, tokenAddress as Address, spenderAddress as Address, amount, network);
884+
const privateKey = getConfiguredPrivateKey();
885+
const senderAddress = getWalletAddressFromKey();
886+
const txHash = await services.approveERC20(privateKey, tokenAddress as Address, spenderAddress as Address, amount, network);
869887
return {
870888
content: [{
871889
type: "text",
872890
text: JSON.stringify({
873891
network,
874892
tokenAddress,
893+
owner: senderAddress,
875894
spender: spenderAddress,
876895
approvalAmount: amount,
877896
txHash,

0 commit comments

Comments
 (0)