Agent skill

Unifi MCP Tool Builder

by enuno in enuno/unifi-mcp-server

Specialized guide for adding new MCP tools to the UniFi MCP Server following project standards, UniFi API patterns, and test-driven development practices.

Apache-2.0Auto-check passedAgent Workflows

Install Unifi MCP Tool Builder

skills CLI
$ npx skills add enuno/unifi-mcp-server --skill unifi-mcp-tool-builder -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install enuno/unifi-mcp-server unifi-mcp-tool-builder --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/enuno/unifi-mcp-server.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/unifi-mcp-tool-builder .claude/skills/unifi-mcp-tool-builder && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
unifi-mcp-tool-builder
GitHub stars
284
Token cost
~5.8k tokens
SKILL.md length
1,097 words
Files
1
Skills in repo
12
Repo updated
First seen
Licence
Apache-2.0

At a glance

Specialized guide for adding new MCP tools to the UniFi MCP Server following project standards, UniFi API patterns, and test-driven development practices.

  • Works in 5 steps: Research and Planning → Implementation → Test-Driven Development → …
  • Implementing new UniFi Network Controller features as MCP tools
  • SKILL.md covers Overview, Phase 1: Research and Planning, Phase 2: Implementation and Phase 3: Test-Driven Development, plus 3 more sections
  • Calls pytest, black and ruff

What it does

Unifi MCP Tool Builder is an agent skill from enuno/unifi-mcp-server. Specialized guide for adding new MCP tools to the UniFi MCP Server following project standards, UniFi API patterns, and test-driven development practices. Use when implementing new UniFi Network Controller features as MCP tools.

Its SKILL.md is about 5.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Agent Workflows, covering MCP servers and Test-driven development. It works with Model Context Protocol and Pydantic. The repository describes itself as: An MCP server that leverages official UniFi API. The licence is Apache-2.0.

When your agent uses it

  • Implementing new UniFi Network Controller features as MCP tools
  • Tasks that involve MCP servers
  • Tasks that involve Test-driven development

Example prompts

  • “/unifi-mcp-tool-builder”

Requirements

  • Python 3

Workflow steps

5 steps, taken from the step headings in SKILL.md.

  1. Research and Planning
  2. Implementation
  3. Test-Driven Development
  4. Documentation
  5. Quality Verification

What it can do on your machine

Read from SKILL.md and the folder at commit a907070. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pytest
    • black
    • ruff
    • mypy
    • uv

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • developer.ui.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Unifi MCP Tool Builder loads about 5.8k tokens when it runs. Until then it costs about 63 tokens; SKILL.md has 1,097 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~63
When it runs · the whole SKILL.md, loaded when a task matches
~5.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from enuno/unifi-mcp-server at commit a907070, republished under its Apache-2.0 licence (© enuno). 1,097 words, ~5,819 tokens.

Download SKILL.mdSave it as .claude/skills/unifi-mcp-tool-builder/SKILL.md (or your agent's skills folder).
name
unifi-mcp-tool-builder
description
Specialized guide for adding new MCP tools to the UniFi MCP Server following project standards, UniFi API patterns, and test-driven development practices. Use when implementing new UniFi Network Controller features as MCP tools.
license
Apache 2.0
version
1.0.0
author
UniFi MCP Server Team

UniFi MCP Tool Builder

Overview

This skill guides you through adding new MCP tools to the existing UniFi MCP Server. Unlike building an MCP server from scratch, this focuses on extending the current 74-tool implementation with new UniFi Network Controller functionality while maintaining the project's quality standards.

Project Context:

  • Existing Tools: 74 MCP tools across 9 feature categories
  • Test Coverage: 990 tests, 78.18% overall coverage
  • Architecture: FastMCP + Pydantic v2 + async/await patterns
  • API Support: Local gateway (full), Cloud V1/EA (limited)
  • Quality Standards: 80% minimum test coverage, TDD required

Process

Phase 1: Research and Planning

1.1 Understand the Tool Request

Before implementation, clarify:

  • What UniFi feature/endpoint needs to be exposed?
  • Which API mode supports it (local, cloud-v1, cloud-ea)?
  • What workflow does this enable for AI agents?
  • How does this fit into existing tool categories?

Tool Categories in UniFi MCP Server:

  1. Device Management (list, control, upgrade)
  2. Client Management (block, unblock, statistics)
  3. Network Configuration (VLANs, subnets, DHCP)
  4. Firewall & Security (rules, zones, ACLs)
  5. WiFi/SSID Management (create, configure, statistics)
  6. QoS & Traffic (profiles, flows, DPI)
  7. Backup & Restore (automated backups, restore)
  8. Site Management (multi-site, aggregation)
  9. Topology & Monitoring (network maps, health)
1.2 Study UniFi API Documentation

Load UniFi API reference:

bash
# Read the comprehensive UniFi API documentation
Read: docs/UNIFI_API.md

This document contains verified endpoints for UniFi Network v10.0.156+.

Critical considerations:

  • Endpoint availability: Not all documented endpoints exist in all versions
  • API mode differences: Local gateway vs Cloud APIs have different capabilities
  • Response formats: Local API returns different structures than Cloud API
  • Authentication: Local uses local credentials, Cloud uses API keys
1.3 Review Existing Patterns

Study similar tools in the codebase:

bash
# Example: For a new device tool, read existing device tools
Read: src/tools/devices.py
Read: src/tools/device_control.py

# For network tools:
Read: src/tools/networks.py
Read: src/tools/network_config.py

# For testing patterns:
Read: tests/unit/test_devices.py

Key patterns to identify:

  • How similar tools structure their inputs (Pydantic models)
  • Response formatting (JSON with TypedDict or Pydantic response models)
  • Error handling patterns
  • Confirmation requirements for mutating operations
  • Dry-run mode implementation
  • Caching strategies (if applicable)
1.4 Verify API Endpoint Availability

CRITICAL: Not all documented API endpoints actually exist!

The UniFi MCP Server has discovered that many documented endpoints don't exist in real controllers. Before implementation:

  1. Check endpoint existence in docs/UNIFI_API.md verification notes
  2. Test on real hardware if possible (U7 Express, UDM Pro, etc.)
  3. Document findings in code comments and API.md

Known endpoint issues:

  • ZBF matrix endpoints don't exist (use Firewall Policies v2 instead)
  • Some statistics endpoints are documented but not available
  • Cloud APIs have very limited endpoint support vs local gateway
1.5 Create Implementation Plan

Document your plan covering:

Tool Definition:

  • Tool name (follow naming convention: {action}_{resource})
  • Description (one-line summary for LLMs)
  • Input parameters (with Pydantic model)
  • Response format (TypedDict or Pydantic model)
  • Error scenarios

Data Models:

  • Pydantic models for request validation
  • Response models (if complex data structure)
  • Enums for allowed values

Testing Strategy:

  • Unit test scenarios (minimum 10-15 tests)
  • Mock API responses
  • Edge cases (empty results, errors, pagination)
  • Target coverage: 85%+ for new code

Documentation:

  • Docstring with examples
  • API.md section update
  • README.md feature list update (if major feature)

Phase 2: Implementation

2.1 Create Pydantic Models (if needed)

Location: src/models/{feature}.py

python
from enum import Enum
from typing import Optional
from pydantic import BaseModel, Field, ConfigDict

class YourRequestModel(BaseModel):
    """Request model for your_tool operation.

    Attributes:
        site_id: UniFi site identifier
        resource_id: Resource to operate on
        options: Optional configuration parameters
    """
    model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)

    site_id: str = Field(..., description="UniFi site ID (e.g., 'default')")
    resource_id: str = Field(..., min_length=1, description="Resource identifier")
    options: Optional[dict] = Field(None, description="Additional options")

class YourResponseModel(BaseModel):
    """Response from your_tool operation."""
    success: bool
    resource_id: str
    message: str

Key requirements:

  • Use Pydantic v2 syntax (model_config instead of Config)
  • extra="forbid" to reject unknown fields
  • Comprehensive Field descriptions for LLM understanding
  • Type hints for all fields
  • Docstrings explaining purpose
2.2 Implement the MCP Tool

Location: src/tools/{category}.py (or new file if new category)

python
from fastmcp import Context
from src.models.your_model import YourRequestModel, YourResponseModel
from src.api.client import UniFiClient
from src.utils.validators import validate_site_id

@mcp.tool()
async def your_tool_name(
    site_id: str,
    resource_id: str,
    options: dict | None = None,
    settings: Context = None,
    confirm: bool = False,
    dry_run: bool = False,
) -> dict:
    """Brief one-line description of what this tool does.

    Detailed explanation of the tool's purpose, when to use it,
    and what it accomplishes. Include examples of common use cases.

    Args:
        site_id: UniFi site identifier (e.g., 'default')
        resource_id: Resource to operate on
        options: Optional configuration dictionary
        settings: FastMCP context (auto-injected)
        confirm: Required for mutating operations (default: False)
        dry_run: Preview changes without applying (default: False)

    Returns:
        Dictionary containing:
        - success: Operation success status
        - resource_id: Modified resource identifier
        - message: Human-readable result message
        - details: (if dry_run) Preview of changes

    Raises:
        ValueError: If site_id is invalid or resource not found
        PermissionError: If confirm=True not provided for mutation

    Examples:
        >>> # Read-only operation
        >>> result = await your_tool_name(site_id="default", resource_id="abc123")

        >>> # Mutating operation (requires confirmation)
        >>> result = await your_tool_name(
        ...     site_id="default",
        ...     resource_id="abc123",
        ...     confirm=True
        ... )

        >>> # Preview changes first
        >>> preview = await your_tool_name(
        ...     site_id="default",
        ...     resource_id="abc123",
        ...     dry_run=True
        ... )
    """
    # Validate inputs
    validate_site_id(site_id)

    # Get client from context
    client: UniFiClient = settings.get("client")

    # MUTATING OPERATIONS: Require confirmation
    if not dry_run:
        if not confirm:
            raise PermissionError(
                "This operation modifies network configuration. "
                "Set confirm=True to proceed, or use dry_run=True to preview changes."
            )

    # Dry-run mode: Preview changes
    if dry_run:
        return {
            "success": True,
            "dry_run": True,
            "preview": {
                "operation": "your_operation",
                "resource_id": resource_id,
                "changes": {"key": "value"},
            },
            "message": "Dry-run completed. Set confirm=True to apply changes."
        }

    # Execute operation
    try:
        response = await client.request(
            method="POST",
            endpoint=f"/api/s/{site_id}/rest/your_endpoint",
            json={"resource_id": resource_id, **(options or {})},
        )

        return {
            "success": True,
            "resource_id": resource_id,
            "message": f"Successfully processed resource {resource_id}",
            "data": response.get("data", {}),
        }

    except Exception as e:
        # Provide actionable error messages
        if "not found" in str(e).lower():
            raise ValueError(
                f"Resource '{resource_id}' not found in site '{site_id}'. "
                f"Use list_resources tool to see available resources."
            ) from e
        raise

Implementation checklist:

  • FastMCP @mcp.tool() decorator
  • Comprehensive docstring with examples
  • Input validation (use existing validators in src/utils/validators.py)
  • Confirm requirement for mutating operations
  • Dry-run mode support for previewing changes
  • Actionable error messages that guide LLM to correct usage
  • Async/await for all I/O operations
  • Proper exception handling with context
2.3 Register Tool in Main Server

Location: src/main.py

Add your tool to the imports and ensure it's registered:

python
from src.tools.your_category import your_tool_name

# Tools are auto-registered via @mcp.tool() decorator
# No manual registration needed with FastMCP
2.4 Follow Code Quality Standards

Run quality checks:

bash
# Format code
black src/tools/your_file.py
isort src/tools/your_file.py

# Lint
ruff check src/tools/your_file.py --fix

# Type check
mypy src/tools/your_file.py

Phase 3: Test-Driven Development

3.1 Write Tests BEFORE Implementation

Location: tests/unit/test_{category}.py

CRITICAL: UniFi MCP Server requires Test-Driven Development (TDD)

  1. Write failing tests first
  2. Implement just enough to make tests pass
  3. Refactor and improve
  4. Achieve 85%+ coverage for new code
Show full SKILL.md (455 more words)Show less
3.2 Test Structure
python
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from src.tools.your_category import your_tool_name

class TestYourToolName:
    """Test suite for your_tool_name."""

    @pytest.fixture
    def mock_context(self):
        """Mock FastMCP context with UniFi client."""
        context = MagicMock()
        client = AsyncMock()
        context.get.return_value = client
        return context, client

    @pytest.mark.asyncio
    async def test_successful_operation(self, mock_context):
        """Test successful tool execution."""
        context, client = mock_context
        client.request.return_value = {
            "data": {"_id": "abc123", "name": "test"}
        }

        result = await your_tool_name(
            site_id="default",
            resource_id="abc123",
            settings=context,
            confirm=True
        )

        assert result["success"] is True
        assert result["resource_id"] == "abc123"
        client.request.assert_called_once()

    @pytest.mark.asyncio
    async def test_requires_confirmation(self, mock_context):
        """Test that mutating operations require confirm=True."""
        context, client = mock_context

        with pytest.raises(PermissionError, match="Set confirm=True"):
            await your_tool_name(
                site_id="default",
                resource_id="abc123",
                settings=context,
                confirm=False
            )

    @pytest.mark.asyncio
    async def test_dry_run_mode(self, mock_context):
        """Test dry-run preview mode."""
        context, client = mock_context

        result = await your_tool_name(
            site_id="default",
            resource_id="abc123",
            settings=context,
            dry_run=True
        )

        assert result["dry_run"] is True
        assert "preview" in result
        client.request.assert_not_called()

    @pytest.mark.asyncio
    async def test_invalid_site_id(self, mock_context):
        """Test validation of site_id."""
        context, client = mock_context

        with pytest.raises(ValueError, match="Invalid site"):
            await your_tool_name(
                site_id="",
                resource_id="abc123",
                settings=context
            )

    @pytest.mark.asyncio
    async def test_resource_not_found(self, mock_context):
        """Test handling of not found errors."""
        context, client = mock_context
        client.request.side_effect = Exception("Resource not found")

        with pytest.raises(ValueError, match="not found"):
            await your_tool_name(
                site_id="default",
                resource_id="nonexistent",
                settings=context,
                confirm=True
            )

    @pytest.mark.asyncio
    async def test_with_optional_parameters(self, mock_context):
        """Test tool with optional parameters."""
        context, client = mock_context
        client.request.return_value = {"data": {"_id": "abc123"}}

        result = await your_tool_name(
            site_id="default",
            resource_id="abc123",
            options={"key": "value"},
            settings=context,
            confirm=True
        )

        assert result["success"] is True
        # Verify options were passed to API
        call_args = client.request.call_args
        assert call_args[1]["json"]["key"] == "value"

Test coverage requirements:

  • Successful operation (happy path)
  • Confirmation requirement (for mutating ops)
  • Dry-run mode
  • Input validation (invalid site_id, etc.)
  • Error handling (not found, API errors)
  • Optional parameters
  • Edge cases (empty results, pagination)
  • Response format validation

Target: 85%+ coverage for new code

3.3 Run Tests
bash
# Run your specific test file
pytest tests/unit/test_your_category.py -v

# Run with coverage
pytest tests/unit/test_your_category.py --cov=src/tools/your_category --cov-report=term-missing

# Ensure coverage meets target (85%+)
pytest tests/unit/test_your_category.py --cov=src/tools/your_category --cov-report=html
open htmlcov/index.html  # Review coverage report

Phase 4: Documentation

4.1 Update API.md

Location: API.md

Add your tool to the appropriate section with complete documentation:

markdown
### your_tool_name

**Description**: Brief one-line description

**Purpose**: Detailed explanation of when and why to use this tool

**Parameters**:
- `site_id` (string, required): UniFi site identifier (e.g., "default")
- `resource_id` (string, required): Resource identifier to operate on
- `options` (object, optional): Additional configuration options
- `confirm` (boolean, optional): Required for mutating operations (default: false)
- `dry_run` (boolean, optional): Preview changes without applying (default: false)

**Returns**:
```json
{
  "success": true,
  "resource_id": "abc123",
  "message": "Successfully processed resource",
  "data": { /* resource details */ }
}

Dry-run response:

json
{
  "success": true,
  "dry_run": true,
  "preview": {
    "operation": "your_operation",
    "resource_id": "abc123",
    "changes": { /* preview of changes */ }
  },
  "message": "Dry-run completed. Set confirm=True to apply changes."
}

Examples:

python
# Example 1: Preview changes (dry-run)
result = await mcp.call_tool("your_tool_name", {
    "site_id": "default",
    "resource_id": "abc123",
    "dry_run": True
})

# Example 2: Execute operation
result = await mcp.call_tool("your_tool_name", {
    "site_id": "default",
    "resource_id": "abc123",
    "confirm": True
})

Error Handling:

  • ValueError: Invalid site_id or resource not found
  • PermissionError: Mutating operation requires confirm=True
  • APIError: UniFi API returned error (check message for details)

API Endpoint: POST /api/s/{site}/rest/your_endpoint

Supported API Modes:

  • ✅ Local Gateway API (full support)
  • ⚠️ Cloud V1 API (limited support)
  • ❌ Cloud EA API (not supported)

### 4.2 Update README.md (if major feature)

If adding a new feature category, update README.md:

```markdown
### Your New Feature Category

- **Feature Name**: Description of what it enables
- **Tools**: List of new tools
- **Use Cases**: Common scenarios where this is valuable
4.3 Update CHANGELOG.md

Add entry under "Unreleased" section:

markdown
## [Unreleased]

### Added
- New tool `your_tool_name` for managing XYZ (#123)
- Support for ABC feature in UniFi Network 10.0+

Phase 5: Quality Verification

5.1 Run Full Test Suite
bash
# Run all tests
pytest tests/unit/

# Verify no regressions
pytest tests/unit/ --cov=src --cov-report=term-missing

# Check overall coverage (should remain ≥78%)
pytest tests/unit/ --cov=src --cov-report=html
5.2 Code Quality Checks
bash
# Format (auto-fix)
black src/ tests/
isort src/ tests/

# Lint (auto-fix where possible)
ruff check src/ tests/ --fix

# Type check
mypy src/

# Security scan
bandit -r src/

# Pre-commit hooks
pre-commit run --all-files
5.3 Manual Testing with MCP Inspector
bash
# Start MCP Inspector
uv run mcp dev src/main.py

# Open http://localhost:5173
# Test your new tool with real inputs
# Verify responses match expectations
5.4 Test on Real Hardware (if possible)

If you have access to a UniFi controller:

  1. Configure local gateway API credentials
  2. Test tool with real data
  3. Verify API endpoint exists and returns expected format
  4. Document any discrepancies in API.md

Quality Checklist

Before submitting:

Code Quality
  • Tool follows naming convention ({action}_{resource})
  • Comprehensive docstring with examples
  • Input validation using Pydantic models
  • Confirmation required for mutating operations
  • Dry-run mode implemented
  • Actionable error messages
  • Async/await used consistently
  • Type hints throughout
  • No hardcoded values (use constants)
  • Follows existing code patterns
Testing
  • TDD: Tests written before implementation
  • 85%+ coverage for new code
  • Tests cover happy path
  • Tests cover error scenarios
  • Tests cover edge cases
  • Mock API responses properly
  • No integration tests without real hardware
  • All tests passing
Documentation
  • API.md updated with complete tool documentation
  • Examples provided in docstring and API.md
  • Error handling documented
  • API endpoint documented
  • API mode support clearly indicated
  • CHANGELOG.md updated
  • README.md updated (if major feature)
Integration
  • Tool registered in src/main.py
  • Imports organized correctly
  • No circular dependencies
  • Compatible with existing tools
Quality Gates
  • black formatting passes
  • isort import sorting passes
  • ruff linting passes
  • mypy type checking passes
  • bandit security scan passes
  • pytest all tests pass
  • Coverage ≥78% overall, ≥85% for new code
  • Pre-commit hooks pass
  • MCP Inspector manual testing successful

Common Patterns in UniFi MCP Server

Pattern 1: List/Query Tools (Read-Only)
python
@mcp.tool()
async def list_resources(
    site_id: str,
    filters: dict | None = None,
    settings: Context = None,
) -> list[dict]:
    """List resources in the UniFi controller.

    This is a read-only operation requiring no confirmation.
    """
    client = settings.get("client")
    response = await client.request(
        method="GET",
        endpoint=f"/api/s/{site_id}/rest/resource",
        params=filters or {}
    )
    return response.get("data", [])
Pattern 2: Mutating Tools with Confirmation
python
@mcp.tool()
async def update_resource(
    site_id: str,
    resource_id: str,
    updates: dict,
    settings: Context = None,
    confirm: bool = False,
    dry_run: bool = False,
) -> dict:
    """Update a resource (requires confirmation).

    Mutating operations always require confirm=True.
    """
    if not dry_run and not confirm:
        raise PermissionError("Set confirm=True to proceed")

    if dry_run:
        return {"dry_run": True, "preview": updates}

    client = settings.get("client")
    response = await client.request(
        method="PUT",
        endpoint=f"/api/s/{site_id}/rest/resource/{resource_id}",
        json=updates
    )
    return response
Pattern 3: Tools with Pagination
python
@mcp.tool()
async def list_large_dataset(
    site_id: str,
    limit: int = 100,
    offset: int = 0,
    settings: Context = None,
) -> dict:
    """List resources with pagination support."""
    client = settings.get("client")
    response = await client.request(
        method="GET",
        endpoint=f"/api/s/{site_id}/rest/resource",
        params={"limit": limit, "offset": offset}
    )

    return {
        "data": response.get("data", []),
        "total": response.get("meta", {}).get("total", 0),
        "limit": limit,
        "offset": offset
    }
Pattern 4: Multi-Site Aggregation
python
@mcp.tool()
async def aggregate_across_sites(
    settings: Context = None,
) -> dict:
    """Aggregate data across all sites."""
    client = settings.get("client")

    # Get all sites
    sites_response = await client.request(
        method="GET",
        endpoint="/api/self/sites"
    )
    sites = sites_response.get("data", [])

    # Aggregate data
    results = []
    for site in sites:
        site_id = site["name"]
        site_data = await client.request(
            method="GET",
            endpoint=f"/api/s/{site_id}/rest/resource"
        )
        results.append({
            "site_id": site_id,
            "data": site_data.get("data", [])
        })

    return {"sites": results}

References

Project Documentation
  • README.md - Project overview and quick start
  • API.md - Complete MCP tool reference
  • AGENTS.md - AI agent development guidelines
  • DEVELOPMENT_PLAN.md - Roadmap and feature planning
  • TESTING_PLAN.md - Testing strategy and coverage goals
  • CONTRIBUTING.md - Contribution guidelines
UniFi API Documentation
Code Examples
  • src/tools/devices.py - Device management examples
  • src/tools/firewall.py - Firewall rule management patterns
  • src/tools/zbf_tools.py - Zone-Based Firewall implementation
  • src/tools/qos.py - QoS profile management examples
  • tests/unit/test_topology.py - High-coverage test examples (95%+)

Last Updated: 2026-01-25 Maintained By: UniFi MCP Server Team

© enuno, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/unifi-mcp-tool-builder of enuno/unifi-mcp-server.

Open the folder on GitHubat commit a907070

Compare with similar skills

Unifi MCP Tool Builder next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Unifi MCP Tool Builder compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Unifi MCP Tool Builder this skillenuno/unifi-mcp-server284—~5.8kAutomated safety check: PassApache-2.0
MCP Scaffoldtimothywarner-org/claude-code224—~940Automated safety check: PassMIT
MCP Server BuilderjnMetaCode/superpowers-zh8.3k—~1.4kAutomated safety check: PassMIT
Development AssistantRobThePCGuy/Claude-Patent-Creator196—~1.3kAutomated safety check: NotesMIT
MCP DeveloperJeffallan/claude-skills12k—~1.5kAutomated safety check: PassMIT
Agent QA Authoringvostride/agent-qa904—~569Automated safety check: PassCustom licence

Similar skills

  • MCP Scaffold

    timothywarner-org/claude-code

    Scaffold production-ready Python MCP servers using FastMCP. An agent skill from timothywarner-org/claude-code.

    224 GitHub stars~940 tokensUpdated 2 mo ago
    Agent WorkflowsAuto-check passed
  • MCP Server Builder

    jnMetaCode/superpowers-zh

    Methodology for designing, implementing and testing Model Context Protocol servers in TypeScript or Python, covering tool design, error handling and security, in Chinese.

    8.3k GitHub stars~1.4k tokensUpdated 3 days ago
    Agent WorkflowsAuto-check passed
  • Development Assistant

    RobThePCGuy/Claude-Patent-Creator

    Guides through adding new features, MCP tools, analyzers, and extending the patent creator system.

    196 GitHub stars~1.3k tokensUpdated 4 days ago
    Agent WorkflowsAuto-check: notes
  • MCP Developer

    Jeffallan/claude-skills

    Builds and debugs MCP servers and clients in TypeScript or Python, from tool and resource definitions to transport setup and inspector-based protocol checks.

    12k GitHub stars~1.5k tokensUpdated 7 days ago
    Agent WorkflowsAuto-check passed
  • Agent QA Authoring

    vostride/agent-qa

    A skill your agent uses when creating, editing, validating, or running agent-qa tests, suites, or hooks.

    904 GitHub stars~569 tokensUpdated 2 mo ago
    Agent WorkflowsAuto-check passed
  • Agent QA Result Triage

    vostride/agent-qa

    A skill your agent uses when investigating failed agent-qa runs, inspecting artifacts, classifying failures, or comparing recent runs.

    904 GitHub stars~394 tokensUpdated 2 mo ago
    Agent WorkflowsAuto-check passed

More from enuno/unifi-mcp-server

All 12 skills in this repo
  • Unifi

    enuno/unifi-mcp-server

    Manage UniFi network infrastructure via the UniFi MCP Server.

    284 GitHub stars~1k tokensUpdated today
    Auto-check passed
  • Source Command Unifi MCP Add Tool

    enuno/unifi-mcp-server

    Scaffold a new UniFi MCP tool with model, function, tests, and docs

    284 GitHub stars~748 tokensUpdated today
    Auto-check passed
  • Prepare a new release with version bump, changelog, and quality checks

    284 GitHub stars~939 tokensUpdated today
    Auto-check passed
  • Auto-generate and update API.md documentation from tool docstrings

    284 GitHub stars~899 tokensUpdated today
    Auto-check passed

Questions about Unifi MCP Tool Builder

What does Unifi MCP Tool Builder do?

Specialized guide for adding new MCP tools to the UniFi MCP Server following project standards, UniFi API patterns, and test-driven development practices. Unifi MCP Tool Builder is an agent skill from enuno/unifi-mcp-server. Specialized guide for adding new MCP tools to the UniFi MCP Server following project standards, UniFi API patterns, and test-driven development practices.

When should I use Unifi MCP Tool Builder?

Unifi MCP Tool Builder fits situations like: implementing new UniFi Network Controller features as MCP tools; tasks that involve MCP servers; tasks that involve Test-driven development.

How do I install Unifi MCP Tool Builder in Claude Code?

Run `npx skills add enuno/unifi-mcp-server --skill unifi-mcp-tool-builder -a claude-code`. Or copy the skill folder (.agents/skills/unifi-mcp-tool-builder in enuno/unifi-mcp-server) into .claude/skills/unifi-mcp-tool-builder in your project. Claude Code loads it when a task matches its description.

How do I install Unifi MCP Tool Builder in Codex?

Run `npx skills add enuno/unifi-mcp-server --skill unifi-mcp-tool-builder -a codex`. Or copy the skill folder (.agents/skills/unifi-mcp-tool-builder in enuno/unifi-mcp-server) into .agents/skills/unifi-mcp-tool-builder in your project. Codex loads it when a task matches its description.

Can I use Unifi MCP Tool Builder in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add enuno/unifi-mcp-server --skill unifi-mcp-tool-builder -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/unifi-mcp-tool-builder, .gemini/skills/unifi-mcp-tool-builder, .github/skills/unifi-mcp-tool-builder and .opencode/skills/unifi-mcp-tool-builder in your project.

What does Unifi MCP Tool Builder need to run?

Going by SKILL.md and its folder, Unifi MCP Tool Builder needs the command-line tools its instructions call (pytest, black, ruff, mypy and uv). Our summary lists: Python 3.

Does Unifi MCP Tool Builder access the network?

SKILL.md names 1 domain. As links in the text: developer.ui.com. This is read from the text; nothing was executed.

Is Unifi MCP Tool Builder safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Unifi MCP Tool Builder use?

Unifi MCP Tool Builder is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Unifi MCP Tool Builder use?

About 5.8k tokens (SKILL.md is roughly 23k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Unifi MCP Tool Builder?

Skills that share tags, products or a category with Unifi MCP Tool Builder: MCP Scaffold (timothywarner-org/claude-code, 224 stars), MCP Server Builder (jnMetaCode/superpowers-zh, 8.3k stars), Development Assistant (RobThePCGuy/Claude-Patent-Creator, 196 stars) and MCP Developer (Jeffallan/claude-skills, 12k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Unifi MCP Tool Builder?

enuno (a GitHub user) maintains it in enuno/unifi-mcp-server, which has 284 GitHub stars. The repository holds 12 skills in this directory. The repository was last updated on October 11, 2026.

Source: enuno/unifi-mcp-server on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.