1111 CARGO_TERM_COLOR : always
1212 RUST_BACKTRACE : full
1313 NODE_VERSION : ' 18'
14- # Note: The inspector package name is different in your example. Adjust as needed.
15- INSPECTOR_PACKAGE :
' @open-svm/[email protected] ' 16- MCP_HOST : ' 127.0.0.1'
17- MCP_PORT : 31902
14+ # Use the official MCP Inspector package
15+ INSPECTOR_PACKAGE :
' @modelcontextprotocol/[email protected] ' 1816
1917jobs :
2018 mcp-inspector-test :
4240 - name : Build solana-mcp-server
4341 run : cargo build --release
4442
45- - name : Install MCP Inspector CLI and Zod
43+ - name : Install MCP Inspector and Zod
4644 run : |
4745 npm install -g ${{ env.INSPECTOR_PACKAGE }}
4846 npm install zod
@@ -52,82 +50,126 @@ jobs:
5250 mkdir -p test-config
5351 cat <<EOF > test-config/mcp-config.json
5452 {
55- "network": "devnet",
56- "rpc_url": "https://api.devnet.solana.com",
57- "mcp_port": ${{ env.MCP_PORT }},
58- "mcp_host": "${{ env.MCP_HOST }}",
59- "mcp_token": ""
53+ "mcpServers": {
54+ "solana": {
55+ "command": "./target/release/solana-mcp-server",
56+ "args": ["stdio"],
57+ "env": {
58+ "SOLANA_RPC_URL": "https://api.devnet.solana.com",
59+ "SOLANA_COMMITMENT": "confirmed",
60+ "RUST_LOG": "debug"
61+ }
62+ }
63+ }
6064 }
6165 EOF
6266
63- - name : Start Server and Wait for it to be Ready
67+ - name : Test MCP Protocol Communication
6468 run : |
65- echo "Starting server in the background..."
66- ./target/release/solana-mcp-server --config test-config/mcp-config.json > server.log 2>&1 &
69+ echo "Testing MCP protocol communication with Solana server..."
6770
68- echo "Waiting for server to become available..."
69- timeout=120
70- for i in $(seq 1 $timeout); do
71- if mcp-inspector ping --host ${{ env.MCP_HOST }} --port ${{ env.MCP_PORT }}; then
72- echo "✅ Server is up and running!"
73- exit 0
74- fi
75- echo "Still waiting for server... (${i}s)"
76- sleep 1
77- done
71+ # Test the server directly using Node.js to verify MCP protocol
72+ node <<'EOF'
73+ const { spawn } = require('child_process');
74+ const readline = require('readline');
7875
79- echo "❌ Server did not start within $timeout seconds."
80- echo "--- Server Log ---"
81- cat server.log
82- exit 1
83-
84- - name : Run Inspector CLI Tests and Validate Schema
85- run : |
86- echo "--- Testing 'initialize' method ---"
87- mcp-inspector call --host ${{ env.MCP_HOST }} --port ${{ env.MCP_PORT }} --method "initialize" --params '{}' --json > initialize_response.json
88- cat initialize_response.json
76+ // Start the server
77+ const server = spawn('./target/release/solana-mcp-server', ['stdio'], {
78+ env: {
79+ ...process.env,
80+ SOLANA_RPC_URL: 'https://api.devnet.solana.com',
81+ SOLANA_COMMITMENT: 'confirmed',
82+ RUST_LOG: 'debug'
83+ }
84+ });
8985
90- echo "--- Testing 'tools/list' method ---"
91- mcp-inspector call --host ${{ env.MCP_HOST }} --port ${{ env.MCP_PORT }} --method "tools/list" --params '{}' --json > tools_list_response.json
92- cat tools_list_response.json
93-
94- echo "--- Validating response schemas ---"
95- node <<EOF
96- const { z } = require('zod');
97- const fs = require('fs');
86+ let testResults = {
87+ initialize: false,
88+ toolsList: false
89+ };
9890
99- try {
100- const initResp = JSON.parse(fs.readFileSync('initialize_response.json', 'utf8'));
101- const toolsResp = JSON.parse(fs.readFileSync('tools_list_response.json', 'utf8'));
102-
103- // Define schemas based on the MCP spec
104- const initializeResultSchema = z.object({
105- protocolVersion: z.string(),
106- serverInfo: z.object({ name: z.string(), version: z.string() }),
107- }).passthrough();
108-
109- const toolSchema = z.object({
110- name: z.string(),
111- description: z.string().optional(),
112- inputSchema: z.any()
113- });
114-
115- const toolsListResultSchema = z.object({
116- tools: z.array(toolSchema),
117- });
118-
119- // Validate 'initialize'
120- initializeResultSchema.parse(initResp.result);
121- console.log("✅ 'initialize' response schema is valid.");
122-
123- // Validate 'tools/list'
124- toolsListResultSchema.parse(toolsResp.result);
125- console.log("✅ 'tools/list' response schema is valid.");
126-
127- } catch (error) {
128- console.error("❌ Schema validation failed:", error.message);
91+ // Handle server output
92+ server.stdout.on('data', (data) => {
93+ const response = data.toString();
94+ console.log('Server response:', response);
95+
96+ try {
97+ const jsonResponse = JSON.parse(response);
98+
99+ if (jsonResponse.result && jsonResponse.result.protocolVersion) {
100+ console.log('✅ Initialize response received with protocol version:', jsonResponse.result.protocolVersion);
101+ testResults.initialize = true;
102+
103+ // Send tools/list request
104+ const toolsListRequest = {
105+ jsonrpc: "2.0",
106+ id: 2,
107+ method: "tools/list",
108+ params: {}
109+ };
110+ server.stdin.write(JSON.stringify(toolsListRequest) + '\n');
111+ }
112+
113+ if (jsonResponse.result && jsonResponse.result.tools) {
114+ console.log('✅ Tools list response received with', jsonResponse.result.tools.length, 'tools');
115+ testResults.toolsList = true;
116+
117+ // Check if we have the expected Solana RPC methods
118+ const toolNames = jsonResponse.result.tools.map(tool => tool.name);
119+ const expectedMethods = ['getAccountInfo', 'getBalance', 'sendTransaction'];
120+ const hasExpectedMethods = expectedMethods.every(method => toolNames.includes(method));
121+
122+ if (hasExpectedMethods) {
123+ console.log('✅ Expected Solana RPC methods found in tools list');
124+ } else {
125+ console.log('❌ Some expected Solana RPC methods missing from tools list');
126+ process.exit(1);
127+ }
128+
129+ // Test passed
130+ console.log('✅ All MCP protocol tests passed');
131+ server.kill();
132+ process.exit(0);
133+ }
134+ } catch (e) {
135+ // Ignore non-JSON output
136+ }
137+ });
138+
139+ server.stderr.on('data', (data) => {
140+ console.error('Server error:', data.toString());
141+ });
142+
143+ server.on('close', (code) => {
144+ if (!testResults.initialize || !testResults.toolsList) {
145+ console.log('❌ MCP protocol test failed - missing required responses');
146+ process.exit(1);
147+ }
148+ });
149+
150+ // Send initialize request
151+ const initializeRequest = {
152+ jsonrpc: "2.0",
153+ id: 1,
154+ method: "initialize",
155+ params: {
156+ protocolVersion: "2024-11-05",
157+ capabilities: {},
158+ clientInfo: {
159+ name: "test-client",
160+ version: "1.0.0"
161+ }
162+ }
163+ };
164+
165+ server.stdin.write(JSON.stringify(initializeRequest) + '\n');
166+
167+ // Timeout after 30 seconds
168+ setTimeout(() => {
169+ console.log('❌ Test timeout');
170+ server.kill();
129171 process.exit(1);
130- }
172+ }, 30000);
131173 EOF
132174
133175 - name : Upload Test Artifacts
@@ -136,7 +178,5 @@ jobs:
136178 with :
137179 name : mcp-test-artifacts
138180 path : |
139- server.log
140- initialize_response.json
141- tools_list_response.json
181+ test-config/mcp-config.json
142182 retention-days : 7
0 commit comments