

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1234567# UniFi API Guidelines89## Authentication with API Keys1011This project uses the **official UniFi Cloud API** with API key authentication.1213**Authentication Method:**1415- Use `UNIFI_API_KEY` environment variable for authentication16- API key is passed via the `X-API-Key` HTTP header17- No session management or cookies required (stateless authentication)1819**NEVER hardcode API keys:**2021```python22# ❌ BAD - Hardcoded API key23headers = {24 "X-API-Key": "abc123def456..."25}2627# ✅ GOOD - Load from environment28from src.config.config import Settings2930settings = Settings()31headers = {32 "X-API-Key": settings.api_key33}34```3536## API Access Modes3738Support both cloud and local gateway access modes:3940**Cloud API (Default):**41```python42# Base URL: https://api.ui.com/v1/43settings.api_type = "cloud"44settings.cloud_api_url = "https://api.ui.com"45```4647**Local Gateway Proxy:**48```python49# Base URL: https://{gateway-ip}/proxy/network/integration/v1/50settings.api_type = "local"51settings.local_host = "192.168.2.1"52settings.local_port = 44353```5455## Read-Only Limitation5657**IMPORTANT:** The Early Access API is currently **read-only**.5859```python60# ✅ ALLOWED - Read operations61async def list_devices(site_id: str):62 """List all devices - read operation."""63 devices = await client.get(f"/v1/sites/{site_id}/devices")64 return devices6566# ❌ NOT AVAILABLE - Write operations (will fail)67async def create_network(name: str, vlan_id: int):68 """Create network - not yet supported in EA API."""69 # This will return 403 Forbidden in current API version70 raise NotImplementedError(71 "Write operations are not available in the Early Access API. "72 "This feature will be available in v1 Stable release."73 )74```7576**Handling write requests:**7778- Document that write operations are not yet available79- Return clear error messages to users80- Consider implementing a "preview" mode that shows what would be created81- Monitor UniFi API release notes for v1 Stable availability8283## Rate Limiting Considerations8485Implement proper rate limiting to respect API limits:8687**Current Limits:**8889- Early Access: 100 requests/minute90- v1 Stable (future): 10,000 requests/minute9192**Best Practices:**9394- Cache frequently accessed data (devices, sites, networks)95- Batch operations when possible96- Implement exponential backoff for 429 errors97- Use configurable rate limits via `UNIFI_RATE_LIMIT` environment variable98- Log rate limit warnings for monitoring99100## API Error Handling101102Handle UniFi API-specific errors gracefully:103104```python105import httpx106from typing import Dict, Any107108class UniFiAPIError(Exception):109 """Base exception for UniFi API errors."""110 pass111112class UniFiAuthenticationError(UniFiAPIError):113 """Authentication failed - invalid API key."""114 pass115116class UniFiRateLimitError(UniFiAPIError):117 """Rate limit exceeded."""118 pass119120async def safe_api_request(121 client: httpx.AsyncClient,122 method: str,123 endpoint: str,124 **kwargs125) -> Dict[str, Any]:126 """127 Make a safe API request with proper error handling.128129 Args:130 client: HTTP client131 method: HTTP method (GET, POST, etc.)132 endpoint: API endpoint133 **kwargs: Additional request parameters134135 Returns:136 Response data as dictionary137138 Raises:139 UniFiAuthenticationError: Invalid API key140 UniFiRateLimitError: Rate limit exceeded141 UniFiAPIError: Other API errors142 """143 try:144 response = await client.request(method, endpoint, **kwargs)145 response.raise_for_status()146 return response.json()147148 except httpx.HTTPStatusError as e:149 if e.response.status_code == 401:150 raise UniFiAuthenticationError(151 "Invalid API key. Please check your UNIFI_API_KEY."152 )153 elif e.response.status_code == 429:154 retry_after = e.response.headers.get("Retry-After", 60)155 raise UniFiRateLimitError(156 f"Rate limit exceeded. Retry after {retry_after} seconds."157 )158 else:159 raise UniFiAPIError(f"API error: {e.response.status_code}")160161 except httpx.RequestError as e:162 raise UniFiAPIError(f"Request failed: {str(e)}")163```164165## Centralize API Calls166167Keep all API interactions in dedicated modules:168169```python170# src/api/client.py171class UniFiClient:172 async def request(173 self,174 method: str,175 endpoint: str,176 **kwargs177 ) -> Dict[str, Any]:178 """179 Make authenticated request to UniFi API.180181 Handles authentication, retries, and error handling.182 """183 # Centralized implementation184 pass185```186187## Official API Documentation188189Always reference the official UniFi API documentation:190191- **Getting Started**: https://developer.ui.com/site-manager-api/gettingstarted192- **Project Reference**: `docs/UNIFI_API.md` (comprehensive guide)193- **API Tutorial**: https://www.makewithdata.tech/p/build-a-mcp-server-for-ai-access194
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/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 | |
| 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 |
|---|---|---|---|---|---|
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 46 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 46 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| nerds-odd-e/doughnut.cursor/rules/cli.mdc · 49 | Cursor rules | setupbuildteststyle+4 | 96/100 | 14 days ago | |
| pr-pm/prpm.cursor/rules/github-actions-testing.mdc · 121 | Cursor rules | setupbuildstylearch+4 | 93/100 | 14 days ago | |
| enuno/unifi-mcp-server.cursor/rules/common-mistakes.mdc · 226 | Cursor rules | testlint-formatgitdo-not | 93/100 | today | |
| iloveitaly/llm-ide-rules.cursor/rules/general.mdc · 13 | Cursor rules | teststyledo-notagent-behaviour+1 | 92/100 | 14 days ago | |
| pr-pm/prpm.cursor/rules/creating-agents-md.mdc · 121 | Cursor rules | testlint-formatstylearch+7 | 92/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-cursor-rules-unifi-api)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.