How to Integrate External APIs into Claude Skills: A Complete MCP Guide
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, 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:
- Query the discovery endpoint with a concise use-case description (e.g., "create an invoice in Zoho Invoice")
- Parse the returned tool list and input schemas dynamically
This approach is exemplified in composio-skills/zoho_invoice-automation/SKILL.md and reinforced by the "Always search tools first" rule in 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 provides the _make_api_request helper:
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, define models with explicit constraints:
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 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
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. This allows scripted testing of realistic queries without blocking the main process.
Once tested, package the skill following 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 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_TOOLSat runtime rather than hard-coding API endpoints - Abstract HTTP logic: Implement
_make_api_requestand_handle_api_errorhelpers for consistent auth and error handling - Validate strictly: Use Pydantic v2 with
extra="forbid"to prevent parameter hallucination - Annotate accurately: Set
destructiveHint,idempotentHint, andopenWorldHintin FastMCP decorators to guide Claude's decision-making - Package correctly: Follow the
skill-creatordirectory 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →