Skip to main content

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

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.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Supported by

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