# Directory Structure ``` ├── .gitignore ├── debug_lmstudio.py ├── debug_server.py ├── install.bat ├── install.sh ├── INSTALLATION.md ├── prepare_for_claude.bat ├── prepare_for_claude.sh ├── README.md ├── requirements.txt ├── run_server.bat ├── run_server.sh ├── server.py ├── setup.bat ├── setup.sh ├── test_mcp.py └── verify_setup.py ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` venv/ __pycache__/ *.py[cod] *$py.class .env .venv env/ ENV/ .DS_Store ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # Claude-LMStudio Bridge An MCP server that bridges Claude with local LLMs running in LM Studio. ## Overview This tool allows Claude to interact with your local LLMs running in LM Studio, providing: - Access to list all available models in LM Studio - The ability to generate text using your local LLMs - Support for chat completions through your local models - A health check tool to verify connectivity with LM Studio ## Prerequisites - [Claude Desktop](https://claude.ai/desktop) with MCP support - [LM Studio](https://lmstudio.ai/) installed and running locally with API server enabled - Python 3.8+ installed ## Quick Start (Recommended) ### For macOS/Linux: 1. Clone the repository ```bash git clone https://github.com/infinitimeless/claude-lmstudio-bridge.git cd claude-lmstudio-bridge ``` 2. Run the setup script ```bash chmod +x setup.sh ./setup.sh ``` 3. Follow the setup script's instructions to configure Claude Desktop ### For Windows: 1. Clone the repository ```cmd git clone https://github.com/infinitimeless/claude-lmstudio-bridge.git cd claude-lmstudio-bridge ``` 2. Run the setup script ```cmd setup.bat ``` 3. Follow the setup script's instructions to configure Claude Desktop ## Manual Setup If you prefer to set things up manually: 1. Create a virtual environment (optional but recommended) ```bash python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate ``` 2. Install the required packages ```bash pip install -r requirements.txt ``` 3. Configure Claude Desktop: - Open Claude Desktop preferences - Navigate to the 'MCP Servers' section - Add a new MCP server with the following configuration: - **Name**: lmstudio-bridge - **Command**: /bin/bash (on macOS/Linux) or cmd.exe (on Windows) - **Arguments**: - macOS/Linux: /path/to/claude-lmstudio-bridge/run_server.sh - Windows: /c C:\path\to\claude-lmstudio-bridge\run_server.bat ## Usage with Claude After setting up the bridge, you can use the following commands in Claude: 1. Check the connection to LM Studio: ``` Can you check if my LM Studio server is running? ``` 2. List available models: ``` List the available models in my local LM Studio ``` 3. Generate text with a local model: ``` Generate a short poem about spring using my local LLM ``` 4. Send a chat completion: ``` Ask my local LLM: "What are the main features of transformers in machine learning?" ``` ## Troubleshooting ### Diagnosing LM Studio Connection Issues Use the included debugging tool to check your LM Studio connection: ```bash python debug_lmstudio.py ``` For more detailed tests: ```bash python debug_lmstudio.py --test-chat --verbose ``` ### Common Issues **"Cannot connect to LM Studio API"** - Make sure LM Studio is running - Verify the API server is enabled in LM Studio (Settings > API Server) - Check that the port (default: 1234) matches what's in your .env file **"No models are loaded"** - Open LM Studio and load a model - Verify the model is running successfully **"MCP package not found"** - Try reinstalling: `pip install "mcp[cli]" httpx python-dotenv` - Make sure you're using Python 3.8 or later **"Claude can't find the bridge"** - Check Claude Desktop configuration - Make sure the path to run_server.sh or run_server.bat is correct and absolute - Verify the server script is executable: `chmod +x run_server.sh` (on macOS/Linux) ## Advanced Configuration You can customize the bridge behavior by creating a `.env` file with these settings: ``` LMSTUDIO_HOST=127.0.0.1 LMSTUDIO_PORT=1234 DEBUG=false ``` Set `DEBUG=true` to enable verbose logging for troubleshooting. ## License MIT ``` -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- ``` # Core dependencies mcp[cli]>=0.1.0 httpx>=0.24.0 python-dotenv>=1.0.0 # For development and testing pytest>=7.0.0 ``` -------------------------------------------------------------------------------- /debug_server.py: -------------------------------------------------------------------------------- ```python import sys import traceback from mcp.server.fastmcp import FastMCP # Print startup message to stderr for debugging print("Starting debug server...", file=sys.stderr) try: # Initialize FastMCP server print("Initializing FastMCP server...", file=sys.stderr) mcp = FastMCP("lmstudio-bridge") @mcp.tool() async def debug_test() -> str: """Basic test function to verify MCP server is working. Returns: A simple confirmation message """ print("debug_test function called", file=sys.stderr) return "MCP server is working correctly!" if __name__ == "__main__": print("Starting server with stdio transport...", file=sys.stderr) # Initialize and run the server mcp.run(transport='stdio') except Exception as e: print(f"ERROR: {str(e)}", file=sys.stderr) print("Traceback:", file=sys.stderr) traceback.print_exc(file=sys.stderr) ``` -------------------------------------------------------------------------------- /prepare_for_claude.bat: -------------------------------------------------------------------------------- ``` @echo off SETLOCAL echo === Claude-LMStudio Bridge Setup === echo This script will prepare the environment for use with Claude Desktop echo. :: Try to install MCP globally to ensure it's available echo Installing MCP package globally... python -m pip install "mcp[cli]" httpx :: Check if installation was successful python -c "import mcp" >nul 2>&1 IF %ERRORLEVEL% NEQ 0 ( echo X Failed to install MCP package. Please check your Python installation. EXIT /B 1 ) ELSE ( echo ✓ MCP package installed successfully ) :: Create virtual environment if it doesn't exist IF NOT EXIST venv ( echo Creating virtual environment... python -m venv venv echo ✓ Created virtual environment :: Activate and install dependencies CALL venv\Scripts\activate.bat python -m pip install -r requirements.txt echo ✓ Installed dependencies in virtual environment ) ELSE ( echo ✓ Virtual environment already exists ) :: Display configuration instructions echo. echo === Configuration Instructions === echo 1. Open Claude Desktop preferences echo 2. Navigate to the 'MCP Servers' section echo 3. Add a new MCP server with the following configuration: echo. echo Name: lmstudio-bridge echo Command: cmd.exe echo Arguments: /c %CD%\run_server.bat echo. echo 4. Start LM Studio and ensure the API server is running echo 5. Restart Claude Desktop echo. echo Setup complete! You can now use the LMStudio bridge with Claude Desktop. ENDLOCAL ``` -------------------------------------------------------------------------------- /test_mcp.py: -------------------------------------------------------------------------------- ```python #!/usr/bin/env python3 """ Simple script to test if MCP package is working correctly. Run this script to verify the MCP installation before attempting to run the full server. """ import sys import traceback print("Testing MCP installation...") try: print("Importing mcp package...") from mcp.server.fastmcp import FastMCP print("✅ Successfully imported FastMCP") print("Creating FastMCP instance...") mcp = FastMCP("test-server") print("✅ Successfully created FastMCP instance") print("Registering simple tool...") @mcp.tool() async def hello() -> str: return "Hello, world!" print("✅ Successfully registered tool") print("All tests passed! MCP appears to be correctly installed.") print("\nNext steps:") print("1. First try running the debug_server.py script") print("2. Then try running the main server.py script if debug_server works") except ImportError as e: print(f"❌ Error importing MCP: {str(e)}") print("\nTry reinstalling the MCP package with:") print("pip uninstall mcp") print("pip install 'mcp[cli]'") except Exception as e: print(f"❌ Unexpected error: {str(e)}") traceback.print_exc() print("\nTroubleshooting tips:") print("1. Make sure you're using Python 3.8 or newer") print("2. Check that you're in the correct virtual environment") print("3. Try reinstalling dependencies: pip install -r requirements.txt") ``` -------------------------------------------------------------------------------- /prepare_for_claude.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # # This script prepares the Claude-LMStudio Bridge for use with Claude Desktop # It installs required packages and ensures everything is ready to run # echo "=== Claude-LMStudio Bridge Setup ===" echo "This script will prepare the environment for use with Claude Desktop" echo # Make the run script executable chmod +x run_server.sh echo "✅ Made run_server.sh executable" # Try to install MCP globally to ensure it's available echo "Installing MCP package globally..." python -m pip install "mcp[cli]" httpx # Check if installation was successful if python -c "import mcp" 2>/dev/null; then echo "✅ MCP package installed successfully" else echo "❌ Failed to install MCP package. Please check your Python installation." exit 1 fi # Create virtual environment if it doesn't exist if [ ! -d "venv" ]; then echo "Creating virtual environment..." python -m venv venv echo "✅ Created virtual environment" # Activate and install dependencies source venv/bin/activate python -m pip install -r requirements.txt echo "✅ Installed dependencies in virtual environment" else echo "✅ Virtual environment already exists" fi # Display configuration instructions echo echo "=== Configuration Instructions ===" echo "1. Open Claude Desktop preferences" echo "2. Navigate to the 'MCP Servers' section" echo "3. Add a new MCP server with the following configuration:" echo echo " Name: lmstudio-bridge" echo " Command: /bin/bash" echo " Arguments: $(pwd)/run_server.sh" echo echo "4. Start LM Studio and ensure the API server is running" echo "5. Restart Claude Desktop" echo echo "Setup complete! You can now use the LMStudio bridge with Claude Desktop." ``` -------------------------------------------------------------------------------- /setup.bat: -------------------------------------------------------------------------------- ``` @echo off REM setup.bat - Simplified setup script for Claude-LMStudio Bridge echo === Claude-LMStudio Bridge Setup === echo. REM Create and activate virtual environment if not exist venv ( echo Creating virtual environment... python -m venv venv echo ✓ Created virtual environment ) else ( echo ✓ Virtual environment already exists ) REM Activate the virtual environment call venv\Scripts\activate.bat REM Install dependencies echo Installing dependencies... pip install -r requirements.txt echo ✓ Installed dependencies REM Create default configuration if not exist .env ( echo Creating default configuration... ( echo LMSTUDIO_HOST=127.0.0.1 echo LMSTUDIO_PORT=1234 echo DEBUG=false ) > .env echo ✓ Created .env configuration file ) else ( echo ✓ Configuration file already exists ) REM Check if LM Studio is running set PORT_CHECK=0 netstat -an | findstr "127.0.0.1:1234" > nul && set PORT_CHECK=1 if %PORT_CHECK%==1 ( echo ✓ LM Studio is running on port 1234 ) else ( echo ⚠ LM Studio does not appear to be running on port 1234 echo Please start LM Studio and enable the API server (Settings ^> API Server) ) echo. echo ✓ Setup complete! echo. echo To start the bridge, run: echo venv\Scripts\activate.bat ^&^& python server.py echo. echo To configure with Claude Desktop: echo 1. Open Claude Desktop preferences echo 2. Navigate to the 'MCP Servers' section echo 3. Add a new MCP server with the following configuration: echo - Name: lmstudio-bridge echo - Command: cmd.exe echo - Arguments: /c %CD%\run_server.bat echo. echo Make sure LM Studio is running with API server enabled on port 1234. REM Keep the window open pause ``` -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # setup.sh - Simplified setup script for Claude-LMStudio Bridge echo "=== Claude-LMStudio Bridge Setup ===" # Create and activate virtual environment if [ ! -d "venv" ]; then echo "Creating virtual environment..." python -m venv venv echo "✅ Created virtual environment" else echo "✅ Virtual environment already exists" fi # Activate the virtual environment source venv/bin/activate # Install dependencies echo "Installing dependencies..." pip install -r requirements.txt echo "✅ Installed dependencies" # Create default configuration if [ ! -f ".env" ]; then echo "Creating default configuration..." cat > .env << EOL LMSTUDIO_HOST=127.0.0.1 LMSTUDIO_PORT=1234 DEBUG=false EOL echo "✅ Created .env configuration file" else echo "✅ Configuration file already exists" fi # Make run_server.sh executable chmod +x run_server.sh echo "✅ Made run_server.sh executable" # Check if LM Studio is running if nc -z localhost 1234 2>/dev/null; then echo "✅ LM Studio is running on port 1234" else echo "⚠️ LM Studio does not appear to be running on port 1234" echo " Please start LM Studio and enable the API server (Settings > API Server)" fi echo echo "✅ Setup complete!" echo echo "To start the bridge, run:" echo " source venv/bin/activate && python server.py" echo echo "To configure with Claude Desktop:" echo "1. Open Claude Desktop preferences" echo "2. Navigate to the 'MCP Servers' section" echo "3. Add a new MCP server with the following configuration:" echo " - Name: lmstudio-bridge" echo " - Command: /bin/bash" echo " - Arguments: $(pwd)/run_server.sh" echo echo "Make sure LM Studio is running with API server enabled on port 1234." ``` -------------------------------------------------------------------------------- /INSTALLATION.md: -------------------------------------------------------------------------------- ```markdown # Installation Guide for Claude-LMStudio Bridge This guide provides detailed instructions for setting up the Claude-LMStudio Bridge MCP server. ## Installing the MCP Python SDK The primary issue users face is not having the MCP module installed properly. Here are different ways to install it: ### Using uv (Recommended) `uv` is a modern Python package installer that's recommended for MCP development: ```bash # Install uv if you don't have it pip install uv # Install the MCP SDK with CLI support uv add "mcp[cli]" ``` ### Using pip Alternatively, you can use pip: ```bash pip install "mcp[cli]" ``` ## Verifying Installation After installation, verify that the module is correctly installed: ```bash python -c "import mcp; print(mcp.__version__)" ``` This should print the version of the MCP SDK if it's installed correctly. ## Ensuring the Correct Environment Make sure you're using the correct Python environment: 1. If using a virtual environment, activate it before running your script: ```bash # Activate virtual environment source venv/bin/activate # For Mac/Linux # or venv\Scripts\activate # For Windows ``` 2. Verify the Python path to ensure you're using the expected Python interpreter: ```bash which python # On Mac/Linux where python # On Windows ``` ## Testing the Installation Run the test script to verify your setup: ```bash python test_mcp.py ``` If this works successfully, you should be ready to run the server. ## Common Issues and Solutions 1. **ModuleNotFoundError: No module named 'mcp'** - The MCP module isn't installed in your current Python environment - Solution: Install the MCP SDK as described above 2. **MCP installed but still getting import errors** - You might be running Python from a different environment - Solution: Check which Python is being used with `which python` and make sure your virtual environment is activated 3. **Error loading the server in Claude** - Make sure you're using absolute paths in your Claude Desktop configuration - Check that the server is executable and that Python has permission to access it ``` -------------------------------------------------------------------------------- /run_server.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # Configuration - Auto-detect Python path if [ -z "$PYTHON_PATH" ]; then PYTHON_PATH=$(which python3 2>/dev/null || which python 2>/dev/null) if [ -z "$PYTHON_PATH" ]; then echo "ERROR: Python not found. Please install Python 3." >&2 exit 1 fi fi # Print current environment details echo "Current directory: $(pwd)" >&2 echo "Using Python at: $PYTHON_PATH" >&2 # Check if Python exists at the specified path if [ ! -f "$PYTHON_PATH" ]; then echo "ERROR: Python not found at $PYTHON_PATH" >&2 echo "Please install Python or set the correct path in this script." >&2 exit 1 fi # Check if mcp is installed, if not, try to install it if ! $PYTHON_PATH -c "import mcp" 2>/dev/null; then echo "MCP package not found, attempting to install..." >&2 # Try to install using python -m pip $PYTHON_PATH -m pip install "mcp[cli]" httpx || { echo "Failed to install MCP package. Please install manually with:" >&2 echo "$PYTHON_PATH -m pip install \"mcp[cli]\" httpx" >&2 exit 1 } # Check if installation was successful if ! $PYTHON_PATH -c "import mcp" 2>/dev/null; then echo "MCP package was installed but still can't be imported." >&2 echo "This might be due to a Python path issue." >&2 exit 1 fi fi # Check if httpx is installed if ! $PYTHON_PATH -c "import httpx" 2>/dev/null; then echo "httpx package not found, attempting to install..." >&2 $PYTHON_PATH -m pip install httpx || { echo "Failed to install httpx package." >&2 exit 1 } fi # Check if dotenv is installed (for .env file support) if ! $PYTHON_PATH -c "import dotenv" 2>/dev/null; then echo "python-dotenv package not found, attempting to install..." >&2 $PYTHON_PATH -m pip install python-dotenv || { echo "Failed to install python-dotenv package." >&2 exit 1 } fi # Check if virtual environment exists and use it if it does if [ -d "venv" ] && [ -f "venv/bin/python" ]; then echo "Using Python from virtual environment" >&2 PYTHON_PATH=$(pwd)/venv/bin/python echo "Updated Python path to: $PYTHON_PATH" >&2 fi # Attempt to check if LM Studio is running before starting if command -v nc &> /dev/null; then if ! nc -z localhost 1234 2>/dev/null; then echo "WARNING: LM Studio does not appear to be running on port 1234" >&2 echo "Please make sure LM Studio is running with the API server enabled" >&2 else echo "✓ LM Studio API server appears to be running on port 1234" >&2 fi fi # Run the server script echo "Starting server.py with $PYTHON_PATH..." >&2 $PYTHON_PATH server.py ``` -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # Claude-LMStudio Bridge Installer # This script will set up the Claude-LMStudio Bridge for use with Claude Desktop echo "===== Claude-LMStudio Bridge Installer =====" echo "This will configure the bridge to work with Claude Desktop" echo # Find Python location PYTHON_PATH=$(which python3) if [ -z "$PYTHON_PATH" ]; then echo "❌ ERROR: Python 3 not found in your PATH" echo "Please install Python 3 first and try again" exit 1 fi echo "✅ Found Python at: $PYTHON_PATH" # Update the run_server.sh script with the correct Python path echo "Updating run_server.sh with Python path..." sed -i '' "s|PYTHON_PATH=.*|PYTHON_PATH=\"$PYTHON_PATH\"|g" run_server.sh chmod +x run_server.sh # Install required packages echo "Installing required Python packages..." "$PYTHON_PATH" -m pip install "mcp[cli]" httpx # Check if installation was successful if ! "$PYTHON_PATH" -c "import mcp" 2>/dev/null; then echo "❌ ERROR: Failed to install MCP package" echo "Try running manually: $PYTHON_PATH -m pip install \"mcp[cli]\" httpx" exit 1 fi echo "✅ MCP package installed successfully" # Get full path to the run_server.sh script SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" SCRIPT_PATH="$SCRIPT_DIR/run_server.sh" # Create or update Claude Desktop config CONFIG_DIR="$HOME/Library/Application Support/Claude" CONFIG_FILE="$CONFIG_DIR/claude_desktop_config.json" mkdir -p "$CONFIG_DIR" if [ -f "$CONFIG_FILE" ]; then # Backup existing config cp "$CONFIG_FILE" "$CONFIG_FILE.backup" echo "Created backup of existing config at $CONFIG_FILE.backup" # Check if JSON is valid and has mcpServers property if grep -q "\"mcpServers\"" "$CONFIG_FILE"; then # Add or update lmstudio-bridge entry TMP_FILE=$(mktemp) jq --arg path "$SCRIPT_PATH" '.mcpServers["lmstudio-bridge"] = {"command": "/bin/bash", "args": [$path]}' "$CONFIG_FILE" > "$TMP_FILE" mv "$TMP_FILE" "$CONFIG_FILE" else # Create mcpServers section TMP_FILE=$(mktemp) jq --arg path "$SCRIPT_PATH" '. + {"mcpServers": {"lmstudio-bridge": {"command": "/bin/bash", "args": [$path]}}}' "$CONFIG_FILE" > "$TMP_FILE" mv "$TMP_FILE" "$CONFIG_FILE" fi else # Create new config file echo "{ \"mcpServers\": { \"lmstudio-bridge\": { \"command\": \"/bin/bash\", \"args\": [ \"$SCRIPT_PATH\" ] } } }" > "$CONFIG_FILE" fi echo "✅ Updated Claude Desktop configuration at $CONFIG_FILE" echo echo "✅ Installation complete!" echo "Please restart Claude Desktop to use the LMStudio bridge" echo echo "If you encounter any issues, edit run_server.sh to check settings" echo "or refer to the README.md for troubleshooting steps." ``` -------------------------------------------------------------------------------- /run_server.bat: -------------------------------------------------------------------------------- ``` @echo off SETLOCAL REM Configuration - Auto-detect Python path IF "%PYTHON_PATH%"=="" ( FOR /F "tokens=*" %%i IN ('where python') DO ( SET PYTHON_PATH=%%i GOTO :found_python ) echo ERROR: Python not found in your PATH 1>&2 echo Please install Python first and make sure it's in your PATH 1>&2 EXIT /B 1 :found_python ) REM Print current environment details echo Current directory: %CD% 1>&2 echo Using Python at: %PYTHON_PATH% 1>&2 REM Check if Python exists at the specified path IF NOT EXIST "%PYTHON_PATH%" ( echo ERROR: Python not found at %PYTHON_PATH% 1>&2 echo Please install Python or set the correct path in this script. 1>&2 EXIT /B 1 ) REM Check if mcp is installed, if not, try to install it "%PYTHON_PATH%" -c "import mcp" >nul 2>&1 IF %ERRORLEVEL% NEQ 0 ( echo MCP package not found, attempting to install... 1>&2 REM Try to install using python -m pip "%PYTHON_PATH%" -m pip install "mcp[cli]" httpx IF %ERRORLEVEL% NEQ 0 ( echo Failed to install MCP package. Please install manually with: 1>&2 echo "%PYTHON_PATH%" -m pip install "mcp[cli]" httpx 1>&2 EXIT /B 1 ) REM Check if installation was successful "%PYTHON_PATH%" -c "import mcp" >nul 2>&1 IF %ERRORLEVEL% NEQ 0 ( echo MCP package was installed but still can't be imported. 1>&2 echo This might be due to a Python path issue. 1>&2 EXIT /B 1 ) ) REM Check if httpx is installed "%PYTHON_PATH%" -c "import httpx" >nul 2>&1 IF %ERRORLEVEL% NEQ 0 ( echo httpx package not found, attempting to install... 1>&2 "%PYTHON_PATH%" -m pip install httpx IF %ERRORLEVEL% NEQ 0 ( echo Failed to install httpx package. 1>&2 EXIT /B 1 ) ) REM Check if dotenv is installed (for .env file support) "%PYTHON_PATH%" -c "import dotenv" >nul 2>&1 IF %ERRORLEVEL% NEQ 0 ( echo python-dotenv package not found, attempting to install... 1>&2 "%PYTHON_PATH%" -m pip install python-dotenv IF %ERRORLEVEL% NEQ 0 ( echo Failed to install python-dotenv package. 1>&2 EXIT /B 1 ) ) REM Check if virtual environment exists and use it if it does IF EXIST "venv\Scripts\python.exe" ( echo Using Python from virtual environment 1>&2 SET PYTHON_PATH=%CD%\venv\Scripts\python.exe echo Updated Python path to: %PYTHON_PATH% 1>&2 ) REM Attempt to check if LM Studio is running before starting netstat -an | findstr "127.0.0.1:1234" >nul IF %ERRORLEVEL% NEQ 0 ( echo WARNING: LM Studio does not appear to be running on port 1234 1>&2 echo Please make sure LM Studio is running with the API server enabled 1>&2 ) ELSE ( echo ✓ LM Studio API server appears to be running on port 1234 1>&2 ) REM Run the server script echo Starting server.py with %PYTHON_PATH%... 1>&2 "%PYTHON_PATH%" server.py ENDLOCAL ``` -------------------------------------------------------------------------------- /install.bat: -------------------------------------------------------------------------------- ``` @echo off echo ===== Claude-LMStudio Bridge Installer ===== echo This will configure the bridge to work with Claude Desktop echo. :: Find Python location for /f "tokens=*" %%i in ('where python') do ( set PYTHON_PATH=%%i goto :found_python ) echo X ERROR: Python not found in your PATH echo Please install Python first and try again exit /b 1 :found_python echo v Found Python at: %PYTHON_PATH% :: Update the run_server.bat script with the correct Python path echo Updating run_server.bat with Python path... powershell -Command "(Get-Content run_server.bat) -replace 'SET PYTHON_PATH=.*', 'SET PYTHON_PATH=%PYTHON_PATH%' | Set-Content run_server.bat" :: Install required packages echo Installing required Python packages... "%PYTHON_PATH%" -m pip install "mcp[cli]" httpx :: Check if installation was successful "%PYTHON_PATH%" -c "import mcp" >nul 2>&1 if %ERRORLEVEL% NEQ 0 ( echo X ERROR: Failed to install MCP package echo Try running manually: "%PYTHON_PATH%" -m pip install "mcp[cli]" httpx exit /b 1 ) echo v MCP package installed successfully :: Get full path to the run_server.bat script set SCRIPT_DIR=%~dp0 set SCRIPT_PATH=%SCRIPT_DIR%run_server.bat echo Script path: %SCRIPT_PATH% :: Create or update Claude Desktop config set CONFIG_DIR=%APPDATA%\Claude set CONFIG_FILE=%CONFIG_DIR%\claude_desktop_config.json if not exist "%CONFIG_DIR%" mkdir "%CONFIG_DIR%" if exist "%CONFIG_FILE%" ( :: Backup existing config copy "%CONFIG_FILE%" "%CONFIG_FILE%.backup" >nul echo Created backup of existing config at %CONFIG_FILE%.backup :: Create new config file - we'll use a simple approach for Windows echo {> "%CONFIG_FILE%" echo "mcpServers": {>> "%CONFIG_FILE%" echo "lmstudio-bridge": {>> "%CONFIG_FILE%" echo "command": "cmd.exe",>> "%CONFIG_FILE%" echo "args": [>> "%CONFIG_FILE%" echo "/c",>> "%CONFIG_FILE%" echo "%SCRIPT_PATH:\=\\%">> "%CONFIG_FILE%" echo ]>> "%CONFIG_FILE%" echo }>> "%CONFIG_FILE%" echo }>> "%CONFIG_FILE%" echo }>> "%CONFIG_FILE%" ) else ( :: Create new config file echo {> "%CONFIG_FILE%" echo "mcpServers": {>> "%CONFIG_FILE%" echo "lmstudio-bridge": {>> "%CONFIG_FILE%" echo "command": "cmd.exe",>> "%CONFIG_FILE%" echo "args": [>> "%CONFIG_FILE%" echo "/c",>> "%CONFIG_FILE%" echo "%SCRIPT_PATH:\=\\%">> "%CONFIG_FILE%" echo ]>> "%CONFIG_FILE%" echo }>> "%CONFIG_FILE%" echo }>> "%CONFIG_FILE%" echo }>> "%CONFIG_FILE%" ) echo v Updated Claude Desktop configuration at %CONFIG_FILE% echo. echo v Installation complete! echo Please restart Claude Desktop to use the LMStudio bridge echo. echo If you encounter any issues, edit run_server.bat to check settings echo or refer to the README.md for troubleshooting steps. pause ``` -------------------------------------------------------------------------------- /verify_setup.py: -------------------------------------------------------------------------------- ```python #!/usr/bin/env python3 """ Verification script to check if all required packages are installed. This script will check for the presence of essential packages and their versions. """ import sys import subprocess import platform def check_python_version(): """Check if Python version is 3.8 or higher.""" version = sys.version_info if version.major < 3 or (version.major == 3 and version.minor < 8): print(f"❌ Python version too old: {platform.python_version()}") print(" MCP requires Python 3.8 or higher.") return False else: print(f"✅ Python version: {platform.python_version()}") return True def check_package(package_name): """Check if a package is installed and get its version.""" try: if package_name == "mcp": # Special handling for mcp to test import module = __import__(package_name) version = getattr(module, "__version__", "unknown") print(f"✅ {package_name} is installed (version: {version})") return True else: # Use pip to check other packages result = subprocess.run( [sys.executable, "-m", "pip", "show", package_name], capture_output=True, text=True ) if result.returncode == 0: for line in result.stdout.splitlines(): if line.startswith("Version:"): version = line.split(":", 1)[1].strip() print(f"✅ {package_name} is installed (version: {version})") return True print(f"❌ {package_name} is not installed") return False except ImportError: print(f"❌ {package_name} is not installed") return False except Exception as e: print(f"❌ Error checking {package_name}: {str(e)}") return False def check_environment(): """Check if running in a virtual environment.""" in_venv = hasattr(sys, "real_prefix") or ( hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix ) if in_venv: print(f"✅ Running in virtual environment: {sys.prefix}") return True else: print("⚠️ Not running in a virtual environment") print(" It's recommended to use a virtual environment for this project") return True # Not critical def main(): """Run all checks.""" print("🔍 Checking environment setup for Claude-LMStudio Bridge...") print("-" * 60) success = True # Check Python version if not check_python_version(): success = False # Check virtual environment check_environment() # Check essential packages required_packages = ["mcp", "httpx"] for package in required_packages: if not check_package(package): success = False print("-" * 60) if success: print("✅ All essential checks passed! Your environment is ready.") print("\nNext steps:") print("1. Run 'python test_mcp.py' to test MCP functionality") print("2. Run 'python debug_server.py' to test a simple MCP server") print("3. Run 'python server.py' to start the full bridge server") else: print("❌ Some checks failed. Please address the issues above.") print("\nCommon solutions:") print("1. Install MCP: pip install 'mcp[cli]'") print("2. Install httpx: pip install httpx") print("3. Upgrade Python to 3.8+: https://www.python.org/downloads/") return 0 if success else 1 if __name__ == "__main__": sys.exit(main()) ``` -------------------------------------------------------------------------------- /debug_lmstudio.py: -------------------------------------------------------------------------------- ```python #!/usr/bin/env python3 """ debug_lmstudio.py - Simple diagnostic tool for LM Studio connectivity This script tests the connection to LM Studio's API server and helps identify issues with the connection or API calls. """ import sys import json import traceback import argparse import os import httpx import asyncio # Set up command-line arguments parser = argparse.ArgumentParser(description="Test connection to LM Studio API") parser.add_argument("--host", default="127.0.0.1", help="LM Studio API host (default: 127.0.0.1)") parser.add_argument("--port", default="1234", help="LM Studio API port (default: 1234)") parser.add_argument("--test-prompt", action="store_true", help="Test with a simple prompt") parser.add_argument("--test-chat", action="store_true", help="Test with a simple chat message") parser.add_argument("--verbose", "-v", action="store_true", help="Show verbose output") args = parser.parse_args() # Configure API URL API_URL = f"http://{args.host}:{args.port}/v1" print(f"Testing connection to LM Studio API at {API_URL}") async def test_connection(): """Test basic connectivity to the LM Studio API server""" try: print("\n=== Testing basic connectivity ===") async with httpx.AsyncClient() as client: response = await client.get(f"{API_URL}/models", timeout=5.0) if response.status_code == 200: print("✅ Connection successful!") # Check for available models data = response.json() if "data" in data and isinstance(data["data"], list): if len(data["data"]) > 0: models = [model.get("id", "Unknown") for model in data["data"]] print(f"✅ Found {len(models)} available model(s): {', '.join(models)}") else: print("⚠️ No models are currently loaded in LM Studio") else: print("⚠️ Unexpected response format from models endpoint") if args.verbose: print("\nResponse data:") print(json.dumps(data, indent=2)) return True else: print(f"❌ Connection failed with status code: {response.status_code}") print(f"Response: {response.text[:200]}") return False except Exception as e: print(f"❌ Connection error: {str(e)}") if args.verbose: traceback.print_exc() return False async def test_completion(): """Test text completion API with a simple prompt""" if not await test_connection(): return False print("\n=== Testing text completion API ===") try: # Simple test prompt payload = { "prompt": "Hello, my name is", "max_tokens": 50, "temperature": 0.7, "stream": False } print("Sending test prompt: 'Hello, my name is'") async with httpx.AsyncClient() as client: response = await client.post( f"{API_URL}/completions", json=payload, timeout=10.0 ) if response.status_code == 200: data = response.json() if "choices" in data and len(data["choices"]) > 0: completion = data["choices"][0].get("text", "") print(f"✅ Received completion response: '{completion[:50]}...'") if args.verbose: print("\nFull response data:") print(json.dumps(data, indent=2)) return True else: print("❌ No completion text received in the response") print(f"Response: {json.dumps(data, indent=2)}") return False else: print(f"❌ Completion request failed with status code: {response.status_code}") print(f"Response: {response.text[:200]}") return False except Exception as e: print(f"❌ Error during completion test: {str(e)}") if args.verbose: traceback.print_exc() return False async def test_chat(): """Test chat completion API with a simple message""" if not await test_connection(): return False print("\n=== Testing chat completion API ===") try: # Simple test chat message payload = { "messages": [ {"role": "user", "content": "What is the capital of France?"} ], "max_tokens": 50, "temperature": 0.7, "stream": False } print("Sending test chat message: 'What is the capital of France?'") async with httpx.AsyncClient() as client: response = await client.post( f"{API_URL}/chat/completions", json=payload, timeout=10.0 ) if response.status_code == 200: data = response.json() if "choices" in data and len(data["choices"]) > 0: if "message" in data["choices"][0] and "content" in data["choices"][0]["message"]: message = data["choices"][0]["message"]["content"] print(f"✅ Received chat response: '{message[:50]}...'") if args.verbose: print("\nFull response data:") print(json.dumps(data, indent=2)) return True else: print("❌ No message content received in the response") print(f"Response: {json.dumps(data, indent=2)}") return False else: print("❌ No choices received in the response") print(f"Response: {json.dumps(data, indent=2)}") return False else: print(f"❌ Chat request failed with status code: {response.status_code}") print(f"Response: {response.text[:200]}") return False except Exception as e: print(f"❌ Error during chat test: {str(e)}") if args.verbose: traceback.print_exc() return False async def run_tests(): """Run all selected tests""" try: connection_ok = await test_connection() if args.test_prompt and connection_ok: await test_completion() if args.test_chat and connection_ok: await test_chat() if not args.test_prompt and not args.test_chat and connection_ok: # If no specific tests are requested, but connection is OK, # give a helpful message about next steps print("\n=== Next Steps ===") print("Connection to LM Studio API is working.") print("Try these additional tests:") print(" python debug_lmstudio.py --test-prompt # Test text completion") print(" python debug_lmstudio.py --test-chat # Test chat completion") print(" python debug_lmstudio.py -v --test-chat # Verbose test output") except Exception as e: print(f"❌ Unexpected error: {str(e)}") traceback.print_exc() # Run the tests if __name__ == "__main__": try: asyncio.run(run_tests()) except KeyboardInterrupt: print("\nTests interrupted.") sys.exit(1) ``` -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- ```python import sys import traceback import os import json import logging from typing import Any, Dict, List, Optional, Union from mcp.server.fastmcp import FastMCP import httpx # Configure logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", handlers=[ logging.StreamHandler(sys.stderr) ] ) # Print startup message logging.info("Starting LMStudio bridge server...") try: # ===== Configuration ===== # Load from environment variables with defaults LMSTUDIO_HOST = os.getenv("LMSTUDIO_HOST", "127.0.0.1") LMSTUDIO_PORT = os.getenv("LMSTUDIO_PORT", "1234") LMSTUDIO_API_URL = f"http://{LMSTUDIO_HOST}:{LMSTUDIO_PORT}/v1" DEBUG = os.getenv("DEBUG", "false").lower() in ("true", "1", "yes") # Set more verbose logging if debug mode is enabled if DEBUG: logging.getLogger().setLevel(logging.DEBUG) logging.debug(f"Debug mode enabled") logging.info(f"Configured LM Studio API URL: {LMSTUDIO_API_URL}") # Initialize FastMCP server mcp = FastMCP("lmstudio-bridge") # ===== Helper Functions ===== async def call_lmstudio_api(endpoint: str, payload: Dict[str, Any], timeout: float = 60.0) -> Dict[str, Any]: """Unified API communication function with better error handling""" headers = { "Content-Type": "application/json", "User-Agent": "claude-lmstudio-bridge/1.0" } url = f"{LMSTUDIO_API_URL}/{endpoint}" logging.debug(f"Making request to {url}") logging.debug(f"Payload: {json.dumps(payload, indent=2)}") try: async with httpx.AsyncClient() as client: response = await client.post( url, json=payload, headers=headers, timeout=timeout ) # Better error handling with specific error messages if response.status_code != 200: error_message = f"LM Studio API error: {response.status_code}" try: error_json = response.json() if "error" in error_json: if isinstance(error_json["error"], dict) and "message" in error_json["error"]: error_message += f" - {error_json['error']['message']}" else: error_message += f" - {error_json['error']}" except: error_message += f" - {response.text[:100]}" logging.error(f"Error response: {error_message}") return {"error": error_message} result = response.json() logging.debug(f"Response received: {json.dumps(result, indent=2, default=str)[:200]}...") return result except httpx.RequestError as e: logging.error(f"Request error: {str(e)}") return {"error": f"Connection error: {str(e)}"} except Exception as e: logging.error(f"Unexpected error: {str(e)}") return {"error": f"Unexpected error: {str(e)}"} def prepare_chat_messages(messages_input: Union[str, List, Dict]) -> List[Dict[str, str]]: """Convert various input formats to what LMStudio expects""" try: # If messages_input is a string if isinstance(messages_input, str): # Try to parse it as JSON try: parsed = json.loads(messages_input) if isinstance(parsed, list): return parsed else: # If it's parsed but not a list, make it a user message return [{"role": "user", "content": messages_input}] except json.JSONDecodeError: # If not valid JSON, assume it's a simple message return [{"role": "user", "content": messages_input}] # If it's a list already elif isinstance(messages_input, list): return messages_input # If it's a dict, assume it's a single message elif isinstance(messages_input, dict) and "content" in messages_input: if "role" not in messages_input: messages_input["role"] = "user" return [messages_input] # If it's some other format, convert to string and make it a user message else: return [{"role": "user", "content": str(messages_input)}] except Exception as e: logging.error(f"Error preparing chat messages: {str(e)}") # Fallback to simplest format return [{"role": "user", "content": str(messages_input)}] # ===== MCP Tools ===== @mcp.tool() async def check_lmstudio_connection() -> str: """Check if the LM Studio server is running and accessible. Returns: Connection status and model information """ try: # Try to get the server status via models endpoint async with httpx.AsyncClient() as client: response = await client.get(f"{LMSTUDIO_API_URL}/models", timeout=5.0) if response.status_code == 200: models_data = response.json() if "data" in models_data and len(models_data["data"]) > 0: active_model = models_data["data"][0]["id"] return f"✅ Connected to LM Studio. Active model: {active_model}" else: return "✅ Connected to LM Studio but no models are currently loaded" else: return f"❌ LM Studio returned an error: {response.status_code}" except Exception as e: return f"❌ Failed to connect to LM Studio: {str(e)}" @mcp.tool() async def list_lmstudio_models() -> str: """List available LLM models in LM Studio. Returns: A formatted list of available models with their details. """ logging.info("list_lmstudio_models function called") try: # Use the API helper function models_response = await call_lmstudio_api("models", {}, timeout=10.0) # Check for errors from the API helper if "error" in models_response: return f"Error listing models: {models_response['error']}" if not models_response or "data" not in models_response: return "No models found or unexpected response format." models = models_response["data"] model_info = [] for model in models: model_info.append(f"ID: {model.get('id', 'Unknown')}") model_info.append(f"Name: {model.get('name', 'Unknown')}") if model.get('description'): model_info.append(f"Description: {model.get('description')}") model_info.append("---") if not model_info: return "No models available in LM Studio." return "\n".join(model_info) except Exception as e: logging.error(f"Unexpected error in list_lmstudio_models: {str(e)}") traceback.print_exc(file=sys.stderr) return f"Unexpected error: {str(e)}" @mcp.tool() async def generate_text( prompt: str, model_id: str = "", max_tokens: int = 1000, temperature: float = 0.7 ) -> str: """Generate text using a local LLM in LM Studio. Args: prompt: The text prompt to send to the model model_id: ID of the model to use (leave empty for default model) max_tokens: Maximum number of tokens in the response (default: 1000) temperature: Randomness of the output (0-1, default: 0.7) Returns: The generated text from the local LLM """ logging.info("generate_text function called") try: # Validate inputs if not prompt or not prompt.strip(): return "Error: Prompt cannot be empty." if max_tokens < 1: return "Error: max_tokens must be a positive integer." if temperature < 0 or temperature > 1: return "Error: temperature must be between 0 and 1." # Prepare payload payload = { "prompt": prompt, "max_tokens": max_tokens, "temperature": temperature, "stream": False } # Add model if specified if model_id and model_id.strip(): payload["model"] = model_id.strip() # Make request to LM Studio API using the helper function response = await call_lmstudio_api("completions", payload) # Check for errors from the API helper if "error" in response: return f"Error generating text: {response['error']}" # Extract and return the generated text if "choices" in response and len(response["choices"]) > 0: return response["choices"][0].get("text", "") return "No response generated." except Exception as e: logging.error(f"Unexpected error in generate_text: {str(e)}") traceback.print_exc(file=sys.stderr) return f"Unexpected error: {str(e)}" @mcp.tool() async def chat_completion( messages: str, model_id: str = "", max_tokens: int = 1000, temperature: float = 0.7 ) -> str: """Generate a chat completion using a local LLM in LM Studio. Args: messages: JSON string of messages in the format [{"role": "user", "content": "Hello"}, ...] or a simple text string which will be treated as a user message model_id: ID of the model to use (leave empty for default model) max_tokens: Maximum number of tokens in the response (default: 1000) temperature: Randomness of the output (0-1, default: 0.7) Returns: The generated text from the local LLM """ logging.info("chat_completion function called") try: # Standardize message format using the helper function messages_formatted = prepare_chat_messages(messages) logging.debug(f"Formatted messages: {json.dumps(messages_formatted, indent=2)}") # Validate inputs if not messages_formatted: return "Error: At least one message is required." if max_tokens < 1: return "Error: max_tokens must be a positive integer." if temperature < 0 or temperature > 1: return "Error: temperature must be between 0 and 1." # Prepare payload payload = { "messages": messages_formatted, "max_tokens": max_tokens, "temperature": temperature, "stream": False } # Add model if specified if model_id and model_id.strip(): payload["model"] = model_id.strip() # Make request to LM Studio API using the helper function response = await call_lmstudio_api("chat/completions", payload) # Check for errors from the API helper if "error" in response: return f"Error generating chat completion: {response['error']}" # Extract and return the generated text if "choices" in response and len(response["choices"]) > 0: choice = response["choices"][0] if "message" in choice and "content" in choice["message"]: return choice["message"]["content"] return "No response generated." except Exception as e: logging.error(f"Unexpected error in chat_completion: {str(e)}") traceback.print_exc(file=sys.stderr) return f"Unexpected error: {str(e)}" if __name__ == "__main__": logging.info("Starting server with stdio transport...") # Initialize and run the server mcp.run(transport='stdio') except Exception as e: logging.critical(f"CRITICAL ERROR: {str(e)}") logging.critical("Traceback:") traceback.print_exc(file=sys.stderr) sys.exit(1) ```