#
tokens: 2988/50000 5/5 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
node_modules/
dist/
*.log
.env*
PRIVATE_README.md
vscode
.vscode

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# Free USDC Transfer MCP Server

An MCP server implementation enabling free USDC transfers on **[Base](https://base.org)** with **[Coinbase CDP](https://docs.cdp.coinbase.com/)** MPC Wallet integration.

<img width="1374" alt="image" src="https://github.com/user-attachments/assets/3a58a720-8489-4f02-9075-19c8f264e3cc" />

## Features

- Free USDC Transfers: Send USDC to any address or ENS/BaseName domain on Base - no fees, just simple transfers
- Coinbase MPC Wallet: Create and manage your Coinbase MPC wallet for secure, feeless transactions
- Name Resolution: Automatic support for **ENS** and **BaseName** domains

## Functions

### `tranfer-usdc`
- Description: Analyze the value of the purchased items and transfer USDC to the recipient via the Base chain. Due to the uncertainty of blockchain transaction times, the transaction is only scheduled here and will not wait for the transaction to be completed.
- Inputs:
    - usdc_amount (number): USDC amount, greater than 0.
    - recipient (string): Recipient's on-chain address or ENS domain (e.g., example.eth).
- Behavior:
    - Verifies the recipient's address or resolves ENS domains.
    - Schedules a USDC transfer on the Base chain.
    - Provides a link to view transaction details on BaseScan.

### `create_coinbase_mpc_wallet`
- Description: Create a Coinbase MPC wallet address.
- Behavior:
    - Creates a new Coinbase MPC wallet and saves the seed to a secure file.
    - If a wallet already exists, returns the existing wallet address.
    - The seed file for Coinbase MPC wallets is stored in the Documents directory under the file name mpc_info.json.

## Configuration

### Getting an API Key
1. Sign up for a [Coinbase CDP account](https://portal.cdp.coinbase.com/)
2. Generate your API key from the developer dashboard

### Usage with Claude Desktop

1. Add this to your `claude_desktop_config.json`:
```json
{
  "mcpServers": {
    "free-usdc-transfer": {
      "command": "npx",
      "args": [
        "-y",
        "@magnetai/free-usdc-transfer"
      ],
      "env": {
        "COINBASE_CDP_API_KEY_NAME": "YOUR_COINBASE_CDP_API_KEY_NAME",
        "COINBASE_CDP_PRIVATE_KEY": "YOUR_COINBASE_CDP_PRIVATE_KEY"
      }
    }
  }
}
```

2. Or install the server with **[magnet-desktop](https://github.com/magnetai/magnet-desktop)**

## License

This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.

---

Crafted by [Magnet Labs](https://magnetlabs.xyz) with our vibrant AI & Crypto community

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
    "compilerOptions": {
        "target": "ES2022",
        "module": "Node16",
        "moduleResolution": "Node16",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules",
        "dist"
    ]
}

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@magnetai/free-usdc-transfer",
  "version": "0.1.5",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc && node -e \"require('fs').chmodSync('dist/index.js', '755')\""
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@coinbase/coinbase-sdk": "^0.13.0",
    "@ensdomains/ensjs": "^4.0.2",
    "@modelcontextprotocol/sdk": "^1.1.0",
    "@types/global-agent": "^2.1.3",
    "ethers": "^6.13.5",
    "global-agent": "^3.0.0",
    "zod": "^3.24.1"
  },
  "devDependencies": {
    "@types/node": "^22.10.5",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.3"
  },
  "type": "module",
  "bin": {
    "free-usdc-transfer": "dist/index.js"
  },
  "files": [
    "dist"
  ]
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
    CallToolRequestSchema,
    ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import * as fs from 'fs/promises';
import { http } from 'viem'
import { mainnet } from 'viem/chains'
import { createEnsPublicClient } from '@ensdomains/ensjs'
import { Coinbase, Wallet } from "@coinbase/coinbase-sdk";
import { ethers } from "ethers";

// import { bootstrap } from 'global-agent';
// process.env.GLOBAL_AGENT_HTTP_PROXY = 'http://127.0.0.1:10080';
// process.env.GLOBAL_AGENT_HTTPS_PROXY = 'http://127.0.0.1:10080';
// process.env.GLOBAL_AGENT_NO_PROXY = 'localhost,127.0.0.1';
// bootstrap();

// Base scan
const BASE_SCAN_ADDR = "https://basescan.org/address/"

// Check for API key
const COINBASE_CDP_API_KEY_NAME = process.env.COINBASE_CDP_API_KEY_NAME!;
if (!COINBASE_CDP_API_KEY_NAME) {
    console.error("Error: COINBASE_CDP_API_KEY_NAME environment variable is required");
    process.exit(1);
}
const COINBASE_CDP_PRIVATE_KEY = process.env.COINBASE_CDP_PRIVATE_KEY!;
if (!COINBASE_CDP_PRIVATE_KEY) {
    console.error("Error: COINBASE_CDP_SECRET environment variable is required");
    process.exit(1);
}
Coinbase.configure({ apiKeyName: COINBASE_CDP_API_KEY_NAME, privateKey: COINBASE_CDP_PRIVATE_KEY });

// Store
import os from 'os';
import path from 'path';
const homeDir = os.homedir();
const documentsDir = path.join(homeDir, 'Documents');
const seedFilePath = path.join(documentsDir, "mpc_info.json");

// Create server instance
const server = new Server(
    {
        name: "free-usdc-transfer",
        version: "0.1.3",
    },
    {
        capabilities: {
            tools: {},
        },
    }
);

// Define Zod schemas for validation
const BstsArgumentsSchema = z.object({
    usdc_amount: z.number().gt(0),
    recipient: z.string()
});

// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
    return {
        tools: [
            {
                name: "tranfer-usdc",
                description: "Analyze the value of the purchased items and transfer USDC to the recipient via the Base chain. Due to the uncertainty of blockchain transaction times, the transaction is only scheduled here and will not wait for the transaction to be completed.",
                inputSchema: {
                    type: "object",
                    properties: {
                        usdc_amount: {
                            type: "number",
                            description: "USDC amount, greater than 0",
                        },
                        recipient: {
                            type: "string",
                            description: "Recipient's on-chain address or ENS addresses ending in .eth",
                        }
                    },
                    required: ["usdc_amount", "recipient"],
                },
            },
            {
                name: "create_coinbase_mpc_wallet",
                description: "Used to create your Coinbase MPC wallet address. The newly created wallet cannot be used directly; the user must first deposit USDC. The transfer after creation requires user confirmation",
                inputSchema: {
                    type: "object"
                },
            }
        ],
    };
});

// Create the client
const client = createEnsPublicClient({
    chain: mainnet,
    transport: http(),
})

// ENS
async function getAddress(recipient: string) {
    if (recipient.toLowerCase().endsWith('.eth')) {
        return (await client.getAddressRecord({ name: recipient }))?.value
    }
    if (!recipient || recipient.length != 42) {
        return undefined
    }
    return recipient;
};

async function createMPCWallet() {
    let wallet = await Wallet.create({ networkId: "base-mainnet" });
    wallet.saveSeedToFile(seedFilePath);
    return (await wallet.getDefaultAddress()).getId();
}

async function sendUSDCUseMPCWallet(walletId: string, recipientAddr: string, amount: number) {
    const wallet = await Wallet.fetch(walletId)
    await wallet.loadSeedFromFile(seedFilePath)
    const defaultAddress = await wallet.getDefaultAddress()

    await defaultAddress.createTransfer({
        amount: amount,
        assetId: Coinbase.assets.Usdc,
        destination: ethers.getAddress(recipientAddr),
        gasless: true
    })

    return defaultAddress.getId()
}

async function queryMpcWallet() {
    try {
        const jsonString = await fs.readFile(seedFilePath, 'utf8')
        const ids = Object.keys(JSON.parse(jsonString))
        if (!ids || ids.length === 0) {
            return { mpcAddress: "", mpcId: "" }
        }
        const wallet = await Wallet.fetch(ids[0])
        await wallet.loadSeedFromFile(seedFilePath)
        return { mpcAddress: (await wallet.getDefaultAddress()).getId(), mpcId: ids[0] }
    } catch (err) {
        console.error(`${err}`)
        return { mpcAddress: "", mpcId: "" }
    }
}

async function queryMpcWalletId() {
    try {
        const jsonString = await fs.readFile(seedFilePath, 'utf8')
        const ids = Object.keys(JSON.parse(jsonString))
        if (!ids || ids.length === 0) {
            return ""
        }
        return ids[0]
    } catch (err) {
        console.error(`${err}`)
        return ""
    }
}

// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const { name, arguments: args } = request.params;
    try {
        if (name === "tranfer-usdc") {
            const { usdc_amount, recipient } = BstsArgumentsSchema.parse(args);
            const mpcId= await queryMpcWalletId();
            if (!mpcId) {
                return {
                    content: [
                        {
                            type: "text",
                            text: "You haven't created a Coinbase MPC wallet yet",
                        },
                    ],
                };
            }
            const recipientAddr = await getAddress(recipient)
            if (!recipientAddr) {
                return {
                    content: [
                        {
                            type: "text",
                            text: 'Invalid address or ENS',
                        },
                    ]
                }
            }
            const addr= await sendUSDCUseMPCWallet(mpcId, recipientAddr, usdc_amount)
            const linkAddr = BASE_SCAN_ADDR + addr + "#tokentxns"
            return {
                content: [
                    {
                        type: "text",
                        text: `The transaction (sending ${usdc_amount} USDC to ${recipientAddr}) has been scheduled on the Base chain. You can view the details via the link: ${linkAddr}`,
                    },
                ],
            };
        } else if (name === "create_coinbase_mpc_wallet") {
            const { mpcAddress } = await queryMpcWallet();
            if (!mpcAddress) {
                const newMpcAddress = await createMPCWallet()
                return {
                    content: [
                        {
                            type: "text",
                            text: `Your Coinbase MPC wallet address has been successfully created (${newMpcAddress}). Now please transfer USDC to MPC wallet, and you can later use it to transfer funds to others without fees.`,
                        },
                    ],
                };
            }
            return {
                content: [
                    {
                        type: "text",
                        text: `You already have an address, which is ${mpcAddress}`,
                    },
                ],
            };
        }
        else {
            throw new Error(`Unknown tool: ${name}`);
        }
    } catch (error) {
        if (error instanceof z.ZodError) {
            throw new Error(
                `Invalid arguments: ${error.errors
                    .map((e) => `${e.path.join(".")}: ${e.message}`)
                    .join(", ")}`
            );
        }
        throw error;
    }
});

// Start the server
async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
    console.error("Free USDC transfer MCP Server running on stdio");
}

main().catch((error) => {
    console.error("Fatal error in main():", error);
    process.exit(1);
});

```