Skip to main content

Initialise the ToolSet

Start by creating a StackOneToolSet instance. The SDK automatically reads STACKONE_API_KEY, so you typically only provide fallback account IDs or custom HTTP settings:
from stackone_ai import StackOneToolSet

toolset = StackOneToolSet()
account_id = "your-customer-account-id"

Fetch Tools

Use fetch_tools() to dynamically load tools from StackOne’s MCP endpoint with glob patterns:
# Get all BambooHR tools
bamboohr_tools = toolset.fetch_tools(actions=['bamboohr_*'], account_ids=[account_id])

# Get all HiBob tools
hibob_tools = toolset.fetch_tools(actions=['hibob_*'], account_ids=[account_id])

# Get specific list operations
list_tools = toolset.fetch_tools(actions=['*_list_*'], account_ids=[account_id])

Execute Tools

Basic Tool Execution

# Fetch tools for your account
tools = toolset.fetch_tools(actions=['bamboohr_*'], account_ids=[account_id])
employee_tool = tools.get_tool('bamboohr_list_employees')

# Execute with keyword arguments via call()
employees = employee_tool.call(limit=10, include_details=True)
print(employees.data)

Alternative Execution Methods

# Method 1: call() with keyword arguments (recommended)
result = employee_tool.call(id="employee-123", include_details=True)

# Method 2: execute() with dictionary payloads
result = employee_tool.execute({"id": "employee-123", "include_details": True})

# Method 3: execute() with OpenAI-style arguments
payload = {"arguments": {"id": "employee-123"}}
result = employee_tool.execute(payload)

# Convert back to native dataclasses or dicts as needed
print(result.data)

Attaching Session Context to Calls

Both execution styles accept an optional options keyword to pass metadata that is not forwarded to the StackOne API. The Python SDK uses this information to power telemetry features such as LangSmith implicit feedback streams:
employee_tool.call(
    id="employee-123",
    options={
        "feedback_session_id": "chat-42",
        "feedback_user_id": "user-123",
        "feedback_metadata": {"conversation_id": "abc"},
    },
)

Error Handling

from stackone_ai.exceptions import StackOneError, ToolExecutionError

try:
    result = employee_tool.call(id="employee-123")
    print("Success:", result)
except ToolExecutionError as e:
    print(f"Tool execution failed: {e.message}")
except StackOneError as e:
    print(f"StackOne API error: {e.message}")
except Exception as e:
    print(f"Unexpected error: {e}")

Tool Filtering

Advanced Filtering Patterns

# Filter by providers
all_tools = toolset.fetch_tools(providers=['hibob', 'bamboohr'], account_ids=[account_id])

# Get only read operations
read_only_tools = toolset.fetch_tools(actions=['*_list_*', '*_get_*'], account_ids=[account_id])

# Combine multiple filters
filtered_tools = toolset.fetch_tools(
    providers=['hibob'],
    actions=['*_list_*'],
    account_ids=[account_id]
)

List Available Tools

# Get all available tools
tools = toolset.fetch_tools(account_ids=[account_id])

# List tool names
tool_names = tools.list_tools()
print('Available tools:', tool_names)

# Get specific tool
tool = tools.get_tool('bamboohr_list_employees')
print('Tool:', tool)

Working with Results

Processing Tool Results

employees = employee_tool.call(limit=50)

# Process the results
for employee in employees.data:
    print(f"{employee.first_name} {employee.last_name} - {employee.email}")

# Check pagination
if employees.next:
    print('More results available')

Handling Different Data Types

# List operations return arrays
departments = dept_tool.call()
print(f"Found {len(departments.data)} departments")

# Get operations return single objects
employee = employee_tool.call(id='emp_123')
print(f"Employee: {employee.data.display_name}")

Environment Configuration

Using Environment Variables

import os
from stackone_ai import StackOneToolSet

# Set in your .env file
# STACKONE_API_KEY=your_api_key
# STACKONE_ACCOUNT_ID=your_account_id

toolset = StackOneToolSet(
    api_key=os.getenv('STACKONE_API_KEY')
)

# Use environment account ID as default
account_id = os.getenv('STACKONE_ACCOUNT_ID') or 'fallback-account-id'

Using python-dotenv

from dotenv import load_dotenv
import os

# Load environment variables from .env file
load_dotenv()

from stackone_ai import StackOneToolSet

toolset = StackOneToolSet(
    api_key=os.getenv('STACKONE_API_KEY')
)

Dynamic Account Handling

# Handle multiple customer accounts
customer_accounts = ['account-1', 'account-2', 'account-3']

for account_id in customer_accounts:
    tools = toolset.fetch_tools(actions=['bamboohr_list_employees'], account_ids=[account_id])
    employee_tool = tools.get_tool('bamboohr_list_employees')
    if employee_tool:
        employees = employee_tool.call()
        print(f"Account {account_id}: {len(employees.data)} employees")

Meta Tools

Use meta tools to discover and execute StackOne tools dynamically via natural language search:
tools = toolset.fetch_tools(account_ids=[account_id])
meta_tools = tools.meta_tools()

search = meta_tools.get_tool('meta_search_tools')
results = search.call(query='manage employees create update list', limit=5, minScore=0.3)

if results.get('tools'):
    execute = meta_tools.get_tool('meta_execute_tool')
    output = execute.call(
        tool_name=results['tools'][0]['name'],
        params={'limit': 10}
    )
    print(output)
Meta tools work with LangChain, CrewAI, and OpenAI out of the box—see /agents/python/meta-tools for adapters and best practices.

Example

examples/index.py
View on GitHub →

Implicit Feedback

The SDK can emit implicit behavioural signals to LangSmith whenever a tool is executed. Provide a LangSmith API key and optional overrides via environment variables:
LANGSMITH_API_KEY=your_langsmith_key
STACKONE_IMPLICIT_FEEDBACK_ENABLED=true  # defaults to true when an API key exists
STACKONE_IMPLICIT_FEEDBACK_PROJECT=stackone-agents
STACKONE_IMPLICIT_FEEDBACK_TAGS=python-sdk,stackone
For full control, configure the feedback manager in code:
from stackone_ai import configure_implicit_feedback

configure_implicit_feedback(
    project_name='stackone-agents',
    default_tags=['python-sdk'],
    session_resolver=lambda: 'chat-42',
    user_resolver=lambda: 'user-123',
)
The callbacks give you a chance to derive identifiers from your chat state before telemetry is sent. When the same session triggers two tool calls in quick succession, the SDK emits a refinement_needed event so you can diagnose loops or poor results inside LangSmith.

Next Steps