Claude Skill

creating-mcp-servers

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.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download oaustegard-claude-skills-plugins_development-tools_skills_creating-mcp-servers-e39c726.zip · 21 KB
Part of oaustegard/claude-skills — 39 skills

Install

skills CLI npx skills add https://github.com/oaustegard/claude-skills/tree/main/plugins/development-tools/skills/creating-mcp-servers
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install oaustegard-claude-skills@llmmart
Git git clone https://github.com/oaustegard/claude-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole oaustegard/claude-skills collection as a plugin from our marketplace. Git is the plain clone.

README

creating-mcp-servers

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.

Skill manifest

Creating MCP Servers

Build production-ready MCP servers using FastMCP v2 with optimal context efficiency through progressive disclosure patterns.

Core Capabilities

  1. Apply the core patterns - Four requirements for consistency
  2. Implement progressive disclosure - Gateway patterns achieving 85-93% token reduction
  3. Optimize tool descriptions - 65-70% token reduction through proper patterns
  4. Bundle servers - Package as MCPB files with validation
  5. Proven gateway patterns - Three complete implementations (Skills, API, Query)

Architecture Decision

1-3 simple tools?
  → Standard FastMCP with optimized tools
  Load: references/MANDATORY_PATTERNS.md

5+ related capabilities?
  → Gateway pattern (progressive disclosure)
  Load: references/PROGRESSIVE_DISCLOSURE.md
  Load: references/GATEWAY_PATTERNS.md

Optimize existing server?
  → Apply mandatory patterns
  Load: references/MANDATORY_PATTERNS.md

Package for distribution?
  → MCPB bundler
  Load: references/MCPB_BUNDLING.md
  Execute: scripts/create_mcpb.py

Need FastMCP documentation?
  → Search references/LLMS_TXT.md for relevant URLs
  → Use web_fetch on gofastmcp.com URLs

Mandatory Patterns (Summary)

Every implementation should meet these four requirements:

  1. uv (never pip) - uv pip install fastmcp
  2. Optimized tool descriptions - Annotations, Annotated, concise docstrings
  3. Authoritative documentation - Fetch from gofastmcp.com via LLMS_TXT.md index
  4. Apply all patterns - Every implementation meets verification checklist

Details in references/MANDATORY_PATTERNS.md

Documentation Retrieval Workflow

To fetch FastMCP documentation:

1. Read references/LLMS_TXT.md - complete URL index
2. Search for relevant topic keywords
3. Use web_fetch on matched URLs (append .md for markdown)
4. Apply patterns from fetched documentation

Example: Authentication patterns → Search LLMS_TXT.md for "authentication" → web_fetch https://gofastmcp.com/servers/auth/authentication.md

Progressive Disclosure Pattern

For servers with 5+ capabilities:

Three-tier loading:

  1. Metadata (~20 tokens/capability) - Always loaded
  2. Content (~500 tokens) - Load on demand
  3. Execution (0 tokens) - Execute without loading

Achieves 85-93% baseline reduction. See references/PROGRESSIVE_DISCLOSURE.md

Implementation Phases

Phase 1: Research

Read LLMS_TXT.md → Find relevant URLs → web_fetch documentation

Phase 2: Implement

Load appropriate reference based on architecture decision. Apply all four patterns.

Phase 3: Package (Optional)

cd /home/claude
zip -r server-name.mcpb manifest.json server.py README.md
cp server-name.mcpb /mnt/user-data/outputs/

See references/MCPB_BUNDLING.md for manifest format.

Reference Library

Documentation index (load first for FastMCP knowledge):

Core patterns:

Implementation:

Scripts:

  • scripts/create_mcpb.py - Bundle MCP servers into .mcpb files

Verification Checklist

Before completing any FastMCP implementation:

✓ Uses uv (not pip)
✓ FastMCP docs fetched from LLMS_TXT.md URLs (not web_search)
✓ Tool annotations (readOnlyHint, title, openWorldHint)
✓ Annotated parameters with Field
✓ Single-sentence docstrings
✓ 65-70% token reduction vs verbose
✓ Server instructions concise (<100 chars)

For gateway implementations, additionally verify:

✓ 85%+ baseline context reduction
✓ Discover returns metadata only
✓ Load fetches content on demand
✓ Execute runs without context cost

Tool Description Pattern

Before (180 tokens):

@mcp.tool()
async def search_items(query: str):
    """Search for items in the database.
    This tool allows comprehensive searching..."""

After (55 tokens):

@mcp.tool(
    annotations={"title": "Search", "readOnlyHint": True, "openWorldHint": False}
)
async def search_items(
    query: Annotated[str, Field(description="Search text")],
    ctx: Context = None
):
    """Search items. Fast full-text search across all fields."""

Common Pitfalls

❌ Using mcpb pack CLI (causes crashes, just use zip)
❌ Using pip instead of uv
❌ web_search for FastMCP docs (use web_fetch on LLMS_TXT.md URLs)
❌ Verbose tool descriptions
❌ Missing tool annotations
❌ Gateway for 1-3 tools (overhead exceeds benefit)
❌ Mixing unrelated capabilities in single gateway

Files (claude-skills)
  • references
    • GATEWAY_PATTERNS.md 14.9 KB
      # Gateway Patterns for Progressive Disclosure
      
      Complete implementation patterns for building context-efficient MCP servers using the gateway architecture.
      
      ## Pattern 1: Read-Only Skills Gateway
      
      **Use Case:** Replicate Claude Skills architecture in MCP
      
      ```python
      from fastmcp import FastMCP, Context
      from pathlib import Path
      from typing import Annotated, Literal
      from pydantic import Field
      import yaml
      import subprocess
      import sys
      
      mcp = FastMCP(
          name="skills-gateway",
          instructions="Claude Skills for MCP. Discover skills, load on demand."
      )
      
      SKILLS_DIRS = [
          Path.home() / ".claude" / "skills",
          Path.cwd() / ".claude" / "skills",
      ]
      
      def find_skill_directories() -> list[Path]:
          """Find all skill directories."""
          skills = []
          for base_dir in SKILLS_DIRS:
              if base_dir.exists():
                  for path in base_dir.iterdir():
                      if path.is_dir() and (path / "SKILL.md").exists():
                          skills.append(path)
          return skills
      
      def parse_skill_frontmatter(skill_path: Path) -> dict:
          """Extract YAML frontmatter from SKILL.md."""
          content = (skill_path / "SKILL.md").read_text()
          if content.startswith("---\n"):
              end = content.find("\n---\n", 4)
              if end != -1:
                  frontmatter = content[4:end]
                  return yaml.safe_load(frontmatter)
          return {}
      
      def find_skill_path(skill_name: str) -> Path | None:
          """Find path for named skill."""
          for path in find_skill_directories():
              metadata = parse_skill_frontmatter(path)
              if metadata.get("name") == skill_name:
                  return path
          return None
      
      @mcp.tool(
          annotations={
              "title": "Skill Gateway",
              "readOnlyHint": True,
              "openWorldHint": False
          }
      )
      async def skill(
          action: Annotated[
              Literal["discover", "load", "list_refs", "read_ref", "run"],
              Field(description="Operation: discover, load, list_refs, read_ref, or run")
          ],
          skill_name: Annotated[str | None, Field(description="Skill name (from discover)")] = None,
          ref_path: Annotated[str | None, Field(description="Reference path (for read_ref)")] = None,
          script_name: Annotated[str | None, Field(description="Script name (for run)")] = None,
          script_args: Annotated[list[str] | None, Field(description="Script arguments")] = None,
          ctx: Context = None
      ) -> dict:
          """Gateway to Skills. Progressive disclosure: discover→load→use."""
          
          if action == "discover":
              skills = []
              for path in find_skill_directories():
                  metadata = parse_skill_frontmatter(path)
                  skills.append({
                      "name": metadata.get("name", "unknown"),
                      "description": metadata.get("description", ""),
                      "path": str(path)
                  })
              return {"skills": skills, "count": len(skills)}
          
          elif action == "load":
              if not skill_name:
                  raise ValueError("skill_name required for load action")
              path = find_skill_path(skill_name)
              if not path:
                  raise ValueError(f"Skill not found: {skill_name}")
              content = (path / "SKILL.md").read_text()
              refs_dir = path / "references"
              references = []
              if refs_dir.exists():
                  references = [str(p.relative_to(path)) for p in refs_dir.rglob("*.md")]
              return {"skill": skill_name, "content": content, "references": references}
          
          elif action == "list_refs":
              if not skill_name:
                  raise ValueError("skill_name required for list_refs action")
              path = find_skill_path(skill_name)
              if not path:
                  raise ValueError(f"Skill not found: {skill_name}")
              refs_dir = path / "references"
              references = []
              if refs_dir.exists():
                  for ref_file in refs_dir.rglob("*.md"):
                      rel_path = str(ref_file.relative_to(path))
                      references.append({
                          "path": rel_path,
                          "name": ref_file.stem,
                          "size": ref_file.stat().st_size
                      })
              return {"skill": skill_name, "references": references, "count": len(references)}
          
          elif action == "read_ref":
              if not skill_name or not ref_path:
                  raise ValueError("skill_name and ref_path required for read_ref action")
              path = find_skill_path(skill_name)
              if not path:
                  raise ValueError(f"Skill not found: {skill_name}")
              ref_file = path / ref_path
              if not ref_file.exists():
                  raise ValueError(f"Reference not found: {ref_path}")
              content = ref_file.read_text()
              return {"skill": skill_name, "reference": ref_path, "content": content}
          
          elif action == "run":
              if not skill_name or not script_name:
                  raise ValueError("skill_name and script_name required for run action")
              path = find_skill_path(skill_name)
              if not path:
                  raise ValueError(f"Skill not found: {skill_name}")
              script_path = path / "scripts" / f"{script_name}.py"
              if not script_path.exists():
                  raise ValueError(f"Script not found: {script_name}.py")
              result = subprocess.run(
                  [sys.executable, str(script_path), *(script_args or [])],
                  capture_output=True,
                  text=True,
                  timeout=30
              )
              return {
                  "skill": skill_name,
                  "script": script_name,
                  "exit_code": result.returncode,
                  "stdout": result.stdout,
                  "stderr": result.stderr
              }
          
          else:
              raise ValueError(f"Unknown action: {action}")
      ```
      
      **Token Efficiency:**
      ```
      Baseline: 55 tokens
      Discover: 55 + (N × 20) tokens
      Traditional: N tools × 80 tokens
      Savings: 93% reduction for 10 tools
      ```
      
      ---
      
      ## Pattern 2: API Gateway (CRUD Operations)
      
      **Use Case:** Single tool for complete API integration
      
      ```python
      from fastmcp import FastMCP, Context
      from typing import Annotated, Literal
      from pydantic import Field
      import aiohttp
      
      mcp = FastMCP(
          name="api-gateway",
          instructions="API integration gateway. CRUD operations across resource types."
      )
      
      RESOURCE_TYPES = Literal["users", "projects", "tasks", "comments"]
      
      @mcp.tool(
          annotations={
              "title": "API Gateway",
              "readOnlyHint": False,
              "openWorldHint": True
          }
      )
      async def api(
          action: Annotated[
              Literal["list", "get", "search", "create", "update", "delete"],
              Field(description="CRUD operation")
          ],
          resource_type: Annotated[RESOURCE_TYPES, Field(description="Resource type")],
          identifier: Annotated[str | None, Field(description="Resource ID (for get/update/delete)")] = None,
          query: Annotated[str | None, Field(description="Search query (for search)")] = None,
          data: Annotated[dict | None, Field(description="Data payload (for create/update)")] = None,
          limit: Annotated[int, Field(description="Max results", ge=1, le=100)] = 50,
          ctx: Context = None
      ) -> dict:
          """API gateway. Progressive: list→get→search→create/update/delete."""
          
          base_url = f"https://api.example.com/{resource_type}"
          
          if action == "list":
              async with aiohttp.ClientSession() as session:
                  async with session.get(f"{base_url}?limit={limit}") as resp:
                      items = await resp.json()
              return {"items": items, "count": len(items)}
          
          elif action == "get":
              if not identifier:
                  raise ValueError("identifier required for get action")
              async with aiohttp.ClientSession() as session:
                  async with session.get(f"{base_url}/{identifier}") as resp:
                      item = await resp.json()
              return {"item": item}
          
          elif action == "search":
              if not query:
                  raise ValueError("query required for search action")
              async with aiohttp.ClientSession() as session:
                  async with session.get(f"{base_url}/search", params={"q": query, "limit": limit}) as resp:
                      results = await resp.json()
              return {"results": results, "count": len(results)}
          
          elif action == "create":
              if not data:
                  raise ValueError("data required for create action")
              async with aiohttp.ClientSession() as session:
                  async with session.post(base_url, json=data) as resp:
                      created = await resp.json()
              return {"created": created}
          
          elif action == "update":
              if not identifier or not data:
                  raise ValueError("identifier and data required for update action")
              async with aiohttp.ClientSession() as session:
                  async with session.put(f"{base_url}/{identifier}", json=data) as resp:
                      updated = await resp.json()
              return {"updated": updated}
          
          elif action == "delete":
              if not identifier:
                  raise ValueError("identifier required for delete action")
              async with aiohttp.ClientSession() as session:
                  async with session.delete(f"{base_url}/{identifier}") as resp:
                      success = resp.status == 204
              return {"deleted": success, "identifier": identifier}
      ```
      
      **Token Efficiency:**
      ```
      Single tool: 55 tokens
      6 actions × 4 resource types = 24 virtual endpoints
      Traditional: 24 tools × 80 tokens = 1,920 tokens
      Savings: 97% reduction
      ```
      
      ---
      
      ## Pattern 3: Query Gateway (Database Operations)
      
      **Use Case:** Safe SQL query interface with progressive disclosure
      
      ```python
      from fastmcp import FastMCP, Context
      from typing import Annotated, Literal
      from pydantic import Field
      import sqlite3
      
      mcp = FastMCP(
          name="query-gateway",
          instructions="Database query interface. Read-only. SQL with parameter escaping."
      )
      
      @mcp.tool(
          annotations={
              "title": "Query Gateway",
              "readOnlyHint": True,
              "openWorldHint": False
          }
      )
      async def query(
          action: Annotated[
              Literal["tables", "schema", "validate", "execute"],
              Field(description="Operation: tables, schema, validate, or execute")
          ],
          table: Annotated[str | None, Field(description="Table name (for schema)")] = None,
          sql: Annotated[str | None, Field(description="SQL query (for validate/execute)")] = None,
          limit: Annotated[int, Field(description="Max rows", ge=1, le=1000)] = 100,
          format: Annotated[
              Literal["json", "markdown", "csv"],
              Field(description="Output format")
          ] = "json",
          ctx: Context = None
      ) -> dict | str:
          """Query database. Progressive: tables→schema→validate→execute."""
          
          conn = sqlite3.connect("database.db")
          conn.row_factory = sqlite3.Row
          
          try:
              cursor = conn.cursor()
              
              if action == "tables":
                  cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
                  tables = [row[0] for row in cursor.fetchall()]
                  return {"tables": tables, "count": len(tables)}
              
              elif action == "schema":
                  if not table:
                      raise ValueError("table required for schema action")
                  cursor.execute(f"PRAGMA table_info({table})")
                  columns = [
                      {"name": row["name"], "type": row["type"], "notnull": bool(row["notnull"]), "pk": bool(row["pk"])}
                      for row in cursor.fetchall()
                  ]
                  return {"table": table, "columns": columns, "count": len(columns)}
              
              elif action == "validate":
                  if not sql:
                      raise ValueError("sql required for validate action")
                  try:
                      cursor.execute(f"EXPLAIN QUERY PLAN {sql}")
                      return {"valid": True, "query": sql}
                  except sqlite3.Error as e:
                      return {"valid": False, "error": str(e)}
              
              elif action == "execute":
                  if not sql:
                      raise ValueError("sql required for execute action")
                  cursor.execute(f"{sql} LIMIT {limit}")
                  rows = cursor.fetchall()
                  
                  if format == "json":
                      results = [dict(row) for row in rows]
                      return {"query": sql, "rows": results, "count": len(results)}
                  
                  elif format == "markdown":
                      if not rows:
                          return "No results"
                      columns = rows[0].keys()
                      lines = []
                      lines.append("| " + " | ".join(columns) + " |")
                      lines.append("| " + " | ".join(["---"] * len(columns)) + " |")
                      for row in rows:
                          values = [str(row[col]) for col in columns]
                          lines.append("| " + " | ".join(values) + " |")
                      return "\n".join(lines)
                  
                  elif format == "csv":
                      if not rows:
                          return ""
                      import csv
                      import io
                      output = io.StringIO()
                      writer = csv.DictWriter(output, fieldnames=rows[0].keys())
                      writer.writeheader()
                      for row in rows:
                          writer.writerow(dict(row))
                      return output.getvalue()
          
          finally:
              conn.close()
      ```
      
      **Token Efficiency:**
      ```
      Single tool: 55 tokens
      4 actions × 3 formats = 12 virtual endpoints
      Traditional: 12 tools × 80 tokens = 960 tokens
      Savings: 94% reduction
      ```
      
      ---
      
      ## Best Practices
      
      ### Action-First Design
      ```python
      # ✅ Good: Action determines behavior
      @mcp.tool()
      async def gateway(action: Literal["list", "get", "create"], ...):
          if action == "list": ...
          elif action == "get": ...
      
      # ❌ Bad: Separate tools for each action
      @mcp.tool()
      async def list_items(...): ...
      
      @mcp.tool()
      async def get_item(...): ...
      ```
      
      ### Optional Parameters by Action
      ```python
      # ✅ Good: Validate by action
      async def gateway(
          action: Literal["list", "get"],
          identifier: str | None = None,  # Required only for "get"
      ):
          if action == "get" and not identifier:
              raise ValueError("identifier required for get")
      ```
      
      ### Context-Aware Error Messages
      ```python
      # ✅ Good: Tell Claude what to do next
      raise ValueError(
          "identifier required for get action. "
          "Use list action first to discover available identifiers."
      )
      ```
      
      ---
      
      ## Anti-Patterns
      
      ❌ **Gateway for 1-3 tools** - Complexity outweighs benefit  
      ❌ **Mix unrelated capabilities** - Create separate gateways instead  
      ❌ **Overload single action** - Break into specific actions  
      
      ---
      
      ## Decision Matrix
      
      | Scenario | Pattern | Reason |
      |----------|---------|--------|
      | 1-3 related operations | Standard tools | Overhead not worth it |
      | 5+ related operations | Gateway pattern | Context efficiency wins |
      | CRUD on resources | API Gateway | Standardized operations |
      | Skills replication | Skills Gateway | Progressive disclosure |
      | Database queries | Query Gateway | Safety + flexibility |
      | Completely unrelated ops | Separate gateways | Logical separation |
      
      ---
      
      ## Token Efficiency Targets
      
      ```python
      traditional_tokens = num_tools * avg_tokens_per_tool
      gateway_tokens = single_tool_tokens + (metadata * num_capabilities)
      savings = 1 - (gateway_tokens / traditional_tokens)
      ```
      
      **Targets:**
      - Baseline: <100 tokens (single gateway)
      - Discovery: <1000 tokens (all capabilities)
      - Per-use: Only tokens for capability used
      - Overall: 65-93% reduction vs traditional
      
    • LLMS_TXT.md 20.2 KB
      # FastMCP Documentation Index (llms.txt)
      
      **Purpose:** Authoritative URL index for FastMCP v2 documentation. Use web_fetch on these URLs to retrieve complete documentation.
      
      **Usage:**
      1. Search this file for topic keywords
      2. Use web_fetch on the matched URL (append .md if needed)
      3. Apply patterns from fetched documentation
      
      **Example:**
      - Need authentication → Search "authentication" → web_fetch https://gofastmcp.com/servers/auth/authentication.md
      
      ---
      
      # FastMCP
      
      ## Docs
      
      - [Changelog](https://gofastmcp.com/changelog.md)
      - [Bearer Token Authentication](https://gofastmcp.com/clients/auth/bearer.md): Authenticate your FastMCP client with a Bearer token.
      - [OAuth Authentication](https://gofastmcp.com/clients/auth/oauth.md): Authenticate your FastMCP client via OAuth 2.1.
      - [The FastMCP Client](https://gofastmcp.com/clients/client.md): Programmatic client for interacting with MCP servers through a well-typed, Pythonic interface.
      - [User Elicitation](https://gofastmcp.com/clients/elicitation.md): Handle server-initiated user input requests with structured schemas.
      - [Server Logging](https://gofastmcp.com/clients/logging.md): Receive and handle log messages from MCP servers.
      - [Message Handling](https://gofastmcp.com/clients/messages.md): Handle MCP messages, requests, and notifications with custom message handlers.
      - [Progress Monitoring](https://gofastmcp.com/clients/progress.md): Handle progress notifications from long-running server operations.
      - [Prompts](https://gofastmcp.com/clients/prompts.md): Use server-side prompt templates with automatic argument serialization.
      - [Resource Operations](https://gofastmcp.com/clients/resources.md): Access static and templated resources from MCP servers.
      - [Client Roots](https://gofastmcp.com/clients/roots.md): Provide local context and resource boundaries to MCP servers.
      - [LLM Sampling](https://gofastmcp.com/clients/sampling.md): Handle server-initiated LLM sampling requests.
      - [Background Tasks](https://gofastmcp.com/clients/tasks.md): Execute operations asynchronously and track their progress
      - [Tool Operations](https://gofastmcp.com/clients/tools.md): Discover and execute server-side tools with the FastMCP client.
      - [Client Transports](https://gofastmcp.com/clients/transports.md): Configure how FastMCP Clients connect to and communicate with servers.
      - [FastMCP Cloud](https://gofastmcp.com/deployment/fastmcp-cloud.md): The fastest way to deploy your MCP server
      - [HTTP Deployment](https://gofastmcp.com/deployment/http.md): Deploy your FastMCP server over HTTP for remote access
      - [Running Your Server](https://gofastmcp.com/deployment/running-server.md): Learn how to run your FastMCP server locally for development and testing
      - [Project Configuration](https://gofastmcp.com/deployment/server-configuration.md): Use fastmcp.json for portable, declarative project configuration
      - [Contributing](https://gofastmcp.com/development/contributing.md): Development workflow for FastMCP contributors
      - [Releases](https://gofastmcp.com/development/releases.md): FastMCP versioning and release process
      - [Tests](https://gofastmcp.com/development/tests.md): Testing patterns and requirements for FastMCP
      - [Upgrade Guide](https://gofastmcp.com/development/upgrade-guide.md): Migration instructions for upgrading between FastMCP versions
      - [Installation](https://gofastmcp.com/getting-started/installation.md)
      - [Quickstart](https://gofastmcp.com/getting-started/quickstart.md)
      - [Welcome to FastMCP 2.0!](https://gofastmcp.com/getting-started/welcome.md): The fast, Pythonic way to build MCP servers and clients.
      - [Anthropic API 🤝 FastMCP](https://gofastmcp.com/integrations/anthropic.md): Connect FastMCP servers to the Anthropic API
      - [Auth0 OAuth 🤝 FastMCP](https://gofastmcp.com/integrations/auth0.md): Secure your FastMCP server with Auth0 OAuth
      - [AuthKit 🤝 FastMCP](https://gofastmcp.com/integrations/authkit.md): Secure your FastMCP server with AuthKit by WorkOS
      - [AWS Cognito OAuth 🤝 FastMCP](https://gofastmcp.com/integrations/aws-cognito.md): Secure your FastMCP server with AWS Cognito user pools
      - [Azure (Microsoft Entra ID) OAuth 🤝 FastMCP](https://gofastmcp.com/integrations/azure.md): Secure your FastMCP server with Azure/Microsoft Entra OAuth
      - [ChatGPT 🤝 FastMCP](https://gofastmcp.com/integrations/chatgpt.md): Connect FastMCP servers to ChatGPT in Chat and Deep Research modes
      - [Claude Code 🤝 FastMCP](https://gofastmcp.com/integrations/claude-code.md): Install and use FastMCP servers in Claude Code
      - [Claude Desktop 🤝 FastMCP](https://gofastmcp.com/integrations/claude-desktop.md): Connect FastMCP servers to Claude Desktop
      - [Cursor 🤝 FastMCP](https://gofastmcp.com/integrations/cursor.md): Install and use FastMCP servers in Cursor
      - [Descope 🤝 FastMCP](https://gofastmcp.com/integrations/descope.md): Secure your FastMCP server with Descope
      - [Discord OAuth 🤝 FastMCP](https://gofastmcp.com/integrations/discord.md): Secure your FastMCP server with Discord OAuth
      - [Eunomia Authorization 🤝 FastMCP](https://gofastmcp.com/integrations/eunomia-authorization.md): Add policy-based authorization to your FastMCP servers with Eunomia
      - [FastAPI 🤝 FastMCP](https://gofastmcp.com/integrations/fastapi.md): Integrate FastMCP with FastAPI applications
      - [Gemini SDK 🤝 FastMCP](https://gofastmcp.com/integrations/gemini.md): Connect FastMCP servers to the Google Gemini SDK
      - [Gemini CLI 🤝 FastMCP](https://gofastmcp.com/integrations/gemini-cli.md): Install and use FastMCP servers in Gemini CLI
      - [GitHub OAuth 🤝 FastMCP](https://gofastmcp.com/integrations/github.md): Secure your FastMCP server with GitHub OAuth
      - [Google OAuth 🤝 FastMCP](https://gofastmcp.com/integrations/google.md): Secure your FastMCP server with Google OAuth
      - [MCP JSON Configuration 🤝 FastMCP](https://gofastmcp.com/integrations/mcp-json-configuration.md): Generate standard MCP configuration files for any compatible client
      - [OCI IAM OAuth 🤝 FastMCP](https://gofastmcp.com/integrations/oci.md): Secure your FastMCP server with OCI IAM OAuth
      - [OpenAI API 🤝 FastMCP](https://gofastmcp.com/integrations/openai.md): Connect FastMCP servers to the OpenAI API
      - [OpenAPI 🤝 FastMCP](https://gofastmcp.com/integrations/openapi.md): Generate MCP servers from any OpenAPI specification
      - [Permit.io Authorization 🤝 FastMCP](https://gofastmcp.com/integrations/permit.md): Add fine-grained authorization to your FastMCP servers with Permit.io
      - [Scalekit 🤝 FastMCP](https://gofastmcp.com/integrations/scalekit.md): Secure your FastMCP server with Scalekit
      - [Supabase 🤝 FastMCP](https://gofastmcp.com/integrations/supabase.md): Secure your FastMCP server with Supabase Auth
      - [WorkOS 🤝 FastMCP](https://gofastmcp.com/integrations/workos.md): Authenticate FastMCP servers with WorkOS Connect
      - [FastMCP CLI](https://gofastmcp.com/patterns/cli.md): Learn how to use the FastMCP command-line interface
      - [Contrib Modules](https://gofastmcp.com/patterns/contrib.md): Community-contributed modules extending FastMCP
      - [Decorating Methods](https://gofastmcp.com/patterns/decorating-methods.md): Properly use instance methods, class methods, and static methods with FastMCP decorators.
      - [Testing your FastMCP Server](https://gofastmcp.com/patterns/testing.md): How to test your FastMCP server.
      - [Tool Transformation](https://gofastmcp.com/patterns/tool-transformation.md): Create enhanced tool variants with modified schemas, argument mappings, and custom behavior.
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-cli-__init__.md)
      - [cli](https://gofastmcp.com/python-sdk/fastmcp-cli-cli.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-cli-install-__init__.md)
      - [claude_code](https://gofastmcp.com/python-sdk/fastmcp-cli-install-claude_code.md)
      - [claude_desktop](https://gofastmcp.com/python-sdk/fastmcp-cli-install-claude_desktop.md)
      - [cursor](https://gofastmcp.com/python-sdk/fastmcp-cli-install-cursor.md)
      - [gemini_cli](https://gofastmcp.com/python-sdk/fastmcp-cli-install-gemini_cli.md)
      - [mcp_json](https://gofastmcp.com/python-sdk/fastmcp-cli-install-mcp_json.md)
      - [shared](https://gofastmcp.com/python-sdk/fastmcp-cli-install-shared.md)
      - [run](https://gofastmcp.com/python-sdk/fastmcp-cli-run.md)
      - [tasks](https://gofastmcp.com/python-sdk/fastmcp-cli-tasks.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-client-__init__.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-client-auth-__init__.md)
      - [bearer](https://gofastmcp.com/python-sdk/fastmcp-client-auth-bearer.md)
      - [oauth](https://gofastmcp.com/python-sdk/fastmcp-client-auth-oauth.md)
      - [client](https://gofastmcp.com/python-sdk/fastmcp-client-client.md)
      - [elicitation](https://gofastmcp.com/python-sdk/fastmcp-client-elicitation.md)
      - [logging](https://gofastmcp.com/python-sdk/fastmcp-client-logging.md)
      - [messages](https://gofastmcp.com/python-sdk/fastmcp-client-messages.md)
      - [oauth_callback](https://gofastmcp.com/python-sdk/fastmcp-client-oauth_callback.md)
      - [progress](https://gofastmcp.com/python-sdk/fastmcp-client-progress.md)
      - [roots](https://gofastmcp.com/python-sdk/fastmcp-client-roots.md)
      - [sampling](https://gofastmcp.com/python-sdk/fastmcp-client-sampling.md)
      - [tasks](https://gofastmcp.com/python-sdk/fastmcp-client-tasks.md)
      - [transports](https://gofastmcp.com/python-sdk/fastmcp-client-transports.md)
      - [dependencies](https://gofastmcp.com/python-sdk/fastmcp-dependencies.md)
      - [exceptions](https://gofastmcp.com/python-sdk/fastmcp-exceptions.md)
      - [mcp_config](https://gofastmcp.com/python-sdk/fastmcp-mcp_config.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-prompts-__init__.md)
      - [prompt](https://gofastmcp.com/python-sdk/fastmcp-prompts-prompt.md)
      - [prompt_manager](https://gofastmcp.com/python-sdk/fastmcp-prompts-prompt_manager.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-resources-__init__.md)
      - [resource](https://gofastmcp.com/python-sdk/fastmcp-resources-resource.md)
      - [resource_manager](https://gofastmcp.com/python-sdk/fastmcp-resources-resource_manager.md)
      - [template](https://gofastmcp.com/python-sdk/fastmcp-resources-template.md)
      - [types](https://gofastmcp.com/python-sdk/fastmcp-resources-types.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-server-__init__.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-server-auth-__init__.md)
      - [auth](https://gofastmcp.com/python-sdk/fastmcp-server-auth-auth.md)
      - [jwt_issuer](https://gofastmcp.com/python-sdk/fastmcp-server-auth-jwt_issuer.md)
      - [middleware](https://gofastmcp.com/python-sdk/fastmcp-server-auth-middleware.md)
      - [oauth_proxy](https://gofastmcp.com/python-sdk/fastmcp-server-auth-oauth_proxy.md)
      - [oidc_proxy](https://gofastmcp.com/python-sdk/fastmcp-server-auth-oidc_proxy.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-__init__.md)
      - [auth0](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-auth0.md)
      - [aws](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-aws.md)
      - [azure](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-azure.md)
      - [debug](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-debug.md)
      - [descope](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-descope.md)
      - [discord](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-discord.md)
      - [github](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-github.md)
      - [google](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-google.md)
      - [in_memory](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-in_memory.md)
      - [introspection](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-introspection.md)
      - [jwt](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-jwt.md)
      - [oci](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-oci.md)
      - [scalekit](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-scalekit.md)
      - [supabase](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-supabase.md)
      - [workos](https://gofastmcp.com/python-sdk/fastmcp-server-auth-providers-workos.md)
      - [redirect_validation](https://gofastmcp.com/python-sdk/fastmcp-server-auth-redirect_validation.md)
      - [context](https://gofastmcp.com/python-sdk/fastmcp-server-context.md)
      - [dependencies](https://gofastmcp.com/python-sdk/fastmcp-server-dependencies.md)
      - [elicitation](https://gofastmcp.com/python-sdk/fastmcp-server-elicitation.md)
      - [event_store](https://gofastmcp.com/python-sdk/fastmcp-server-event_store.md)
      - [http](https://gofastmcp.com/python-sdk/fastmcp-server-http.md)
      - [low_level](https://gofastmcp.com/python-sdk/fastmcp-server-low_level.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-__init__.md)
      - [caching](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-caching.md)
      - [error_handling](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-error_handling.md)
      - [logging](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-logging.md)
      - [middleware](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-middleware.md)
      - [rate_limiting](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-rate_limiting.md)
      - [timing](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-timing.md)
      - [tool_injection](https://gofastmcp.com/python-sdk/fastmcp-server-middleware-tool_injection.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-server-openapi-__init__.md)
      - [components](https://gofastmcp.com/python-sdk/fastmcp-server-openapi-components.md)
      - [routing](https://gofastmcp.com/python-sdk/fastmcp-server-openapi-routing.md)
      - [server](https://gofastmcp.com/python-sdk/fastmcp-server-openapi-server.md)
      - [proxy](https://gofastmcp.com/python-sdk/fastmcp-server-proxy.md)
      - [server](https://gofastmcp.com/python-sdk/fastmcp-server-server.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-server-tasks-__init__.md)
      - [capabilities](https://gofastmcp.com/python-sdk/fastmcp-server-tasks-capabilities.md)
      - [config](https://gofastmcp.com/python-sdk/fastmcp-server-tasks-config.md)
      - [converters](https://gofastmcp.com/python-sdk/fastmcp-server-tasks-converters.md)
      - [handlers](https://gofastmcp.com/python-sdk/fastmcp-server-tasks-handlers.md)
      - [protocol](https://gofastmcp.com/python-sdk/fastmcp-server-tasks-protocol.md)
      - [subscriptions](https://gofastmcp.com/python-sdk/fastmcp-server-tasks-subscriptions.md)
      - [settings](https://gofastmcp.com/python-sdk/fastmcp-settings.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-tools-__init__.md)
      - [tool](https://gofastmcp.com/python-sdk/fastmcp-tools-tool.md)
      - [tool_manager](https://gofastmcp.com/python-sdk/fastmcp-tools-tool_manager.md)
      - [tool_transform](https://gofastmcp.com/python-sdk/fastmcp-tools-tool_transform.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-utilities-__init__.md)
      - [auth](https://gofastmcp.com/python-sdk/fastmcp-utilities-auth.md)
      - [cli](https://gofastmcp.com/python-sdk/fastmcp-utilities-cli.md)
      - [components](https://gofastmcp.com/python-sdk/fastmcp-utilities-components.md)
      - [exceptions](https://gofastmcp.com/python-sdk/fastmcp-utilities-exceptions.md)
      - [http](https://gofastmcp.com/python-sdk/fastmcp-utilities-http.md)
      - [inspect](https://gofastmcp.com/python-sdk/fastmcp-utilities-inspect.md)
      - [json_schema](https://gofastmcp.com/python-sdk/fastmcp-utilities-json_schema.md)
      - [json_schema_type](https://gofastmcp.com/python-sdk/fastmcp-utilities-json_schema_type.md)
      - [logging](https://gofastmcp.com/python-sdk/fastmcp-utilities-logging.md)
      - [mcp_config](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_config.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-__init__.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-__init__.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-environments-__init__.md)
      - [base](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-environments-base.md)
      - [uv](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-environments-uv.md)
      - [mcp_server_config](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-mcp_server_config.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-sources-__init__.md)
      - [base](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-sources-base.md)
      - [filesystem](https://gofastmcp.com/python-sdk/fastmcp-utilities-mcp_server_config-v1-sources-filesystem.md)
      - [__init__](https://gofastmcp.com/python-sdk/fastmcp-utilities-openapi-__init__.md)
      - [director](https://gofastmcp.com/python-sdk/fastmcp-utilities-openapi-director.md)
      - [formatters](https://gofastmcp.com/python-sdk/fastmcp-utilities-openapi-formatters.md)
      - [json_schema_converter](https://gofastmcp.com/python-sdk/fastmcp-utilities-openapi-json_schema_converter.md)
      - [models](https://gofastmcp.com/python-sdk/fastmcp-utilities-openapi-models.md)
      - [parser](https://gofastmcp.com/python-sdk/fastmcp-utilities-openapi-parser.md)
      - [schemas](https://gofastmcp.com/python-sdk/fastmcp-utilities-openapi-schemas.md)
      - [tests](https://gofastmcp.com/python-sdk/fastmcp-utilities-tests.md)
      - [types](https://gofastmcp.com/python-sdk/fastmcp-utilities-types.md)
      - [ui](https://gofastmcp.com/python-sdk/fastmcp-utilities-ui.md)
      - [Authentication](https://gofastmcp.com/servers/auth/authentication.md): Secure your FastMCP server with flexible authentication patterns, from simple API keys to full OAuth 2.1 integration with external identity providers.
      - [Full OAuth Server](https://gofastmcp.com/servers/auth/full-oauth-server.md): Build a self-contained authentication system where your FastMCP server manages users, issues tokens, and validates them.
      - [OAuth Proxy](https://gofastmcp.com/servers/auth/oauth-proxy.md): Bridge traditional OAuth providers to work seamlessly with MCP's authentication flow.
      - [OIDC Proxy](https://gofastmcp.com/servers/auth/oidc-proxy.md): Bridge OIDC providers to work seamlessly with MCP's authentication flow.
      - [Remote OAuth](https://gofastmcp.com/servers/auth/remote-oauth.md): Integrate your FastMCP server with external identity providers like Descope, WorkOS, Auth0, and corporate SSO systems.
      - [Token Verification](https://gofastmcp.com/servers/auth/token-verification.md): Protect your server by validating bearer tokens issued by external systems.
      - [Server Composition](https://gofastmcp.com/servers/composition.md): Combine multiple FastMCP servers into a single, larger application using mounting and importing.
      - [MCP Context](https://gofastmcp.com/servers/context.md): Access MCP capabilities like logging, progress, and resources within your MCP objects.
      - [User Elicitation](https://gofastmcp.com/servers/elicitation.md): Request structured input from users during tool execution through the MCP context.
      - [Icons](https://gofastmcp.com/servers/icons.md): Add visual icons to your servers, tools, resources, and prompts
      - [Client Logging](https://gofastmcp.com/servers/logging.md): Send log messages back to MCP clients through the context.
      - [MCP Middleware](https://gofastmcp.com/servers/middleware.md): Add cross-cutting functionality to your MCP server with middleware that can inspect, modify, and respond to all MCP requests and responses.
      - [Progress Reporting](https://gofastmcp.com/servers/progress.md): Update clients on the progress of long-running operations through the MCP context.
      - [Prompts](https://gofastmcp.com/servers/prompts.md): Create reusable, parameterized prompt templates for MCP clients.
      - [Proxy Servers](https://gofastmcp.com/servers/proxy.md): Use FastMCP to act as an intermediary or change transport for other MCP servers.
      - [Resources & Templates](https://gofastmcp.com/servers/resources.md): Expose data sources and dynamic content generators to your MCP client.
      - [LLM Sampling](https://gofastmcp.com/servers/sampling.md): Request LLM text generation from the client or a configured provider through the MCP context.
      - [The FastMCP Server](https://gofastmcp.com/servers/server.md): The core FastMCP server class for building MCP applications with tools, resources, and prompts.
      - [Storage Backends](https://gofastmcp.com/servers/storage-backends.md): Configure persistent and distributed storage for caching and OAuth state management
      - [Background Tasks](https://gofastmcp.com/servers/tasks.md): Run long-running operations asynchronously with progress tracking
      - [Tools](https://gofastmcp.com/servers/tools.md): Expose functions as executable capabilities for your MCP client.
      - [FastMCP Updates](https://gofastmcp.com/updates.md)
      
    • MANDATORY_PATTERNS.md 6.5 KB
      # FastMCP Mandatory Patterns
      
      Four critical requirements for ALL FastMCP implementations.
      
      ## 1. Use uv (Never pip)
      
      **Rule:** Always use uv for dependency management.
      
      **Installation:**
      ```bash
      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:**
      ```bash
      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):**
      ```python
      @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):**
      ```python
      @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)**
      ```python
      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**
      ```python
      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**
      ```python
      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
      
      ```python
      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)}
      ```
      
    • MCPB_BUNDLING.md 4.6 KB
      # MCPB Bundling Guide
      
      ## Simple Method (Use This)
      
      **MCPB is just a ZIP archive with `.mcpb` extension.**
      
      ```bash
      # 1. Create manifest.json (see format below)
      # 2. Bundle with zip
      cd /home/claude
      zip -r server-name.mcpb manifest.json server.py README.md
      cp server-name.mcpb /mnt/user-data/outputs/
      ```
      
      **DO NOT use `mcpb pack` CLI** - causes container crashes.
      
      ---
      
      ## Bundle Structure
      
      ```
      server-name.mcpb (ZIP archive)
      ├── manifest.json             # Required
      ├── server.py                 # Entry point
      ├── requirements.txt          # Optional
      ├── README.md                 # Optional
      └── assets/                   # Optional
      ```
      
      ---
      
      ## Manifest Format
      
      ```json
      {
          "manifest_version": "0.1",
          "name": "server-name",
          "version": "1.0.0",
          "description": "Server description",
          "author": "Your Name <email@example.com>",
          "license": "MIT",
          "server": {
              "type": "python",
              "entry_point": "server.py",
              "mcp_config": {
                  "command": "uv",
                  "args": [
                      "run",
                      "--with", "fastmcp>=2.0.0",
                      "--with", "other-package>=1.0.0",
                      "--", "server.py"
                  ],
                  "env": {
                      "API_KEY": "",
                      "API_URL": ""
                  }
              }
          }
      }
      ```
      
      ### Field Descriptions
      
      **Top-level:**
      - `manifest_version`: MCPB spec version ("0.1")
      - `name`: Package identifier (lowercase, hyphens, no spaces)
      - `version`: Semantic version (MAJOR.MINOR.PATCH)
      - `description`: One-line description
      - `author`: Name and email
      - `license`: SPDX identifier or "Proprietary"
      
      **Server configuration:**
      - `type`: "python" or "node"
      - `entry_point`: Main server file
      - `mcp_config.command`: Executable ("uv" for Python)
      - `mcp_config.args`: Command-line arguments
      - `mcp_config.env`: Environment variables (empty = user must provide)
      
      ---
      
      ## Creating Bundles
      
      ### Minimal Bundle
      
      ```bash
      # Create manifest
      cat > manifest.json << 'EOF'
      {
          "manifest_version": "0.1",
          "name": "my-server",
          "version": "1.0.0",
          "description": "Brief server description",
          "server": {
              "type": "python",
              "entry_point": "server.py",
              "mcp_config": {
                  "command": "uv",
                  "args": ["run", "--with", "fastmcp>=2.0.0", "--", "server.py"]
              }
          }
      }
      EOF
      
      # Create ZIP
      zip -r my-server.mcpb manifest.json server.py README.md
      
      # Move to outputs
      cp my-server.mcpb /mnt/user-data/outputs/
      ```
      
      ### With Dependencies
      
      ```json
      "args": [
          "run",
          "--with", "fastmcp>=2.0.0",
          "--with", "requests>=2.31.0",
          "--with", "pydantic>=2.0.0",
          "--", "server.py"
      ]
      ```
      
      ### With Environment Variables
      
      ```json
      "mcp_config": {
          "command": "uv",
          "args": ["run", "--with", "fastmcp>=2.0.0", "--", "server.py"],
          "env": {
              "API_KEY": "",
              "API_URL": "",
              "DEBUG": "false"
          }
      }
      ```
      
      ---
      
      ## Installing Bundles
      
      ### Claude Desktop
      ```bash
      fastmcp install claude-desktop server.mcpb
      ```
      
      ### Claude Code
      ```bash
      fastmcp install claude-code server.mcpb
      ```
      
      ### Manual
      ```bash
      mkdir -p ~/mcp-servers/server-name
      unzip server.mcpb -d ~/mcp-servers/server-name
      # Add to MCP client config from manifest.json
      ```
      
      ---
      
      ## Validation
      
      ```bash
      # Check ZIP structure
      unzip -l server.mcpb
      
      # Extract and test
      unzip -d /tmp/test server.mcpb
      cd /tmp/test
      uv run --with fastmcp server.py
      ```
      
      ---
      
      ## Common Patterns
      
      ### Single-File Server
      ```
      simple-server.mcpb
      ├── manifest.json
      └── server.py
      ```
      
      ### Multi-File with Assets
      ```
      complex-server.mcpb
      ├── manifest.json
      ├── server.py
      ├── requirements.txt
      ├── README.md
      └── assets/
          └── schemas/
      ```
      
      ### Environment-Configured
      ```json
      {
          "description": "Requires API_KEY and API_URL",
          "server": {
              "mcp_config": {
                  "env": {
                      "API_KEY": "",
                      "API_URL": ""
                  }
              }
          }
      }
      ```
      
      ---
      
      ## Best Practices
      
      **Manifest:**
      - Pin FastMCP version: `"fastmcp>=2.0.0,<3.0.0"`
      - Document required env vars in description
      - Include contact info in author field
      
      **Security:**
      - Environment variables for secrets (never hardcode)
      - Empty values = user must provide
      
      **Dependencies:**
      - Pin major versions, allow minor updates
      - Example: `"requests>=2.31.0,<3.0.0"`
      
      ---
      
      ## Troubleshooting
      
      **Bundle extraction fails:**
      ```bash
      unzip -t server.mcpb  # Check integrity
      ```
      
      **Server won't start:**
      ```bash
      uv pip list
      uv run --with fastmcp server.py
      ```
      
      **Environment variables not set:**
      ```bash
      export API_KEY="your-key"
      export API_URL="https://api.example.com"
      fastmcp install claude-desktop server.mcpb
      ```
      
    • PROGRESSIVE_DISCLOSURE.md 6.8 KB
      # 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:
      
      ```python
      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)
      
      ```python
      @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)
      
      ```python
      @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:**
      ```python
      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
      ```
      
  • scripts
    • create_mcpb.py 11.5 KB
      #!/usr/bin/env python3
      """Create MCPB (MCP Bundle) packages from FastMCP servers.
      
      This script packages FastMCP servers into distributable .mcpb files with
      proper manifest generation, dependency handling, and file inclusion.
      
      Usage:
          python create_mcpb.py server.py [options]
      
      Examples:
          # Basic usage
          python create_mcpb.py server.py
      
          # With custom metadata
          python create_mcpb.py server.py \\
              --name my-server \\
              --version 2.0.0 \\
              --description "API integration server"
      
          # With dependencies
          python create_mcpb.py server.py \\
              --with requests \\
              --with pydantic>=2.0.0
      
          # Complete example
          python create_mcpb.py server.py \\
              --name jira-integration \\
              --version 1.0.0 \\
              --author "Your Name <email@example.com>" \\
              --license MIT \\
              --with atlassian-python-api>=3.41.0 \\
              --env JIRA_URL \\
              --env JIRA_PAT \\
              --include assets/ \\
              --include LICENSE
      """
      
      import argparse
      import json
      import re
      import sys
      import zipfile
      from pathlib import Path
      from typing import Any
      
      
      def extract_server_name(server_path: Path) -> str:
          """Extract server name from Python file."""
          content = server_path.read_text()
          
          # Try to find FastMCP(name="...") pattern
          match = re.search(r'FastMCP\s*\(\s*name\s*=\s*["\']([^"\']+)["\']', content)
          if match:
              return match.group(1)
          
          # Fallback to filename
          return server_path.stem.replace('_', '-')
      
      def extract_dependencies(requirements_file: Path) -> list[str]:
          """Extract dependencies from requirements.txt."""
          if not requirements_file.exists():
              return []
          
          deps = []
          for line in requirements_file.read_text().splitlines():
              line = line.strip()
              if line and not line.startswith('#'):
                  deps.append(line)
          return deps
      
      def create_manifest(
          server_path: Path,
          name: str | None = None,
          version: str = "1.0.0",
          description: str | None = None,
          author: str | None = None,
          license: str = "MIT",
          homepage: str | None = None,
          dependencies: list[str] | None = None,
          env_vars: list[str] | None = None,
          tags: list[str] | None = None,
      ) -> dict[str, Any]:
          """Create MCPB manifest dictionary."""
          
          server_name = name or extract_server_name(server_path)
          
          # Build args for uv command
          args = ["run"]
          
          # Always include fastmcp
          args.extend(["--with", "fastmcp>=2.0.0,<3.0.0"])
          
          # Add other dependencies
          if dependencies:
              for dep in dependencies:
                  args.extend(["--with", dep])
          
          # Add entry point
          args.extend(["--", server_path.name])
          
          # Build manifest
          manifest = {
              "manifest_version": "0.1",
              "name": server_name,
              "version": version,
              "server": {
                  "type": "python",
                  "entry_point": server_path.name,
                  "mcp_config": {
                      "command": "uv",
                      "args": args,
                  }
              }
          }
          
          # Add optional fields
          if description:
              manifest["description"] = description
          
          if author:
              manifest["author"] = author
          
          if license:
              manifest["license"] = license
          
          if homepage:
              manifest["homepage"] = homepage
          
          # Add environment variables
          if env_vars:
              manifest["server"]["mcp_config"]["env"] = {var: "" for var in env_vars}
          
          # Add metadata
          if tags:
              manifest["metadata"] = {"tags": tags}
          
          return manifest
      
      def create_bundle(
          server_path: Path,
          output_path: Path,
          manifest: dict[str, Any],
          include_files: list[str] | None = None,
          exclude_patterns: list[str] | None = None,
      ) -> None:
          """Create MCPB bundle ZIP file."""
          
          # Default exclusions
          default_excludes = [
              '__pycache__',
              '*.pyc',
              '.pytest_cache',
              '.venv',
              'venv',
              '.git',
              '.vscode',
              '.idea',
              '*.swp',
              '.DS_Store',
              'node_modules',
          ]
          
          exclude_patterns = (exclude_patterns or []) + default_excludes
          
          def should_exclude(path: Path) -> bool:
              """Check if path matches exclusion patterns."""
              import fnmatch
              for pattern in exclude_patterns:
                  if fnmatch.fnmatch(str(path), f"*{pattern}*"):
                      return True
              return False
          
          with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zf:
              # Add manifest
              zf.writestr('mcpb.json', json.dumps(manifest, indent=2))
              
              # Add server file
              zf.write(server_path, server_path.name)
              
              # Add requirements.txt if exists
              req_file = server_path.parent / 'requirements.txt'
              if req_file.exists():
                  zf.write(req_file, 'requirements.txt')
              
              # Add README if exists
              readme = server_path.parent / 'README.md'
              if readme.exists():
                  zf.write(readme, 'README.md')
              
              # Add LICENSE if exists
              license_file = server_path.parent / 'LICENSE'
              if license_file.exists():
                  zf.write(license_file, 'LICENSE')
              
              # Add explicitly included files
              if include_files:
                  for pattern in include_files:
                      for path in Path.cwd().glob(pattern):
                          if path.is_file() and not should_exclude(path):
                              # Preserve directory structure
                              arcname = str(path.relative_to(Path.cwd()))
                              zf.write(path, arcname)
                          elif path.is_dir():
                              # Add directory recursively
                              for subpath in path.rglob('*'):
                                  if subpath.is_file() and not should_exclude(subpath):
                                      arcname = str(subpath.relative_to(Path.cwd()))
                                      zf.write(subpath, arcname)
      
      def validate_bundle(bundle_path: Path) -> bool:
          """Validate MCPB bundle structure."""
          try:
              with zipfile.ZipFile(bundle_path) as zf:
                  names = zf.namelist()
                  
                  # Check required files
                  if 'mcpb.json' not in names:
                      print("❌ Missing mcpb.json manifest")
                      return False
                  
                  # Validate manifest
                  manifest = json.loads(zf.read('mcpb.json'))
                  
                  # Required fields
                  required = ['manifest_version', 'name', 'version', 'server']
                  for field in required:
                      if field not in manifest:
                          print(f"❌ Manifest missing required field: {field}")
                          return False
                  
                  # Check entry point exists
                  entry = manifest['server']['entry_point']
                  if entry not in names:
                      print(f"❌ Entry point not in bundle: {entry}")
                      return False
                  
                  print("✓ Bundle is valid")
                  return True
                  
          except (zipfile.BadZipFile, json.JSONDecodeError, KeyError) as e:
              print(f"❌ Validation failed: {e}")
              return False
      
      def main():
          parser = argparse.ArgumentParser(
              description="Create MCPB bundles from FastMCP servers",
              formatter_class=argparse.RawDescriptionHelpFormatter,
              epilog=__doc__
          )
          
          # Required arguments
          parser.add_argument(
              'server',
              type=Path,
              help='Path to FastMCP server Python file'
          )
          
          # Optional metadata
          parser.add_argument(
              '--name',
              help='Package name (default: extracted from server file)'
          )
          parser.add_argument(
              '--version',
              default='1.0.0',
              help='Package version (default: 1.0.0)'
          )
          parser.add_argument(
              '--description',
              help='Package description'
          )
          parser.add_argument(
              '--author',
              help='Author name and email (e.g., "Name <email@example.com>")'
          )
          parser.add_argument(
              '--license',
              default='MIT',
              help='License identifier (default: MIT)'
          )
          parser.add_argument(
              '--homepage',
              help='Homepage URL'
          )
          
          # Dependencies
          parser.add_argument(
              '--with',
              dest='dependencies',
              action='append',
              default=[],
              help='Additional dependency (can be used multiple times)'
          )
          parser.add_argument(
              '--requirements',
              type=Path,
              default=Path('requirements.txt'),
              help='Path to requirements.txt (default: ./requirements.txt)'
          )
          
          # Environment
          parser.add_argument(
              '--env',
              dest='env_vars',
              action='append',
              default=[],
              help='Environment variable name (can be used multiple times)'
          )
          
          # File inclusion
          parser.add_argument(
              '--include',
              dest='include_files',
              action='append',
              default=[],
              help='Additional files/directories to include (can be used multiple times)'
          )
          parser.add_argument(
              '--exclude',
              dest='exclude_patterns',
              action='append',
              default=[],
              help='File patterns to exclude (can be used multiple times)'
          )
          
          # Tags
          parser.add_argument(
              '--tag',
              dest='tags',
              action='append',
              default=[],
              help='Package tags (can be used multiple times)'
          )
          
          # Output
          parser.add_argument(
              '--output',
              '-o',
              type=Path,
              help='Output path (default: <name>.mcpb)'
          )
          
          # Validation
          parser.add_argument(
              '--no-validate',
              action='store_true',
              help='Skip bundle validation'
          )
          
          args = parser.parse_args()
          
          # Validate input
          if not args.server.exists():
              print(f"❌ Server file not found: {args.server}")
              sys.exit(1)
          
          # Extract dependencies from requirements.txt
          deps_from_file = extract_dependencies(args.requirements) if args.requirements.exists() else []
          all_deps = args.dependencies + deps_from_file
          
          # Create manifest
          manifest = create_manifest(
              server_path=args.server,
              name=args.name,
              version=args.version,
              description=args.description,
              author=args.author,
              license=args.license,
              homepage=args.homepage,
              dependencies=all_deps,
              env_vars=args.env_vars if args.env_vars else None,
              tags=args.tags if args.tags else None,
          )
          
          # Determine output path
          output_path = args.output or Path(f"{manifest['name']}.mcpb")
          
          # Create bundle
          print(f"Creating bundle: {output_path}")
          print(f"  Server: {args.server}")
          print(f"  Name: {manifest['name']}")
          print(f"  Version: {manifest['version']}")
          if all_deps:
              print(f"  Dependencies: {', '.join(all_deps)}")
          if args.env_vars:
              print(f"  Environment: {', '.join(args.env_vars)}")
          
          create_bundle(
              server_path=args.server,
              output_path=output_path,
              manifest=manifest,
              include_files=args.include_files if args.include_files else None,
              exclude_patterns=args.exclude_patterns if args.exclude_patterns else None,
          )
          
          print(f"✓ Bundle created: {output_path}")
          
          # Validate bundle
          if not args.no_validate:
              print("\nValidating bundle...")
              if not validate_bundle(output_path):
                  sys.exit(1)
          
          # Show manifest
          print("\nManifest:")
          print(json.dumps(manifest, indent=2))
          
          print(f"\n✓ Successfully created {output_path}")
          print("\nInstall with:")
          print(f"  fastmcp install claude-desktop {output_path}")
      
      if __name__ == '__main__':
          main()
      
  • CHANGELOG.md 904 B
    # creating-mcp-servers - Changelog
    
    All notable changes to the `creating-mcp-servers` skill are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
    
    ## [1.2.0] - 2026-09-09
    
    ### Added
    
    - add mapping-features skill for behavioral web app documentation (#432)
    - add line numbers, markdown ToC, and other files listing
    - add code maps and CLAUDE.md integration guidance
    - Delete VERSION files, complete migration to frontmatter
    - Migrate all 27 skills from VERSION files to frontmatter
    
    ### Fixed
    
    - repair broken frontmatter, mark obsolete skills, close registry gaps (#746)
    - limit markdown ToC to h1/h2 headings only
    
    ### Other
    
    - prompt-audit: dated prompting patterns across the skill catalogue (#791)
    - Deprecate mapping-codebases; adopt ruff 0.16.0 baseline (#747)
    - Remove _MAP.md files, direct agents to tree-sitting for code navigation (#545)
    
  • README.md 265 B
    # creating-mcp-servers
    
    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.
    
  • SKILL.md 5.2 KB
    ---
    name: creating-mcp-servers
    description: 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.
    metadata:
      version: 1.2.0
    ---
    
    # Creating MCP Servers
    
    Build production-ready MCP servers using FastMCP v2 with optimal context efficiency through progressive disclosure patterns.
    
    ## Core Capabilities
    
    1. **Apply the core patterns** - Four requirements for consistency
    2. **Implement progressive disclosure** - Gateway patterns achieving 85-93% token reduction  
    3. **Optimize tool descriptions** - 65-70% token reduction through proper patterns
    4. **Bundle servers** - Package as MCPB files with validation
    5. **Proven gateway patterns** - Three complete implementations (Skills, API, Query)
    
    ## Architecture Decision
    
    ```
    1-3 simple tools?
      → Standard FastMCP with optimized tools
      Load: references/MANDATORY_PATTERNS.md
    
    5+ related capabilities?
      → Gateway pattern (progressive disclosure)
      Load: references/PROGRESSIVE_DISCLOSURE.md
      Load: references/GATEWAY_PATTERNS.md
    
    Optimize existing server?
      → Apply mandatory patterns
      Load: references/MANDATORY_PATTERNS.md
    
    Package for distribution?
      → MCPB bundler
      Load: references/MCPB_BUNDLING.md
      Execute: scripts/create_mcpb.py
    
    Need FastMCP documentation?
      → Search references/LLMS_TXT.md for relevant URLs
      → Use web_fetch on gofastmcp.com URLs
    ```
    
    ## Mandatory Patterns (Summary)
    
    Every implementation should meet these four requirements:
    
    1. **uv (never pip)** - `uv pip install fastmcp`
    2. **Optimized tool descriptions** - Annotations, Annotated, concise docstrings
    3. **Authoritative documentation** - Fetch from gofastmcp.com via LLMS_TXT.md index
    4. **Apply all patterns** - Every implementation meets verification checklist
    
    Details in [references/MANDATORY_PATTERNS.md](references/MANDATORY_PATTERNS.md)
    
    ## Documentation Retrieval Workflow
    
    **To fetch FastMCP documentation:**
    
    ```
    1. Read references/LLMS_TXT.md - complete URL index
    2. Search for relevant topic keywords
    3. Use web_fetch on matched URLs (append .md for markdown)
    4. Apply patterns from fetched documentation
    ```
    
    **Example:** Authentication patterns → Search LLMS_TXT.md for "authentication" → web_fetch https://gofastmcp.com/servers/auth/authentication.md
    
    ## Progressive Disclosure Pattern
    
    For servers with 5+ capabilities:
    
    **Three-tier loading:**
    1. Metadata (~20 tokens/capability) - Always loaded
    2. Content (~500 tokens) - Load on demand
    3. Execution (0 tokens) - Execute without loading
    
    Achieves 85-93% baseline reduction. See [references/PROGRESSIVE_DISCLOSURE.md](references/PROGRESSIVE_DISCLOSURE.md)
    
    ## Implementation Phases
    
    ### Phase 1: Research
    Read LLMS_TXT.md → Find relevant URLs → web_fetch documentation
    
    ### Phase 2: Implement
    Load appropriate reference based on architecture decision. Apply all four patterns.
    
    ### Phase 3: Package (Optional)
    ```bash
    cd /home/claude
    zip -r server-name.mcpb manifest.json server.py README.md
    cp server-name.mcpb /mnt/user-data/outputs/
    ```
    
    See [references/MCPB_BUNDLING.md](references/MCPB_BUNDLING.md) for manifest format.
    
    ## Reference Library
    
    **Documentation index (load first for FastMCP knowledge):**
    - [LLMS_TXT.md](references/LLMS_TXT.md) - Complete FastMCP v2 documentation URLs
    
    **Core patterns:**
    - [MANDATORY_PATTERNS.md](references/MANDATORY_PATTERNS.md) - the four core requirements
    - [PROGRESSIVE_DISCLOSURE.md](references/PROGRESSIVE_DISCLOSURE.md) - Architecture for 5+ capabilities
    
    **Implementation:**
    - [GATEWAY_PATTERNS.md](references/GATEWAY_PATTERNS.md) - Three production-ready implementations
    - [MCPB_BUNDLING.md](references/MCPB_BUNDLING.md) - Packaging and distribution
    
    **Scripts:**
    - `scripts/create_mcpb.py` - Bundle MCP servers into .mcpb files
    
    ## Verification Checklist
    
    Before completing any FastMCP implementation:
    
    ```
    ✓ Uses uv (not pip)
    ✓ FastMCP docs fetched from LLMS_TXT.md URLs (not web_search)
    ✓ Tool annotations (readOnlyHint, title, openWorldHint)
    ✓ Annotated parameters with Field
    ✓ Single-sentence docstrings
    ✓ 65-70% token reduction vs verbose
    ✓ Server instructions concise (<100 chars)
    ```
    
    For gateway implementations, additionally verify:
    ```
    ✓ 85%+ baseline context reduction
    ✓ Discover returns metadata only
    ✓ Load fetches content on demand
    ✓ Execute runs without context cost
    ```
    
    ## Tool Description Pattern
    
    **Before (180 tokens):**
    ```python
    @mcp.tool()
    async def search_items(query: str):
        """Search for items in the database.
        This tool allows comprehensive searching..."""
    ```
    
    **After (55 tokens):**
    ```python
    @mcp.tool(
        annotations={"title": "Search", "readOnlyHint": True, "openWorldHint": False}
    )
    async def search_items(
        query: Annotated[str, Field(description="Search text")],
        ctx: Context = None
    ):
        """Search items. Fast full-text search across all fields."""
    ```
    
    ## Common Pitfalls
    
    ❌ Using `mcpb pack` CLI (causes crashes, just use `zip`)  
    ❌ Using pip instead of uv  
    ❌ web_search for FastMCP docs (use web_fetch on LLMS_TXT.md URLs)  
    ❌ Verbose tool descriptions  
    ❌ Missing tool annotations  
    ❌ Gateway for 1-3 tools (overhead exceeds benefit)  
    ❌ Mixing unrelated capabilities in single gateway
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related