cotiv2-mcp
Version:
> A plug-and-play MCP tool server to **send COTI**, **transfer BEP-20 tokens**, **deploy tokens**, and **interact with smart contracts** on the **COTI v2 Network (COTI)** ā built for **Claude Desktop**, **AI agents**, and **developers.**
110 lines (109 loc) ⢠3.74 kB
JavaScript
import prompts from "prompts";
import figlet from "figlet";
import chalk from "chalk";
import path from "path";
import fs from "fs-extra";
import { encryptPrivateKey } from "./PrivateAES.js";
import dotenv from "dotenv";
import { privateKeyToAccount } from "viem/accounts";
import { blue } from "./config.js";
import { configureStorage } from "./lib/storage.js";
import { configureClaude } from "./lib/claude.js";
import { fileURLToPath } from "url";
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Cancel handler
const onCancel = () => {
console.log(chalk.red("\nā Configuration cancelled by user (Ctrl+C or ESC). Exiting..."));
process.exit(0);
};
// Show Banner
const showBanner = () => {
const banner = figlet.textSync("COTI v2 Network MCP ", { font: "Big" });
console.log(blue(banner));
console.log(blue("š Welcome to the COTI v2 Network MCP Configurator\n"));
};
// Ask for credentials
const getInputs = async () => {
const questions = [
{
type: "password",
name: "walletPassword",
message: "š Enter your Wallet Password (must be exactly 8 characters):",
validate: (val) => {
if (val.trim() === "")
return "Wallet Password is required!";
if (val.length !== 8)
return "Wallet Password must be exactly 8 characters!";
return true;
},
},
{
type: "password",
name: "privateKey",
message: "š Enter your Wallet Private Key:",
validate: (val) => val.trim() === "" ? "Private key is required!" : true,
},
];
return (await prompts(questions, { onCancel }));
};
// Generate .env file
const generateEnvFile = async (privateKey, address) => {
const envContent = `
WALLET_PRIVATE_KEY=${privateKey}
WALLET_ADDRESS=${address}
`.trim();
await fs.writeFile(".env", envContent);
console.log(blue("ā
.env file generated."));
};
// Generate config object
const generateConfig = async (privateKey, address) => {
return {
WALLET_PRIVATE_KEY: privateKey,
WALLET_ADDRESS: address,
};
};
// Save fallback config file
const saveFallbackConfig = async (config) => {
await fs.writeJSON("config.json", config, { spaces: 2 });
console.log(blue("š Saved config.json in root project folder."));
};
// Generate config object
const generateClaudeConfig = async () => {
const indexPath = path.resolve(__dirname, "..", "build", "index.js"); // one level up from cli/
return {
"coti-mcp": {
command: "node",
args: [indexPath],
disabled: false,
autoApprove: [],
},
};
};
// Main logic
const init = async () => {
showBanner();
const { privateKey, walletPassword } = await getInputs();
const _0xPrivateKey = privateKey.startsWith("0x")
? privateKey
: `0x${privateKey}`;
const account = privateKeyToAccount(_0xPrivateKey);
const privateKeyEncrypt = await encryptPrivateKey(_0xPrivateKey, walletPassword);
await generateEnvFile(privateKeyEncrypt, account.address);
const config = await generateConfig(privateKeyEncrypt, account.address);
const success = await configureStorage(config);
if (!success) {
await saveFallbackConfig(config);
}
const { setupClaude } = await prompts({
type: "confirm",
name: "setupClaude",
message: "š§ Do you want to configure in Claude Desktop?",
initial: true,
}, { onCancel });
if (setupClaude) {
await configureClaude(await generateClaudeConfig());
}
};
init();