Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
9.4 KiB
Contributing to Nadlan-MCP
Thank you for your interest in contributing! This guide will help you get started.
Code of Conduct
- Be respectful and inclusive
- Focus on constructive feedback
- Help others learn and grow
Development Setup
1. Fork and Clone
git clone https://github.com/your-username/nadlan-mcp.git
cd nadlan-mcp
2. Create Virtual Environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
3. Install Dependencies
# Install main dependencies
pip install -r requirements.txt
# Install development dependencies
pip install -r requirements-dev.txt
4. Set Up IDE Integration (Recommended)
For VSCode/Cursor users:
The project includes .vscode/settings.json which automatically:
- Formats code on save with Ruff
- Shows lint errors inline
- Organizes imports automatically
- Runs tests with pytest
Install recommended extensions:
- Open VSCode/Cursor in the project directory
- You'll be prompted to install recommended extensions
- Install "Ruff" extension by charliermarsh
Benefits:
- ✅ Automatic formatting on save
- ✅ Real-time lint errors
- ✅ Auto-fix on save
- ✅ No manual commands needed
5. Verify Setup
# Run tests
pytest tests/ -m "not api_health" -q
# Check code quality
ruff check .
ruff format --check .
# Or use the quick check script
./check-quality.sh
Development Workflow
1. Create a Branch
git checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-description
2. Make Changes
Follow the code style guidelines below.
If using VSCode/Cursor with Ruff extension:
- Code is automatically formatted on save
- Lint errors are shown inline
- Auto-fixes apply on save
- No manual commands needed!
If not using IDE integration:
- Run
./check-quality.shbefore committing - Or run individual commands below
3. Check Before Committing
Quick check (recommended):
./check-quality.sh
This script runs all checks that will run in the PR:
- Ruff format check
- Ruff linting
- All tests
Manual checks:
# Format code
ruff format .
# Lint code
ruff check . --fix
# Run tests
pytest tests/ -m "not api_health" -q
# Check remaining issues
ruff check .
4. Commit Changes
git add .
git commit -m "feat: add new feature"
# or
git commit -m "fix: resolve issue with..."
Commit Message Format:
feat:- New featurefix:- Bug fixdocs:- Documentation changestest:- Test additions/changesrefactor:- Code refactoringstyle:- Code style changeschore:- Build/tooling changes
5. Push and Create PR
git push origin feature/your-feature-name
Then create a Pull Request on GitHub.
Code Style
Python Style Guide
We use Ruff for formatting and linting (replaces black, isort, flake8):
- Line length: 100 characters
- Use double quotes for strings
- Follow PEP 8 conventions
Formatting
# Auto-format all code
ruff format .
Linting
# Check for issues
ruff check .
# Auto-fix issues
ruff check . --fix
Type Hints
Use type hints for function signatures:
from typing import List, Optional
from nadlan_mcp.govmap.models import Deal
def process_deals(
deals: List[Deal],
min_price: Optional[float] = None
) -> List[Deal]:
"""Process and filter deals."""
...
Testing Guidelines
Test Structure
tests/
├── govmap/ # Unit tests for govmap package
├── e2e/ # End-to-end integration tests
└── api_health/ # API health monitoring (weekly)
Writing Tests
import pytest
from nadlan_mcp.govmap.models import Deal
class TestYourFeature:
"""Test cases for your feature."""
@pytest.fixture
def sample_deals(self):
"""Create sample test data."""
return [
Deal(objectid=1, deal_amount=1000000, deal_date="2024-01-01"),
Deal(objectid=2, deal_amount=1500000, deal_date="2024-02-01"),
]
def test_basic_functionality(self, sample_deals):
"""Test basic functionality."""
result = your_function(sample_deals)
assert len(result) == 2
Test Coverage
Aim for >80% coverage for new code:
pytest --cov=nadlan_mcp --cov-report=html
open htmlcov/index.html
Running Different Test Suites
# Fast tests only (default, ~12s)
pytest tests/ -m "not api_health" -q
# Integration tests (makes real API calls)
pytest -m integration -v
# API health checks (weekly)
pytest -m api_health -v
# Specific test file
pytest tests/govmap/test_filters.py
Architecture Guidelines
Package Structure
nadlan_mcp/
├── govmap/ # Core business logic
│ ├── models.py # Pydantic data models
│ ├── client.py # API client
│ ├── filters.py # Deal filtering
│ ├── statistics.py # Statistical calculations
│ ├── market_analysis.py # Market analysis
│ ├── validators.py # Input validation
│ └── utils.py # Helper functions
├── fastmcp_server.py # MCP tool definitions
└── config.py # Configuration management
Design Principles
-
MCP provides data, LLM provides intelligence
- Keep analysis simple in MCP layer
- Let LLM interpret and reason about data
-
Return Pydantic models, not dicts
- All API methods return typed models
- Use
.model_dump()to serialize for JSON
-
Separation of concerns
client.py- API calls onlyfilters.py- Filtering logicstatistics.py- Calculationsmarket_analysis.py- Analysis functions
-
Backward compatibility
- Use
govmap/__init__.pyfor public exports - Maintain existing function signatures
- Use
Adding New Features
1. Add Pydantic Model (if needed)
# nadlan_mcp/govmap/models.py
class YourModel(BaseModel):
"""Your model description."""
field_name: str = Field(..., description="Field description")
optional_field: Optional[int] = Field(None, description="Optional field")
2. Add Business Logic
# nadlan_mcp/govmap/your_module.py
from typing import List
from .models import Deal, YourModel
def your_function(deals: List[Deal]) -> YourModel:
"""
Your function description.
Args:
deals: List of Deal instances
Returns:
YourModel instance
Raises:
ValueError: If deals list is empty
"""
if not deals:
raise ValueError("Cannot process empty deals list")
# Your logic here
return YourModel(field_name="value")
3. Add Client Method
# nadlan_mcp/govmap/client.py
def your_method(self, param: str) -> YourModel:
"""
Client method description.
Args:
param: Parameter description
Returns:
YourModel instance
"""
# Implementation
return your_function(data)
4. Add MCP Tool
# nadlan_mcp/fastmcp_server.py
@mcp.tool()
def your_mcp_tool(param: str) -> str:
"""
MCP tool description visible to LLM.
Args:
param: Parameter description
Returns:
JSON string with results
"""
try:
result = client.your_method(param)
return json.dumps({
"result": result.model_dump(exclude_none=True)
}, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"Error in your_mcp_tool: {e}")
return f"Error: {str(e)}"
5. Add Tests
# tests/govmap/test_your_module.py
def test_your_function():
"""Test your function."""
deals = [Deal(...)]
result = your_function(deals)
assert isinstance(result, YourModel)
assert result.field_name == "expected_value"
6. Update Documentation
- Add to
API_REFERENCE.md - Add example to
examples/if useful - Update
README.mdif it's a major feature
Pull Request Process
Before Submitting
- ✅ All tests pass
- ✅ Code formatted with Ruff
- ✅ No Ruff warnings
- ✅ Added tests for new features
- ✅ Updated documentation
PR Checklist
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Added new tests
- [ ] All existing tests pass
- [ ] Tested manually
## Documentation
- [ ] Updated README.md (if needed)
- [ ] Updated API_REFERENCE.md (if needed)
- [ ] Added examples (if needed)
Code Review
- PRs reviewed by maintainers
- Address feedback constructively
- CI checks must pass (Ruff + tests)
Common Tasks
Adding a New MCP Tool
See "Adding New Features" section above.
Fixing a Bug
- Write a failing test that reproduces the bug
- Fix the bug
- Verify test now passes
- Add regression test if needed
Updating Dependencies
# Update requirements files
pip list --outdated
pip install <package> --upgrade
pip freeze > requirements.txt
# Test everything still works
pytest tests/ -m "not api_health"
Running API Health Checks
# Weekly check that Govmap API still works
pytest -m api_health -v
Questions?
- Create an issue for questions
- Check existing issues and PRs
- Read ARCHITECTURE.md for design decisions
- Review examples/ for usage patterns
License
By contributing, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to Nadlan-MCP! 🎉