Agent Runtime

Tools and approvals

Besides its built-in tools, an agent can call your own tools: a toolset is one MCP server (kind: mcp) or a set of HTTP endpoints (kind: http) under one base URL. The model sees each tool as <toolset>__<tool>, for example github__create_issue.

Keys stay with orkestr

The agent's VM only knows tool names and schemas. When it calls a tool, the orkestr gateway adds the toolset's credential and makes the call server-side, then hands back the result. A credential is stored encrypted and is never shown again, not even to you.

Add a toolset

from orkestr import Toolset

docs = Toolset.create("docs", "mcp", "https://mcp.example.com/mcp")
print([t["name"] for t in docs["tools"]])   # discovered from the server

# A server that needs a key: orkestr keeps it, the agent never sees it.
github = Toolset.create(
    "github", "mcp", "https://api.githubcopilot.com/mcp/",
    auth_header_name="Authorization", auth_secret="Bearer " + token,
)

From the CLI, pass the key by the name of an environment variable, so it never appears in a terminal history or a coding assistant's chat:

bash
export GITHUB_TOKEN=...    # in your own shell
orkestr agents tools add github --url https://api.githubcopilot.com/mcp/ --auth-env GITHUB_TOKEN
orkestr agents publish my-agent --tools github

--auth-header (default Authorization) and --auth-scheme (default Bearer for that header) shape the value. For --kind http, describe the endpoints in a JSON file: --http-tools-file tools.json, a list of {name, description, method, path, input_schema}.

Toolsets are not versioned: rotating a key or turning a tool off applies to every version that uses the toolset. Which toolsets an agent may use is part of its version (toolset_ids).

Connectors (OAuth)

Many services run their own MCP server and sign you in with their own OAuth: Linear, Notion, Sentry, Atlassian and others. Add one as a toolset with auth_type: oauth and connect it once: orkestr finds the provider's sign-in, registers itself as a client, and gives you a link. You approve in your browser; orkestr keeps the tokens encrypted, refreshes them, and sends them only from its gateway. The agent's VM never sees a token.

bash
orkestr agents tools catalog
orkestr agents tools add linear --catalog linear
orkestr agents tools connect linear          # prints the link, waits for the approval
orkestr agents publish my-agent --tools linear
from orkestr import Toolset

print([c["slug"] for c in Toolset.catalog()])

linear = Toolset.create("linear", "mcp", "https://mcp.linear.app/mcp",
                        auth_type="oauth", catalog_slug="linear")
print(Toolset.connect(linear["id"]))   # a person opens this link and approves

Any other MCP server that uses OAuth works the same with --url URL --oauth. A few providers (Google, Microsoft, Slack) do not let clients register themselves: create an OAuth app there with the redirect URL https://api.orkestr.eu/api/agent-toolsets/oauth/callback and pass --client-id and --client-secret-env VAR.

If the provider stops accepting the tokens (you revoked access, or removed a scope), the toolset shows needs_reconnect and the agent gets a plain "reconnect it" tool error instead of a crash. Run connect again. orkestr agents tools disconnect NAME forgets the tokens and asks the provider to revoke them where it can.

A connector acts on a real account, so every tool its server does not mark read-only (the MCP readOnlyHint) starts as approval: always. Change that per tool below; your choice is kept when the tool list is refreshed.

Connections per end user

By default a connector has one connection, yours, and every run uses it. If your agent serves your own users and should act in their Linear or Jira, turn on oauth_per_end_user: each end user connects their own account, and a run for that end_user_id uses only theirs.

from orkestr import Toolset

# Once: each end user connects their own account.
Toolset.update(linear_id, oauth_per_end_user=True)

# In your app, when a user clicks "Connect Linear":
url = Toolset.connect(linear_id, end_user_id="cust-42",
                      return_url="https://app.example.com/settings/integrations")
# redirect the user to url

Toolset.connections(linear_id)                    # who is connected ("-" = you)
Toolset.disconnect_end_user(linear_id, "cust-42")

Your app asks for a link with the user's end_user_id and sends them to it. After they approve, they land on your return_url (https) with ?orkestr_connected=1, or ?orkestr_error=... if they declined. Without a return_url they see a short "connected, you can close this tab" page. From the CLI: orkestr agents tools connect linear --end-user cust-42.

Never your account
In this mode a run for an end user who has not connected never falls back to your connection: the tool tells the agent the user has not connected yet, so it can ask them to. Runs without an end user (your own tests) use your connection. Erasing an end user also deletes their connected accounts.

Turn tools off, or require approval

bash
orkestr agents tools set github create_issue --approval always
orkestr agents tools set github delete_repo --disable
orkestr agents tools refresh github          # re-read the MCP server's tool list

Over the API this is the toolset's tool_overrides: {"create_issue": {"enabled": true, "approval": "always"}}.

Approving a call

When the model calls a tool marked approval: always, the run pauses: an invoke returns status: pending_approval with the tool and its arguments, and a stream ends with run.paused. Approve or deny from your app, the API, or the console (the agent page, and the workspace's "Waiting for you"). On approval orkestr makes the call and the run continues where it stopped. Approvals expire after 24 hours by default.

from orkestr import AgentRun

result = agent.invoke("Open an issue for the login bug")
if result.status == "pending_approval":
    print(result.approval.tool, result.approval.arguments)
    AgentRun.get(result.run_id).approve()      # or .deny()
Tokens
Deciding needs agents:invoke; managing toolsets needs agents:write.
Reading with an agent? This page is also plain markdown at /docs/agents/tools.md, and the full docs index lives at /docs/llms.txt.