#
tokens: 8624/50000 8/8 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── claude_desktop_config.json
├── glama.json
├── LICENSE
├── package.json
├── pnpm-lock.yaml
├── README.md
├── scripts
│   └── install.sh
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

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

```
1 | .env
2 | node_modules
3 | build
4 | .DS_Store
```

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

```markdown
  1 | # Solana Agent Kit MCP Server
  2 | 
  3 | [![npm version](https://badge.fury.io/js/solana-mcp.svg)](https://www.npmjs.com/package/solana-mcp)
  4 | [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
  5 | <a href="https://cloud.phala.network/features/mcp-hosting/solana-mcp-by-sendai-and-dark" target="_blank" rel="noopener noreferrer" style="display:inline-flex;align-items:center;text-decoration:none;background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:2px 8px;font-size:16px;font-family:sans-serif;">
  6 |   <img src="https://raw.githubusercontent.com/Phala-Network/mcp-hosting/refs/heads/main/assets/logs/phala.png" alt="Phala Logo" height="24" style="vertical-align:middle;margin-right:8px;"/>
  7 |   <span style="color:#222;font-weight:600;">Check on Phala</span>
  8 | </a>
  9 | 
 10 | A Model Context Protocol (MCP) server that provides onchain tools for Claude AI, allowing it to interact with the Solana blockchain through a standardized interface. This implementation is based on the Solana Agent Kit and enables AI agents to perform blockchain operations seamlessly.
 11 | 
 12 | 
 13 | 
 14 | 
 15 | ## Overview
 16 | 
 17 | This MCP server extends Claude's capabilities by providing tools to:
 18 | 
 19 | * Interact with Solana blockchain
 20 | * Execute transactions
 21 | * Query account information
 22 | * Manage Solana wallets
 23 | 
 24 | The server implements the Model Context Protocol specification to standardize blockchain interactions for AI agents.
 25 | 
 26 | ## Prerequisites
 27 | 
 28 | * Node.js (v16 or higher)
 29 | * pnpm (recommended), npm, or yarn
 30 | * Solana wallet with private key
 31 | * Solana RPC URL (mainnet, testnet, or devnet)
 32 | 
 33 | ## Installation
 34 | 
 35 | ### Option 1: Quick Install (Recommended)
 36 | 
 37 | ```bash
 38 | # Download the installation script
 39 | curl -fsSL https://raw.githubusercontent.com/sendaifun/solana-mcp/main/scripts/install.sh -o solana-mcp-install.sh
 40 | 
 41 | # Make it executable and run
 42 | chmod +x solana-mcp-install.sh && ./solana-mcp-install.sh --backup
 43 | ```
 44 | 
 45 | This will start an interactive installation process that will guide you through:
 46 | - Setting up Node.js if needed
 47 | - Configuring your Solana RPC URL and private key
 48 | - Setting up the Claude Desktop integration
 49 | 
 50 | ### Option 2: Install from npm ( recommend for clients like Cursor/Cline)
 51 | 
 52 | ```bash
 53 | # Install globally
 54 | npm install -g solana-mcp
 55 | 
 56 | # Or install locally in your project
 57 | npm install solana-mcp
 58 | ```
 59 | 
 60 | ### Option 3: Build from Source
 61 | 
 62 | 1. Clone this repository:
 63 | ```bash
 64 | git clone https://github.com/sendaifun/solana-mcp
 65 | cd solana-mcp
 66 | ```
 67 | 
 68 | 2. Install dependencies:
 69 | ```bash
 70 | pnpm install
 71 | ```
 72 | 
 73 | 3. Build the project:
 74 | ```bash
 75 | pnpm run build
 76 | ```
 77 | 
 78 | ## Configuration
 79 | 
 80 | ### Environment Setup
 81 | 
 82 | Create a `.env` file with your credentials:
 83 | 
 84 | ```env
 85 | # Solana Configuration
 86 | SOLANA_PRIVATE_KEY=your_private_key_here
 87 | RPC_URL=your_solana_rpc_url_here
 88 | OPENAI_API_KEY=your_openai_api_key # OPTIONAL
 89 | ```
 90 | 
 91 | ### Integration with Claude Desktop
 92 | 
 93 | To add this MCP server to Claude Desktop, follow these steps:
 94 | 
 95 | 1. **Locate the Claude Desktop Configuration File**
 96 |    - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
 97 |    - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
 98 |    - Linux: `~/.config/Claude/claude_desktop_config.json`
 99 | 
100 | 2. **Add the Configuration**
101 |    Create or edit the configuration file and add the following JSON:
102 | 
103 |    If you installed via npm (Option 1):
104 |    ```json
105 |    {
106 |      "mcpServers": {
107 |        "solana-mcp": {
108 |          "command": "npx",
109 |          "args": ["solana-mcp"],
110 |          "env": {
111 |            "RPC_URL": "your_solana_rpc_url_here",
112 |            "SOLANA_PRIVATE_KEY": "your_private_key_here",
113 |            "OPENAI_API_KEY": "your_openai_api_key"  // OPTIONAL
114 |          },
115 |          "disabled": false,
116 |          "autoApprove": []
117 |        }
118 |      }
119 |    }
120 |    ```
121 | 
122 |    If you built from source (Option 2):
123 |    ```json
124 |    {
125 |      "mcpServers": {
126 |        "solana-mcp": {
127 |          "command": "node",
128 |          "args": ["/path/to/solana-mcp/build/index.js"],
129 |          "env": {
130 |            "RPC_URL": "your_solana_rpc_url_here",
131 |            "SOLANA_PRIVATE_KEY": "your_private_key_here",
132 |            "OPENAI_API_KEY": "your_openai_api_key"  // OPTIONAL
133 |          },
134 |          "disabled": false,
135 |          "autoApprove": []
136 |        }
137 |      }
138 |    }
139 |    ```
140 | 
141 | 3. **Restart Claude Desktop**
142 |    After making these changes, restart Claude Desktop for the configuration to take effect.
143 | 
144 | ## Project Structure
145 | 
146 | ```
147 | solana-agent-kit-mcp/
148 | ├── src/
149 | │   ├── index.ts          # Main entry point
150 | ├── package.json
151 | └── tsconfig.json
152 | ```
153 | 
154 | ## Available Tools
155 | 
156 | The MCP server provides the following Solana blockchain tools:
157 | 
158 | * `GET_ASSET` - Retrieve information about a Solana asset/token
159 | * `DEPLOY_TOKEN` - Deploy a new token on Solana
160 | * `GET_PRICE` - Fetch price information for tokens
161 | * `WALLET_ADDRESS` - Get the wallet address
162 | * `BALANCE` - Check wallet balance
163 | * `TRANSFER` - Transfer tokens between wallets
164 | * `MINT_NFT` - Create and mint new NFTs
165 | * `TRADE` - Execute token trades
166 | * `REQUEST_FUNDS` - Request funds (useful for testing/development)
167 | * `RESOLVE_DOMAIN` - Resolve Solana domain names
168 | * `GET_TPS` - Get current transactions per second on Solana
169 | 
170 | ## Security Considerations
171 | 
172 | * Keep your private key secure and never share it
173 | * Use environment variables for sensitive information
174 | * Consider using a dedicated wallet for AI agent operations
175 | * Regularly monitor and audit AI agent activities
176 | * Test operations on devnet/testnet before mainnet
177 | 
178 | ## Troubleshooting
179 | 
180 | If you encounter issues:
181 | 
182 | 1. Verify your Solana private key is correct
183 | 2. Check your RPC URL is accessible
184 | 3. Ensure you're on the intended network (mainnet, testnet, or devnet)
185 | 4. Check Claude Desktop logs for error messages
186 | 5. Verify the build was successful
187 | 
188 | ## Dependencies
189 | 
190 | Key dependencies include:
191 | * [@solana/web3.js](https://github.com/solana-labs/solana-web3.js)
192 | * [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk)
193 | * [solana-agent-kit](https://github.com/sendaifun/solana-agent-kit)
194 | 
195 | ## Contributing
196 | 
197 | Contributions are welcome! Please feel free to submit a Pull Request.
198 | 
199 | 1. Fork the repository
200 | 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
201 | 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
202 | 4. Push to the branch (`git push origin feature/amazing-feature`)
203 | 5. Open a Pull Request
204 | 
205 | ## License
206 | 
207 | This project is licensed under the MIT License.
208 | 
```

--------------------------------------------------------------------------------
/glama.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |     "$schema": "https://glama.ai/mcp/schemas/server.json",
3 |     "maintainers": [
4 |       "thearyanag"
5 |     ]
6 |   }
```

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

```json
 1 | {
 2 |     "compilerOptions": {
 3 |       "target": "ES2022",
 4 |       "module": "Node16",
 5 |       "moduleResolution": "Node16",
 6 |       "outDir": "./build",
 7 |       "rootDir": "./src",
 8 |       "strict": true,
 9 |       "esModuleInterop": true,
10 |       "skipLibCheck": true,
11 |       "forceConsistentCasingInFileNames": true
12 |     },
13 |     "include": ["src/**/*"],
14 |     "exclude": ["node_modules"]
15 |   }
```

--------------------------------------------------------------------------------
/claude_desktop_config.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |     "mcpServers": {
 3 |         "agent-kit": {
 4 |             "command": "node",
 5 |             "env" : {
 6 |                 "OPENAI_API_KEY": "optional_openai_api_key_here",
 7 |                 "RPC_URL": "your_rpc_url_here",
 8 |                 "SOLANA_PRIVATE_KEY": "your_private_key_here"
 9 |             },
10 |             "args": [
11 |                 "/absolute/path/to/build/index.js"
12 |             ]
13 |         }
14 |     }
15 | }
16 | 
17 | 
```

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

```json
 1 | {
 2 |   "name": "solana-mcp",
 3 |   "version": "1.0.0",
 4 |   "description": "A Model Context Protocol server for interacting with the Solana blockchain, powered by the Solana Agent Kit (https://github.com/sendaifun/solana-agent-kit)",
 5 |   "main": "build/index.js",
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "solana-mcp": "./build/index.js"
 9 |   },
10 |   "scripts": {
11 |     "build": "tsc",
12 |     "start": "node build/index.js",
13 |     "dev": "tsx watch src/index.ts"
14 |   },
15 |   "files": [
16 |     "build"
17 |   ],
18 |   "repository": {
19 |     "type": "git",
20 |     "url": "https://github.com/sendaifun/solana-mcp"
21 |   },
22 |   "keywords": [
23 |     "solana",
24 |     "mcp",
25 |     "solana-agent-kit",
26 |     "solana-mcp"
27 |   ],
28 |   "author": "sendaifun",
29 |   "license": "MIT",
30 |   "dependencies": {
31 |     "@modelcontextprotocol/sdk": "^1.11.4",
32 |     "@solana-agent-kit/adapter-mcp": "^2.0.4",
33 |     "@solana-agent-kit/plugin-god-mode": "^0.0.1",
34 |     "@solana/web3.js": "^1.98.2",
35 |     "bs58": "^6.0.0",
36 |     "cors": "^2.8.5",
37 |     "dotenv": "^16.4.7",
38 |     "express": "^5.1.0",
39 |     "solana-agent-kit": "2.0.4"
40 |   },
41 |   "devDependencies": {
42 |     "@types/cors": "^2.8.17",
43 |     "@types/express": "^5.0.1",
44 |     "@types/node": "^22.13.4",
45 |     "tsx": "^4.19.4",
46 |     "typescript": "^5.7.3"
47 |   },
48 |   "packageManager": "[email protected]"
49 | }
50 | 
```

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

```typescript
  1 | // #!/usr/bin/env node
  2 | 
  3 | import { SolanaAgentKit, KeypairWallet, type Action } from "solana-agent-kit";
  4 | import { startMcpServer, createMcpServer } from "@solana-agent-kit/adapter-mcp";
  5 | import GodModePlugin from "@solana-agent-kit/plugin-god-mode";
  6 | import * as dotenv from "dotenv";
  7 | import { Keypair } from "@solana/web3.js";
  8 | import bs58 from "bs58";
  9 | import express, { type Request, type Response } from "express";
 10 | import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
 11 | import cors from "cors";
 12 | 
 13 | dotenv.config();
 14 | 
 15 | // Validate required environment variables
 16 | function validateEnvironment() {
 17 |   const requiredEnvVars = {
 18 |     SOLANA_PRIVATE_KEY: process.env.SOLANA_PRIVATE_KEY,
 19 |     RPC_URL: process.env.RPC_URL,
 20 |   };
 21 | 
 22 |   const missingVars = Object.entries(requiredEnvVars)
 23 |     .filter(([_, value]) => !value)
 24 |     .map(([key]) => key);
 25 | 
 26 |   if (missingVars.length > 0) {
 27 |     throw new Error(
 28 |       `Missing required environment variables: ${missingVars.join(", ")}`
 29 |     );
 30 |   }
 31 | }
 32 | 
 33 | // New function to start MCP server with SSE support
 34 | async function startMcpServerWithSse(
 35 |   actions: Record<string, any>,
 36 |   agent: SolanaAgentKit,
 37 |   options: {
 38 |     name: string;
 39 |     version: string;
 40 |   },
 41 |   port: number = 3000
 42 | ) {
 43 |   const app = express();
 44 |   app.use(cors());
 45 |   // Store active transport instances
 46 |   const transports: { [sessionId: string]: SSEServerTransport } = {};
 47 | 
 48 |   // SSE endpoint for client connections
 49 |   app.get("/sse", async (_req: Request, res: Response) => {
 50 |     console.log("Received connection on /sse");
 51 |     const transport = new SSEServerTransport("/messages", res);
 52 | 
 53 |     // Store the transport for this session
 54 |     transports[transport.sessionId] = transport;
 55 | 
 56 |     res.on("close", () => {
 57 |       console.log(`Connection closed for session ${transport.sessionId}`);
 58 |       delete transports[transport.sessionId];
 59 |     });
 60 | 
 61 |     // Create the server and connect it to this transport
 62 |     const server = createMcpServer(actions, agent, options);
 63 |     await server.connect(transport);
 64 |   });
 65 | 
 66 |   // Message endpoint for client-to-server communication
 67 |   app.post("/messages", async (req: Request, res: Response) => {
 68 |     const sessionId = req.query.sessionId as string;
 69 |     console.log(`Received message for session ${sessionId}`);
 70 | 
 71 |     const transport = transports[sessionId];
 72 |     if (transport) {
 73 |       await transport.handlePostMessage(req, res);
 74 |     } else {
 75 |       res.status(400).send("No transport found for sessionId");
 76 |     }
 77 |   });
 78 | 
 79 |   // Start the Express server
 80 |   app.listen(port, () => {
 81 |     console.log(`MCP SSE server listening on port ${port}`);
 82 |   });
 83 | 
 84 |   return app;
 85 | }
 86 | 
 87 | async function main() {
 88 |   try {
 89 |     // Validate environment before proceeding
 90 |     validateEnvironment();
 91 | 
 92 |     // Initialize the agent with error handling
 93 |     const decodedPrivateKey = bs58.decode(
 94 |       process.env.SOLANA_PRIVATE_KEY as string
 95 |     );
 96 |     const keypair = Keypair.fromSecretKey(decodedPrivateKey);
 97 |     const keypairWallet = new KeypairWallet(
 98 |       keypair,
 99 |       process.env.RPC_URL as string
100 |     );
101 | 
102 |     const agent = new SolanaAgentKit(keypairWallet, keypairWallet.rpcUrl, {})
103 |       .use(GodModePlugin);
104 | 
105 |     const mcp_actions: Record<string, Action> = {};
106 | 
107 |     for (const action of agent.actions) {
108 |       mcp_actions[action.name] = action;
109 |     }
110 | 
111 |     const serverOptions = {
112 |       name: "sendai-agent",
113 |       version: "0.0.1",
114 |     };
115 | 
116 |     // Check if PORT environment variable exists to determine whether to use SSE
117 |     if (process.env.PORT) {
118 |       const port = Number.parseInt(process.env.PORT, 10);
119 |       console.log(`Starting MCP server with SSE on port ${port}`);
120 |       await startMcpServerWithSse(mcp_actions, agent, serverOptions, port);
121 |     } else {
122 |       // Start the MCP server with stdio transport (original behavior)
123 |       console.log("Starting MCP server with stdio transport");
124 |       await startMcpServer(mcp_actions, agent, serverOptions);
125 |     }
126 |   } catch (error) {
127 |     console.error(
128 |       "Failed to start MCP server:",
129 |       error instanceof Error ? error.message : String(error)
130 |     );
131 |     process.exit(1);
132 |   }
133 | }
134 | 
135 | main();
136 | 
```

--------------------------------------------------------------------------------
/scripts/install.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash
  2 | 
  3 | # Colors for output
  4 | RED='\033[0;31m'
  5 | GREEN='\033[0;32m'
  6 | YELLOW='\033[1;33m'
  7 | BLUE='\033[0;34m'
  8 | NC='\033[0m' # No Color
  9 | 
 10 | # ASCII Art Banner
 11 | echo -e "${BLUE}"
 12 | cat << "EOF"
 13 |  ____        _                     __  __  ____ ____  
 14 | / ___|  ___ | | __ _ _ __   __ _ |  \/  |/ ___|  _ \ 
 15 | \___ \ / _ \| |/ _` | '_ \ / _` || |\/| | |   | |_) |
 16 |  ___) | (_) | | (_| | | | | (_| || |  | | |__|  __/ 
 17 | |____/ \___/|_|\__,_|_| |_|\__,_||_|  |_|\____|_|    
 18 |                                                       
 19 | EOF
 20 | echo -e "${NC}"
 21 | 
 22 | # Function to display help
 23 | show_help() {
 24 |     echo -e "${BLUE}Solana MCP Server Installation Script${NC}"
 25 |     echo -e "This script helps you set up the Solana MCP server for Claude Desktop.\n"
 26 |     echo -e "The script will:"
 27 |     echo -e "  1. Check and install Node.js if needed"
 28 |     echo -e "  2. Install solana-mcp globally"
 29 |     echo -e "  3. Configure Claude Desktop settings\n"
 30 |     echo -e "Requirements:"
 31 |     echo -e "  - Internet connection"
 32 |     echo -e "  - Admin privileges (for some installations)"
 33 |     echo -e "  - Solana RPC URL"
 34 |     echo -e "  - Solana private key\n"
 35 |     echo -e "Options:"
 36 |     echo -e "  -h, --help     Show this help message"
 37 |     echo -e "  -b, --backup   Backup existing configuration before modifying"
 38 |     echo -e "  -y, --yes      Non-interactive mode (skip confirmations)\n"
 39 | }
 40 | 
 41 | # Function to validate Solana RPC URL
 42 | validate_rpc_url() {
 43 |     local url=$1
 44 |     if [[ ! $url =~ ^https?:// ]]; then
 45 |         echo -e "${RED}Error: Invalid RPC URL format. URL should start with http:// or https://${NC}"
 46 |         return 1
 47 |     fi
 48 |     return 0
 49 | }
 50 | 
 51 | # Function to validate Solana private key
 52 | validate_private_key() {
 53 |     local key=$1
 54 |     local key_length=${#key}
 55 |     echo -e "${YELLOW}Debug: Key length is $key_length characters${NC}"
 56 |     echo -e "${YELLOW}Debug: Key value: '$key'${NC}"
 57 |     if [[ ! $key =~ ^[0-9a-zA-Z]+$ ]]; then
 58 |         echo -e "${RED}Error: Invalid private key format. Should contain only alphanumeric characters${NC}"
 59 |         return 1
 60 |     fi
 61 |     return 0
 62 | }
 63 | 
 64 | # Function to backup config
 65 | backup_config() {
 66 |     local config_file=$1
 67 |     if [ -f "$config_file" ]; then
 68 |         local backup_file="${config_file}.backup.$(date +%Y%m%d_%H%M%S)"
 69 |         cp "$config_file" "$backup_file"
 70 |         echo -e "${GREEN}Backup created: ${YELLOW}$backup_file${NC}"
 71 |     fi
 72 | }
 73 | 
 74 | # Parse command line arguments
 75 | BACKUP=false
 76 | NON_INTERACTIVE=false
 77 | 
 78 | while [[ "$#" -gt 0 ]]; do
 79 |     case $1 in
 80 |         -h|--help) show_help; exit 0 ;;
 81 |         -b|--backup) BACKUP=true ;;
 82 |         -y|--yes) NON_INTERACTIVE=true ;;
 83 |         *) echo -e "${RED}Unknown parameter: $1${NC}"; show_help; exit 1 ;;
 84 |     esac
 85 |     shift
 86 | done
 87 | 
 88 | # Function to check if a command exists
 89 | command_exists() {
 90 |     command -v "$1" >/dev/null 2>&1
 91 | }
 92 | 
 93 | # Function to get OS type
 94 | get_os_type() {
 95 |     case "$(uname -s)" in
 96 |         Darwin*)    echo "macos";;
 97 |         Linux*)     echo "linux";;
 98 |         MINGW*|CYGWIN*|MSYS*) echo "windows";;
 99 |         *)          echo "unknown";;
100 |     esac
101 | }
102 | 
103 | # Function to install Node.js and npm on macOS
104 | install_node_macos() {
105 |     echo -e "${YELLOW}Installing Node.js and npm using Homebrew...${NC}"
106 |     if ! command_exists brew; then
107 |         echo -e "${YELLOW}Installing Homebrew first...${NC}"
108 |         /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
109 |     fi
110 |     brew install node
111 | }
112 | 
113 | # Function to install Node.js and npm on Linux
114 | install_node_linux() {
115 |     echo -e "${YELLOW}Installing Node.js and npm using package manager...${NC}"
116 |     if command_exists apt-get; then
117 |         # Debian/Ubuntu
118 |         curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
119 |         sudo apt-get install -y nodejs
120 |     elif command_exists dnf; then
121 |         # Fedora
122 |         sudo dnf install -y nodejs npm
123 |     elif command_exists yum; then
124 |         # CentOS/RHEL
125 |         curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash -
126 |         sudo yum install -y nodejs
127 |     elif command_exists pacman; then
128 |         # Arch Linux
129 |         sudo pacman -S nodejs npm
130 |     else
131 |         echo -e "${RED}Unsupported Linux distribution. Please install Node.js manually.${NC}"
132 |         exit 1
133 |     fi
134 | }
135 | 
136 | # Function to install Node.js and npm on Windows
137 | install_node_windows() {
138 |     echo -e "${YELLOW}Installing Node.js and npm using winget...${NC}"
139 |     if command_exists winget; then
140 |         winget install -e --id OpenJS.NodeJS
141 |     else
142 |         echo -e "${RED}Please install Node.js manually from https://nodejs.org/${NC}"
143 |         exit 1
144 |     fi
145 | }
146 | 
147 | # Function to install Node.js based on OS
148 | install_node() {
149 |     local os_type=$1
150 |     case "$os_type" in
151 |         "macos")
152 |             install_node_macos
153 |             ;;
154 |         "linux")
155 |             install_node_linux
156 |             ;;
157 |         "windows")
158 |             install_node_windows
159 |             ;;
160 |         *)
161 |             echo -e "${RED}Unsupported operating system${NC}"
162 |             exit 1
163 |             ;;
164 |     esac
165 | }
166 | 
167 | # Function to get Claude config path based on OS
168 | get_claude_config_path() {
169 |     local os_type=$1
170 |     case "$os_type" in
171 |         "macos")
172 |             echo "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
173 |             ;;
174 |         "linux")
175 |             echo "$HOME/.config/Claude/claude_desktop_config.json"
176 |             ;;
177 |         "windows")
178 |             echo "%APPDATA%\\Claude\\claude_desktop_config.json"
179 |             ;;
180 |         *)
181 |             echo ""
182 |             ;;
183 |     esac
184 | }
185 | 
186 | # Function to merge JSON configurations
187 | merge_config() {
188 |     local config_file=$1
189 |     local temp_file=$(mktemp)
190 |     
191 |     # Check if jq is installed
192 |     if ! command_exists jq; then
193 |         echo -e "${YELLOW}Installing jq for JSON processing...${NC}"
194 |         case "$OS_TYPE" in
195 |             "macos")
196 |                 brew install jq
197 |                 ;;
198 |             "linux")
199 |                 if command_exists apt-get; then
200 |                     sudo apt-get install -y jq
201 |                 elif command_exists dnf; then
202 |                     sudo dnf install -y jq
203 |                 elif command_exists yum; then
204 |                     sudo yum install -y jq
205 |                 elif command_exists pacman; then
206 |                     sudo pacman -S jq
207 |                 fi
208 |                 ;;
209 |             "windows")
210 |                 echo -e "${RED}Please install jq manually${NC}"
211 |                 exit 1
212 |                 ;;
213 |         esac
214 |     fi
215 | 
216 |     # Create new MCP config
217 |     local mcp_config="{
218 |       \"command\": \"npx\",
219 |       \"args\": [\"solana-mcp\"],
220 |       \"env\": {
221 |         \"RPC_URL\": \"$RPC_URL\",
222 |         \"SOLANA_PRIVATE_KEY\": \"$SOLANA_PRIVATE_KEY\""
223 | 
224 |     if [ ! -z "$OPENAI_API_KEY" ]; then
225 |         mcp_config="$mcp_config,
226 |         \"OPENAI_API_KEY\": \"$OPENAI_API_KEY\""
227 |     fi
228 | 
229 |     mcp_config="$mcp_config
230 |       },
231 |       \"disabled\": false,
232 |       \"autoApprove\": []
233 |     }"
234 | 
235 |     if [ -f "$config_file" ]; then
236 |         # File exists, merge configurations
237 |         jq --arg mcp "$mcp_config" '.mcpServers."solana-mcp" = ($mcp | fromjson)' "$config_file" > "$temp_file"
238 |     else
239 |         # Create new config file
240 |         echo "{
241 |   \"mcpServers\": {
242 |     \"solana-mcp\": $mcp_config
243 |   }
244 | }" > "$temp_file"
245 |     fi
246 | 
247 |     # Move temp file to config location
248 |     mv "$temp_file" "$config_file"
249 |     chmod 644 "$config_file"
250 | }
251 | 
252 | echo -e "${BLUE}Welcome to Solana MCP Server Installation Script${NC}"
253 | echo -e "${YELLOW}This script will help you set up the Solana MCP server for Claude Desktop${NC}"
254 | echo "----------------------------------------"
255 | 
256 | if [ "$NON_INTERACTIVE" = false ]; then
257 |     read -p "Would you like to proceed with the installation? (y/N) " confirm
258 |     if [[ ! $confirm =~ ^[Yy]$ ]]; then
259 |         echo -e "${YELLOW}Installation cancelled by user${NC}"
260 |         exit 0
261 |     fi
262 | fi
263 | 
264 | # Check OS type
265 | OS_TYPE=$(get_os_type)
266 | echo -e "\n${BLUE}System Information:${NC}"
267 | echo -e "Operating System: ${YELLOW}$OS_TYPE${NC}"
268 | 
269 | # Check for Node.js and install if not present
270 | if ! command_exists node; then
271 |     echo -e "\n${YELLOW}Node.js is not installed. Installing now...${NC}"
272 |     if [ "$NON_INTERACTIVE" = false ]; then
273 |         read -p "Would you like to install Node.js? (Y/n) " confirm
274 |         if [[ ! $confirm =~ ^[Nn]$ ]]; then
275 |             install_node "$OS_TYPE"
276 |         else
277 |             echo -e "${RED}Node.js is required for this installation. Exiting.${NC}"
278 |             exit 1
279 |         fi
280 |     else
281 |         install_node "$OS_TYPE"
282 |     fi
283 |     
284 |     # Verify installation
285 |     if ! command_exists node; then
286 |         echo -e "${RED}Node.js installation failed. Please install manually from https://nodejs.org/${NC}"
287 |         exit 1
288 |     fi
289 | fi
290 | 
291 | NODE_VERSION=$(node -v)
292 | echo -e "Node.js version: ${GREEN}$NODE_VERSION${NC}"
293 | 
294 | # Check for npm and install if not present
295 | if ! command_exists npm; then
296 |     echo -e "${YELLOW}npm is not installed. Installing now...${NC}"
297 |     # npm usually comes with Node.js, but if not:
298 |     case "$OS_TYPE" in
299 |         "linux")
300 |             sudo apt-get install -y npm || sudo dnf install -y npm || sudo yum install -y npm || sudo pacman -S npm
301 |             ;;
302 |         *)
303 |             echo -e "${RED}npm installation failed. Please install manually${NC}"
304 |             exit 1
305 |             ;;
306 |     esac
307 |     
308 |     # Verify installation
309 |     if ! command_exists npm; then
310 |         echo -e "${RED}npm installation failed. Please install manually${NC}"
311 |         exit 1
312 |     fi
313 | fi
314 | 
315 | NPM_VERSION=$(npm -v)
316 | echo -e "npm version: ${GREEN}$NPM_VERSION${NC}"
317 | 
318 | # Check if solana-mcp is already installed globally
319 | if npm list -g solana-mcp > /dev/null 2>&1; then
320 |     SOLANA_MCP_VERSION=$(npm list -g solana-mcp | grep solana-mcp | cut -d@ -f2)
321 |     echo -e "\nsolana-mcp is already installed globally (version: ${GREEN}$SOLANA_MCP_VERSION${NC})"
322 |     if [ "$NON_INTERACTIVE" = false ]; then
323 |         read -p "Would you like to reinstall/update solana-mcp? (y/N) " confirm
324 |         if [[ $confirm =~ ^[Yy]$ ]]; then
325 |             echo -e "\n${YELLOW}Updating solana-mcp globally...${NC}"
326 |             npm install -g solana-mcp@latest
327 |         fi
328 |     fi
329 | else
330 |     echo -e "\n${YELLOW}Installing solana-mcp globally...${NC}"
331 |     npm install -g solana-mcp
332 | fi
333 | 
334 | # Get Claude config path
335 | CONFIG_PATH=$(get_claude_config_path "$OS_TYPE")
336 | if [ -z "$CONFIG_PATH" ]; then
337 |     echo -e "${RED}Unsupported operating system${NC}"
338 |     exit 1
339 | fi
340 | 
341 | # Backup existing config if requested
342 | if [ "$BACKUP" = true ] && [ -f "$CONFIG_PATH" ]; then
343 |     backup_config "$CONFIG_PATH"
344 | fi
345 | 
346 | # Collect required information with validation
347 | echo -e "\n${BLUE}Configuration Setup:${NC}"
348 | echo -e "${YELLOW}Please provide the following information:${NC}"
349 | 
350 | while true; do
351 |     read -p "Enter your Solana RPC URL: " RPC_URL
352 |     if validate_rpc_url "$RPC_URL"; then
353 |         break
354 |     fi
355 | done
356 | 
357 | while true; do
358 |     read -p "Enter your Solana private key: " SOLANA_PRIVATE_KEY
359 |     if validate_private_key "$SOLANA_PRIVATE_KEY"; then
360 |         break
361 |     fi
362 | done
363 | 
364 | read -p "Enter your OpenAI API key (optional, press Enter to skip): " OPENAI_API_KEY
365 | 
366 | # Create directory if it doesn't exist
367 | CONFIG_DIR=$(dirname "$CONFIG_PATH")
368 | mkdir -p "$CONFIG_DIR"
369 | 
370 | # Merge or create configuration
371 | echo -e "\n${YELLOW}Updating Claude configuration...${NC}"
372 | merge_config "$CONFIG_PATH"
373 | 
374 | echo -e "\n${GREEN}Installation completed successfully!${NC}"
375 | echo -e "Configuration file has been updated at: ${YELLOW}$CONFIG_PATH${NC}"
376 | echo -e "\n${BLUE}Next steps:${NC}"
377 | echo -e "1. Restart Claude Desktop for the changes to take effect"
378 | echo -e "2. Test the Solana MCP server functionality"
379 | echo -e "3. If you encounter any issues, check the logs in Claude Desktop\n"
380 | 
381 | if [ "$BACKUP" = true ]; then
382 |     echo -e "${YELLOW}Note: A backup of your previous configuration was created${NC}"
383 | fi 
```