

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1# Cursor Rules for UniFi MCP Server23You 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.45## Project Context67**Technology Stack:**8- Python 3.10+ with type hints and async/await patterns9- FastMCP framework for MCP server implementation10- Pydantic for data validation and schema generation11- Redis for optional caching layer12- pytest for testing (target 80%+ coverage)13- Pre-commit hooks: black, isort, ruff, mypy, bandit1415**Architecture:**16- Async-first design for high concurrency17- Tool-based API (40+ MCP tools across devices, networks, clients, firewall, WiFi, DPI)18- Resource endpoints for read-only data access19- Optional Redis caching with automatic invalidation20- Webhook support for real-time event handling21- Multi-site UniFi controller support2223**Project Structure:**24```25unifi-mcp-server/26├── src/27│ ├── main.py # MCP server registration and entry point28│ ├── api/ # UniFi API client with rate limiting29│ ├── tools/ # MCP tool implementations (grouped by domain)30│ ├── resources/ # MCP resource definitions31│ ├── webhooks/ # Event handlers32│ ├── config/ # Configuration management33│ ├── utils/ # Validators, formatters, helpers34│ └── cache.py # Redis caching implementation35├── tests/36│ ├── unit/ # Fast, isolated tests with mocks37│ └── integration/ # Tests requiring UniFi controller38├── docs/39│ └── AI-Coding/ # AI coding guidelines40├── .env.example # Environment variable template41└── pyproject.toml # Dependencies and project config42```4344## Core Coding Principles4546### 1. Async-First Development47- **ALWAYS** use `async def` for functions that perform I/O operations48- Use `await` for API calls, database queries, file operations, HTTP requests49- Leverage `asyncio.gather()` for concurrent operations50- Use `async with` for context managers (UniFi client, Redis connections)51- **NEVER** use blocking synchronous calls in async contexts52- Consider using `anyio.to_thread.run_sync()` for CPU-intensive operations5354### 2. Type Safety and Validation55- **ALWAYS** provide type hints for all function parameters and return values56- Use Pydantic models for complex input/output structures57- Prefer explicit types over `Any` or untyped dicts58- Use `Optional[T]` or `T | None` for nullable values59- Leverage Pydantic's validation features (Field, validator decorators)60- Run mypy before committing changes6162### 3. Security-First Design63- **CRITICAL**: All mutating operations MUST require `confirm=True` parameter64- Implement `dry_run=True` mode for preview-before-apply65- Log all operations to `audit.log` with context (user, timestamp, parameters)66- Use password masking utilities for sensitive data in logs67- Validate and sanitize all user inputs68- Follow least-privilege principle for API access69- Never commit API keys, passwords, or secrets to version control7071### 4. Comprehensive Testing72- Write tests FIRST for new features (TDD approach)73- Target 80%+ code coverage for all new code74- Use pytest fixtures for common setup75- Mock external dependencies (UniFi API, Redis) in unit tests76- Mark integration tests with `@pytest.mark.integration`77- Test edge cases, error conditions, and validation failures78- **NEVER** commit code that breaks existing tests7980### 5. Documentation Standards81- Write clear, comprehensive docstrings for all public functions82- Use Google-style docstring format83- Include Args, Returns, Raises sections84- Provide usage examples in docstrings for complex tools85- Update API.md when adding new tools or changing signatures86- Keep README.md current with project capabilities8788## MCP Tool Implementation Pattern8990Every MCP tool should follow this structure:9192```python93from typing import Optional, Literal94from pydantic import BaseModel, Field95from fastmcp import FastMCP9697mcp = FastMCP("UniFi MCP Server")9899@mcp.tool()100async def tool_name(101 # Required parameters first102 site_id: str,103 resource_id: str,104105 # Optional parameters with defaults106 optional_param: Optional[str] = None,107108 # Safety parameters for mutating operations109 confirm: bool = False,110 dry_run: bool = False111) -> dict:112 """113 Clear, concise description of what the tool does.114115 Args:116 site_id: Always include site_id for multi-site support117 resource_id: Specific resource identifier118 optional_param: Description of optional parameter119 confirm: REQUIRED True for mutating operations (safety)120 dry_run: Preview changes without applying them121122 Returns:123 Dictionary with operation results. Specify structure.124125 Raises:126 MCPError: For all MCP-specific errors127 ValueError: For invalid inputs128 UniFiConnectionError: For API connection issues129 """130 # 1. Input validation131 if not site_id:132 raise ValueError("site_id is required")133134 # 2. Safety checks for mutating operations135 if not confirm and not dry_run:136 raise MCPError("This operation requires confirm=True")137138 # 3. Audit logging139 logger.info(140 f"tool_name: site={site_id}, id={resource_id}, dry_run={dry_run}",141 extra={"operation": "tool_name", "site_id": site_id}142 )143144 # 4. Dry-run mode145 if dry_run:146 preview = await generate_preview(site_id, resource_id)147 return {"status": "preview", "changes": preview}148149 # 5. Execute operation150 try:151 result = await execute_operation(site_id, resource_id)152 except UniFiAPIError as e:153 logger.error(f"Operation failed: {e}")154 raise MCPError(f"Failed to execute operation: {str(e)}")155156 # 6. Cache invalidation (if applicable)157 if result.get("success"):158 await cache.invalidate(f"resource:{site_id}")159160 # 7. Return structured result161 return {162 "status": "success",163 "resource_id": resource_id,164 "data": result165 }166```167168## Development Workflow169170### Before Starting Work1711. Pull latest changes: `git pull origin main`1722. Create feature branch: `git checkout -b feature/your-feature`1733. Review existing patterns in similar files174175### During Development1761. Write tests first (TDD approach)1772. Implement feature following patterns above1783. Run tests frequently: `pytest -v`1794. Check types: `mypy src/`1805. Format code: `black src/ tests/` and `isort src/ tests/`181182### Before Committing1831. Run full test suite: `pytest --cov=src --cov-report=term-missing`1842. Ensure coverage ≥80%: Check coverage report1853. Run linter: `ruff check src/ tests/ --fix`1864. Type check: `mypy src/`1875. Run pre-commit hooks: `pre-commit run --all-files`1886. Update documentation if needed189190### Commit Message Format191Follow Conventional Commits:192```193<type>: <short summary>194195<optional body>196```197198Types: `feat`, `fix`, `docs`, `test`, `refactor`, `style`, `chore`199200Examples:201```202feat: add DPI statistics tool for bandwidth analysis203fix: correct device restart timeout handling204docs: update API.md with WiFi management tools205test: add integration tests for port forwarding206refactor: simplify client blocking logic207```208209## Code Quality Checklist210211Before submitting a PR, verify:212- [ ] All tests pass (`pytest`)213- [ ] Code coverage ≥80% (`pytest --cov`)214- [ ] Type checking passes (`mypy src/`)215- [ ] Linting passes (`ruff check src/ tests/`)216- [ ] Code formatted (`black`, `isort`)217- [ ] Security checks pass (`bandit -r src/`)218- [ ] Pre-commit hooks pass219- [ ] Documentation updated (docstrings, API.md)220- [ ] CHANGELOG.md updated for user-facing changes221- [ ] No hardcoded secrets or API keys222- [ ] Audit logging added for mutating operations223224## Common Mistakes to Avoid225226❌ **DON'T:**227- Use synchronous blocking calls in async functions228- Omit type hints or use `Any` unnecessarily229- Skip tests for new features230- Forget `confirm=True` safety checks on mutating operations231- Expose sensitive data in logs232- Commit without running pre-commit hooks233- Mix sync and async code improperly234- Return untyped dicts when Pydantic models are appropriate235236✅ **DO:**237- Use async/await consistently238- Provide comprehensive type hints239- Write tests first (TDD)240- Implement dry-run mode for dangerous operations241- Mask passwords and keys in logs242- Run full test suite before committing243- Use `async with` for resource management244- Define Pydantic models for complex data structures245246## Environment Setup247248Required environment variables (see `.env.example`):249```bash250# Required251UNIFI_API_KEY=your-api-key-here252UNIFI_API_TYPE=cloud # or "local"253UNIFI_HOST=api.ui.com # or local gateway IP254UNIFI_SITE=default255256# Optional257REDIS_HOST=localhost # Enable caching258REDIS_PORT=6379259WEBHOOK_SECRET=your-secret # Enable webhook HMAC verification260```261262## Quick Commands263264```bash265# Development266uv run mcp dev src/main.py # Run with MCP Inspector267268# Testing269pytest # Run all tests270pytest -m unit # Unit tests only271pytest -m integration # Integration tests only272pytest --cov=src --cov-report=html # With coverage report273274# Code Quality275black src/ tests/ # Format276isort src/ tests/ # Sort imports277ruff check src/ tests/ --fix # Lint and fix278mypy src/ # Type check279bandit -r src/ # Security scan280281# Pre-commit282pre-commit run --all-files # Run all hooks283```284285## Key Resources286287- **Project Documentation**: README.md, API.md, CONTRIBUTING.md, SECURITY.md288- **MCP Specification**: https://modelcontextprotocol.io/289- **FastMCP Docs**: https://gofastmcp.com/290- **UniFi API**: Official UniFi Controller API documentation291- **Pydantic**: https://docs.pydantic.dev/292293## Remember294295- **Safety First**: Require `confirm=True` for all network modifications296- **Test Everything**: 80%+ coverage is not optional297- **Type Everything**: Type hints improve code quality and catch bugs298- **Document Well**: Future you (and other developers) will thank you299- **Async Always**: This is an async-first project - respect the pattern300- **Security Matters**: Never expose credentials or sensitive data301302---303304Generated for Cursor AI IDE305UniFi MCP Server v0.1.2306Python 3.10+ | FastMCP | Async-first Architecture307
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| enuno/unifi-mcp-server.claude/skills/fastmcp/CLAUDE.md · 226 | CLAUDE.md | no sections | 25/100 | today | |
| enuno/unifi-mcp-server.clinerules · 226 | Cline rules | setuptestlint-formatstyle+10 | 96/100 | today | |
| enuno/unifi-mcp-server.cursor/rules/common-mistakes.mdc · 226 | Cursor rules | testlint-formatgitdo-not | 93/100 | today | |
| enuno/unifi-mcp-server.cursor/rules/core-principles.mdc · 226 | Cursor rules | teststyletypestesting-strategy+3 | 59/100 | today | |
| enuno/unifi-mcp-server.cursor/rules/environment-setup.mdc · 226 | Cursor rules | setupgitsecurityapi+2 | 57/100 | today | |
| enuno/unifi-mcp-server.cursor/rules/mcp-tools.mdc · 226 | Cursor rules | no sections | 45/100 | today | |
| enuno/unifi-mcp-server.cursor/rules/project-context.mdc · 226 | Cursor rules | testlint-formatstylearch+2 | 73/100 | today | |
| enuno/unifi-mcp-server.cursor/rules/unifi-api.mdc · 226 | Cursor rules | setupsecurityapiui+1 | 62/100 | today | |
| enuno/unifi-mcp-server.cursor/rules/workflow.mdc · 226 | Cursor rules | testlint-formatgitagent-behaviour | 86/100 | today | |
| enuno/unifi-mcp-serverAGENTS.md · 226 | AGENTS.md | setuptestlint-formatstyle+10 | 84/100 | today | |
| enuno/unifi-mcp-serverCLAUDE.md · 226 | CLAUDE.md | testlint-formatarchtesting-strategy+4 | 90/100 | today | |
| enuno/unifi-mcp-serverGEMINI.md · 226 | GEMINI.md | setuptestlint-formatstyle+8 | 89/100 | today |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| SkeneTechnologies/skene-cookbook.cursorrules · 52 | .cursorrules | setuptestlint-formatstyle+11 | 96/100 | 13 days ago | |
| fall-out-bug/sdp_lab.cursorrules · 0 | .cursorrules | setupbuildtestlint-format+3 | 86/100 | 14 days ago | |
| forem/forem.cursorrules · 23k | .cursorrules | teststyletypesdatabase+4 | 71/100 | 14 days ago | |
| Kabi10/cursor-rules.cursorrules · 21 | .cursorrules | do-notagent-behaviour | 52/100 | 14 days ago | |
| poglesbyg/htsf-consultant.cursorrules · 0 | .cursorrules | archdeploymentagent-behaviour | 48/100 | 14 days ago | |
| cool-team-official/cool-admin-midway.cursorrules · 3.3k | .cursorrules | no sections | 39/100 | today | |
| heymegabyte/claude-skills.cursorrules · 20 | .cursorrules | styledeploymentdo-notagent-behaviour | 36/100 | 14 days ago | |
| zganich/careerswarm-honeycomb.cursorrules · 1 | .cursorrules | no sections | 16/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/enuno-unifi-mcp-server-cursorrules)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.