Development GuideΒΆ
Configuring your development environment for best success
Project StructureΒΆ
jamfmcp/
βββ src/jamfmcp/ # Source code
β βββ server.py # MCP server and tools
β βββ api.py # Jamf API client
β βββ auth.py # Authentication
β βββ cli.py # CLI entry point
β βββ health_analyzer.py # Health analysis
β βββ sofa.py # SOFA integration
β βββ jamfsdk/ # Embedded SDK
βββ tests/ # Test suite
β βββ conftest.py # Pytest configuration
β βββ fixtures/ # Test data
β βββ test_*.py # Test modules
βββ docs/ # Documentation
βββ pyproject.toml # Project configuration
βββ Makefile # Development tasks
Key TechnologiesΒΆ
Python 3.13+: Modern Python features
FastMCP: MCP server framework
httpx: Async HTTP client
Pydantic: Data validation
pytest: Testing framework
Sphinx: Documentation
uv: Package management
Development WorkflowΒΆ
1. Create Feature BranchΒΆ
Fork the repository on GitHub
Clone your fork:
git clone https://github.com/YOUR_USERNAME/jamfmcp.git && cd jamfmcpAdd upstream remote:
git remote add upstream https://github.com/liquidz00/jamfmcp.gitInstall development dependencies:
make install-devCreate a feature branch:
git checkout -b feature/your-feature-name
Tip
All make commands are configured to use uv. You do not need to worry about creating a virtual environment for dependency installation as this is all handled automatically by uv. To see a list of all available commands in the Makefile, see Makefile commands
2. Make Your ChangesΒΆ
Follow these guidelines:
Code Style: Follow existing patterns
Type Hints: Add type hints to all functions
Docstrings: Use Sphinx-style docstrings
Example DocString
async def get_example_data(
item_id: str,
include_details: bool = False
) -> dict[str, Any]:
"""
Get example data from Jamf Pro.
This function retrieves example data with optional details.
:param item_id: The unique identifier for the item
:type item_id: str
:param include_details: Whether to include additional details
:type include_details: bool
:return: Dictionary containing the example data
:rtype: dict[str, Any]
:raises ValueError: If item_id is invalid
:raises JamfApiError: If API call fails
"""
# Implementation
Building DocumentationΒΆ
# Build HTML docs
make docs
# Serve locally
cd docs/_build && python -m http.server
3. Write TestsΒΆ
Write comprehensive tests for your changes:
import pytest
from unittest.mock import AsyncMock
@pytest.mark.asyncio
async def test_get_example_data_success(mock_jamf_api):
"""Test successful data retrieval."""
# Arrange
mock_jamf_api.get_example.return_value = {
"id": "123",
"name": "Test Item"
}
# Act
result = await get_example_data("123")
# Assert
assert result["id"] == "123"
assert result["name"] == "Test Item"
mock_jamf_api.get_example.assert_called_once_with("123", details=False)
@pytest.mark.asyncio
async def test_get_example_data_invalid_id():
"""Test handling of invalid ID."""
# Act & Assert
with pytest.raises(ValueError, match="Invalid ID"):
await get_example_data("")
Running TestsΒΆ
# All tests
make test
# With coverage
make test-cov
# Specific test file
uv run pytest tests/test_health_analyzer.py
# Specific test
uv run pytest tests/test_health_analyzer.py::test_score_calculation
All changes must include appropriate tests. We use pytest for our test suite.
See also
See the full Testing Guide for detailed information on:
Writing unit tests
Using fixtures
Testing async functions
Running tests with coverage
Debugging tests
4. Format and Lint CodeΒΆ
We use Ruff for code formatting and linting:
# Format code
make format
# Check style
make lint
Style GuidelinesΒΆ
Line Length: Maximum 100 characters
Imports: Use absolute imports
Naming: Follow PEP 8 conventions
snake_casefor functions and variablesPascalCasefor classesUPPER_CASEfor constants
5. Commit Your ChangesΒΆ
Use conventional commit messages:
# Format: <type>(<scope>): <subject>
feat(tools): add new inventory search tool
fix(auth): handle token expiration correctly
docs(readme): update installation instructions
test(health): add tests for CVE analysis
refactor(api): simplify error handling
Types:
feat: New featurefix: Bug fixdocs: Documentation changestest: Test additions/changesrefactor: Code refactoringstyle: Code style changeschore: Maintenance tasks
6. Push and Create Pull Request (PR)ΒΆ
Push to your fork:
git push origin feature/your-feature-nameCreate Pull Request on GitHub
Fill out PR template completely
Link related issues if applicable
Pull Request GuidelinesΒΆ
PR ChecklistΒΆ
Tests pass locally (
make test)Code is formatted (
make format)Linting passes (
make lint)Documentation is updated
PR description is complete
Review ProcessΒΆ
What to ExpectΒΆ
Initial Review: Maintainers review code changes and/or documentation updates
Feedback: Address requested changes
CI Checks: Ensure all checks pass
Approval: Maintainer approval required
Merge: Maintainer merges PR
Review CriteriaΒΆ
Code Quality: Clean, readable, maintainable
Tests: Comprehensive test coverage
Documentation: Clear and complete
Performance: No performance regressions
Security: No security vulnerabilities
Makefile CommandsΒΆ
In order to use make commands on macOS you must install Xcode Command Line Tools
To view all command options, execute make help:
Available commands:
Installation & Setup:
make venv - Create virtual environment
make install - Install base dependencies
make install-dev - Install dev dependencies (includes docs)
make uninstall - Remove virtual environment
make sync - Alias for 'make install'
Development:
make lint - Check code style with ruff
make format - Auto-format code with ruff
make pre-commit - Install pre-commit hooks
make pre-commit-run - Run pre-commit on all files
make pre-commit-update - Update pre-commit hooks to latest versions
Testing:
make test - Run all tests (verbose)
make test-cov - Run tests with coverage report
make test-cov-html - Generate HTML coverage report
Building & Documentation:
make build - Build distribution packages (wheel & sdist)
make docs - Build Sphinx documentation
Dependency Management:
make lock - Update uv.lock file
make upgrade - Upgrade all dependencies to latest versions
Cleanup:
make clean - Remove build artifacts and cache files
make flush - Deep clean (remove all generated files)
make restore - Full cleanup (clean + flush)
Common Development TasksΒΆ
Adding a New ToolΒΆ
Add tool function to
server.pyUse
@mcp.tooldecoratorAdd proper type hints
Include comprehensive docstring
Handle errors appropriately
Example:
@mcp.tool
async def get_new_data(
param: str,
optional: bool = False
) -> dict[str, Any]:
"""
Get new data from Jamf Pro.
:param param: Required parameter
:type param: str
:param optional: Optional flag
:type optional: bool
:return: Data dictionary
:rtype: dict[str, Any]
"""
try:
return await jamf_api.get_new_data(param, optional)
except Exception as e:
logger.error(f"Error: {e}")
return {"error": str(e)}
Adding Health ChecksΒΆ
Extend Health Analysis in
src/jamfmcp/health_analyzer.pyAdd scoring logic, allow for configurable weight scoring
Include recommendations for remediation or troubleshooting
Update unit tests in
tests/test_health_analyzer.py
Custom AnalyzersΒΆ
class CustomAnalyzer(HealthAnalyzer):
def _calculate_custom_score(self) -> HealthScore:
# Custom scoring logic
pass
RecognitionΒΆ
Contributors are recognized in:
CHANGELOG.md for their contributions
GitHub contributors page
Release notes
Thank you for contributing to JamfMCP! π