Skip to main content

Python client for the ToolRouter API

Project description

ToolRouter Python SDK

A comprehensive Python client for the ToolRouter API supporting both direct access and account-level operations with full async support and type safety.

โœจ ToolRouter Key Features

๐Ÿš€ Instant Integration - Deploy Model Control Panels (MCPs) in seconds and seamlessly integrate with your AI agents

๐Ÿ” Authentication Made Simple - Built-in credential management with secure authentication handling, no manual setup needed

๐Ÿ”„ Flexible Tool Composition - Mix and match tools across different MCPs to create powerful custom workflows

๐Ÿค– Universal Model Support - Compatible with OpenAI, Anthropic, Meta Llama, and all major AI models

๐Ÿ› ๏ธ Extensive Tool Library - Access to 450+ production-ready tools across 40+ MCPs, with bi-weekly updates

๐Ÿ’ช Enterprise-Grade Reliability - Production-tested infrastructure trusted by numerous companies, with continuous improvements

๐Ÿš€ SDK Features

  • Two Client Types: DirectAccessClient for MCP-style tool calling, APIClient for full account management
  • Full Async Support: Built with httpx for modern async/await patterns
  • Type Safety: Complete Pydantic models for all API responses
  • Error Handling: Custom exceptions for different error types
  • Rate Limiting: Built-in client-side rate limiting
  • Retry Logic: Automatic retry with exponential backoff
  • Schema Support: OpenAI, Anthropic, and default schema formats
  • Backward Compatibility: Maintains compatibility with existing code
  • Production Ready: Comprehensive error handling, logging, and testing

๐Ÿ“ฆ Installation

pip install toolrouter

๐Ÿƒ Quick Start

Direct Access (MCP-style)

import asyncio
from toolrouter import DirectAccessClient

async def main():
    async with DirectAccessClient(
        client_id="your-client-id",
        api_key="your-api-key",
        schema="openai"  # or "anthropic", "default"
    ) as client:
        
        # List available tools
        tools = await client.list_tools()
        print(f"Available: {len(tools)} tools")
        
        # Call a tool
        if tools:
            result = await client.call_tool(
                tool_name=tools[0]['name'],
                tool_input={"location": "San Francisco"}
            )
            print(f"Result: {result}")

asyncio.run(main())

Account Management

import asyncio
from toolrouter import APIClient

async def main():
    async with APIClient(
        api_key="your-account-api-key",
        schema="openai"
    ) as client:
        
        # Create a stack with server
        stack = await client.create_stack_with_server(
            stack_name="my-ai-stack",
            server_id="github-server",
            enable_all_tools=True,
            credentials={"token": "ghp_your_token"}
        )
        
        # List tools in the stack
        tools = await client.list_stack_tools(stack.stack_id)
        print(f"Stack has {len(tools)} tools available")
        
        # Invoke a tool
        result = await client.invoke_tool(
            stack_id=stack.stack_id,
            tool_id="create_issue",
            tool_input={"title": "Bug report", "body": "Description"}
        )
        print(f"Tool result: {result}")

asyncio.run(main())

๐Ÿ“š API Documentation

Available Methods

DirectAccessClient (MCP-Style)

Method Description Parameters Returns
list_tools() Get available tools from ToolRouter schema: Optional[str] List[Union[Tool, Dict[str, Any]]]
call_tool() Call a tool using ToolRouter tool_name: str, tool_input: Dict[str, Any] Dict[str, Any]

APIClient (Account Level API)

Stack Management
Method Description Parameters Returns
list_stacks() List all stacks None List[Stack]
create_stack() Create a new stack stack_name: str, analytics_enabled: bool = False Stack
update_stack() Update an existing stack stack_id: str, stack_name: Optional[str] = None, analytics_enabled: Optional[bool] = None Stack
delete_stack() Delete a stack stack_id: str bool
Server Management
Method Description Parameters Returns
list_servers() List all available servers None List[Server]
add_server_to_stack() Add a server to a stack stack_id: str, server_id: str, enable_all_tools: bool = False, enabled_tools: Optional[List[str]] = None bool
remove_server_from_stack() Remove a server from a stack stack_id: str, server_id: str bool
update_server_tools() Update enabled tools for a server stack_id: str, server_id: str, enabled_tools: List[str] bool
Credential Management
Method Description Parameters Returns
get_credentials_status() Get credentials status for a server stack_id: str, server_id: str CredentialsStatus
update_credentials() Update credentials for a server stack_id: str, server_id: str, credentials: Dict[str, str] bool
Tool Operations
Method Description Parameters Returns
list_stack_tools() List tools available in a stack stack_id: str, schema: Optional[str] = None List[Union[Tool, Dict[str, Any]]]
invoke_tool() Invoke a tool in a stack stack_id: str, tool_id: str, tool_input: Dict[str, Any] Dict[str, Any]
Convenience Methods
Method Description Parameters Returns
create_stack_with_server() Create stack and add server in one call stack_name: str, server_id: str, enable_all_tools: bool = True, analytics_enabled: bool = False, credentials: Optional[Dict[str, str]] = None Stack
get_stack_summary() Get comprehensive stack summary stack_id: str Dict[str, Any]

Backward Compatibility Functions

Function Description Parameters Returns
setup_default_router() Configure the default direct access client client_id: str, api_key: str, base_url: str = "https://api.toolrouter.ai/s", **kwargs DirectAccessClient
list_tools() Sync wrapper for list_tools (uses default client) schema: str = "openai" List[Union[Tool, Dict[str, Any]]]
call_tool() Sync wrapper for call_tool (uses default client) tool_name: str, tool_input: Dict[str, Any] Dict[str, Any]

Usage Examples

DirectAccessClient

For MCP-style direct tool access:

from toolrouter import DirectAccessClient

client = DirectAccessClient(
    client_id="your-client-id",
    api_key="your-api-key",
    base_url="https://api.toolrouter.ai/s",  # optional
    schema="openai",  # or "anthropic", "default"
    timeout=30.0,
    max_retries=3,
    rate_limit_requests=60,
    rate_limit_window=60
)

# List tools
tools = await client.list_tools(schema="openai")

# Call tool
result = await client.call_tool("tool_name", {"param": "value"})

APIClient

For full account and stack management:

from toolrouter import APIClient

client = APIClient(
    api_key="your-account-api-key",
    base_url="https://api.toolrouter.ai/v1",  # optional
    schema="openai",
    timeout=30.0,
    max_retries=3
)

# Stack operations
stacks = await client.list_stacks()
stack = await client.create_stack("My Stack", analytics_enabled=True)
await client.update_stack(stack.stack_id, stack_name="Updated Name")
await client.delete_stack(stack.stack_id)

# Server operations
servers = await client.list_servers()
await client.add_server_to_stack(stack_id, server_id, enable_all_tools=True)
await client.remove_server_from_stack(stack_id, server_id)
await client.update_server_tools(stack_id, server_id, ["tool1", "tool2"])

# Credential management
status = await client.get_credentials_status(stack_id, server_id)
await client.update_credentials(stack_id, server_id, {"api_key": "secret"})

# Tool operations
tools = await client.list_stack_tools(stack_id, schema="openai")
result = await client.invoke_tool(stack_id, tool_id, {"param": "value"})

# Convenience methods
stack = await client.create_stack_with_server(
    "Stack Name", "server-id", 
    enable_all_tools=True,
    credentials={"token": "secret"}
)
summary = await client.get_stack_summary(stack_id)

๐Ÿ”ง Configuration

Environment Variables

export TOOLROUTER_CLIENT_ID="your-client-id"
export TOOLROUTER_API_KEY="your-api-key"
export TOOLROUTER_ACCOUNT_API_KEY="your-account-api-key"

Client Configuration

# Custom configuration
client = DirectAccessClient(
    client_id="your-client-id",
    api_key="your-api-key",
    timeout=60.0,           # Request timeout
    max_retries=5,          # Retry attempts
    rate_limit_requests=100, # Requests per window
    rate_limit_window=60     # Window in seconds
)

๐Ÿšจ Error Handling

The SDK provides specific exception types:

from toolrouter import (
    ToolRouterError,        # Base exception
    AuthenticationError,    # Invalid credentials
    NotFoundError,         # Resource not found
    ValidationError,       # Invalid request
    ServerError,          # Server-side error
    RateLimitError        # Rate limit exceeded
)

try:
    result = await client.call_tool("tool_name", {})
except AuthenticationError:
    print("Check your API key")
except NotFoundError:
    print("Tool or resource not found")
except RateLimitError:
    print("Rate limit exceeded, slow down")
except ToolRouterError as e:
    print(f"General error: {e.message} (Status: {e.status_code})")

๐Ÿ”„ Backward Compatibility

Existing code continues to work:

# Old synchronous API still works
from toolrouter import ToolRouter, setup_default_router, list_tools, call_tool

setup_default_router("client-id", "api-key")
tools = list_tools(schema="openai")
result = call_tool("tool_name", {"param": "value"})

# ToolRouter class is now an alias for DirectAccessClient
client = ToolRouter("client-id", "api-key")  # Same as DirectAccessClient

๐Ÿ—๏ธ Architecture

toolrouter/
โ”œโ”€โ”€ client.py              # Main SDK implementation
โ”‚   โ”œโ”€โ”€ BaseClient         # Shared functionality
โ”‚   โ”œโ”€โ”€ DirectAccessClient # MCP-style tool calling
โ”‚   โ”œโ”€โ”€ APIClient         # Account management
โ”‚   โ”œโ”€โ”€ Exception classes # Custom error types
โ”‚   โ””โ”€โ”€ Pydantic models   # Type safety
โ”œโ”€โ”€ __init__.py           # Public API exports
โ”œโ”€โ”€ examples.py           # Comprehensive examples
โ””โ”€โ”€ tests/                # Test suite
    โ””โ”€โ”€ test_toolrouter.py

๐Ÿงช Development

Running Tests

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest tests/

# Run with coverage
pytest tests/ --cov=toolrouter

Code Quality

# Format code
black toolrouter/

# Sort imports
isort toolrouter/

# Lint
flake8 toolrouter/

๐Ÿ“‹ Examples

Check out examples.py for comprehensive usage examples including:

  • Basic DirectAccessClient usage
  • Complete APIClient workflows
  • Credential management
  • Error handling patterns
  • Convenience methods
  • Backward compatibility

๐Ÿ“ Changelog

v0.2.0

  • โœจ Added APIClient for account-level operations
  • โœจ Full async support with httpx
  • โœจ Type safety with Pydantic models
  • โœจ Custom exception hierarchy
  • โœจ Built-in rate limiting and retries
  • โœจ Support for multiple schema formats
  • โœจ Convenience methods for common workflows
  • ๐Ÿ”„ Maintained backward compatibility

v0.1.0

  • ๐ŸŽ‰ Initial release with DirectAccessClient

๐Ÿ“„ License

Apache 2.0 License - see LICENSE file for details.

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

๐Ÿ“ž Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

toolrouter-0.2.0.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

toolrouter-0.2.0-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

Details for the file toolrouter-0.2.0.tar.gz.

File metadata

  • Download URL: toolrouter-0.2.0.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.0b2

File hashes

Hashes for toolrouter-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7d9ed00b1a7679b4b4930a79b102c1bce7bd76488fac7eae4a6f65884cc44b98
MD5 3801ffeebb5d85beba6f0ca0f5e429b5
BLAKE2b-256 462ef4a36c0addc43e98525ceeb1ba653500de6cc807da93fcd822c2cb98582c

See more details on using hashes here.

File details

Details for the file toolrouter-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: toolrouter-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 15.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.0b2

File hashes

Hashes for toolrouter-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 45b0fb61bcc93ca9f88a54f4ceee52348cf4bf9150d927f67a87629f4a6b3935
MD5 754ff86398ef7dd6a0dd298f0ccd1bbd
BLAKE2b-256 06f43b51ca4bc73b0a0b914f15b38c544a2aac369341a0c10cf9e88a382bd5da

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page