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.

referencesMANDATORY_PATTERNS.md

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

FastMCP Mandatory Patterns

Four critical requirements for ALL FastMCP implementations.

1. Use uv (Never pip)

Rule: Always use uv for dependency management.

Installation:

uv pip install fastmcp
uv pip install -r requirements.txt
uv venv
uv sync
fastmcp install claude-desktop server.py --with dependency

Apply to:

  • README installation instructions
  • requirements.txt notes (add: "Install with: uv pip install -r requirements.txt")
  • Installation scripts
  • All code examples and documentation

Installation Script Pattern:

if ! command -v uv &> /dev/null; then
    curl -LsSf https://astral.sh/uv/install.sh | sh
fi
uv pip install -r requirements.txt

2. Fetch FastMCP Docs from Authoritative Sources

Rule: For FastMCP knowledge, use LLMS_TXT.md + web_fetch

Workflow:

1. Read references/LLMS_TXT.md - comprehensive URL index
2. Search LLMS_TXT.md for relevant topic
3. Use web_fetch: https://gofastmcp.com/[path].md
4. Apply authoritative patterns

Common topics:

  • Authentication → Search for "authentication"
  • Tool optimization → Search for "tools"
  • Client integration → Search for "transports" or client name
  • Deployment → Search for "deployment" or "running"
  • OAuth flows → Search for "oauth"
  • Middleware → Search for "middleware"

URL Structure:

  • Base: https://gofastmcp.com/
  • All docs have .md extension
  • Example: https://gofastmcp.com/servers/tools.md

3. Optimize ALL MCP Tool Descriptions

Target: 65-70% token reduction vs. verbose approach

Verbose (~180 tokens):

@mcp.tool()
async def search_jql(jql: str, max_results: int = 50):
    """
    Search Jira issues using JQL (Jira Query Language).
    
    This tool allows you to search through all issues...
    
    Args:
        jql: JQL query string...
        max_results: Maximum number of results...
    
    Returns:
        Dictionary with issues, total, maxResults
        
    Example JQL queries:
        - "project = MYPROJ"
        ...
    """

Optimized (~55 tokens):

@mcp.tool(
    annotations={
        "title": "Search Jira with JQL",
        "readOnlyHint": True,
        "openWorldHint": False
    }
)
async def search_jql(
    jql: Annotated[str, Field(
        description="JQL query. Ex: 'project = PROJ', 'status = Open'"
    )],
    max_results: Annotated[int, Field(
        description="Max results (1-100)",
        ge=1,
        le=100
    )] = 50,
    ctx: Context = None
):
    """Search Jira using JQL. Supports projects, status, assignee, dates, sorting."""

Optimization Techniques

1. Annotations (Metadata Outside Context)

annotations={
    "title": "Human-Readable Title",    # UI display name
    "readOnlyHint": True,               # Signals no modifications
    "openWorldHint": False,             # Internal system vs external APIs
    "idempotentHint": True,             # Repeated calls safe
    "destructiveHint": False            # Non-destructive operations
}

2. Annotated Parameters with Field

from typing import Annotated
from pydantic import Field

# Basic pattern
param: Annotated[str, Field(description="Concise description")]

# With validation
count: Annotated[int, Field(
    description="Item count (1-100)",
    ge=1,
    le=100
)] = 10

# With inline examples
query: Annotated[str, Field(
    description="JQL query. Ex: 'project = KEY', 'status = Open'"
)]

# With pattern validation
key: Annotated[str, Field(
    description="Issue key (PROJECT-123)",
    pattern=r'^[A-Z]+-\d+$'
)]

3. Single-Sentence Docstring Pattern

"{Action verb} {scope/target}. {Key capabilities/differentiators}."

Examples:

  • "Search Jira using JQL. Supports projects, status, assignee, dates, sorting."
  • "Retrieve complete issue details. Returns description, comments, attachments, history."
  • "Add comment to issue. Supports Markdown formatting and @mentions."

4. Server-Level Instructions

mcp = FastMCP(
    name="Service Name",
    instructions="High-level guidance. Key capabilities. Permission/scope info."
)

Pattern: Single sentence, <100 characters

Examples:

  • "Read-only Jira access. All operations respect user permissions."
  • "GitHub repo management. Read/write access."
  • "Database query interface. Read-only. SQL with parameter escaping."

5. Context Efficiency Targets

Tool Complexity Before After Reduction
Simple (list) 120 35 71%
Medium (search) 180 55 69%
Complex (multi-param) 250 75 70%

4. Implementation Checklist

Before delivering any FastMCP implementation:

✓ All commands use uv (not pip)
✓ FastMCP docs fetched from LLMS_TXT.md URLs (not web_search)
✓ Tool annotations include readOnlyHint, title, openWorldHint  
✓ Parameters use Annotated[type, Field(description="...")]
✓ Docstrings are single sentence, high-density
✓ Token usage ~65-70% less than verbose approach
✓ Server instructions concise (<100 chars)
✓ No pip references anywhere
✓ Validation constraints in Field (ge, le, pattern)
✓ Error handling specific (ApiError vs generic Exception)
✓ Security measures (input validation, escaping)

Quick Decision Tree

Starting new FastMCP implementation?
│
├─ Will use uv? (not pip)
│  ├─ Yes → Continue
│  └─ No → Fix this first
│
├─ Need FastMCP docs?
│  ├─ Yes → Use LLMS_TXT.md + web_fetch (not web_search)
│  └─ No → Continue
│
├─ Creating MCP tools?
│  ├─ Yes → Apply optimization patterns
│  │         (annotations, Annotated, concise docstrings)
│  └─ No → Continue
│
└─ Verify all four patterns applied

Example: Complete Tool Implementation

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

mcp = FastMCP(
    name="example-service",
    instructions="Example integration. Read-only access."
)

@mcp.tool(
    annotations={
        "title": "Search Items",
        "readOnlyHint": True,
        "openWorldHint": False
    }
)
async def search_items(
    query: Annotated[str, Field(
        description="Search text. Ex: 'status:active', 'name:test'"
    )],
    limit: Annotated[int, Field(
        description="Max results (1-100)",
        ge=1,
        le=100
    )] = 50,
    ctx: Context = None
) -> dict:
    """Search items by text. Full-text search across all fields."""
    
    # Implementation
    results = await api.search(query, limit=limit)
    return {"items": results, "count": len(results)}

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