Skip to content

StackOne

Use StackOne when an agent needs to work with one of a user’s linked business applications, such as BambooHR, Salesforce, or Zendesk. Each instance is scoped to one linked account, which is one authenticated connection between StackOne and a provider.

Source

The API may change between releases. Where practical, breaking changes ship with a deprecation warning.

Before you start

Follow the StackOne docs to:

  1. Configure a connector and link an account. For your first test, enable only the read actions you need.
  2. Copy the linked account ID from the StackOne dashboard.
  3. Create a StackOne API key that can execute actions.

You also need an API key for the model your agent uses.

Installation

Terminal
uv add "pydantic-ai-harness[stackone]" "pydantic-ai-slim[openai,spec]"

The openai and spec extras support the model and agent-spec examples below. Install the provider extra for a different model provider instead.

Set the credentials in the shell where you will run the example:

Terminal
export STACKONE_API_KEY='your-stackone-api-key'
export STACKONE_ACCOUNT_ID='your-linked-account-id'
export OPENAI_API_KEY='your-openai-api-key'

StackOne reads STACKONE_API_KEY automatically. The example reads STACKONE_ACCOUNT_ID explicitly so the account ID is not hard-coded. You can pass api_key= directly instead, but keep secrets out of source control.

Run your first agent

import os

from pydantic_ai import Agent
from pydantic_ai_harness.stackone import StackOne

agent = Agent(
    'openai:gpt-5',
    capabilities=[
        StackOne(account_id=os.environ['STACKONE_ACCOUNT_ID']),
    ],
)
result = agent.run_sync('List the first 5 employees')
print(result.output)

By default, the model receives two tools. It searches for an action that matches the request, then executes the returned action ID. The final output depends on the linked provider and its data.

Control available actions

StackOne controls which actions are enabled for the linked account. Treat that configuration as the primary access control.

Use actions when you also want to limit which tools the model sees. Patterns use Python fnmatch syntax, where * is a wildcard. They ignore case and match the full {connector}_{action}_{entity} tool name:

from pydantic_ai_harness.stackone import StackOne

StackOne(account_id='your-linked-account-id', actions=['*_list_*'])            # All matching list tools
StackOne(account_id='your-linked-account-id', actions=['workday_get_worker'])  # One exact tool

Passing actions selects individual mode automatically. Explicitly combining actions with tool_mode='search_execute' raises an error because that mode registers only the search and execute tools.

Choose a tool mode

ModeWhat the model receivesUse it when
search_executeTwo tools: search for an action, then execute it by IDThe account has many enabled actions. This is the default when actions is omitted.
individualOne tool and schema per enabled actionYou need to select exact actions or add per-tool behavior. Passing actions selects this mode.

In search_execute mode, action IDs are returned by the search tool at runtime and should not be guessed. In individual mode, all selected tool schemas are sent to the model, so filter large action sets with actions.

To keep StackOne tools out of the model context until they are needed, pass defer_loading=True. The capability uses id='stackone' by default so it can be loaded on demand. Give each instance a distinct id when one agent uses multiple StackOne accounts:

from pydantic_ai_harness.stackone import StackOne

StackOne(account_id='your-linked-account-id', defer_loading=True)

Bound large tool results

Provider actions can return large exports. Combine StackOne with the Tool Output Limits capability to reduce oversized tool returns agent-wide:

from pydantic_ai import Agent
from pydantic_ai_harness.stackone import StackOne
from pydantic_ai_harness.tool_output_limits import ToolOutputLimits

agent = Agent(
    'openai:gpt-5',
    capabilities=[
        StackOne(account_id='your-linked-account-id'),
        ToolOutputLimits(),
    ],
)

Require approval

Approval is not enabled automatically. For operations that need human confirmation, use the public StackOneToolset with Pydantic AI’s tool approval:

import os

from pydantic_ai import Agent
from pydantic_ai_harness.stackone import StackOneToolset

stackone_tools = StackOneToolset(
    account_id=os.environ['STACKONE_ACCOUNT_ID'],
    actions=['workday_create_worker'],
).approval_required()

agent = Agent('openai:gpt-5', toolsets=[stackone_tools])

Handle the resulting deferred approval requests as described in the linked guide.

Define the agent in YAML or JSON

The capability also works with Pydantic AI’s agent spec format for YAML or JSON. Keep the API key in STACKONE_API_KEY rather than storing it in the file:

# agent.yaml
model: openai:gpt-5
capabilities:
  - StackOne:
      account_id: 'your-linked-account-id'
      actions: ['*_list_*']
from pydantic_ai import Agent
from pydantic_ai_harness.stackone import StackOne

agent = Agent.from_file('agent.yaml', custom_capability_types=[StackOne])

Pass custom_capability_types so the spec loader knows how to instantiate StackOne.

Use the lower-level StackOneToolset directly when you need Agent(toolsets=[...]) or other toolset wrappers.

Custom base_url and URL-valued client values must use HTTPS. The toolset adds auth headers and appends the tool-mode query parameter for URL values when it is absent. It raises an error when the URL’s tool-mode conflicts with the configured mode because rewriting would invalidate signed URLs. When using search_execute with a signed URL, include tool-mode=search_execute before signing. Prebuilt clients are used as-is; configure their HTTPS transport, auth, account selection, and tool mode yourself.

API reference

StackOne

Bases: AbstractCapability[AgentDepsT]

Actions on the user’s SaaS account (HRIS, ATS, CRM, and more) via StackOne.

Connects an agent to one linked account’s actions over StackOne’s MCP endpoint, with authentication, tool filtering, and usage instructions.

Attributes

account_id

The linked account to act on (one account is one provider connection).

Type: str

id

Stable capability and toolset ID. Override it when one agent uses several StackOne accounts.

Type: str | None Default: _DEFAULT_ID

description

Routing description used when the capability is loaded on demand.

Type: str | None Default: _DEFAULT_DESCRIPTION

api_key

StackOne API key. Defaults to the STACKONE_API_KEY environment variable.

Type: str | None Default: field(default=None, repr=False)

base_url

HTTPS StackOne API host. Point at a regional or staging host if needed.

Type: str Default: STACKONE_BASE_URL

actions

fnmatch globs over full tool names (case-insensitive), e.g. ['*_list_*']. Giving actions switches the default tool_mode to individual, where the globs apply.

Type: str | Sequence[str] Default: ()

tool_mode

individual registers one tool per enabled action; search_execute registers two server-side meta-tools (search the catalog, execute an action by id) whose prompt footprint stays constant however large the catalog is. None picks search_execute, or individual when actions are given.

Type: ToolMode | None Default: None

include_instructions

Inject StackOne usage instructions into the system prompt.

Type: bool Default: True

metadata

Metadata merged onto every tool, available to tool-selection machinery such as CodeMode(tools={'code_mode': True}) or custom prepare_tools hooks.

Type: Mapping[str, object] | None Default: None

client

Replacement for the default {base_url}/mcp connection. URL values must use HTTPS; prebuilt clients keep their own transport, auth, and account selection, so account_id is not applied to them.

Type: MCPToolsetClient | None Default: field(default=None, repr=False)

Methods

get_toolset
def get_toolset() -> StackOneToolset[AgentDepsT]

Build the StackOne toolset.

Returns

StackOneToolset[AgentDepsT]

get_instructions
def get_instructions() -> str | None

StackOne usage guidance; the underlying MCP toolset provides none itself.

Returns

str | None

from_spec

@classmethod

def from_spec(
    cls,
    account_id: str,
    *,
    id: str | None = _DEFAULT_ID,
    description: str | None = _DEFAULT_DESCRIPTION,
    defer_loading: bool = False,
    api_key: str | None = None,
    base_url: str = STACKONE_BASE_URL,
    actions: str | Sequence[str] = (),
    tool_mode: ToolMode | None = None,
    include_instructions: bool = True,
    metadata: Mapping[str, object] | None = None,
) -> StackOne[AgentDepsT]

Construct from serializable options, excluding the runtime-only client.

Returns

StackOne[AgentDepsT]

get_serialization_name

@classmethod

def get_serialization_name(cls) -> str

Return the agent-spec capability name.

Returns

str

StackOneToolset

Bases: MCPToolset[AgentDepsT]

StackOne actions on one linked SaaS account, as an agent toolset.

An MCPToolset connected to StackOne’s MCP endpoint. URL clients receive StackOne auth and account headers. Action filtering and metadata merging apply to the tools listed by the server. Prebuilt clients keep their own transport configuration. Instances support the full MCPToolset surface.

Use the StackOne capability for usage instructions and agent-spec support. Use this class for toolset combinators such as approval_required().

Methods

__init__
def __init__(
    *,
    account_id: str,
    api_key: str | None = None,
    base_url: str = STACKONE_BASE_URL,
    actions: Sequence[str] = (),
    tool_mode: ToolMode | None = None,
    metadata: Mapping[str, object] | None = None,
    client: MCPToolsetClient | None = None,
    id: str = 'stackone',
) -> None

Build a StackOne MCP toolset.

Returns

None

Parameters

account_id : str

Linked account used for StackOne requests.

api_key : str | None Default: None

API key, or STACKONE_API_KEY when omitted.

base_url : str Default: STACKONE_BASE_URL

HTTPS StackOne API host.

actions : Sequence[str] Default: ()

Case-insensitive globs over individual action tool names. Selects individual; incompatible with explicit search_execute.

tool_mode : ToolMode | None Default: None

Individual tools or the search/execute pair. Inferred when omitted.

metadata : Mapping[str, object] | None Default: None

Metadata merged onto each tool definition.

client : MCPToolsetClient | None Default: None

URL, FastMCP, or prebuilt client accepted by MCPToolset. Non-URL clients keep their own transport, auth, and account selection, so account_id is not applied to them.

id : str Default: 'stackone'

Toolset ID; use distinct values for multiple accounts.