Tools

Tools are the capabilities agents can use. Three kinds:

  • Built-in tools: capabilities the platform provides directly (memory, task history, task setup, feedback). Never passed in tools; the configurable ones are toggled with enable_* fields. See Built-in tools.
  • 3rd-party integrations: external services like Gmail, Slack, and Google Ads, connected via OAuth.
  • Desktop tools: when sandbox execution is enabled, every run also gets computer, bash, and a file editor over a full Linux desktop, automatically. See Computer use.

The tools array below is only for 3rd-party integrations and custom tools. Passing a built-in name (e.g. "memory") returns a 422.

List available integrations

Python
from m8tes import M8tes

client = M8tes()

page = client.apps.list()
for app in page.data:
    status = "connected" if app.connected else "not connected"
    print(f"{app.name} ({app.category}): {status}")

Each app has a stable key such as google:ads or google:search_console. Use the key in app operations and tools arrays to select the exact integration. Existing provider aliases such as gmail remain supported. The catalog includes connection guidance, API-key labels, and region choices without exposing internal IDs or OAuth secrets.

Python
# List every connection in this exact scope (omit user_id for your own account).
connections = client.apps.connections.list(user_id="cust_123")
for connection in connections.data:
    print(connection.app_key, connection.status, connection.account_label)

# Provider-specific key options, such as a data region.
client.apps.connect_api_key("sentry:error_tracking", api_key="sntrys_...",
                            options={"region": "eu"})

Connections expose selected account IDs and accessible Google Ads customer IDs as explicit fields. Credential metadata is never returned. API-key connects and Composio completion accept agent_id to grant an account-scoped agent access after connecting; an end-user connection cannot use this account assignment shortcut.

Native Google connections use the same app API. Start and complete OAuth with google:ads or google:search_console, then discover and select the resource in the exact scope:

Python
customers = client.apps.list_customers("google:ads", user_id="cust_123")
client.apps.select_customer("google:ads", customers.data[0].id, user_id="cust_123")

sites = client.apps.list_sites("google:search_console", user_id="cust_123")
client.apps.select_site("google:search_console", sites.data[0].site_url, user_id="cust_123")

Slack's account setup helpers expose native V2 response shapes:

Python
workspaces = client.apps.list_workspaces("slack:messaging")
channels = client.apps.list_channels("slack:messaging")
members = client.apps.list_members("slack:messaging")

Apps with auth_type="external_oauth" use connect_external_oauth(app.key, redirect_uri=...), followed by complete_external_oauth(app.key, code=..., state=..., redirect_uri=...). This flow supports account scope only; passing user_id is rejected. Pass the m8tes /apps page as redirect_uri (for example https://www.m8tes.ai/apps); the server adds its app marker. The authenticated browser that authorized completes the connection. Arbitrary external callbacks are rejected, matching the account-consent boundary of Composio.

Assign tools to an agent

Set the base tool set when creating an agent. These tools are available on every run:

Python
bot = client.agents.create(
    name="marketing bot",
    tools=["slack", "googlesheets", "gmail"],
    instructions="Manage marketing campaigns and report on metrics",
    user_id="cust_123",
)

Override per task or per run

Tasks and runs can override the agent's tool set:

Python
task = client.tasks.create(
    agent_id=bot.id,
    instructions="Send the weekly newsletter via Slack",
    tools=["slack"],  # only Slack for this task
    user_id="cust_123",
)

run = client.runs.create(
    agent_id=bot.id,
    message="Send the weekly newsletter",
    tools=["slack"],  # only Slack for this run
    stream=False,
    user_id="cust_123",
)

The most specific level wins: run over task over agent. If a run omits tools, the task's tools apply, then the agent's.

Agents discover tool schemas as needed across model providers. Assigned integrations remain available without loading every schema into each model request; the agent searches for a tool by name and loads only that schema. Approvals apply to the individual tool being called, under its own name.

Discovery reduces the initial tool count, but a long conversation can accumulate selected schemas. If a provider rejects the count, the run fails with tool_limit_exceeded and auto_retryable=false. Repeating the same request or Continue without changing the tool set can fail again. Narrow the run's tools override where applicable; see Run errors and Detecting failures.

This cascade covers catalog tools. Custom tools attach to an agent only. A task- or run-level tools list containing a custom slug is rejected. For one agent per end-user acting on your own API, see Your API as MCP tools.

Account-level connections are made through the Developer Dashboard; OAuth flows are handled automatically, and client.apps.list() (above) shows what's connected.

End-user connections (multi-tenant OAuth)

Connect apps programmatically for your end-users. Each customer authorizes their own Gmail, Slack, etc.

1. Initiate connection

Python
conn = client.apps.connect_oauth(
    "gmail",
    redirect_uri="https://yourapp.com/callback",
    user_id="cust_123",
)
print(conn.authorization_url)  # redirect your user here; keep conn.connection_id

2. Complete connection

After the user completes OAuth and is redirected back:

Python
result = client.apps.connect_complete("gmail", connection_id=conn.connection_id, user_id="cust_123")
print(result.status)  # "connected"

3. Check status and disconnect

Python
connections = client.apps.connections.list("gmail", user_id="cust_123")
for connection in connections.data:
    print(connection.status, connection.account_label, connection.scopes)

client.apps.disconnect("gmail", user_id="cust_123")

Several accounts of one app

Connect a second Gmail inbox or Sentry organization next to the first with add_account=True. Runs get every account. The app keeps one tool set, and each of its tools takes a required connected_account argument. The agent picks an account per call, so it can read one inbox and reply from another in the same run.

Python
client.apps.connect_api_key("sentry:error_tracking", api_key="sntrys_...", add_account=True)

for c in client.apps.connections.list("sentry:error_tracking").data:
    print(c.id, c.name)  # c.name is what the agent passes as connected_account

# A label and a one-line note tell the agent which account is for what.
client.apps.connections.update(42, label="EU org", notes="EU production errors only")
client.apps.connections.delete(42)  # disconnect just this account

For OAuth apps, pass add_account=True to both connect_oauth and connect_complete. apps.disconnect(app) returns 409 when the app has several accounts, so it never disconnects the wrong one.

Isolation

  • Each end-user gets their own OAuth connection, scoped by user_id
  • Runs for that user automatically use their connected accounts
  • There is no fallback from user_id-scoped runs to account-level connections

Next: Built-in tools · Computer use · Human-in-the-loop · Users

Was this page helpful?