

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1**UniFi MCP Server - Google Gemini AI Configuration**23This document provides Google Gemini-specific instructions for developing, testing, and extending the UniFi MCP Server. For universal agent rules and conventions, refer to [AGENTS.md](AGENTS.md).45***67## Quick Start with Gemini CLI89### Prerequisites1011```bash12# Install Gemini CLI13npm install -g @google/generative-ai-cli1415# Set up API key (get from Google AI Studio)16export GEMINI_API_KEY="your-api-key"1718# Or add to .env19echo "GEMINI_API_KEY=your-api-key" >> .gemini/.env20```2122### Configuration2324Create `.gemini/settings.json` in project root:2526```json27{28 "model": {29 "name": "gemini-2.5-pro",30 "temperature": 0.331 },32 "context": {33 "fileName": ["GEMINI.md", "AGENTS.md", "API.md", "README.md"]34 },35 "mcpServers": {36 "unifi": {37 "command": "uv",38 "args": ["--directory", ".", "run", "python", "src/main.py"],39 "env": {40 "UNIFI_API_KEY": "${UNIFI_API_KEY}",41 "UNIFI_API_TYPE": "cloud"42 }43 }44 }45}46```4748***4950## Project Context for Gemini5152### Technology Stack5354- **Language**: Python 3.10+55- **Framework**: FastMCP (Model Context Protocol server)56- **API Client**: Async UniFi Network API57- **Testing**: pytest, pytest-asyncio, pytest-cov58- **Caching**: Redis (optional, with async client)59- **Validation**: Pydantic v2 models60- **Code Quality**: black, isort, ruff, mypy, pre-commit6162### Architecture Overview6364```65src/66├── main.py # MCP server entry point (55 tools)67├── api/ # UniFi API client with rate limiting68├── models/ # Pydantic data models69│ └── zbf.py # Zone-Based Firewall models70├── tools/ # MCP tool implementations (read + write)71├── resources/ # MCP resource definitions72├── cache.py # Redis caching layer73├── webhooks/ # Event handlers74└── utils/ # Validators and helpers75```7677***7879## Gemini-Specific Development Guidelines8081### 1. Code Generation Standards8283**When generating Python code for this project:**8485#### Type Safety8687- Always use Python 3.10+ type hints88- Use `from __future__ import annotations` for forward references89- Leverage Pydantic v2 for data validation90- Use `typing` module: `Optional`, `List`, `Dict`, `Literal`, `TypedDict`9192```python93from typing import Optional, List, Dict, Literal94from pydantic import BaseModel, Field, validator9596class FirewallRule(BaseModel):97 """Firewall rule configuration."""98 name: str = Field(..., description="Rule name")99 action: Literal["accept", "drop", "reject"]100 enabled: bool = True101 protocol: Optional[Literal["tcp", "udp", "icmp"]] = None102```103104#### Async/Await Patterns105106- All I/O operations MUST be async107- Use `asyncio.gather()` for parallel operations108- Implement proper error handling with try/except blocks109- Use `async with` for context managers110111```python112async def get_devices(self, site_id: str) -> List[Dict]:113 """Fetch devices with error handling."""114 try:115 async with self.session.get(f"/sites/{site_id}/devices") as response:116 response.raise_for_status()117 return await response.json()118 except aiohttp.ClientError as e:119 logger.error(f"Failed to fetch devices: {e}")120 raise121```122123### 2. MCP Tool Development124125#### Tool Structure Template126127When creating new MCP tools, follow this pattern:128129```python130@mcp.tool()131async def tool_name(132 site_id: str,133 param: str,134 confirm: bool = False,135 dry_run: bool = False136) -> Dict[str, Any]:137 """138 Brief description of what the tool does.139140 Args:141 site_id: UniFi site identifier (e.g., 'default')142 param: Description of parameter143 confirm: Required safety flag for mutating operations144 dry_run: Preview changes without applying145146 Returns:147 Dictionary containing operation results148149 Raises:150 ValueError: If validation fails151 APIError: If UniFi API request fails152 """153 # 1. Input validation154 if not site_id:155 raise ValueError("site_id is required")156157 # 2. Safety checks for mutating operations158 if not dry_run and not confirm:159 return {160 "error": "confirm=True required for this operation",161 "dry_run_available": True162 }163164 # 3. Dry-run preview165 if dry_run:166 return {167 "dry_run": True,168 "would_perform": "description of action",169 "affected_resources": ["list", "of", "resources"]170 }171172 # 4. Execute operation173 try:174 result = await unifi_api.perform_action(site_id, param)175176 # 5. Audit logging177 logger.info(f"Tool executed: {tool_name}", extra={178 "site_id": site_id,179 "param": param,180 "result": result181 })182183 return result184185 except Exception as e:186 logger.error(f"Tool failed: {e}")187 raise188```189190#### Safety Mechanisms (CRITICAL)191192**All mutating operations MUST implement:**1931941. **`confirm` parameter**: Explicit opt-in for changes1952. **`dry_run` parameter**: Preview before execution1963. **Input validation**: Comprehensive parameter checks1974. **Audit logging**: Record all actions to `audit.log`1985. **Error handling**: Graceful failure with informative messages199200### 3. Testing Requirements201202#### Test Coverage Expectations203204- **Unit tests**: 80% coverage target (currently 37%)205- **Test file location**: `tests/unit/test_<module>.py`206- **Fixtures**: Use pytest fixtures for common setup207- **Mocking**: Mock external API calls208209```python210import pytest211from unittest.mock import AsyncMock, patch212213@pytest.mark.asyncio214async def test_create_firewall_rule():215 """Test firewall rule creation with validation."""216 # Arrange217 mock_api = AsyncMock()218 mock_api.create_rule.return_value = {"_id": "rule123", "name": "test"}219220 # Act221 with patch("src.api.client.UniFiAPI", return_value=mock_api):222 result = await create_firewall_rule(223 site_id="default",224 name="test",225 action="accept",226 confirm=True227 )228229 # Assert230 assert result["name"] == "test"231 mock_api.create_rule.assert_called_once()232```233234#### Running Tests235236```bash237# Run all tests with coverage238pytest tests/unit/ --cov=src --cov-report=html --cov-report=term-missing239240# Run specific test file241pytest tests/unit/test_firewall_tools.py -v242243# Run tests for specific feature244pytest -k "firewall" -v245246# Run with debugging247pytest --pdb tests/unit/test_firewall_tools.py248```249250### 4. API Integration Patterns251252#### UniFi API Client Usage253254```python255# Always use the configured API client256from src.api.client import UniFiAPI257258async with UniFiAPI(config) as api:259 # List operations260 devices = await api.get(f"/sites/{site_id}/devices")261262 # Create operations263 new_rule = await api.post(264 f"/sites/{site_id}/firewall/rules",265 json=rule_data266 )267268 # Update operations269 updated = await api.put(270 f"/sites/{site_id}/firewall/rules/{rule_id}",271 json=updated_data272 )273274 # Delete operations275 await api.delete(f"/sites/{site_id}/firewall/rules/{rule_id}")276```277278#### Rate Limiting279280The API client implements automatic rate limiting:281282- Default: 10 requests per second283- Automatic backoff on 429 responses284- No manual rate limiting needed in tools285286### 5. Pydantic Model Development287288#### Model Best Practices289290```python291from pydantic import BaseModel, Field, validator, root_validator292from typing import Optional, List, Literal293294class FirewallZone(BaseModel):295 """Zone-Based Firewall zone configuration."""296297 # Required fields with descriptions298 name: str = Field(..., description="Zone name (e.g., 'LAN', 'IoT')")299 site_id: str = Field(..., description="UniFi site identifier")300301 # Optional fields with defaults302 description: Optional[str] = Field(None, description="Zone description")303 enabled: bool = Field(True, description="Whether zone is active")304305 # Constrained fields306 networks: List[str] = Field(307 default_factory=list,308 description="Network IDs in this zone",309 min_items=0,310 max_items=50311 )312313 # Custom validation314 @validator("name")315 def validate_name(cls, v):316 """Validate zone name format."""317 if not v or len(v) < 3:318 raise ValueError("Zone name must be at least 3 characters")319 if not v.replace("-", "").replace("_", "").isalnum():320 raise ValueError("Zone name must be alphanumeric")321 return v322323 @root_validator324 def check_consistency(cls, values):325 """Validate field consistency."""326 if values.get("enabled") and not values.get("networks"):327 raise ValueError("Enabled zones must have at least one network")328 return values329330 class Config:331 """Pydantic configuration."""332 # Allow extra fields for forward compatibility333 extra = "allow"334 # Use enum values directly335 use_enum_values = True336 # Validate on assignment337 validate_assignment = True338```339340### 6. Error Handling \& Logging341342#### Logging Standards343344```python345import logging346from src.utils.logging import get_logger347348logger = get_logger(__name__)349350# Info: Normal operations351logger.info("Device restarted", extra={"device_id": device_id, "site_id": site_id})352353# Warning: Recoverable issues354logger.warning("Rate limit approached", extra={"requests": count})355356# Error: Operation failures357logger.error("API request failed", extra={"endpoint": url, "status": status}, exc_info=True)358359# Debug: Detailed tracing (development only)360logger.debug("Request payload", extra={"data": sanitize(payload)})361```362363#### Exception Handling364365```python366from src.utils.exceptions import (367 UniFiAPIError,368 ValidationError,369 AuthenticationError,370 RateLimitError371)372373try:374 result = await api.create_resource(data)375except ValidationError as e:376 logger.error(f"Validation failed: {e}")377 return {"error": "Invalid input", "details": str(e)}378except AuthenticationError as e:379 logger.error("Authentication failed")380 raise # Re-raise auth errors381except RateLimitError as e:382 logger.warning("Rate limited, retrying...")383 await asyncio.sleep(e.retry_after)384 # Retry logic385except UniFiAPIError as e:386 logger.error(f"API error: {e}")387 return {"error": "API request failed", "message": str(e)}388```389390***391392## Gemini Workflow Examples393394### Adding a New MCP Tool395396```bash397# 1. Understand the UniFi API endpoint398gemini "Explain the UniFi API endpoint for creating VLANs. Include request format, parameters, and response structure."399400# 2. Generate the tool implementation401gemini "Create an MCP tool called 'create_vlan' that creates a VLAN in UniFi. Follow the patterns in src/tools/network_config.py. Include confirm and dry_run parameters."402403# 3. Generate Pydantic models404gemini "Create Pydantic models for VLAN configuration with validation. Include fields for VLAN ID (1-4094), name, subnet, DHCP settings."405406# 4. Generate unit tests407gemini "Generate pytest unit tests for the create_vlan tool. Mock the UniFi API client. Test successful creation, validation errors, and dry-run mode."408409# 5. Update documentation410gemini "Update API.md to document the new create_vlan tool. Include examples and parameter descriptions."411```412413### Debugging Existing Code414415```bash416# Analyze error logs417gemini "Analyze this error traceback and suggest fixes: [paste traceback]"418419# Optimize performance420gemini "Review src/tools/dpi.py for performance issues. The list_top_applications tool is slow with large datasets. Suggest optimizations."421422# Refactor for clarity423gemini "Refactor src/tools/firewall_zones.py to improve readability. Reduce complexity in the assign_network_to_zone function."424```425426### Code Review Assistance427428```bash429# Before committing430gemini "Review my changes in src/tools/wifi.py. Check for: type safety, error handling, async patterns, test coverage, documentation."431432# Security audit433gemini "Security audit this code for potential vulnerabilities: [paste code]. Focus on input validation, authentication, and data sanitization."434```435436***437438## Common Tasks \& Commands439440### Development Workflow441442```bash443# Start with context loading444gemini /init # Generate initial GEMINI.md context445446# Daily development447gemini "Review open issues on GitHub and suggest which to tackle first"448gemini "Explain the Zone-Based Firewall implementation in src/models/zbf.py"449gemini "Help me implement the missing endpoint for zone policy matrix"450451# Before PR452gemini "Run pre-commit checks and fix any issues"453gemini "Generate release notes for changes in the current branch"454```455456### Testing \& Quality457458```bash459# Generate test cases460gemini "Generate test cases for edge cases in src/tools/client_management.py"461462# Improve coverage463gemini "Which modules have coverage below 50%? Suggest unit tests to improve coverage."464465# Static analysis466gemini "Run mypy on src/ and fix type errors"467```468469### Documentation470471```bash472# Generate docstrings473gemini "Add comprehensive docstrings to all functions in src/tools/port_forwarding.py following Google style"474475# Update API docs476gemini "Update API.md with the latest tool signatures from src/main.py"477478# Create examples479gemini "Create 5 practical examples of using the DPI statistics tools"480```481482***483484## Known Limitations \& Workarounds485486### Zone-Based Firewall API Issues487488**Problem**: 8 ZBF tools cannot function due to missing UniFi API endpoints (verified on v10.0.156):489490- Zone policy matrix endpoints (get, update, delete)491- Application blocking per zone492- Zone statistics493494**Workaround**:495496```python497# Use console-based configuration for these features498# Document limitations clearly in tool docstrings499500@mcp.tool()501async def update_zbf_policy_matrix(site_id: str, source_zone_id: str, dest_zone_id: str, action: str) -> Dict:502 """503 ⚠️ API LIMITATION: This endpoint does not exist in UniFi API v10.0.156.504505 Configure zone policies via UniFi Console:506 Settings → Security → Zone-Based Firewall → Policy Matrix507508 Args:509 site_id: UniFi site identifier510 source_zone_id: Source zone ID511 dest_zone_id: Destination zone ID512 action: Policy action ('accept', 'drop', 'reject')513514 Returns:515 Error message explaining API limitation516 """517 return {518 "error": "API endpoint not available",519 "api_version": "v10.0.156",520 "workaround": "Configure via UniFi Console UI",521 "documentation": "See ZBF_STATUS.md for details"522 }523```524525### Redis Caching526527**Best Practice**: Always check cache configuration:528529```python530# Tools should handle cache absence gracefully531cache = get_cache() # May return None532if cache:533 cached_data = await cache.get(key)534 if cached_data:535 return cached_data536537# Fetch from API538data = await api.get_data()539540# Cache if available541if cache:542 await cache.set(key, data, ttl=300)543```544545***546547## Integration with Other AI Agents548549### Cross-Agent Collaboration550551This project supports multiple AI coding assistants. Coordination patterns:5525531. **Gemini**: High-level architecture, API design, batch operations5542. **Claude**: Complex refactoring, documentation generation, code review5553. **Copilot**: Rapid boilerplate, autocomplete, inline suggestions5564. **Cursor**: Multi-file edits, codebase-wide changes557558### Shared Context Files559560All agents read from:561562- `AGENTS.md` - Universal rules563- `API.md` - API documentation564- `SECURITY.md` - Security policies565- `CONTRIBUTING.md` - Contribution guidelines566567Agent-specific files:568569- `GEMINI.md` (this file)570- `CLAUDE.md`571- `.cursorrules`572- `copilot-instructions.md`573574***575576## Performance Optimization577578### Batch Operations579580```python581# Use asyncio.gather for parallel requests582async def batch_restart_devices(device_ids: List[str], site_id: str):583 """Restart multiple devices in parallel."""584 tasks = [restart_device(device_id, site_id) for device_id in device_ids]585 results = await asyncio.gather(*tasks, return_exceptions=True)586587 # Process results588 successes = [r for r in results if not isinstance(r, Exception)]589 failures = [r for r in results if isinstance(r, Exception)]590591 return {"successes": len(successes), "failures": len(failures)}592```593594### Caching Strategies595596```python597# Cache expensive operations598@cached(ttl=600) # 10 minutes599async def get_network_topology(site_id: str) -> Dict:600 """Get network topology with caching."""601 devices = await api.get_devices(site_id)602 clients = await api.get_clients(site_id)603 networks = await api.get_networks(site_id)604605 # Build topology606 return build_topology(devices, clients, networks)607```608609***610611## Security Considerations612613### API Key Management614615```python616# ✅ CORRECT: Load from environment617UNIFI_API_KEY = os.getenv("UNIFI_API_KEY")618619# ❌ WRONG: Hardcode API key620UNIFI_API_KEY = "xyz123abc" # NEVER DO THIS621```622623### Input Sanitization624625```python626# Sanitize user inputs627def sanitize_firewall_rule_name(name: str) -> str:628 """Remove unsafe characters from rule name."""629 # Allow alphanumeric, hyphens, underscores, spaces630 return re.sub(r'[^a-zA-Z0-9\-_ ]', '', name)631```632633### Audit Logging634635All mutating operations are logged to `audit.log`:636637```python638# Audit log format639{640 "timestamp": "2025-11-19T21:30:00Z",641 "tool": "create_firewall_rule",642 "user": "system",643 "site_id": "default",644 "action": "create",645 "resource_type": "firewall_rule",646 "resource_id": "rule_id",647 "parameters": {"name": "block-malware", "action": "drop"},648 "result": "success"649}650```651652***653654## Troubleshooting655656### Common Issues657658#### MCP Server Won't Start659660```bash661# Check Python version662python --version # Must be 3.10+663664# Check dependencies665uv pip list | grep fastmcp666667# Test configuration668python -c "from src.config import load_config; print(load_config())"669```670671#### UniFi API Connection Fails672673```bash674# Verify API key675echo $UNIFI_API_KEY676677# Test API connectivity678curl -H "X-API-Key: $UNIFI_API_KEY" https://api.ui.com/ea/hosts679```680681#### Tests Failing682683```bash684# Clear pytest cache685rm -rf .pytest_cache686687# Run with verbose output688pytest -vv tests/unit/test_failing_module.py689690# Check for async issues691pytest -k "async" --tb=short692```693694***695696## Contributing Back697698### Before Submitting PR6997001. **Run full test suite**: `pytest tests/unit/ --cov=src`7012. **Run pre-commit**: `pre-commit run --all-files`7023. **Update documentation**: Ensure API.md reflects changes7034. **Add tests**: Maintain >80% coverage7045. **Follow conventions**: Review CONTRIBUTING.md705706### Commit Message Format707708```709feat(tools): add VLAN creation tool710711- Implement create_vlan MCP tool712- Add VLANConfig Pydantic model with validation713- Include unit tests (95% coverage)714- Update API.md documentation715716Closes #123717```718719***720721## Additional Resources722723### Documentation724725- **Main README**: [README.md](README.md)726- **API Reference**: [API.md](API.md)727- **Security Policy**: [SECURITY.md](SECURITY.md)728- **Development Plan**: [DEVELOPMENT_PLAN.md](DEVELOPMENT_PLAN.md)729- **Testing Strategy**: [TESTING_PLAN.md](TESTING_PLAN.md)730- **ZBF Status**: [ZBF_STATUS.md](ZBF_STATUS.md)731732### External Links733734- **UniFi API Documentation**: <https://developer.ui.com/>735- **FastMCP Framework**: <https://github.com/jlowin/fastmcp>736- **MCP Specification**: <https://modelcontextprotocol.io/>737- **Gemini CLI Docs**: <https://geminicli.com/>738739### Community740741- **GitHub Issues**: <https://github.com/enuno/unifi-mcp-server/issues>742- **GitHub Discussions**: <https://github.com/enuno/unifi-mcp-server/discussions>743- **UniFi Community**: <https://community.ui.com/>744745***746747## Version History748749- **v1.0.0** (2025-11-19): Initial Gemini configuration for UniFi MCP Server750- Updated with project-specific context, tool patterns, and Gemini CLI integration751752***753754**Last Updated**: November 19, 2025755**Maintained By**: UniFi MCP Server Team756**Review Cycle**: Monthly or upon significant Gemini CLI updates757
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-server.cursorrules · 226 | .cursorrules | setuptestlint-formatstyle+7 | 93/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 |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| google-gemini/gemini-cliGEMINI.md · 107k | GEMINI.md | setupbuildtestlint-format+6 | 91/100 | 14 days ago | |
| compozy/gographGEMINI.md · 9 | GEMINI.md | setuptestlint-formatarch+4 | 86/100 | 14 days ago | |
| doubts-suplab/eeik-bootstrapGEMINI.md · 1 | GEMINI.md | teststylearchgit+2 | 80/100 | today | |
| zigcc/zig-cookbookGEMINI.md · 1.2k | GEMINI.md | setupbuildlint-formatstyle+3 | 79/100 | 14 days ago | |
| iloveitaly/llm-ide-rulesGEMINI.md · 13 | GEMINI.md | setupteststyletypes+7 | 77/100 | 14 days ago | |
| nodejs/nodedeps/v8/GEMINI.md · 119k | GEMINI.md | buildteststylearch+4 | 77/100 | 14 days ago | |
| zyx77550/spardaGEMINI.md · 5 | GEMINI.md | testlint-formatgitapi+2 | 75/100 | 14 days ago | |
| google-gemini/gemini-clipackages/devtools/GEMINI.md · 107k | GEMINI.md | setupbuildarchapi+1 | 74/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-gemini)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.