Skip to content

Fix Issue #7: Implement automatic Pyodide download for uvx users#8

Merged
ohtaman merged 4 commits into
mainfrom
feature/add-ci-system
Aug 3, 2025
Merged

Fix Issue #7: Implement automatic Pyodide download for uvx users#8
ohtaman merged 4 commits into
mainfrom
feature/add-ci-system

Conversation

@ohtaman
Copy link
Copy Markdown
Owner

@ohtaman ohtaman commented Aug 2, 2025

Summary

Resolves #7 by implementing automatic Pyodide download functionality for users installing with uvx/pipx, eliminating "Pyodide module not found" errors.

Problem Addressed

  • uvx/pipx users experienced Pyodide initialization failures
  • No npm dependency management during Python package installation
  • Manual npm install requirement created friction and blocked usage

Solution: Hybrid Runtime Download System

🎯 Core Features

  • Automatic fallback: Downloads pyodide from npm registry if not found locally
  • Smart caching: Stores files in ~/.cache/mip-mcp/pyodide/ for fast subsequent runs
  • Universal compatibility: Works with uvx, pip, pipx, conda, any installation method
  • Zero npm dependency: Users don't need Node.js/npm installed
  • Robust error handling: Clear messages with manual installation fallback

🔧 Technical Implementation

  • _download_pyodide(): Downloads 12MB package from npm registry asynchronously
  • _extract_pyodide_package(): Extracts only required files (pyodide.js, pyodide.asm.wasm, python_stdlib.zip, etc.)
  • _find_or_download_pyodide_path(): Unified entry point with fallback logic
  • Cross-platform caching: Windows (%APPDATA%) and Unix (~/.cache) support
  • Async download: Non-blocking event loop using run_in_executor()

📈 User Experience Improvements

  • Seamless installation: uvx mip-mcp now "just works"
  • Fast subsequent runs: One-time download, permanent cache
  • No setup friction: Zero manual installation steps required
  • Clear error messages: Helpful fallback instructions if download fails

🏗️ Architecture Benefits

  • Backward compatible: Existing local pyodide detection unchanged
  • No build system changes: No pyproject.toml or dependency modifications
  • Superior to build hooks: Works with uvx/pipx (unlike setuptools approach)
  • Maintainable: Simple, focused solution without complex dependencies

Test Plan

  • Download functionality: Downloads from npm registry successfully (12MB)
  • File extraction: All required pyodide files extracted correctly
  • Caching system: Subsequent runs use cached files instantly
  • Pyodide initialization: WebAssembly environment starts properly with downloaded files
  • Complete MCP workflow: Problem generation (Pyodide) + solving (SCIP) working end-to-end
  • Cross-platform: Cache directory creation works on Windows/Unix

Files Changed

  • src/mip_mcp/executor/pyodide_executor.py: Added download and caching functionality (+111 lines)

Performance Impact

  • Initial run: +12MB download (one-time, with progress feedback)
  • Subsequent runs: Zero overhead (uses cached files)
  • Installation: No impact (no build-time downloads)

Breaking Changes

None - fully backward compatible with existing installations.

Benefits Over Alternative Solutions

Approach uvx Compatible npm Required Build Complexity User Experience
Runtime Download Yes No Low Excellent
setuptools build hooks Maybe Yes High Poor
Documentation only Yes Yes None Poor

Usage After This Change

# Before: Manual setup required
npm install pyodide
uvx mip-mcp

# After: Just works
uvx mip-mcp  # Automatically downloads pyodide on first run

This solution provides the optimal user experience while maintaining security, reliability, and broad compatibility across all Python installation methods.

🤖 Generated with Claude Code

ohtaman and others added 4 commits August 3, 2025 07:29
Major enhancement to resolve Pyodide initialization failures:

## Problem Solved
- uvx/pipx users experienced "Pyodide module not found" errors
- No mechanism to install npm dependencies during Python package installation
- Manual npm install requirement created friction for users

## Solution: Hybrid Runtime Download System

### Core Features
- **Automatic fallback**: Downloads pyodide from npm registry if not found locally
- **Smart caching**: Stores files in ~/.cache/mip-mcp/pyodide/ for fast subsequent runs
- **Universal compatibility**: Works with uvx, pip, pipx, conda, any installation method
- **No npm dependency**: Users don't need Node.js/npm installed
- **Robust error handling**: Clear messages with manual installation fallback

### Technical Implementation
- Add _download_pyodide() method for npm registry download (12MB)
- Add _extract_pyodide_package() for selective file extraction
- Add _find_or_download_pyodide_path() as unified entry point
- Cross-platform cache directory handling (Windows/Unix)
- Async download to prevent event loop blocking
- Extract only required files: pyodide.js, pyodide.asm.wasm, python_stdlib.zip, etc.

### User Experience Improvements
- Fast Python package installation (no build-time npm requirements)
- One-time 12MB download cached for future use
- Seamless experience: uvx mip-mcp "just works"
- Graceful degradation if download fails with helpful error messages

### Architecture Benefits
- Maintains existing local pyodide detection (backward compatible)
- No changes to build system or dependencies required
- No npm requirement at install time
- Better than setuptools build hooks (uvx/pipx compatible)

### Testing Results
- ✅ Download from npm registry successful
- ✅ All required files extracted and cached properly
- ✅ Pyodide initialization successful with downloaded files
- ✅ Complete MCP workflow verified: Problem generation + SCIP solving
- ✅ Cache reuse working for subsequent executions

Resolves #7

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replace runtime download approach with build-time bundling for better PyPI compatibility:

## Key Changes

### Build System (pyproject.toml)
- Add hatchling shared-data configuration to bundle node_modules/pyodide files
- Bundle 5 essential pyodide files (~12MB total) in wheel distribution:
  - pyodide.js, pyodide.asm.js, pyodide.asm.wasm
  - pyodide-lock.json, python_stdlib.zip

### Pyodide Path Detection (pyodide_executor.py)
- Add _check_bundled_pyodide() method to detect wheel-bundled files
- Update _find_pyodide_path() to check bundled location first
- Maintain backward compatibility with npm install workflow

## Benefits for PyPI Distribution

✅ **Self-contained wheels**: Perfect for `uv tool run mip-mcp`
✅ **Instant execution**: No runtime downloads or network dependencies
✅ **Offline capable**: Works in restricted environments/firewalls
✅ **Standard practice**: Follows industry patterns (PuLP, pyscipopt)
✅ **Clean repository**: No binary files in git (bundled only in wheels)

## Workflow Support

**Development**: `npm install` → local node_modules (unchanged)
**Distribution**: `uv build` → bundles pyodide in wheel → PyPI ready

## Technical Implementation
- Use pkg_resources.resource_filename() for bundled file access
- Bundled files stored in `mip_mcp/pyodide/` within wheel
- Graceful fallback to npm-installed pyodide for development
- Build process automatically includes existing node_modules files

This approach provides the optimal user experience for PyPI distribution while maintaining
clean development workflow and following established packaging patterns.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@ohtaman ohtaman merged commit c07d119 into main Aug 3, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix Pyodide initialization issue in MIP MCP server

1 participant