Skip to main content
Glama
claude-pilot.js6.64 kB
// Claude AI Pilot for GeoFS MCP Server const WebSocket = require('ws'); const fetch = require('node-fetch'); const { default: Anthropic } = require('@anthropic-ai/sdk'); const readline = require('readline'); // Configuration const SERVER_URL = 'http://localhost:3000'; const WS_URL = 'ws://localhost:3000'; const ANTHROPIC_API_KEY = 'YOUR_ANTHROPIC_API_KEY'; // Replace with your API key // Initialize Anthropic client const anthropic = new Anthropic({ apiKey: ANTHROPIC_API_KEY, }); // Create readline interface for user input const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // Connect to the WebSocket server const ws = new WebSocket(WS_URL); // Message ID counter let messageId = 1; // Flight state let flightState = { flightData: null, lastCommand: null, history: [] }; // WebSocket event handlers ws.on('open', () => { console.log('Connected to GeoFS MCP Server'); startInteraction(); }); ws.on('message', (data) => { try { const message = JSON.parse(data); console.log('Received from GeoFS:', message); // Update flight state with response if (message.result) { if (flightState.lastCommand === 'getFlightData') { flightState.flightData = message.result; } // Add to history flightState.history.push({ timestamp: new Date().toISOString(), command: flightState.lastCommand, result: message.result }); // Keep history at a reasonable size if (flightState.history.length > 10) { flightState.history.shift(); } } } catch (error) { console.error('Error parsing message:', error); } }); ws.on('error', (error) => { console.error('WebSocket error:', error); }); ws.on('close', () => { console.log('Disconnected from GeoFS MCP Server'); process.exit(0); }); // Send a command to GeoFS function sendCommand(command, params = {}) { return new Promise((resolve, reject) => { const id = messageId++; // Set up one-time listener for this specific message ID const messageHandler = (data) => { try { const response = JSON.parse(data); if (response.id === id) { ws.removeListener('message', messageHandler); resolve(response.result); } } catch (error) { // Ignore parsing errors for other messages } }; ws.on('message', messageHandler); // Store the last command flightState.lastCommand = command; // Send the command ws.send(JSON.stringify({ id, type: 'command', command, params })); console.log(`Sent command: ${command}`, params); // Set timeout to prevent hanging setTimeout(() => { ws.removeListener('message', messageHandler); reject(new Error(`Command ${command} timed out`)); }, 10000); }); } // Get flight instructions from Claude async function getFlightInstructions(userInput) { // First, get the latest flight data try { flightState.flightData = await sendCommand('getFlightData'); } catch (error) { console.error('Error getting flight data:', error); } // Prepare the context for Claude const context = ` You are an AI flight assistant helping a pilot fly in the GeoFS flight simulator. Current flight data: ${JSON.stringify(flightState.flightData, null, 2)} Recent command history: ${JSON.stringify(flightState.history, null, 2)} Available commands: - setThrottle(value: 0-1) - Set engine throttle - setHeading(degrees: 0-360) - Set target heading - getPosition() - Get current aircraft position - selectAircraft(aircraftId: number) - Change aircraft - takeOff() - Execute takeoff procedure - land() - Execute landing procedure - getFlightData() - Get comprehensive flight data The user wants to: ${userInput} Respond with specific flight instructions that can be executed using the available commands. Format your response as valid JSON with a "commands" array containing objects with "command" and "params" properties. `; try { const response = await anthropic.messages.create({ model: 'claude-3-opus-20240229', max_tokens: 1000, messages: [ { role: 'user', content: context } ], }); // Extract JSON from Claude's response const content = response.content[0].text; const jsonMatch = content.match(/```json\n([\s\S]*?)\n```/) || content.match(/```\n([\s\S]*?)\n```/) || content.match(/{[\s\S]*?}/); if (jsonMatch) { try { return JSON.parse(jsonMatch[1] || jsonMatch[0]); } catch (e) { console.error('Error parsing Claude response as JSON:', e); console.log('Raw response:', content); return null; } } else { console.error('Could not find JSON in Claude response'); console.log('Raw response:', content); return null; } } catch (error) { console.error('Error getting instructions from Claude:', error); return null; } } // Execute flight instructions async function executeInstructions(instructions) { if (!instructions || !instructions.commands || !Array.isArray(instructions.commands)) { console.log('No valid instructions received'); return; } console.log('Executing flight instructions:'); for (const cmd of instructions.commands) { console.log(`- ${cmd.command}:`, cmd.params); try { const result = await sendCommand(cmd.command, cmd.params); console.log(` Result:`, result); } catch (error) { console.error(` Error executing ${cmd.command}:`, error.message); } // Small delay between commands await new Promise(resolve => setTimeout(resolve, 1000)); } console.log('All instructions executed'); } // Start the interaction loop function startInteraction() { console.log('\n=== Claude AI Pilot for GeoFS ==='); console.log('Type your flight instructions or "exit" to quit'); askForInput(); } function askForInput() { rl.question('\nWhat would you like to do? ', async (input) => { if (input.toLowerCase() === 'exit') { console.log('Exiting...'); ws.close(); rl.close(); return; } console.log('Getting instructions from Claude...'); const instructions = await getFlightInstructions(input); if (instructions) { await executeInstructions(instructions); } askForInput(); }); } // Handle process termination process.on('SIGINT', () => { console.log('Closing connection...'); ws.close(); rl.close(); process.exit(0); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lobstercare/geofs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server