# Cursor Rules for UniFi MCP Server

You are an expert Python developer working on a production-grade MCP (Model Context Protocol) server for UniFi Network Controller integration. This server enables AI agents to manage UniFi network infrastructure through 40+ standardized tools.

## Project Context

**Technology Stack:**
- Python 3.10+ with type hints and async/await patterns
- FastMCP framework for MCP server implementation
- Pydantic for data validation and schema generation
- Redis for optional caching layer
- pytest for testing (target 80%+ coverage)
- Pre-commit hooks: black, isort, ruff, mypy, bandit

**Architecture:**
- Async-first design for high concurrency
- Tool-based API (40+ MCP tools across devices, networks, clients, firewall, WiFi, DPI)
- Resource endpoints for read-only data access
- Optional Redis caching with automatic invalidation
- Webhook support for real-time event handling
- Multi-site UniFi controller support

**Project Structure:**
```
unifi-mcp-server/
├── src/
│   ├── main.py              # MCP server registration and entry point
│   ├── api/                 # UniFi API client with rate limiting
│   ├── tools/               # MCP tool implementations (grouped by domain)
│   ├── resources/           # MCP resource definitions
│   ├── webhooks/            # Event handlers
│   ├── config/              # Configuration management
│   ├── utils/               # Validators, formatters, helpers
│   └── cache.py             # Redis caching implementation
├── tests/
│   ├── unit/                # Fast, isolated tests with mocks
│   └── integration/         # Tests requiring UniFi controller
├── docs/
│   └── AI-Coding/           # AI coding guidelines
├── .env.example             # Environment variable template
└── pyproject.toml           # Dependencies and project config
```

## Core Coding Principles

### 1. Async-First Development
- **ALWAYS** use `async def` for functions that perform I/O operations
- Use `await` for API calls, database queries, file operations, HTTP requests
- Leverage `asyncio.gather()` for concurrent operations
- Use `async with` for context managers (UniFi client, Redis connections)
- **NEVER** use blocking synchronous calls in async contexts
- Consider using `anyio.to_thread.run_sync()` for CPU-intensive operations

### 2. Type Safety and Validation
- **ALWAYS** provide type hints for all function parameters and return values
- Use Pydantic models for complex input/output structures
- Prefer explicit types over `Any` or untyped dicts
- Use `Optional[T]` or `T | None` for nullable values
- Leverage Pydantic's validation features (Field, validator decorators)
- Run mypy before committing changes

### 3. Security-First Design
- **CRITICAL**: All mutating operations MUST require `confirm=True` parameter
- Implement `dry_run=True` mode for preview-before-apply
- Log all operations to `audit.log` with context (user, timestamp, parameters)
- Use password masking utilities for sensitive data in logs
- Validate and sanitize all user inputs
- Follow least-privilege principle for API access
- Never commit API keys, passwords, or secrets to version control

### 4. Comprehensive Testing
- Write tests FIRST for new features (TDD approach)
- Target 80%+ code coverage for all new code
- Use pytest fixtures for common setup
- Mock external dependencies (UniFi API, Redis) in unit tests
- Mark integration tests with `@pytest.mark.integration`
- Test edge cases, error conditions, and validation failures
- **NEVER** commit code that breaks existing tests

### 5. Documentation Standards
- Write clear, comprehensive docstrings for all public functions
- Use Google-style docstring format
- Include Args, Returns, Raises sections
- Provide usage examples in docstrings for complex tools
- Update API.md when adding new tools or changing signatures
- Keep README.md current with project capabilities

## MCP Tool Implementation Pattern

Every MCP tool should follow this structure:

```python
from typing import Optional, Literal
from pydantic import BaseModel, Field
from fastmcp import FastMCP

mcp = FastMCP("UniFi MCP Server")

@mcp.tool()
async def tool_name(
    # Required parameters first
    site_id: str,
    resource_id: str,

    # Optional parameters with defaults
    optional_param: Optional[str] = None,

    # Safety parameters for mutating operations
    confirm: bool = False,
    dry_run: bool = False
) -> dict:
    """
    Clear, concise description of what the tool does.

    Args:
        site_id: Always include site_id for multi-site support
        resource_id: Specific resource identifier
        optional_param: Description of optional parameter
        confirm: REQUIRED True for mutating operations (safety)
        dry_run: Preview changes without applying them

    Returns:
        Dictionary with operation results. Specify structure.

    Raises:
        MCPError: For all MCP-specific errors
        ValueError: For invalid inputs
        UniFiConnectionError: For API connection issues
    """
    # 1. Input validation
    if not site_id:
        raise ValueError("site_id is required")

    # 2. Safety checks for mutating operations
    if not confirm and not dry_run:
        raise MCPError("This operation requires confirm=True")

    # 3. Audit logging
    logger.info(
        f"tool_name: site={site_id}, id={resource_id}, dry_run={dry_run}",
        extra={"operation": "tool_name", "site_id": site_id}
    )

    # 4. Dry-run mode
    if dry_run:
        preview = await generate_preview(site_id, resource_id)
        return {"status": "preview", "changes": preview}

    # 5. Execute operation
    try:
        result = await execute_operation(site_id, resource_id)
    except UniFiAPIError as e:
        logger.error(f"Operation failed: {e}")
        raise MCPError(f"Failed to execute operation: {str(e)}")

    # 6. Cache invalidation (if applicable)
    if result.get("success"):
        await cache.invalidate(f"resource:{site_id}")

    # 7. Return structured result
    return {
        "status": "success",
        "resource_id": resource_id,
        "data": result
    }
```

## Development Workflow

### Before Starting Work
1. Pull latest changes: `git pull origin main`
2. Create feature branch: `git checkout -b feature/your-feature`
3. Review existing patterns in similar files

### During Development
1. Write tests first (TDD approach)
2. Implement feature following patterns above
3. Run tests frequently: `pytest -v`
4. Check types: `mypy src/`
5. Format code: `black src/ tests/` and `isort src/ tests/`

### Before Committing
1. Run full test suite: `pytest --cov=src --cov-report=term-missing`
2. Ensure coverage ≥80%: Check coverage report
3. Run linter: `ruff check src/ tests/ --fix`
4. Type check: `mypy src/`
5. Run pre-commit hooks: `pre-commit run --all-files`
6. Update documentation if needed

### Commit Message Format
Follow Conventional Commits:
```
<type>: <short summary>

<optional body>
```

Types: `feat`, `fix`, `docs`, `test`, `refactor`, `style`, `chore`

Examples:
```
feat: add DPI statistics tool for bandwidth analysis
fix: correct device restart timeout handling
docs: update API.md with WiFi management tools
test: add integration tests for port forwarding
refactor: simplify client blocking logic
```

## Code Quality Checklist

Before submitting a PR, verify:
- [ ] All tests pass (`pytest`)
- [ ] Code coverage ≥80% (`pytest --cov`)
- [ ] Type checking passes (`mypy src/`)
- [ ] Linting passes (`ruff check src/ tests/`)
- [ ] Code formatted (`black`, `isort`)
- [ ] Security checks pass (`bandit -r src/`)
- [ ] Pre-commit hooks pass
- [ ] Documentation updated (docstrings, API.md)
- [ ] CHANGELOG.md updated for user-facing changes
- [ ] No hardcoded secrets or API keys
- [ ] Audit logging added for mutating operations

## Common Mistakes to Avoid

❌ **DON'T:**
- Use synchronous blocking calls in async functions
- Omit type hints or use `Any` unnecessarily
- Skip tests for new features
- Forget `confirm=True` safety checks on mutating operations
- Expose sensitive data in logs
- Commit without running pre-commit hooks
- Mix sync and async code improperly
- Return untyped dicts when Pydantic models are appropriate

✅ **DO:**
- Use async/await consistently
- Provide comprehensive type hints
- Write tests first (TDD)
- Implement dry-run mode for dangerous operations
- Mask passwords and keys in logs
- Run full test suite before committing
- Use `async with` for resource management
- Define Pydantic models for complex data structures

## Environment Setup

Required environment variables (see `.env.example`):
```bash
# Required
UNIFI_API_KEY=your-api-key-here
UNIFI_API_TYPE=cloud  # or "local"
UNIFI_HOST=api.ui.com  # or local gateway IP
UNIFI_SITE=default

# Optional
REDIS_HOST=localhost  # Enable caching
REDIS_PORT=6379
WEBHOOK_SECRET=your-secret  # Enable webhook HMAC verification
```

## Quick Commands

```bash
# Development
uv run mcp dev src/main.py      # Run with MCP Inspector

# Testing
pytest                          # Run all tests
pytest -m unit                  # Unit tests only
pytest -m integration           # Integration tests only
pytest --cov=src --cov-report=html  # With coverage report

# Code Quality
black src/ tests/               # Format
isort src/ tests/               # Sort imports
ruff check src/ tests/ --fix   # Lint and fix
mypy src/                       # Type check
bandit -r src/                  # Security scan

# Pre-commit
pre-commit run --all-files      # Run all hooks
```

## Key Resources

- **Project Documentation**: README.md, API.md, CONTRIBUTING.md, SECURITY.md
- **MCP Specification**: https://modelcontextprotocol.io/
- **FastMCP Docs**: https://gofastmcp.com/
- **UniFi API**: Official UniFi Controller API documentation
- **Pydantic**: https://docs.pydantic.dev/

## Remember

- **Safety First**: Require `confirm=True` for all network modifications
- **Test Everything**: 80%+ coverage is not optional
- **Type Everything**: Type hints improve code quality and catch bugs
- **Document Well**: Future you (and other developers) will thank you
- **Async Always**: This is an async-first project - respect the pattern
- **Security Matters**: Never expose credentials or sensitive data

---

Generated for Cursor AI IDE
UniFi MCP Server v0.1.2
Python 3.10+ | FastMCP | Async-first Architecture
