9pros/lmstudio-mcp icon
public
Published on 5/19/2025
LMStudio Command Executor2

LMStudio Command Executor

node -e const fs = require('fs');
const path = require('path');
const http = require('http');
const https = require('https');

// Parse input from continue.dev
const input = JSON.parse(process.argv[2] || '{}');
const command = input.command || '';
const params = input.params || {};

// Configuration - use localhost:1235 as the server
const LM_STUDIO_API = 'http://localhost:1235';

// Helper function to make HTTP requests to LM Studio API
function makeAPIRequest(endpoint, method, data = null) {
  return new Promise((resolve, reject) => {
    const url = new URL(endpoint, LM_STUDIO_API);
    const options = {
      method: method,
      headers: {
        'Content-Type': 'application/json'
      }
    };
    
    if (data) {
      options.headers['Content-Length'] = Buffer.byteLength(JSON.stringify(data));
    }
    
    const req = http.request(url, options, (res) => {
      let responseData = '';
      
      res.on('data', (chunk) => {
        responseData += chunk;
      });
      
      res.on('end', () => {
        try {
          // Try to parse as JSON, fall back to raw text
          try {
            const parsedData = JSON.parse(responseData);
            resolve(parsedData);
          } catch {
            resolve(responseData);
          }
        } catch (error) {
          reject(`Error parsing response: ${error.message}`);
        }
      });
    });
    
    req.on('error', (error) => {
      reject(`Error making request: ${error.message}`);
    });
    
    if (data) {
      req.write(JSON.stringify(data));
    }
    
    req.end();
  });
}

// Execute the appropriate command
async function executeCommand() {
  try {
    let result;
    
    switch (command) {
      // LM Studio Model Management
      case 'list-models':
        result = await makeAPIRequest('/v1/models', 'GET');
        break;
        
      case 'chat-completion':
        if (!params.messages) {
          return { success: false, message: 'Missing messages for chat completion' };
        }
        
        const chatData = {
          model: params.model || 'default',
          messages: params.messages,
          temperature: params.temperature || 0.7,
          max_tokens: params.maxTokens || 2048,
          stream: false
        };
        
        result = await makeAPIRequest('/v1/chat/completions', 'POST', chatData);
        break;
        
      case 'text-completion':
        if (!params.prompt) {
          return { success: false, message: 'Missing prompt for text completion' };
        }
        
        const textData = {
          model: params.model || 'default',
          prompt: params.prompt,
          temperature: params.temperature || 0.7,
          max_tokens: params.maxTokens || 2048,
          stream: false
        };
        
        result = await makeAPIRequest('/v1/completions', 'POST', textData);
        break;
        
      case 'embeddings':
        if (!params.input) {
          return { success: false, message: 'Missing input for embeddings' };
        }
        
        const embeddingData = {
          model: params.model || 'default',
          input: Array.isArray(params.input) ? params.input : [params.input]
        };
        
        result = await makeAPIRequest('/v1/embeddings', 'POST', embeddingData);
        break;
        
      // File Operations
      case 'read-file':
        if (!params.filePath) {
          return { success: false, message: 'Missing filePath' };
        }
        
        if (!fs.existsSync(params.filePath)) {
          return { success: false, message: 'File does not exist' };
        }
        
        const content = fs.readFileSync(params.filePath, params.encoding || 'utf8');
        result = { success: true, content, path: params.filePath };
        break;
        
      case 'write-file':
        if (!params.filePath || params.content === undefined) {
          return { success: false, message: 'Missing filePath or content' };
        }
        
        // Create directory if it doesn't exist
        const dirPath = path.dirname(params.filePath);
        fs.mkdirSync(dirPath, { recursive: true });
        
        // Write the file
        fs.writeFileSync(params.filePath, params.content, params.encoding || 'utf8');
        result = { success: true, message: `File ${params.filePath} written successfully` };
        break;
        
      case 'modify-file':
        if (!params.filePath || !params.searchText || !params.replaceText) {
          return { success: false, message: 'Missing filePath, searchText, or replaceText' };
        }
        
        if (!fs.existsSync(params.filePath)) {
          return { success: false, message: 'File does not exist' };
        }
        
        // Read, modify, and write back
        let fileContent = fs.readFileSync(params.filePath, params.encoding || 'utf8');
        const searchRegex = new RegExp(params.searchText, params.flags || 'g');
        fileContent = fileContent.replace(searchRegex, params.replaceText);
        fs.writeFileSync(params.filePath, fileContent, params.encoding || 'utf8');
        
        result = { 
          success: true, 
          message: `File ${params.filePath} modified successfully` 
        };
        break;
        
      case 'list-directory':
        if (!params.dirPath) {
          return { success: false, message: 'Missing dirPath' };
        }
        
        if (!fs.existsSync(params.dirPath)) {
          return { success: false, message: 'Directory does not exist' };
        }
        
        const items = fs.readdirSync(params.dirPath, { withFileTypes: true })
          .map(item => ({
            name: item.name,
            isDirectory: item.isDirectory(),
            path: path.join(params.dirPath, item.name)
          }));
        
        result = { success: true, items, path: params.dirPath };
        break;
        
      // Shell Command
      case 'execute-shell':
        if (!params.shellCommand) {
          return { success: false, message: 'Missing shellCommand' };
        }
        
        try {
          const { execSync } = require('child_process');
          const output = execSync(params.shellCommand, { 
            encoding: 'utf8',
            cwd: params.workingDir || process.cwd(),
            timeout: params.timeout || 30000
          });
          
          result = { success: true, output, command: params.shellCommand };
        } catch (error) {
          result = { 
            success: false, 
            error: error.message, 
            stderr: error.stderr?.toString(),
            stdout: error.stdout?.toString(),
            command: params.shellCommand 
          };
        }
        break;
        
      // Unknown command
      default:
        result = { 
          success: false, 
          message: `Unknown command: ${command}`, 
          availableCommands: [
            'list-models', 'chat-completion', 'text-completion', 'embeddings',
            'read-file', 'write-file', 'modify-file', 'list-directory',
            'execute-shell'
          ]
        };
    }
    
    return result;
  } catch (error) {
    return { 
      success: false, 
      message: `Error executing command: ${error.message}`,
      command: command
    };
  }
}

// Execute command and output result
executeCommand()
  .then(result => {
    console.log(JSON.stringify(result, null, 2));
  })
  .catch(error => {
    console.error(JSON.stringify({ 
      success: false, 
      message: `Execution error: ${error.message}`,
      command: command
    }, null, 2));
  });