UNPKG

ai-cli-hub

Version:

Unified MCP Server for AI CLI Tools (Gemini, Qwen, OpenCode)

259 lines (218 loc) 7.54 kB
#!/usr/bin/env node /** * AI CLI Hub MCP Client Demo * このスクリプトはMCPサーバーの各ツールをテストするためのクライアントです */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { spawn } from "child_process"; import { join } from "path"; import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // MCPサーバーへの接続をシミュレートするテストクライアント class MCPTestClient { constructor(serverCommand, serverArgs) { this.serverProcess = null; this.serverCommand = serverCommand; this.serverArgs = serverArgs; } async start() { console.log("🚀 AI CLI Hub MCP Server Demo"); console.log("===================================="); // サーバープロセス起動 this.serverProcess = spawn(this.serverCommand, this.serverArgs, { stdio: ['pipe', 'pipe', 'inherit'], cwd: join(__dirname, '..') }); console.log("✅ MCP Server started with PID:", this.serverProcess.pid); // リストツール要求 await this.testListTools(); // 各ツールのテスト実行 await this.testFileOperations(); await this.testAuthTools(); await this.testGitOperations(); await this.testOpenCodeTools(); } async sendMCPMessage(message) { return new Promise((resolve, reject) => { const msgString = JSON.stringify(message) + '\\n'; this.serverProcess.stdin.write(msgString); let responseBuffer = ''; const timeout = setTimeout(() => { reject(new Error('Request timeout')); }, 5000); const onData = (chunk) => { responseBuffer += chunk.toString(); try { const response = JSON.parse(responseBuffer); clearTimeout(timeout); this.serverProcess.stdout.off('data', onData); resolve(response); } catch (e) { // まだ完全なJSONではない、継続 } }; this.serverProcess.stdout.on('data', onData); }); } async testListTools() { console.log("\\n📋 Testing: List Tools"); try { const request = { jsonrpc: "2.0", id: 1, method: "tools/list", params: {} }; const response = await this.sendMCPMessage(request); console.log("✅ Available tools:", response.result?.tools?.length || 0); if (response.result?.tools) { response.result.tools.slice(0, 5).forEach(tool => { console.log(` - ${tool.name}: ${tool.description || 'No description'}`); }); if (response.result.tools.length > 5) { console.log(` ... and ${response.result.tools.length - 5} more tools`); } } } catch (error) { console.error("❌ List tools failed:", error.message); } } async testFileOperations() { console.log("\\n📁 Testing: File Operations"); try { // Hello World ファイル作成テスト const writeRequest = { jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "file_write", arguments: { path: "/tmp/hello-world-mcp.txt", content: "Hello World from AI CLI Hub MCP Server!\\nCreated on: " + new Date().toISOString() + "\\n" } } }; const writeResponse = await this.sendMCPMessage(writeRequest); console.log("✅ File write:", writeResponse.result ? "Success" : "Failed"); // ファイル読み込みテスト const readRequest = { jsonrpc: "2.0", id: 3, method: "tools/call", params: { name: "file_read", arguments: { path: "/tmp/hello-world-mcp.txt" } } }; const readResponse = await this.sendMCPMessage(readRequest); console.log("✅ File read result:"); console.log(" Content:", JSON.parse(readResponse.result?.content?.[0]?.text || '{}').content?.substring(0, 50) + "..."); } catch (error) { console.error("❌ File operations failed:", error.message); } } async testAuthTools() { console.log("\\n🔐 Testing: Authentication Tools"); try { const statusRequest = { jsonrpc: "2.0", id: 4, method: "tools/call", params: { name: "auth_check_status", arguments: {} } }; const statusResponse = await this.sendMCPMessage(statusRequest); const authData = JSON.parse(statusResponse.result?.content?.[0]?.text || '{}'); console.log("✅ Auth status check:"); console.log(" Providers:", Object.keys(authData.providers || {})); console.log(" Authenticated:", authData.authenticatedCount || 0, "/", authData.totalCount || 0); } catch (error) { console.error("❌ Auth tools failed:", error.message); } } async testGitOperations() { console.log("\\n🌟 Testing: Git Operations"); try { const gitStatusRequest = { jsonrpc: "2.0", id: 5, method: "tools/call", params: { name: "git_status", arguments: { repository: "/Users/jun/ai-cli" } } }; const gitResponse = await this.sendMCPMessage(gitStatusRequest); const gitData = JSON.parse(gitResponse.result?.content?.[0]?.text || '{}'); console.log("✅ Git status:"); console.log(" Repository:", gitData.repository || "Unknown"); console.log(" Branch:", gitData.branch || "Unknown"); console.log(" Status:", gitData.hasChanges ? "Has changes" : "Clean"); } catch (error) { console.error("❌ Git operations failed:", error.message); } } async testOpenCodeTools() { console.log("\\n🤖 Testing: OpenCode AI Tools"); try { const chatRequest = { jsonrpc: "2.0", id: 6, method: "tools/call", params: { name: "opencode_chat", arguments: { message: "Hello! Please respond with a simple 'Hello World from OpenCode' message.", provider: "anthropic" } } }; const chatResponse = await this.sendMCPMessage(chatRequest); const chatData = JSON.parse(chatResponse.result?.content?.[0]?.text || '{}'); console.log("✅ OpenCode chat:"); console.log(" Response:", chatData.message || chatData.response || "No response"); } catch (error) { console.error("❌ OpenCode tools failed:", error.message); } } async stop() { if (this.serverProcess) { console.log("\\n🛑 Stopping MCP Server..."); this.serverProcess.kill('SIGTERM'); console.log("✅ Demo completed!"); } } } // メイン実行 async function main() { const client = new MCPTestClient('npm', ['run', 'dev']); try { await client.start(); // 5秒後に終了 setTimeout(async () => { await client.stop(); process.exit(0); }, 8000); } catch (error) { console.error("Demo failed:", error); await client.stop(); process.exit(1); } } // 実行制御 if (process.argv[2] === '--run') { main().catch(console.error); } else { console.log("AI CLI Hub MCP Client Demo"); console.log("Usage: node test-mcp-client.js --run"); }