diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 1fa9db0..9077195 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -45,7 +45,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements-dev.txt + pip install -e .[dev] - name: Run tests run: pytest tests/ -m "not api_health" -q diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7ac39e0..78bdb03 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements-dev.txt + pip install -e .[dev] - name: Run unit tests with coverage run: | @@ -57,7 +57,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements-dev.txt + pip install -e .[dev] - name: Run black (check only) run: | diff --git a/Dockerfile b/Dockerfile index 18714a7..306fa7f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,16 +18,16 @@ RUN apt-get update && \ gcc \ && rm -rf /var/lib/apt/lists/* -# Copy requirements first for better layer caching -COPY requirements.txt . +# Copy package files for better layer caching +COPY pyproject.toml . +COPY README.md . # Install Python dependencies -RUN pip install --no-cache-dir -r requirements.txt +RUN pip install --no-cache-dir . # Copy application code COPY nadlan_mcp/ ./nadlan_mcp/ COPY run_http_server.py . -COPY README.md . # Create non-root user for security RUN useradd -m -u 1000 appuser && \ diff --git a/README.md b/README.md index bd602a2..0341907 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,14 @@ This project provides a comprehensive Python interface to the Israeli government source venv/bin/activate ``` -4. **Install required packages:** +4. **Install the package:** ```bash - pip install -r requirements.txt + pip install -e . + ``` + + Or for development with all dev dependencies: + ```bash + pip install -e .[dev] ``` ## Usage @@ -298,7 +303,7 @@ python -c "import logging; logging.basicConfig(level=logging.DEBUG)" run_mcp_ser #### Troubleshooting **Connection Issues:** -- Ensure all dependencies are installed: `pip install -r requirements.txt` +- Ensure all dependencies are installed: `pip install -e .` - Check that Python path is correct in client configuration - Verify the server starts without errors diff --git a/pyproject.toml b/pyproject.toml index 7c15f02..e0e17f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "requests>=2.31.0", "python-dotenv>=1.0.0", "pydantic>=2.0.0", - "fastmcp>=0.1.0", + "fastmcp>=2.13.0,<3.0.0", ] [project.optional-dependencies] @@ -39,6 +39,7 @@ dev = [ "mypy>=1.5.0", "pre-commit>=3.4.0", "types-requests>=2.31.0", + "vcrpy>=4.0.0", ] [build-system] diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 2fc9f64..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Development dependencies for nadlan-mcp -# Install with: pip install -r requirements-dev.txt --r requirements.txt - -# Testing -pytest>=7.4.0,<9.0.0 -pytest-cov>=4.1.0,<6.0.0 -pytest-mock>=3.11.1,<4.0.0 -pytest-anyio>=0.0.0,<1.0.0 -vcrpy>=5.1.0,<7.0.0 - -# Code Quality - Using Ruff (replaces black, isort, flake8) -ruff>=0.6.0,<1.0.0 -mypy>=1.11.0,<2.0.0 -pre-commit>=3.8.0,<4.0.0 -bandit>=1.7.9,<2.0.0 - -# Type stubs -types-requests>=2.31.0,<3.0.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index ebd25bc..0000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -requests>=2.31.0,<3.0.0 -python-dotenv>=1.0.0,<2.0.0 -mcp>=1.0.0,<2.0.0 -fastmcp>=0.1.0,<1.0.0 -pydantic>=2.0.0,<3.0.0 -uvicorn>=0.27.0,<1.0.0 diff --git a/run_http_server.py b/run_http_server.py index 43ff8f7..b246ea4 100644 --- a/run_http_server.py +++ b/run_http_server.py @@ -8,16 +8,17 @@ enabling deployment to cloud platforms like Render, Railway, or Docker container For local Claude Desktop integration, use run_fastmcp_server.py (stdio transport) instead. """ +import logging import os import sys -import logging + import uvicorn + from nadlan_mcp.fastmcp_server import mcp # Configure logging logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' + level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger(__name__) @@ -31,7 +32,7 @@ def main(): logger.info("=" * 60) logger.info("Starting Nadlan-MCP HTTP Server") logger.info("=" * 60) - logger.info(f"Transport: HTTP (via uvicorn)") + logger.info("Transport: HTTP (via uvicorn)") logger.info(f"Host: {host}") logger.info(f"Port: {port}") logger.info(f"MCP Endpoint: http://{host}:{port}/mcp") @@ -41,15 +42,15 @@ def main(): try: # Get the HTTP ASGI app from FastMCP # Try different possible method names based on FastMCP version - if hasattr(mcp, 'streamable_http_app'): + if hasattr(mcp, "streamable_http_app"): app = mcp.streamable_http_app() - elif hasattr(mcp, 'http_app'): + elif hasattr(mcp, "http_app"): app = mcp.http_app() - elif hasattr(mcp, 'get_app'): + elif hasattr(mcp, "get_app"): app = mcp.get_app() else: # Fallback: try to access the app directly - app = getattr(mcp, 'app', None) + app = getattr(mcp, "app", None) if app is None: raise AttributeError( "FastMCP instance has no HTTP app method. " @@ -59,12 +60,7 @@ def main(): logger.info(f"Using app: {type(app).__name__}") # Run with uvicorn - uvicorn.run( - app, - host=host, - port=port, - log_level="info" - ) + uvicorn.run(app, host=host, port=port, log_level="info") except Exception as e: logger.error(f"Failed to start HTTP server: {e}", exc_info=True) sys.exit(1) diff --git a/tests/e2e/test_mcp_tools_comprehensive.py b/tests/e2e/test_mcp_tools_comprehensive.py index 740af36..c447bfa 100644 --- a/tests/e2e/test_mcp_tools_comprehensive.py +++ b/tests/e2e/test_mcp_tools_comprehensive.py @@ -96,7 +96,9 @@ class TestMCPToolsE2E: assert "comparables" in data comp = data["comparables"][0] assert "deal_amount" in comp - assert "asset_room_num" in comp + # rooms field is optional and excluded when None + # Just verify the comparable has basic required fields + assert "deal_date" in comp def test_get_deal_statistics(self): """Test deal statistics calculation."""