# How to Integrate External APIs into Claude Skills: A Complete MCP Guide

> Learn how to integrate external APIs into Claude skills using the Model Context Protocol MCP. Discover workflow-oriented design and runtime schema discovery for seamless integration.

- Repository: [Composio/awesome-claude-skills](https://github.com/composiohq/awesome-claude-skills)
- Tags: how-to-guide
- Published: 2026-07-23

---

**Integrate external APIs into Claude skills by wrapping HTTP endpoints as Model Context Protocol (MCP) tools with workflow-oriented design, runtime schema discovery, and Pydantic-validated inputs.**

The ComposioHQ/awesome-claude-skills repository provides a production-ready framework for converting any REST API into a Claude-compatible skill. By following the MCP (Model Context Protocol) patterns established in this codebase, you can expose external services as type-safe, discoverable tools that Claude invokes with automatic validation and error handling.

## Design Workflow-Oriented Tools

Claude skills should expose complete user actions rather than raw HTTP endpoints. According to [`mcp-builder/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/SKILL.md), tools must represent workflows like *"find a client in Zoho Invoice"* instead of isolated GET or POST operations.

**Tool naming conventions** require service-specific prefixes to help the LLM route requests correctly. Use patterns like `zoho_invoice_create_invoice` or `github_create_issue` rather than generic names. This prefixing strategy is documented under **Tool Naming** in the MCP builder guide and ensures Claude selects the correct integration when processing natural language requests.

## Implement Runtime Tool Discovery

Hard-coding tool slugs violates the dynamic design principles of the repository. Instead, Claude should discover available tools at runtime using the **RUBE_SEARCH_TOOLS** pattern:

1. Query the discovery endpoint with a concise use-case description (e.g., "create an invoice in Zoho Invoice")
2. Parse the returned tool list and input schemas dynamically

This approach is exemplified in [`composio-skills/zoho_invoice-automation/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/composio-skills/zoho_invoice-automation/SKILL.md) and reinforced by the *"Always search tools first"* rule in [`mcp-builder/reference/mcp_best_practices.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/mcp_best_practices.md). Runtime discovery allows skills to adapt when APIs add new endpoints without requiring code changes.

## Build a Reusable API Client

Create a thin async wrapper to handle authentication, pagination, and error normalization. The reference implementation in [`mcp-builder/reference/python_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/python_mcp_server.md) provides the `_make_api_request` helper:

```python
import httpx
import os

API_BASE_URL = "https://api.zoho.com/invoice/v1"

async def _make_api_request(endpoint: str, method: str = "GET", **kwargs) -> dict:
    """Reusable async client for all external API calls."""
    headers = {
        "Authorization": f"Bearer {os.environ['API_TOKEN']}",
        "Content-Type": "application/json"
    }
    
    async with httpx.AsyncClient() as client:
        resp = await client.request(
            method,
            f"{API_BASE_URL}/{endpoint}",
            headers=headers,
            timeout=30.0,
            **kwargs,
        )
        resp.raise_for_status()
        return resp.json()

```

The same file provides `_handle_api_error` for standardizing 401, 403, 429, and timeout responses across your skill.

## Validate Inputs with Pydantic Models

All tool inputs must use **Pydantic v2** models with strict configuration. As shown in [`python_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/python_mcp_server.md), define models with explicit constraints:

```python
from pydantic import BaseModel, Field, ConfigDict
from enum import Enum

class ResponseFormat(str, Enum):
    MARKDOWN = "markdown"
    JSON = "json"

class CreateInvoiceInput(BaseModel):
    model_config = ConfigDict(
        str_strip_whitespace=True, 
        validate_assignment=True, 
        extra="forbid"
    )

    client_id: str = Field(
        ..., 
        description="Zoho client identifier", 
        min_length=1
    )
    amount: float = Field(
        ..., 
        description="Invoice total amount", 
        gt=0
    )
    due_date: str = Field(
        ..., 
        description="ISO-8601 due date, e.g. 2024-05-01"
    )
    response_format: ResponseFormat = Field(
        default=ResponseFormat.MARKDOWN,
        description="Choose human-readable or machine-readable output",
    )

```

The `extra="forbid"` setting prevents Claude from hallucinating parameters, while `validate_assignment` ensures type safety throughout the tool execution.

## Register Tools Using FastMCP

Expose your API client through FastMCP with detailed annotations that guide Claude's behavior. The [`mcp-builder/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/SKILL.md) specifies these annotation flags:

- **readOnlyHint**: Boolean indicating if the tool modifies data
- **destructiveHint**: Boolean for irreversible operations
- **idempotentHint**: Boolean for safe retry behavior
- **openWorldHint**: Boolean indicating external network access

```python
from mcp.server.fastmcp import FastMCP
import json

mcp = FastMCP("zoho_invoice_mcp")

@mcp.tool(
    name="zoho_invoice_create_invoice",
    annotations={
        "title": "Create a Zoho Invoice",
        "readOnlyHint": False,
        "destructiveHint": True,
        "idempotentHint": False,
        "openWorldHint": True,
    },
)
async def create_invoice(params: CreateInvoiceInput) -> str:
    """Create a new invoice in Zoho Invoice.
    
    Validates inputs, calls the Zoho API, and returns formatted results.
    """
    try:
        data = await _make_api_request(
            "invoices",
            method="POST",
            json={
                "client_id": params.client_id,
                "amount": params.amount,
                "due_date": params.due_date,
            },
        )
        
        if params.response_format == ResponseFormat.MARKDOWN:
            return (
                f"# Invoice Created\n"

                f"- **ID:** {data['invoice_id']}\n"
                f"- **Amount:** ${data['amount']}\n"
                f"- **Due:** {data['due_date']}"
            )
        return json.dumps(data, indent=2)
    except Exception as e:
        return _handle_api_error(e)

```

These annotations help Claude determine when to ask user confirmation before executing destructive operations or when it can safely retry failed requests.

## Handle Dual Response Formats

Claude skills should support both human-readable and machine-parseable outputs. Include a `response_format` enum field in your input models, then branch the return logic accordingly. The example above demonstrates returning markdown for conversational context or JSON for downstream processing.

## Test and Package Your Skill

Before deployment, validate your integration using the evaluation harness described in **Phase 4** of [`mcp-builder/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/SKILL.md). This allows scripted testing of realistic queries without blocking the main process.

Once tested, package the skill following [`skill-creator/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/skill-creator/SKILL.md) conventions:

- Place server scripts in `scripts/`
- Store API reference documentation in `references/`
- Add static assets (templates, schemas) in `assets/`

The [`init_skill.py`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/init_skill.py) script in the skill-creator workflow scaffolds this directory structure automatically.

## Summary

- **Design workflows, not endpoints**: Tools should represent complete actions with service-prefixed names like `zoho_invoice_create_invoice`
- **Discover dynamically**: Use `RUBE_SEARCH_TOOLS` at runtime rather than hard-coding API endpoints
- **Abstract HTTP logic**: Implement `_make_api_request` and `_handle_api_error` helpers for consistent auth and error handling
- **Validate strictly**: Use Pydantic v2 with `extra="forbid"` to prevent parameter hallucination
- **Annotate accurately**: Set `destructiveHint`, `idempotentHint`, and `openWorldHint` in FastMCP decorators to guide Claude's decision-making
- **Package correctly**: Follow the `skill-creator` directory layout for reusable distribution

## Frequently Asked Questions

### What is the Model Context Protocol (MCP) in Claude skills?

MCP is the standardized protocol that allows Claude to discover and invoke external tools through a structured interface. In the ComposioHQ/awesome-claude-skills repository, MCP servers wrap HTTP APIs as type-safe functions that Claude calls with validated JSON inputs, enabling secure integration with third-party services like Zoho Invoice, GitHub, or custom REST endpoints.

### How does runtime tool discovery work with RUBE_SEARCH_TOOLS?

Rather than embedding tool names in prompts, Claude calls `RUBE_SEARCH_TOOLS` with a natural language use-case description (e.g., "create an invoice"). The system returns matching tool slugs and their input schemas, allowing Claude to dynamically construct valid requests. This pattern is implemented in [`composio-skills/zoho_invoice-automation/SKILL.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/composio-skills/zoho_invoice-automation/SKILL.md) and ensures skills adapt to API changes without manual updates.

### Why should I use Pydantic models for API inputs?

Pydantic models enforce schema validation at the boundary between Claude and your API. By setting `ConfigDict(extra="forbid", validate_assignment=True)`, you prevent the LLM from sending unexpected parameters while ensuring type safety. The [`mcp-builder/reference/python_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/python_mcp_server.md) file demonstrates how these models provide clear error messages when Claude generates invalid requests, improving reliability.

### What do the FastMCP annotation flags control?

The annotation flags in `@mcp.tool()` decorators provide metadata about side effects and safety. `destructiveHint: True` warns Claude that the operation modifies data irreversibly, prompting user confirmation. `idempotentHint: True` indicates safe retry behavior on network failures. `openWorldHint: True` signals that the tool contacts external networks. These flags help Claude decide when to execute, retry, or request approval for API calls.