All skills
oaustegard avatar

/creating-mcp-servers

@5e58100

Creates production-ready MCP servers using FastMCP v2. Use when building MCP servers, optimizing tool descriptions for context efficiency, implementing progressive disclosure for multiple capabilities, or packaging servers for distribution.

Use this Skill: https://skilld.dev/gh/oaustegard/claude-skills/creating-mcp-servers

This session only. Nothing lands on disk.

referencesPROGRESSIVE_DISCLOSURE.md

≈1.7k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Progressive Disclosure Architecture

Context management pattern that loads information incrementally. Reduces baseline token consumption by 85-93% while maintaining full functionality.

Three-Tier Loading

Tier 1: Metadata (Always in context)
    ├─ Name
    ├─ Description (~100 words)
    └─ Trigger keywords
    Cost: ~20 tokens per capability

Tier 2: Content (Load on-demand)
    ├─ Full instructions
    ├─ Examples
    └─ Workflow steps
    Cost: ~500 tokens when needed

Tier 3: Execution (No context cost)
    ├─ Run scripts directly
    ├─ Execute validation
    └─ Process without loading source
    Cost: 0 tokens

Gateway Pattern Implementation

Single Tool, Multiple Capabilities

Expose 1 gateway tool that routes internally instead of N tools:

from fastmcp import FastMCP, Context
from typing import Annotated, Literal
from pydantic import Field

mcp = FastMCP(
    name="skills-gateway",
    instructions="Progressive disclosure gateway. Discover skills, load on demand."
)

@mcp.tool(
    annotations={
        "title": "Skill Gateway",
        "readOnlyHint": True,
        "openWorldHint": False
    }
)
async def skill(
    action: Annotated[
        Literal["discover", "load", "run"],
        Field(description="Operation: discover skills, load content, or run script")
    ],
    skill_name: Annotated[
        str | None,
        Field(description="Skill name (from discover results)")
    ] = None,
    params: Annotated[
        dict | None,
        Field(description="Parameters for run action")
    ] = None,
    ctx: Context = None
) -> dict:
    """Gateway to Skills. Progressive disclosure: discover→load→use."""
    
    if action == "discover":
        # Tier 1: Return lightweight metadata only
        skills = []
        for path in find_skill_directories():
            metadata = parse_frontmatter(path / "SKILL.md")
            skills.append({
                "name": metadata["name"],
                "description": metadata["description"],
                "path": str(path)
            })
        return {"skills": skills, "count": len(skills)}
    
    elif action == "load":
        # Tier 2: Load full content on demand
        if not skill_name:
            raise ValueError("skill_name required for load action")
        
        path = find_skill_path(skill_name)
        content = (path / "SKILL.md").read_text()
        return {"skill": skill_name, "content": content}
    
    elif action == "run":
        # Tier 3: Execute without loading source
        if not skill_name:
            raise ValueError("skill_name required for run action")
        
        path = find_skill_path(skill_name)
        script_path = path / "scripts" / f"{params['script']}.py"
        
        result = subprocess.run(
            [sys.executable, str(script_path), *params.get('args', [])],
            capture_output=True,
            text=True
        )
        
        return {
            "exit_code": result.returncode,
            "stdout": result.stdout,
            "stderr": result.stderr
        }

Architecture Comparison

Traditional MCP (All Upfront)

Baseline Context:
├─ Tool 1 schema: 180 tokens
├─ Tool 2 schema: 180 tokens
├─ Tool 3 schema: 180 tokens
├─ Tool 4 schema: 180 tokens
├─ Tool 5 schema: 180 tokens
└─ Tool 6 schema: 180 tokens
Total: 1,080 tokens ALWAYS in context

Gateway MCP (Progressive Disclosure)

Baseline Context:
└─ Gateway tool schema: 55 tokens

Tier 1 (discover):
├─ Skill 1 metadata: 20 tokens
├─ Skill 2 metadata: 20 tokens
├─ Skill 3 metadata: 20 tokens
└─ ...
Subtotal: 55 + (N × 20) tokens

Tier 2 (load):
└─ Full skill content: ~500 tokens (ONLY when used)

Tier 3 (run):
└─ Execution result: ~0 tokens

Token Comparison:

Scenario Traditional Gateway Savings
Baseline (no use) 1,080 55 95%
Discover capabilities 1,080 230 79%
Use 1 skill 1,080 730 32%
Use 3 skills 1,080 1,730 -60%*

*Gateway uses more tokens when heavily using multiple capabilities—this is the correct tradeoff.


Implementation Patterns

Pattern 1: Simple Gateway (Read-Only)

@mcp.tool(annotations={"title": "Data Gateway", "readOnlyHint": True})
async def query(
    action: Literal["list", "get", "search"],
    target: str | None = None,
    params: dict | None = None
) -> dict:
    """Query data. Progressive: list→get→search."""
    
    if action == "list":
        return {"items": get_item_list(), "count": N}
    elif action == "get":
        return {"item": get_item_details(target)}
    elif action == "search":
        return {"results": search_items(params["query"])}

Pattern 2: Full Gateway (With References)

@mcp.tool(annotations={"title": "Skills Gateway", "readOnlyHint": True})
async def skill(
    action: Literal["discover", "load", "list_refs", "read_ref", "run"],
    skill_name: str | None = None,
    ref_path: str | None = None,
    params: dict | None = None
) -> dict:
    """Gateway to Skills. Full progressive disclosure pattern."""
    
    if action == "discover":
        return {"skills": [...], "count": N}
    
    elif action == "load":
        return {"content": load_skill_md(skill_name)}
    
    elif action == "list_refs":
        return {"references": list_reference_files(skill_name)}
    
    elif action == "read_ref":
        return {"content": read_reference_file(skill_name, ref_path)}
    
    elif action == "run":
        return execute_script(skill_name, params)

When to Use

✅ Use gateway when:

  • 5+ related capabilities
  • Many capabilities rarely used
  • Context efficiency critical
  • Capabilities can be logically grouped

❌ Don't use gateway when:

  • Only 1-3 simple tools
  • All capabilities frequently used
  • Capabilities completely unrelated
  • Complexity outweighs benefits

Context Efficiency Metrics

Target:

  • Baseline: <100 tokens (single gateway tool)
  • Discover: <1000 tokens (up to 50 capabilities)
  • Per-use: ~500 tokens (only when capability actually used)
  • Overall: 85-93% reduction vs traditional approach

Formula:

traditional_tokens = num_tools × avg_tokens_per_tool
gateway_tokens = single_tool_tokens + (metadata × num_capabilities)
savings = 1 - (gateway_tokens / traditional_tokens)

Implementation Checklist

□ Identify if gateway pattern appropriate (>5 capabilities)
□ Design tier structure (metadata, content, execution)
□ Create discovery mechanism (list capabilities)
□ Implement on-demand loading (fetch when needed)
□ Add execution tier if applicable (scripts/validation)
□ Measure token reduction (target 85-93%)
□ Test progressive loading flow
□ Verify functionality preserved

Source: SKILL.md on GitHub

2 warnings5mo4 checks · Risk SAFE
  • Gen Agent Trust Hub5mo

    This skill provides a comprehensive toolkit for building production-ready Model Context Protocol (MCP) servers using the FastMCP framework. It includes architectural patterns for context-efficient design, a utility script for packaging servers into .mcpb bundles, and an index for official FastMCP documentation. The skill leverages official documentation sources and well-known dependency management tools.

  • Socket5mo

    No alerts

  • Snyk5mo

    Risk: MEDIUM · 2 issues

  • Runlayer7mo

    12/12 files flagged

Signed by skilld at 5e58100. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 weeks ago
metadata
{
  "version": "1.2.0"
}

README badge

README badge for oaustegard/claude-skills/creating-mcp-servers