Awesome-omni-skill MCP Tool Design

This skill should be used when the user asks to "define a tool", "create tool schema", "design inputSchema", "add tool annotations", "handle file uploads", "tool descriptions", "tool naming", or needs guidance on designing MCP tools for the OpenAI Apps SDK including schemas, annotations, and best practices.

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/design/mcp-tool-design" ~/.claude/skills/diegosouzapw-awesome-omni-skill-mcp-tool-design && rm -rf "$T"
manifest: skills/design/mcp-tool-design/SKILL.md
source content

MCP Tool Design for OpenAI Apps SDK

Overview

Tools are the primary interface between ChatGPT and your MCP server. Well-designed tools enable natural conversations, proper model behavior, and secure operations. This skill covers tool definition patterns, schema design, annotations, and best practices.

Tool Definition Structure

Every tool requires these components:

FieldRequiredPurpose
name
YesMachine-readable identifier
description
YesHuman-readable explanation for the model
inputSchema
YesJSON Schema defining parameters
annotations
NoBehavioral hints (read-only, destructive, etc.)
_meta
NoApps SDK extensions (file params, visibility)

Tool Naming Best Practices

Do:

  • Use verb_noun format:
    get_order
    ,
    create_user
    ,
    search_products
  • Be specific and descriptive:
    get_order_status
    not
    get_status
  • Use lowercase with underscores
  • Keep names under 64 characters

Don't:

  • Use promotional language:
    best_search
    ,
    official_api
  • Use generic names:
    do_thing
    ,
    process
  • Include version numbers:
    search_v2

Input Schema Design

Basic Schema

{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "description": "Search query to find products"
    },
    "limit": {
      "type": "integer",
      "description": "Maximum results to return",
      "default": 10
    }
  },
  "required": ["query"]
}

Schema with Enums

{
  "type": "object",
  "properties": {
    "category": {
      "type": "string",
      "enum": ["electronics", "clothing", "books"],
      "description": "Product category to filter by"
    }
  }
}

Nested Objects

{
  "type": "object",
  "properties": {
    "filter": {
      "type": "object",
      "properties": {
        "minPrice": { "type": "number" },
        "maxPrice": { "type": "number" }
      }
    }
  }
}

Tool Annotations

Annotations inform ChatGPT about tool behavior and safety:

AnnotationDefaultPurpose
readOnlyHint
falseSafe to auto-approve, no side effects
destructiveHint
falseMay delete/overwrite data, requires confirmation
openWorldHint
falsePublishes to external systems
idempotentHint
falseRepeated calls have no additional effect

Python Example

@mcp.tool(
    annotations={
        "readOnlyHint": True,
        "idempotentHint": True
    }
)
def get_user(user_id: str) -> dict:
    """Retrieve user information by ID."""
    return fetch_user(user_id)

@mcp.tool(
    annotations={
        "destructiveHint": True
    }
)
def delete_user(user_id: str) -> dict:
    """Permanently delete a user account."""
    return remove_user(user_id)

TypeScript Example

{
  name: "get_user",
  description: "Retrieve user information by ID",
  inputSchema: { /* ... */ },
  annotations: {
    readOnlyHint: true,
    idempotentHint: true
  }
}

Apps SDK _meta Extensions

Output Template

Link tools to widget UIs:

@mcp.tool()
def get_dashboard() -> dict:
    return {
        "structuredContent": {"data": [...]},
        "_meta": {
            "openai/outputTemplate": "ui://widget/dashboard.html"
        }
    }

Widget Accessibility

Enable widgets to call this tool:

{
  "_meta": {
    "openai/widgetAccessible": true
  }
}

Tool Visibility

Hide tools from the model (only callable from widgets):

{
  "_meta": {
    "openai/visibility": "private"
  }
}

File Parameters

Accept file uploads:

{
  "name": "process_image",
  "inputSchema": {
    "type": "object",
    "properties": {
      "image": {
        "type": "object",
        "properties": {
          "download_url": { "type": "string" },
          "file_id": { "type": "string" }
        }
      }
    }
  },
  "_meta": {
    "openai/fileParams": ["image"]
  }
}

Tool Description Guidelines

Descriptions help the model understand when and how to use tools:

Good:

"Search for products in the catalog. Returns matching products with prices and availability. Use when the user wants to find or browse products."

Bad:

"Search function"

Description Components

  1. What it does - Primary action
  2. What it returns - Output format
  3. When to use - Context for the model

Response Patterns

Standard Response

return {
    "structuredContent": {
        "status": "success",
        "data": result
    },
    "content": [
        {"type": "text", "text": "Operation completed"}
    ]
}

Response with Widget

return {
    "structuredContent": {
        "summary": "Found 5 items"
    },
    "_meta": {
        "items": full_item_list,  # Widget-only data
        "openai/outputTemplate": "ui://widget/list.html"
    }
}

Error Response

return {
    "structuredContent": {
        "status": "error",
        "error": "Item not found"
    },
    "content": [
        {"type": "text", "text": "Could not find the requested item"}
    ],
    "isError": True
}

Tool Filtering

Limit which tools the model sees to reduce context and improve accuracy:

# Responses API configuration
{
    "type": "mcp",
    "server_url": "https://example.com/mcp",
    "allowed_tools": ["search", "get_details"],  # Only expose these
    "require_approval": "never"
}

Validation Best Practices

  1. Validate early - Check inputs at the start of tool handlers
  2. Return clear errors - Explain what went wrong
  3. Use strict schemas - Define all constraints in JSON Schema
  4. Document constraints - Include limits in descriptions
@mcp.tool()
def search(query: str, limit: int = 10) -> dict:
    """Search products. Query must be 1-100 chars, limit 1-50."""
    if not 1 <= len(query) <= 100:
        return {"error": "Query must be 1-100 characters"}
    if not 1 <= limit <= 50:
        return {"error": "Limit must be 1-50"}
    return perform_search(query, limit)

Additional Resources

Reference Files

For detailed patterns and examples:

  • references/schema-patterns.md
    - Advanced JSON Schema patterns
  • references/annotation-guide.md
    - Complete annotation reference

Example Files

Working examples in

examples/
:

  • examples/tool-definitions.py
    - Python tool examples
  • examples/tool-definitions.ts
    - TypeScript tool examples

Official Documentation