diff --git a/.github/workflows/build-executable.yml b/.github/workflows/build-executable.yml new file mode 100644 index 0000000..f828951 --- /dev/null +++ b/.github/workflows/build-executable.yml @@ -0,0 +1,189 @@ +name: Build Executables + +on: + push: + branches: [main] + tags: + - "v*" + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + build-windows: + name: Build Windows Executable + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for proper versioning + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install uv + run: python -m pip install uv + + - name: Create virtual environment + run: uv venv + + - name: Install dependencies + run: | + .venv\Scripts\activate + uv sync + + - name: Install PyInstaller + run: | + .venv\Scripts\activate + uv pip install pyinstaller + + - name: Build Windows executable + run: | + .venv\Scripts\activate + pyinstaller --clean authful-mcp-proxy.spec + + - name: Test executable + run: | + dist\authful-mcp-proxy.exe --help + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: authful-mcp-proxy-windows + path: dist/authful-mcp-proxy.exe + retention-days: 90 + + - name: Create release (on tag) + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v1 + with: + files: dist/authful-mcp-proxy.exe + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-macos: + name: Build macOS Executable + runs-on: macos-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install uv + run: python -m pip install uv + + - name: Create virtual environment + run: uv venv + + - name: Install dependencies + run: | + source .venv/bin/activate + uv sync + + - name: Install PyInstaller + run: | + source .venv/bin/activate + uv pip install pyinstaller + + - name: Build macOS executable + run: | + source .venv/bin/activate + pyinstaller --clean authful-mcp-proxy.spec + + - name: Test executable + run: | + ./dist/authful-mcp-proxy --help + + - name: Create DMG (optional) + run: | + # Install create-dmg if you want a .dmg file + brew install create-dmg + create-dmg --volname "Authful MCP Proxy" dist/authful-mcp-proxy.dmg dist/authful-mcp-proxy + # echo "Skipping DMG creation" + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: authful-mcp-proxy-macos + path: dist/authful-mcp-proxy.dmg + retention-days: 90 + + - name: Create release (on tag) + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v1 + with: + files: dist/authful-mcp-proxy.dmg + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-linux: + name: Build Linux Executable + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install uv + run: python -m pip install uv + + - name: Create virtual environment + run: uv venv + + - name: Install dependencies + run: | + source .venv/bin/activate + uv sync + + - name: Install PyInstaller + run: | + source .venv/bin/activate + uv pip install pyinstaller + + - name: Build Linux executable + run: | + source .venv/bin/activate + pyinstaller --clean authful-mcp-proxy.spec + + - name: Test executable + run: | + ./dist/authful-mcp-proxy --help + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: authful-mcp-proxy-linux + path: dist/authful-mcp-proxy + retention-days: 90 + + - name: Create release (on tag) + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v1 + with: + files: dist/authful-mcp-proxy + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 417c0eb..c8e9dc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,10 @@ -.env -mcp*.json - -# Python-generated files -__pycache__/ -*.py[oc] +/lib +/bin +# PyInstaller build artifacts +*.spec +!authful-mcp-proxy.spec +__main__.spec build/ dist/ -wheels/ -*.egg-info - -# Virtual environments -.venv/ - -# Log files -*.log - -# Coverage reports -.coverage -htmlcov/ -.pytest_cache/ - -# MCPB files -*.mcpb - -# VSCode settings -.vscode/PythonImportHelper-v2-Completion.json \ No newline at end of file +*.pyc +*.pyo diff --git a/BUILD_WINDOWS.md b/BUILD_WINDOWS.md new file mode 100644 index 0000000..f1ca099 --- /dev/null +++ b/BUILD_WINDOWS.md @@ -0,0 +1,246 @@ +# Building Windows Executable with PyInstaller + +This guide explains how to create a standalone Windows executable (.exe) for authful-mcp-proxy using PyInstaller. + +## Prerequisites + +- Python 3.10 or later installed on Windows +- Git (to clone the repository) +- Admin rights may be needed for some installations + +## Quick Start (Windows) + +1. **Clone the repository**: + + ```cmd + git clone https://github.com/yourusername/authful-mcp-proxy.git + cd authful-mcp-proxy + ``` + +2. **Set up the virtual environment**: + + ```cmd + python -m pip install uv + uv venv + bin\activate.bat + uv sync + ``` + +3. **Build the executable**: + + ```cmd + build_windows.bat + ``` + +4. **Find your executable**: + The executable will be in `dist\authful-mcp-proxy.exe` + +## Manual Build Steps + +If you prefer to build manually or the automated script doesn't work: + +1. **Activate virtual environment**: + + ```cmd + bin\activate.bat + ``` + +2. **Install PyInstaller**: + + ```cmd + pip install pyinstaller + ``` + +3. **Clean previous builds** (optional): + + ```cmd + rmdir /s /q build + rmdir /s /q dist + ``` + +4. **Build the executable**: + + ```cmd + pyinstaller --clean authful-mcp-proxy.spec + ``` + +5. **Test the executable**: + ```cmd + dist\authful-mcp-proxy.exe --help + ``` + +## Using the Windows Executable + +### With Claude Desktop + +Once built, you can use the executable directly in your Claude Desktop configuration: + +```jsonc +{ + "mcpServers": { + "my-protected-server": { + "command": "C:\\path\\to\\authful-mcp-proxy.exe", + "args": ["https://mcp-backend.company.com/mcp"], + "env": { + "OIDC_ISSUER_URL": "https://auth.company.com", + "OIDC_CLIENT_ID": "your-client-id", + }, + }, + }, +} +``` + +**Important Notes:** + +- Use double backslashes (`\\`) in Windows paths +- Use the full absolute path to the .exe file +- Make sure the OIDC client has `http://localhost:8080/auth/callback` as an allowed redirect URI + +### Standalone Usage + +You can also run the executable directly from the command line: + +```cmd +authful-mcp-proxy.exe ^ + --oidc-issuer-url https://auth.company.com ^ + --oidc-client-id your-client-id ^ + https://mcp-backend.company.com/mcp +``` + +## Customizing the Build + +### Spec File Configuration + +The [authful-mcp-proxy.spec](authful-mcp-proxy.spec) file controls the build process. Key sections: + +- **`hiddenimports`**: Add any missing Python modules +- **`datas`**: Include additional data files +- **`excludes`**: Remove unnecessary packages to reduce size +- **`console=True`**: Must be True for MCP stdio communication + +### Adding an Icon + +To add a custom icon to your executable: + +1. Create or obtain a `.ico` file +2. Edit `authful-mcp-proxy.spec` and change: + ```python + icon=None, # Change to: icon='path/to/your/icon.ico' + ``` +3. Rebuild with `pyinstaller --clean authful-mcp-proxy.spec` + +### Reducing Executable Size + +The executable is ~8-10 MB. To reduce size: + +1. **Remove UPX compression** (if causing issues): + + ```python + upx=False, # In the spec file + ``` + +2. **Exclude more packages**: + ```python + excludes=[ + 'tkinter', + 'matplotlib', + 'numpy', + 'pandas', + 'test', + 'unittest', + ], + ``` + +## Troubleshooting + +### Build Fails with "Module Not Found" + +Add the missing module to `hiddenimports` in the spec file: + +```python +hiddenimports=[ + 'your_missing_module', + # ... other imports +], +``` + +### Executable Doesn't Run on Other Windows Machines + +Make sure you're building on the oldest Windows version you want to support. Executables built on newer Windows versions may not work on older ones. + +Alternatively, install the Microsoft Visual C++ Redistributable on the target machine. + +### "Access Denied" or Antivirus Warnings + +Some antivirus software flags PyInstaller executables as suspicious. To fix: + +1. Add an exception in your antivirus for the executable +2. Code sign the executable (requires a code signing certificate) +3. Upload the executable to VirusTotal and wait for AV vendors to whitelist it + +### Executable is Too Large + +- Remove unnecessary dependencies from the spec file's `excludes` list +- Use `--onefile` mode (creates a larger exe but no separate folder) +- Strip debug symbols (already done by default) + +### Testing Without Windows + +You cannot cross-compile Windows executables on macOS/Linux with PyInstaller. You need: + +- A Windows machine or VM +- Wine (on Linux, experimental) +- Windows in Docker (limited support) + +## Distribution + +### Single File Distribution + +The current configuration creates a single-file executable (`--onefile` mode) that includes all dependencies. Simply distribute `dist\authful-mcp-proxy.exe`. + +### Folder Distribution + +If you prefer faster startup time, modify the spec file to use folder mode: + +```python +# Comment out or remove the '--onefile' behavior by using separate EXE/COLLECT +``` + +Then distribute the entire `dist\authful-mcp-proxy\` folder. + +## Security Considerations + +1. **Code Signing**: Consider signing the executable to avoid security warnings +2. **Credentials**: The executable will store OIDC tokens in `%USERPROFILE%\.fastmcp\oauth-mcp-client-cache\` +3. **Source Code**: The Python source code is embedded but somewhat obfuscated in the executable + +## Advanced Options + +### Debug Build + +To create a debug build with console output: + +```cmd +pyinstaller --clean --debug all authful-mcp-proxy.spec +``` + +### Custom Python Environment + +If you need a specific Python version: + +```cmd +C:\Python310\python.exe -m venv venv +venv\Scripts\activate +pip install -r requirements.txt +pyinstaller authful-mcp-proxy.spec +``` + +## Getting Help + +- Check the [PyInstaller documentation](https://pyinstaller.org/) +- Review the [main README](README.md) for usage instructions +- Open an issue on GitHub with build errors + +## License + +This build configuration is part of authful-mcp-proxy and follows the same license as the main project. diff --git a/README_BUILD.md b/README_BUILD.md new file mode 100644 index 0000000..a961907 --- /dev/null +++ b/README_BUILD.md @@ -0,0 +1,296 @@ +# Windows Executable Build Summary + +This document summarizes the PyInstaller setup for building Windows executables of authful-mcp-proxy. + +## Files Created + +### 1. **authful-mcp-proxy.spec** + +PyInstaller specification file that defines: + +- Entry point: `run_proxy.py` +- All dependencies (fastmcp, httpx, httpcore, h11, certifi, etc.) +- Package metadata for version detection +- Console mode configuration (required for MCP stdio) +- Exclusions to reduce executable size + +### 2. **run_proxy.py** + +Simplified entry point script that: + +- Handles both frozen (PyInstaller) and normal Python execution +- Properly configures sys.path for imports +- Calls the main() function from authful_mcp_proxy + +### 3. **build_windows.bat** + +Windows batch script that: + +- Activates the virtual environment +- Installs PyInstaller if needed +- Cleans previous build artifacts +- Builds the executable +- Reports build status and usage instructions + +### 4. **build_executable.sh** + +Unix/macOS/Linux shell script that builds for the host platform: + +- Same functionality as the .bat file +- Builds native executables for macOS/Linux +- Useful for developers on Unix-like systems + +### 5. **BUILD_WINDOWS.md** + +Comprehensive documentation covering: + +- Prerequisites and installation +- Quick start and manual build instructions +- Usage with Claude Desktop and other MCP clients +- Customization options (icons, size optimization, etc.) +- Troubleshooting common issues +- Distribution and security considerations + +### 6. **WINDOWS_USAGE.md** + +User-friendly guide for end-users: + +- Download and setup instructions +- Claude Desktop configuration examples +- Command-line usage +- Configuration options reference +- Common issues and solutions +- Provider-specific examples (Keycloak, Azure AD, Auth0, Okta) + +## Building the Executable + +### On Windows + +```cmd +REM 1. Set up the environment +git clone +cd authful-mcp-proxy +python -m pip install uv +uv venv +.venv\Scripts\activate +uv sync +uv pip install pyinstaller + +REM 2. Build the executable +build_windows.bat + +REM Output: dist\authful-mcp-proxy.exe (~25MB) +``` + +### On macOS/Linux (for testing only) + +**⚠️ Important**: PyInstaller does NOT support cross-compilation. Running the build script on macOS/Linux will create a macOS/Linux executable, **NOT a Windows .exe**. + +```bash +# 1. Set up the environment +git clone +cd authful-mcp-proxy +python -m pip install uv +uv venv +source .venv/bin/activate +uv sync +uv pip install pyinstaller + +# 2. Build the executable (creates native macOS/Linux binary) +./build_executable.sh + +# Output: dist/authful-mcp-proxy (native macOS/Linux executable) +``` + +#### To Build Actual Windows .exe from macOS/Linux + +Since PyInstaller cannot cross-compile, use one of these methods: + +1. **GitHub Actions** (Recommended - see CI/CD section below) +2. **Windows Virtual Machine** (VirtualBox, Parallels, VMware) +3. **Cloud Windows Instance** (AWS EC2, Azure VM) +4. **Wine on Linux** (experimental, may fail with complex dependencies) + +## Key Technical Details + +### Dependencies Included + +- **fastmcp**: MCP server framework +- **httpx**: HTTP client for backend communication +- **httpcore**: Low-level HTTP transport +- **h11**: HTTP/1.1 protocol implementation +- **certifi**: SSL certificates +- **cryptography**: Cryptographic operations for OIDC +- **authlib**: OAuth/OIDC client library +- **pydantic**: Data validation +- All Python standard library modules needed + +### Package Metadata + +The spec file includes metadata for: + +- `fastmcp` - required for version detection +- `authful-mcp-proxy` - application version +- `httpx` - HTTP client metadata +- `mcp` - MCP protocol metadata + +### Entry Point Strategy + +Instead of using `src/authful_mcp_proxy/__main__.py` directly, we use `run_proxy.py`: + +- Avoids issues with relative imports in frozen executables +- Properly handles `sys._MEIPASS` for PyInstaller temp directory +- Ensures the source path is correctly configured + +### Executable Configuration + +- **Console Mode**: `console=True` is required for MCP stdio communication +- **UPX Compression**: Enabled to reduce size (can be disabled if causing issues) +- **Single File**: Creates a single .exe with all dependencies bundled +- **Architecture**: Builds for the host architecture (x86_64 or ARM) + +## Testing the Build + +```bash +# Test help command +./dist/authful-mcp-proxy --help + +# Test version +./dist/authful-mcp-proxy --version + +# Test with minimal args (will fail authentication but validates imports) +./dist/authful-mcp-proxy --oidc-issuer-url https://example.com --oidc-client-id test https://example.com/mcp +``` + +## Distribution + +### Files to Distribute + +- **Single file**: `dist/authful-mcp-proxy.exe` +- **Documentation**: README.md, WINDOWS_USAGE.md + +### Size + +- Approximately 25 MB for the macOS build +- Windows build will be similar (20-30 MB) + +### Requirements for End Users + +- Windows 10 or later (or macOS for the Mac build) +- No Python installation required +- Network access for OIDC authentication +- Browser for OAuth flow + +## Troubleshooting Build Issues + +### Missing Modules + +If you get `ModuleNotFoundError` when running the executable: + +1. Add the module to `hiddenimports` in the spec file +2. Rebuild with `pyinstaller --clean authful-mcp-proxy.spec` + +### Metadata Errors + +If you get `PackageNotFoundError` for package metadata: + +1. Add `copy_metadata('package-name')` to the spec file +2. Rebuild + +### Import Errors + +If relative imports fail: + +1. Check that `run_proxy.py` is the entry point +2. Verify `pathex` includes the src directory +3. Ensure all modules are in `hiddenimports` + +### Large Executable Size + +To reduce size: + +1. Add more packages to `excludes` list +2. Disable UPX: set `upx=False` +3. Use folder mode instead of onefile (modify spec) + +## Notes for Windows Build + +When building on actual Windows: + +- Replace `.venv/bin/activate` with `.venv\Scripts\activate.bat` +- Use `build_windows.bat` instead of `./build_executable.sh` +- The output will be `dist\authful-mcp-proxy.exe` +- Windows Defender may flag the executable initially +- Consider code signing for production distribution + +## CI/CD Integration + +### GitHub Actions (Recommended) + +A complete GitHub Actions workflow has been created at [`.github/workflows/build-executable.yml`](.github/workflows/build-executable.yml). + +This workflow: + +- ✅ Builds executables for **Windows**, **macOS**, and **Linux** +- ✅ Runs on every push and pull request +- ✅ Tests the executable with `--help` command +- ✅ Uploads build artifacts (available for 90 days) +- ✅ Automatically creates GitHub Releases when you push a version tag + +#### How to Use + +1. **Enable the workflow** (it's already in your repo) +2. **Push a tag to create a release**: + ```bash + git tag v1.0.0 + git push origin v1.0.0 + ``` +3. **Download artifacts**: + - Go to Actions → Build Executables → Click on a run + - Download `authful-mcp-proxy-windows`, `authful-mcp-proxy-macos`, or `authful-mcp-proxy-linux` + +#### Manual Workflow Snippet + +For custom CI/CD systems, here's a minimal example: + +```yaml +- name: Build Windows Executable + run: | + python -m pip install uv + uv venv + .venv\Scripts\activate + uv sync + uv pip install pyinstaller + pyinstaller --clean authful-mcp-proxy.spec + +- name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: authful-mcp-proxy-windows + path: dist/authful-mcp-proxy.exe +``` + +## Version Management + +The executable includes version information from git tags: + +- Version is automatically detected from `importlib.metadata` +- Development versions show git commit hash +- Release versions show semantic version (e.g., "1.0.0") + +## Security Considerations + +1. **Code Signing**: Consider signing the executable for production +2. **Secrets**: Never embed OIDC client secrets in the executable +3. **Updates**: Provide a mechanism for users to update to new versions +4. **Antivirus**: Test with major antivirus software +5. **Credentials**: Stored in `%USERPROFILE%\.fastmcp\oauth-mcp-client-cache\` + +## Support + +For issues or questions: + +- Check [BUILD_WINDOWS.md](BUILD_WINDOWS.md) for detailed instructions +- Review [WINDOWS_USAGE.md](WINDOWS_USAGE.md) for user guidance +- Check the main [README.md](README.md) for general documentation +- Open an issue on GitHub diff --git a/WINDOWS_USAGE.md b/WINDOWS_USAGE.md new file mode 100644 index 0000000..42ab225 --- /dev/null +++ b/WINDOWS_USAGE.md @@ -0,0 +1,301 @@ +# Windows Executable Usage Guide + +Quick reference for using the pre-built Windows executable of authful-mcp-proxy. + +## Download + +Get the latest Windows executable from: + +- GitHub Releases page (if available) +- Build it yourself following [BUILD_WINDOWS.md](BUILD_WINDOWS.md) + +## Quick Setup + +### 1. Place the Executable + +Copy `authful-mcp-proxy.exe` to a permanent location, for example: + +``` +C:\Program Files\authful-mcp-proxy\authful-mcp-proxy.exe +``` + +Or a user directory: + +``` +C:\Users\YourName\Tools\authful-mcp-proxy.exe +``` + +### 2. Configure Claude Desktop + +Open Claude Desktop settings: + +- Click **Settings** → **Developer** → **Edit Config** + +Add your server configuration: + +```jsonc +{ + "mcpServers": { + "my-server": { + "command": "C:\\Program Files\\authful-mcp-proxy\\authful-mcp-proxy.exe", + "args": ["https://your-mcp-backend.com/mcp"], + "env": { + "OIDC_ISSUER_URL": "https://your-auth-server.com", + "OIDC_CLIENT_ID": "your-client-id", + }, + }, + }, +} +``` + +**Important:** + +- Use double backslashes (`\\`) in paths +- Use the full absolute path to the executable +- Configure your OIDC client with redirect URI: `http://localhost:8080/auth/callback` + +### 3. Restart Claude Desktop + +Close and reopen Claude Desktop to load the new configuration. + +### 4. First Run + +On first use: + +1. Claude Desktop will launch the proxy +2. Your browser will open for authentication +3. Sign in to your OIDC provider +4. Approve the requested scopes +5. Return to Claude Desktop + +Your credentials will be cached in: + +``` +C:\Users\YourName\.fastmcp\oauth-mcp-client-cache\ +``` + +## Command Line Usage + +You can also run the executable directly: + +```cmd +authful-mcp-proxy.exe --help +``` + +### Basic Example + +```cmd +authful-mcp-proxy.exe ^ + --oidc-issuer-url https://auth.example.com ^ + --oidc-client-id my-client-id ^ + https://mcp.example.com/mcp +``` + +### With Client Secret + +```cmd +authful-mcp-proxy.exe ^ + --oidc-issuer-url https://auth.example.com ^ + --oidc-client-id my-client-id ^ + --oidc-client-secret my-secret ^ + --oidc-scopes "openid profile email api:access" ^ + https://mcp.example.com/mcp +``` + +### Debug Mode + +```cmd +authful-mcp-proxy.exe --debug https://mcp.example.com/mcp +``` + +## Configuration Options + +### Environment Variables + +Set these in your system or in the `env` block of your Claude Desktop config: + +| Variable | Required | Default | Description | +| -------------------- | -------- | ------------------------------------- | ------------------------------------ | +| `MCP_BACKEND_URL` | Yes\* | - | Backend MCP server URL | +| `OIDC_ISSUER_URL` | Yes | - | OIDC issuer URL | +| `OIDC_CLIENT_ID` | Yes | - | OAuth client ID | +| `OIDC_CLIENT_SECRET` | No | - | OAuth client secret | +| `OIDC_SCOPES` | No | `openid profile email` | Space-separated scopes | +| `OIDC_REDIRECT_URL` | No | `http://localhost:8080/auth/callback` | OAuth redirect URL | +| `MCP_PROXY_DEBUG` | No | `0` | Enable debug logging (1/true/yes/on) | + +\* Can be provided as first command-line argument instead + +### Command-Line Flags + +``` +authful-mcp-proxy.exe [OPTIONS] + +Options: + --oidc-issuer-url URL OIDC issuer URL + --oidc-client-id ID OAuth client ID + --oidc-client-secret SEC OAuth client secret (optional) + --oidc-scopes SCOPES Space-separated OAuth scopes + --oidc-redirect-url URL OAuth redirect URL + --no-banner Don't show startup banner + --silent Show only errors + --debug Enable debug logging + --help Show help message +``` + +## Common Issues + +### "Windows protected your PC" + +Windows SmartScreen may block unsigned executables: + +1. Click **More info** +2. Click **Run anyway** + +To avoid this permanently: + +- Code sign the executable (requires certificate) +- Add to Windows Defender exclusions + +### Browser Doesn't Open + +1. Check if port 8080 is available +2. Manually open the URL shown in logs +3. Check firewall settings + +### "The system cannot find the path specified" + +1. Verify the executable path is correct +2. Use absolute paths, not relative +3. Use double backslashes in JSON: `C:\\path\\to\\file.exe` + +### 401 Unauthorized + +1. Verify OIDC configuration is correct +2. Check scopes are approved +3. Clear cached credentials: + ```cmd + rmdir /s "%USERPROFILE%\.fastmcp\oauth-mcp-client-cache" + ``` +4. Try again with `--debug` flag + +### Antivirus Blocks Execution + +1. Add executable to antivirus exclusions +2. Use a different antivirus that doesn't flag PyInstaller executables +3. Build from source on your own machine + +## Updating + +To update to a new version: + +1. Download/build the new executable +2. Stop Claude Desktop +3. Replace the old .exe file +4. Restart Claude Desktop + +Your cached credentials will be preserved. + +## Uninstalling + +1. Stop Claude Desktop +2. Remove the executable file +3. Remove from Claude Desktop config +4. (Optional) Delete cached credentials: + ```cmd + rmdir /s "%USERPROFILE%\.fastmcp\oauth-mcp-client-cache" + ``` + +## Security Notes + +### Credential Storage + +OAuth tokens are stored in: + +``` +%USERPROFILE%\.fastmcp\oauth-mcp-client-cache\ +``` + +These files contain sensitive access tokens. Protect them: + +- Don't share these files +- Don't commit them to version control +- Use Windows file permissions to restrict access + +### HTTPS Required + +Always use HTTPS URLs for: + +- MCP backend servers +- OIDC issuer URLs +- OAuth redirect URLs (except localhost) + +### Client Secrets + +If using a client secret: + +- Don't hardcode in config files that are shared +- Use Windows environment variables +- Consider using Windows Credential Manager + +## Getting Help + +- Full documentation: [README.md](README.md) +- Build instructions: [BUILD_WINDOWS.md](BUILD_WINDOWS.md) +- GitHub Issues: Report bugs and ask questions + +## Example Configurations + +### Keycloak + +```jsonc +{ + "command": "C:\\Tools\\authful-mcp-proxy.exe", + "args": ["https://api.example.com/mcp"], + "env": { + "OIDC_ISSUER_URL": "https://keycloak.example.com/realms/myrealm", + "OIDC_CLIENT_ID": "mcp-client", + }, +} +``` + +### Azure AD / Entra ID + +```jsonc +{ + "command": "C:\\Tools\\authful-mcp-proxy.exe", + "args": ["https://api.example.com/mcp"], + "env": { + "OIDC_ISSUER_URL": "https://login.microsoftonline.com/{tenant-id}/v2.0", + "OIDC_CLIENT_ID": "your-app-id", + "OIDC_SCOPES": "openid profile email api://your-api/.default", + }, +} +``` + +### Auth0 + +```jsonc +{ + "command": "C:\\Tools\\authful-mcp-proxy.exe", + "args": ["https://api.example.com/mcp"], + "env": { + "OIDC_ISSUER_URL": "https://your-domain.auth0.com", + "OIDC_CLIENT_ID": "your-client-id", + "OIDC_SCOPES": "openid profile email offline_access", + }, +} +``` + +### Okta + +```jsonc +{ + "command": "C:\\Tools\\authful-mcp-proxy.exe", + "args": ["https://api.example.com/mcp"], + "env": { + "OIDC_ISSUER_URL": "https://your-domain.okta.com/oauth2/default", + "OIDC_CLIENT_ID": "your-client-id", + }, +} +``` diff --git a/authful-mcp-proxy.spec b/authful-mcp-proxy.spec new file mode 100644 index 0000000..1228908 --- /dev/null +++ b/authful-mcp-proxy.spec @@ -0,0 +1,106 @@ +# -*- mode: python ; coding: utf-8 -*- +""" +PyInstaller spec file for authful-mcp-proxy Windows executable. + +This spec file creates a standalone executable for Windows that includes: +- All Python dependencies (fastmcp, httpx, etc.) +- Hidden imports for OIDC and async libraries +- Proper console configuration for MCP stdio communication +""" + +import os +import sys +from PyInstaller.utils.hooks import collect_data_files, collect_submodules, copy_metadata + +# Get the project root directory +block_cipher = None +project_root = os.path.abspath(SPECPATH) + +# Collect hidden imports for fastmcp and related packages +hiddenimports = [ + 'authful_mcp_proxy', + 'authful_mcp_proxy.__main__', + 'authful_mcp_proxy.__init__', + 'authful_mcp_proxy.config', + 'authful_mcp_proxy.external_oidc', + 'authful_mcp_proxy.mcp_proxy', + 'fastmcp', + 'httpx', + 'httpx._client', + 'httpx._config', + 'httpx._models', + 'httpcore', + 'h11', + 'certifi', + 'asyncio', + 'json', + 'webbrowser', + 'urllib.parse', + 'base64', + 'hashlib', + 'secrets', + 'pathlib', + 'importlib.metadata', + 'logging', + 'argparse', +] + +# Collect all submodules from fastmcp (may have hidden dependencies) +hiddenimports.extend(collect_submodules('fastmcp')) +hiddenimports.extend(collect_submodules('httpx')) + +# Collect data files from packages if needed +datas = [] +datas += collect_data_files('fastmcp', include_py_files=True) +# Copy package metadata for version detection +datas += copy_metadata('fastmcp') +datas += copy_metadata('authful-mcp-proxy', recursive=True) +datas += copy_metadata('httpx') +datas += copy_metadata('mcp') + +a = Analysis( + ['run_proxy.py'], + pathex=[os.path.join(project_root, 'src')], + binaries=[], + datas=datas, + hiddenimports=hiddenimports, + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[ + 'tkinter', + 'matplotlib', + 'numpy', + 'pandas', + 'IPython', + 'jupyter', + ], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) + +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='authful-mcp-proxy', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, # Must be True for MCP stdio communication + disable_windowed_traceback=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon=None, # Add .ico file path here if you have an icon +) diff --git a/build_executable.sh b/build_executable.sh new file mode 100755 index 0000000..e17a183 --- /dev/null +++ b/build_executable.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# Build script for creating native executable with PyInstaller +# +# This script: +# 1. Activates the virtual environment +# 2. Installs PyInstaller if needed +# 3. Builds the executable for the host platform using the spec file +# 4. Reports the output location + +set -e + +echo "========================================" +echo "Building authful-mcp-proxy executable" +echo "========================================" +echo + +# Check if virtual environment exists +if [ -f ".venv/bin/activate" ]; then + VENV_ACTIVATE=".venv/bin/activate" +elif [ -f "bin/activate" ]; then + VENV_ACTIVATE="bin/activate" +else + echo "ERROR: Virtual environment not found!" + echo "Please run: uv venv" + echo "Then run: source .venv/bin/activate" + echo "Then run: uv sync" + exit 1 +fi + +# Activate virtual environment +echo "Activating virtual environment from $VENV_ACTIVATE..." +source "$VENV_ACTIVATE" + +# Check if PyInstaller is installed +if ! python -c "import PyInstaller" 2>/dev/null; then + echo "PyInstaller not found. Installing..." + if command -v uv &> /dev/null; then + uv pip install pyinstaller + else + python -m pip install pyinstaller + fi +fi + +# Clean previous build artifacts +echo +echo "Cleaning previous build artifacts..." +rm -rf build dist + +# Build the executable +echo +echo "Building executable with PyInstaller..." +pyinstaller --clean authful-mcp-proxy.spec + +# Check if build was successful +if [ -f "dist/authful-mcp-proxy.exe" ] || [ -f "dist/authful-mcp-proxy" ]; then + echo + echo "========================================" + echo "Build completed successfully!" + echo "========================================" + if [ -f "dist/authful-mcp-proxy.exe" ]; then + echo "Executable location: dist/authful-mcp-proxy.exe" + else + echo "Executable location: dist/authful-mcp-proxy" + fi + echo + echo "You can now:" + echo "1. Copy the executable to your desired location" + echo "2. Configure it in Claude Desktop like:" + echo + echo ' "command": "C:\\path\\to\\authful-mcp-proxy.exe",' + echo ' "args": ["https://your-mcp-backend.com/mcp"],' + echo ' "env": {' + echo ' "OIDC_ISSUER_URL": "https://your-auth-server.com",' + echo ' "OIDC_CLIENT_ID": "your-client-id"' + echo ' }' + echo +else + echo + echo "========================================" + echo "Build FAILED!" + echo "========================================" + echo "Please check the error messages above." + exit 1 +fi diff --git a/build_windows.bat b/build_windows.bat new file mode 100644 index 0000000..a2ffff6 --- /dev/null +++ b/build_windows.bat @@ -0,0 +1,81 @@ +@echo off +REM Build script for creating Windows executable with PyInstaller +REM +REM This script: +REM 1. Activates the virtual environment +REM 2. Installs PyInstaller if needed +REM 3. Builds the Windows executable using the spec file +REM 4. Reports the output location + +echo ======================================== +echo Building authful-mcp-proxy for Windows +echo ======================================== +echo. + +REM Check if virtual environment exists +if exist ".venv\Scripts\activate.bat" ( + set VENV_ACTIVATE=.venv\Scripts\activate.bat +) else if exist "bin\activate.bat" ( + set VENV_ACTIVATE=bin\activate.bat +) else ( + echo ERROR: Virtual environment not found! + echo Please run: uv venv + echo Then run: .venv\Scripts\activate.bat + echo Then run: uv sync + exit /b 1 +) + +REM Activate virtual environment +echo Activating virtual environment from %VENV_ACTIVATE%... +call %VENV_ACTIVATE% + +REM Check if PyInstaller is installed +python -c "import PyInstaller" 2>nul +if errorlevel 1 ( + echo PyInstaller not found. Installing... + where uv >nul 2>nul + if errorlevel 1 ( + python -m pip install pyinstaller + ) else ( + uv pip install pyinstaller + ) +) + +REM Clean previous build artifacts +echo. +echo Cleaning previous build artifacts... +if exist "build" rmdir /s /q build +if exist "dist" rmdir /s /q dist + +REM Build the executable +echo. +echo Building executable with PyInstaller... +pyinstaller --clean authful-mcp-proxy.spec + +REM Check if build was successful +if exist "dist\authful-mcp-proxy.exe" ( + echo. + echo ======================================== + echo Build completed successfully! + echo ======================================== + echo Executable location: dist\authful-mcp-proxy.exe + echo. + echo You can now: + echo 1. Copy dist\authful-mcp-proxy.exe to your desired location + echo 2. Configure it in Claude Desktop like: + echo. + echo "command": "C:\\path\\to\\authful-mcp-proxy.exe", + echo "args": ["https://your-mcp-backend.com/mcp"], + echo "env": { + echo "OIDC_ISSUER_URL": "https://your-auth-server.com", + echo "OIDC_CLIENT_ID": "your-client-id" + echo } + echo. +) else ( + echo. + echo ======================================== + echo Build FAILED! + echo ======================================== + echo Please check the error messages above. + exit /b 1 +) diff --git a/pyproject.toml b/pyproject.toml index 294970c..c8295b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,9 +73,12 @@ extend-select = ["I", "UP"] "__init__.py" = ["F401", "I001", "RUF013"] # allow imports not at the top of the file "src/authful_mcp_proxy/__init__.py" = ["E402"] +# PyInstaller entry point - exclude from type checking +"run_proxy.py" = ["F401"] [tool.codespell] -skip = "*.lock,pyproject.toml,*PythonImportHelper*" +skip = "*.lock,pyproject.toml,*PythonImportHelper*,*.spec" +ignore-words-list = "datas" [tool.pytest.ini_options] minversion = "7.0" diff --git a/pyvenv.cfg b/pyvenv.cfg new file mode 100644 index 0000000..8519d02 --- /dev/null +++ b/pyvenv.cfg @@ -0,0 +1,5 @@ +home = /usr/local/opt/python@3.13/bin +include-system-site-packages = false +version = 3.13.3 +executable = /usr/local/Cellar/python@3.13/3.13.3/Frameworks/Python.framework/Versions/3.13/bin/python3.13 +command = /usr/local/opt/python@3.13/bin/python3.13 -m venv /Users/Schwertfeger/git/authful-mcp-proxy diff --git a/run_proxy.py b/run_proxy.py new file mode 100644 index 0000000..99a6cfb --- /dev/null +++ b/run_proxy.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +""" +Entry point script for PyInstaller. + +This script serves as the main entry point for the frozen executable, +avoiding issues with relative imports in __main__.py. +""" + +import os +import sys + +# Ensure the src directory is in the path for frozen executables +if getattr(sys, "frozen", False): + # Running as compiled executable + # sys._MEIPASS is set by PyInstaller at runtime + application_path = sys._MEIPASS # type: ignore[attr-defined] +else: + # Running as script + application_path = os.path.dirname(os.path.abspath(__file__)) + sys.path.insert(0, os.path.join(application_path, "src")) + +# Import and run the main function +from authful_mcp_proxy.__main__ import main + +if __name__ == "__main__": + main()