A Python library for converting REST API specifications into MCP (Model Context Protocol) tools for AI agents.
Transform any REST API specification into tools that Claude, GPT, and other LLM-powered agents can use.
Supported Formats:
- OpenAPI 3.x (JSON, YAML)
- Swagger 2.x (JSON, YAML)
- OpenAPI Actions format (JSON)
β οΈ Beta Status: This library is currently in beta (v0.1.0). The core functionality is stable and production-ready, but the API may evolve based on community feedback. We welcome early adopters and contributors!
from adapter import ToolRegistry, MCPServer, APIExecutor, BearerAuth
# Create registry from OpenAPI spec (includes endpoints)
registry = ToolRegistry.create_from_openapi(
"https://api.example.com/openapi.json"
)
# Set up executor
executor = APIExecutor(
base_url="https://api.example.com",
auth=BearerAuth(token="your-token")
)
# Create server - endpoints are in the registry!
server = MCPServer(
name="My API Server",
version="1.0.0",
tool_registry=registry,
executor=executor
# No endpoints parameter needed!
)
server.run()For advanced usage and individual step control, see Detailed Usage below.
pip install rest-to-mcp-adapterTo install the latest beta version with cutting-edge features:
pip install --pre rest-to-mcp-adapterOr install a specific beta version:
pip install rest-to-mcp-adapter==0.2.0b1git clone https://github.com/pawneetdev/rest-to-mcp-adapter.git
cd rest-to-mcp-adapter
pip install -e .Core dependencies (automatically installed):
pydantic>=2.0.0- Data validation and modelingpyyaml>=6.0- YAML parsingrequests>=2.31.0- HTTP client
Optional dependencies:
langchain-community>=0.0.20- Enhanced OpenAPI validation (install with:pip install rest-to-mcp-adapter[langchain])
- Multiple formats: OpenAPI 3.x, Swagger 2.x, OpenAPI Actions
- JSON & YAML: Full support for both formats
- Load from anywhere: URL, file path, or raw content
- Auto-detection: Automatically determines input type and format
- $ref dereferencing: Resolves all JSON pointer references
- Automatic conversion: OpenAPI endpoints β MCP tools
- Smart naming: 64-character limit with intelligent truncation
- Auth filtering: Automatically hides auth parameters from users
- Hybrid approach: Defaults + auto-detection + custom overrides
- Built-in handlers: API Key, Bearer, Basic, OAuth2
- Custom handlers: Easy to implement your own
- Automatic parameter filtering: Auth params hidden from tool schemas
- Conditional auth: Only applies to endpoints that require it
- Direct API calls: Execute REST requests from canonical endpoints
- Retry logic: Exponential backoff for failed requests
- Error handling: Comprehensive error types and messages
- Response processing: JSON, text, and binary support
- Full MCP protocol: JSON-RPC 2.0 over stdio
- Claude integration: Ready for Claude Desktop
- Tool discovery:
tools/listendpoint - Tool execution:
tools/callendpoint
π‘ Looking for advanced features? See LIBRARY_USAGE.md for:
- Advanced tool generation patterns
- Registry operations (search, filter, export/import)
- Batch API calls
- Integration patterns and best practices
- Troubleshooting guide
- Important limitations (64-char tool name limit, etc.)
The library supports multiple specification formats with automatic detection:
from adapter import OpenAPILoader
loader = OpenAPILoader()
# OpenAPI 3.x (JSON)
spec = loader.load("https://api.example.com/openapi.json")
# OpenAPI 3.x (YAML)
spec = loader.load("./specs/openapi.yaml")
# Swagger 2.x (JSON)
spec = loader.load("./specs/swagger.json")
# Swagger 2.x (YAML)
spec = loader.load("https://api.example.com/swagger.yaml")
# OpenAPI Actions format
spec = loader.load("./specs/actions.json")
# From raw YAML content
yaml_content = """
openapi: 3.0.0
info:
title: My API
version: 1.0.0
paths:
/users:
get:
summary: List users
"""
spec = loader.load(yaml_content)
# From raw JSON content
json_content = '{"openapi": "3.0.0", "info": {"title": "My API"}}'
spec = loader.load(json_content)
# Auto-detection works for all methods
# Automatically detects: URL vs file vs content, JSON vs YAML, OpenAPI vs Swagger
spec = loader.load(source)from adapter import Normalizer
normalizer = Normalizer()
endpoints = normalizer.normalize_openapi(spec)
# Inspect normalized endpoints
for endpoint in endpoints:
print(f"{endpoint.method} {endpoint.path}")
print(f" Name: {endpoint.name}")
print(f" Parameters: {len(endpoint.parameters)}")
print(f" Requires auth: {bool(endpoint.security)}")from adapter import ToolGenerator
generator = ToolGenerator(api_name="myapi")
tools = generator.generate_tools(endpoints)
# Tools are ready to use!
for tool in tools:
print(f"Tool: {tool.name}")
print(f"Description: {tool.description}")
print(f"Parameters: {tool.inputSchema}")from adapter import OpenAPILoader, ToolGenerator
# Load spec
loader = OpenAPILoader()
spec = loader.load("api.yaml")
# Auto-detect auth parameters from security schemes
auto_detected = loader.extract_auth_parameters(spec)
print(f"Auto-detected: {auto_detected}")
# Output: {'x-api-key', 'signature', ...}
# Generate tools with hybrid filtering (defaults + auto-detected)
generator = ToolGenerator(
api_name="myapi",
auto_detected_auth_params=auto_detected
)
tools = generator.generate_tools(endpoints)
# Auth parameters are automatically hidden!
# Users only see business parameters# Override defaults completely
generator = ToolGenerator(
api_name="myapi",
auth_params={'my_signature', 'my_timestamp', 'my_nonce'}
)
tools = generator.generate_tools(endpoints)from adapter import ToolRegistry
# Create registry
registry = ToolRegistry(name="My API")
registry.add_tools(tools)
# Query tools
print(f"Total tools: {registry.count()}")
print(f"Tool names: {registry.get_tool_names()}")
# Filter tools
product_tools = registry.get_tools_by_tag("products")
get_tools = registry.get_tools_by_method("GET")
search_results = registry.search_tools("user")
# Get specific tool
user_tool = registry.get_tool("myapi_get_users")
# Export/Import
registry.export_json("tools.json")
registry2 = ToolRegistry.import_json("tools.json")from adapter import APIExecutor, BearerAuth, APIKeyAuth, BasicAuth
# Bearer Token
executor = APIExecutor(
base_url="https://api.example.com",
auth=BearerAuth(token="your-bearer-token")
)
# API Key (in header)
executor = APIExecutor(
base_url="https://api.example.com",
auth=APIKeyAuth(api_key="your-api-key", header_name="X-API-Key")
)
# API Key (in query)
executor = APIExecutor(
base_url="https://api.example.com",
auth=APIKeyAuth(api_key="your-api-key", location="query", param_name="apikey")
)
# Basic Auth
executor = APIExecutor(
base_url="https://api.example.com",
auth=BasicAuth(username="user", password="pass")
)from adapter.runtime import AuthHandler
class CustomAuth(AuthHandler):
def __init__(self, api_key: str, api_secret: str):
self.api_key = api_key
self.api_secret = api_secret
def apply(self, headers: dict, params: dict) -> None:
# Add custom authentication logic
import time
import hmac
import hashlib
timestamp = int(time.time() * 1000)
params["timestamp"] = str(timestamp)
# Create signature
query_string = "&".join(f"{k}={v}" for k, v in sorted(params.items()))
signature = hmac.new(
self.api_secret.encode(),
query_string.encode(),
hashlib.sha256
).hexdigest()
params["signature"] = signature
headers["X-API-KEY"] = self.api_key
# Use custom auth
executor = APIExecutor(
base_url="https://api.example.com",
auth=CustomAuth(api_key="key", api_secret="secret")
)Real-World Example: The Binance MCP implements a production-grade version of this pattern with additional features:
- Server time synchronization for timestamp accuracy
- Query string canonicalization (sorted parameter ordering)
- Optional
recvWindowparameter for clock skew tolerance - Comprehensive error messages for auth failures
Refer to its auth.py module for a complete implementation you can adapt for similar signature-based APIs.
from adapter import APIExecutor, NoAuth
# Create executor
executor = APIExecutor(
base_url="https://api.example.com",
auth=NoAuth(), # Public endpoints
timeout=30,
max_retries=3
)
# Find an endpoint
endpoint = next(ep for ep in endpoints if ep.name == "get_users")
# Execute call
result = executor.execute(endpoint, arguments={"limit": 10})
if result.success:
print(f"Status: {result.status_code}")
print(f"Data: {result.response.data}")
else:
print(f"Error: {result.error}")from adapter import MCPServer
# Option 1: With create_from_openapi (recommended)
registry = ToolRegistry.create_from_openapi("https://api.example.com/openapi.json")
executor = APIExecutor(base_url="https://api.example.com", auth=BearerAuth(token="token"))
server = MCPServer(
name="My API Server",
version="1.0.0",
tool_registry=registry, # Endpoints included automatically
executor=executor
)
# Option 2: Manual with explicit endpoints (backward compatible)
server = MCPServer(
name="My API Server",
version="1.0.0",
tool_registry=registry,
executor=executor,
endpoints=endpoints # Optional if registry has endpoints
)
# Run server (stdio transport for Claude Desktop)
server.run()Add to claude_desktop_config.json:
{
"mcpServers": {
"myapi": {
"command": "python",
"args": ["/path/to/your/server.py"]
}
}
}One of the most powerful features is automatic authentication parameter filtering. This ensures users never see or need to provide auth-related parameters.
The library uses a hybrid approach combining:
- Default common parameters:
signature,timestamp,api_key,authorization, etc. - Auto-detected from OpenAPI: Extracts from
securitySchemes - Custom overrides: You can specify your own
DEFAULT_AUTH_PARAMS = {
'signature', 'timestamp', 'recvwindow', 'recv_window',
'api_key', 'apikey', 'api_secret', 'apisecret',
'access_token', 'accesstoken', 'token',
'authorization', 'auth',
'nonce', 'sign',
}loader = OpenAPILoader()
spec = loader.load("api.yaml")
# Extract auth params from securitySchemes
auth_params = loader.extract_auth_parameters(spec)
# Returns: {'x-api-key', 'signature', ...}
# Use in tool generation
generator = ToolGenerator(
api_name="myapi",
auto_detected_auth_params=auth_params
)| Type | Auto-Detected Parameters |
|---|---|
apiKey |
Parameter name from spec |
http (bearer/basic) |
authorization |
oauth2 |
authorization, access_token, token |
openIdConnect |
authorization |
Without filtering (β Bad):
# User sees auth parameters
tool.inputSchema = {
"properties": {
"symbol": {"type": "string"},
"timestamp": {"type": "integer"}, # β Exposed
"signature": {"type": "string"} # β Exposed
}
}
# User has to provide them (confusing!)
client.call_tool("get_price", {
"symbol": "BTCUSDT",
"timestamp": 1234567890, # β User shouldn't know this
"signature": "abc123..." # β User shouldn't know this
})With filtering (β Good):
# User only sees business parameters
tool.inputSchema = {
"properties": {
"symbol": {"type": "string"} # β
Only what matters
}
}
# Clean API!
client.call_tool("get_price", {
"symbol": "BTCUSDT" # β
Simple and clear
})
# Auth handler adds timestamp and signature automaticallyOpenAPI Spec (URL/file/content)
β
OpenAPILoader β Parses and dereferences $refs
β
Normalizer β Converts to CanonicalEndpoint models
β
ToolGenerator β Creates MCP tool definitions
β
ToolRegistry β Stores tools and endpoints
β
MCPServer β Exposes tools via JSON-RPC (stdio)
β
Claude/GPT β Calls tools
β
APIExecutor β Executes actual REST API calls
β
Response β Returns to agent
For detailed architecture documentation, see ARCHITECTURE.md.
The REST-to-MCP Adapter powers production MCP servers for real APIs. These example repositories demonstrate complete implementations with different authentication patterns and specification formats.
Repository: https://github.com/pawneetdev/dataforseo-mcp/
Production MCP server for the DataForSEO API demonstrating:
- Authentication: HTTP Basic Authentication
- Spec Format: OpenAPI Actions/JSON format
- Use Case: SEO data retrieval and analysis
- What You'll Learn:
- Loading OpenAPI JSON specifications
- Implementing standard HTTP Basic auth
- Organizing tools by API categories
- Handling paginated responses
Quick Start:
git clone https://github.com/pawneetdev/dataforseo-mcp.git
cd dataforseo-mcp
pip install -e .See the repository README for complete setup instructions and Claude Desktop integration.
Repository: https://github.com/pawneetdev/binance-mcp
Production MCP server for the Binance Spot Trading API demonstrating:
- Authentication: Custom HMAC-SHA256 signature-based authentication
- Spec Format: Swagger/OpenAPI YAML format
- Use Case: Cryptocurrency trading and market data
- What You'll Learn:
- Loading Swagger YAML specifications
- Implementing custom
AuthHandlerwith cryptographic signatures - Query string signing with HMAC-SHA256
- Automatic timestamp and nonce injection
- Advanced parameter filtering for signature-based endpoints
- Handling large APIs (100+ endpoints)
Authentication Pattern:
The Binance MCP extends the AuthHandler base class to implement Binance's specific requirements:
- API key in headers (
X-MBX-APIKEY) - Timestamp query parameter (synchronized with server time)
- HMAC-SHA256 signature of query string
- Optional
recvWindowfor timing flexibility
This pattern can be adapted for other APIs with signature-based authentication (AWS, Kraken, etc.).
Quick Start:
git clone https://github.com/pawneetdev/binance-mcp.git
cd binance-mcp
pip install -e .See the repository README for API key setup, credential management, and Claude Desktop integration.
- Start with DataForSEO: Straightforward authentication, standard OpenAPI patterns
- Progress to Binance: Advanced custom authentication, complex parameter handling
- Build Your Own: Apply these patterns to your target API
Both repositories include:
- Complete source code and project structure
- Production-grade error handling
- Retry logic and timeout management
- Claude Desktop configuration examples
- Deployment documentation
# Run all tests
pytest
# With coverage
pytest --cov=adapter
# Run specific test
pytest tests/test_tool_generator.py- β OpenAPI ingestion and normalization
- β MCP tool generation
- β Runtime execution engine
- β MCP server implementation
- π Additional loaders (Postman, GraphQL)
- π WebSocket transport, enhanced caching
We welcome contributions from the community! Whether you're fixing bugs, adding features, or improving documentation, your help is appreciated.
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/your-username/rest-to-mcp-adapter.git cd rest-to-mcp-adapter - Create a branch for your changes:
git checkout -b feature/your-feature-name
- Install development dependencies:
pip install -e . pip install pytest pytest-cov black ruff - Make your changes and ensure tests pass:
pytest
- Format your code:
black . ruff check .
- Commit and push your changes:
git add . git commit -m "Description of your changes" git push origin feature/your-feature-name
- Open a Pull Request on GitHub
- Additional authentication methods (OAuth2 flows, custom schemes)
- Performance optimizations (caching, parallel processing)
- More loaders (Postman collections, GraphQL schemas, API Blueprint)
- Documentation improvements (tutorials, examples, API docs)
- Real-world usage examples (new MCP server implementations)
- Testing (edge cases, integration tests, CI/CD improvements)
- Follow existing code style and patterns
- Add tests for new features
- Update documentation as needed
- Keep changes focused and atomic
- Write clear commit messages
Found a bug or have a feature request? Please open an issue with:
- Clear description of the problem/feature
- Steps to reproduce (for bugs)
- Expected vs actual behavior
- Relevant code snippets or examples
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2025 Pawneet Singh
- Issues: GitHub Issues
- PyPI Package: rest-to-mcp-adapter
This library was developed with significant assistance from Claude (Anthropic), an AI assistant that helped with:
- Architecture design and implementation
- Code review and optimization
- Documentation and examples
- Testing and debugging
Special thanks to the AI agent and MCP communities for inspiration and feedback.
Built with β€οΈ for the AI agent ecosystem