#!/usr/bin/env node
/**
* Agent Wallet MCP Server
*
* Gives Claude a Solana wallet to send USDC, check balances,
* and manage transactions on devnet.
*/
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from "@modelcontextprotocol/sdk/types.js";
import { AgentWallet } from "./wallet.js";
// Initialize wallet
const wallet = new AgentWallet();
// Define available tools
const TOOLS: Tool[] = [
{
name: "get_wallet_address",
description: "Get the agent's Solana wallet address. Use this to receive funds or share your address.",
inputSchema: {
type: "object",
properties: {},
required: [],
},
},
{
name: "get_balance",
description: "Check the USDC and SOL balance of the agent wallet. Returns balances on Solana devnet.",
inputSchema: {
type: "object",
properties: {},
required: [],
},
},
{
name: "send_usdc",
description: "Send USDC to another Solana address. This executes a real transaction on Solana devnet.",
inputSchema: {
type: "object",
properties: {
recipient: {
type: "string",
description: "The Solana address to send USDC to",
},
amount: {
type: "number",
description: "Amount of USDC to send (e.g., 5.00 for $5)",
},
memo: {
type: "string",
description: "Optional memo/note for the transaction",
},
},
required: ["recipient", "amount"],
},
},
{
name: "get_recent_transactions",
description: "Get recent transactions for the agent wallet.",
inputSchema: {
type: "object",
properties: {
limit: {
type: "number",
description: "Maximum number of transactions to return (default: 10)",
},
},
required: [],
},
},
{
name: "request_devnet_airdrop",
description: "Request free SOL on devnet for testing. Use this to get SOL for transaction fees.",
inputSchema: {
type: "object",
properties: {
amount: {
type: "number",
description: "Amount of SOL to request (max 2)",
},
},
required: [],
},
},
];
// Create MCP server
const server = new Server(
{
name: "agent-wallet-mcp",
version: "0.1.0",
},
{
capabilities: {
tools: {},
},
}
);
// Handle tool listing
server.setRequestHandler(ListToolsRequestSchema, async () => {
return { tools: TOOLS };
});
// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "get_wallet_address": {
const address = wallet.getAddress();
return {
content: [
{
type: "text",
text: JSON.stringify({
address,
network: "devnet",
explorer: `https://explorer.solana.com/address/${address}?cluster=devnet`,
}, null, 2),
},
],
};
}
case "get_balance": {
const balances = await wallet.getBalances();
return {
content: [
{
type: "text",
text: JSON.stringify(balances, null, 2),
},
],
};
}
case "send_usdc": {
const { recipient, amount, memo } = args as {
recipient: string;
amount: number;
memo?: string;
};
const result = await wallet.sendUsdc(recipient, amount, memo);
return {
content: [
{
type: "text",
text: JSON.stringify({
success: true,
...result,
explorer: `https://explorer.solana.com/tx/${result.signature}?cluster=devnet`,
}, null, 2),
},
],
};
}
case "get_recent_transactions": {
const { limit = 10 } = args as { limit?: number };
const transactions = await wallet.getRecentTransactions(limit);
return {
content: [
{
type: "text",
text: JSON.stringify(transactions, null, 2),
},
],
};
}
case "request_devnet_airdrop": {
const { amount = 1 } = args as { amount?: number };
const result = await wallet.requestAirdrop(Math.min(amount, 2));
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
return {
content: [
{
type: "text",
text: JSON.stringify({ error: message }, null, 2),
},
],
isError: true,
};
}
});
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Agent Wallet MCP server running on stdio");
}
main().catch(console.error);