Toolkit

Toolkits: your connections' operations, the operations that need no account, and capabilities as LLM tools.

gmail = noclick.Connection.from_name("gmail", integration="gmail", create_if_missing=True)
toolkit = noclick.Toolkit(["search", gmail])
response = anthropic.messages.create(..., tools=toolkit.definitions())
messages.append({"role": "user", "content": toolkit.handle(response)})

A call never raises for something the model can act on: a missing connection, a policy refusal or a hold for approval comes back as an is_error result. A hold's approval_required (approval_id, request_id, approve_url, operation, approver) is never shown to the model; pass on_approval= to the handle helpers to receive it, and on_connect= to receive each result that needs a connection. request_id (the request a person answers), approve_url and operation (the approval's operation object) are None unless the request is addressed to you; the approver is emailed either way. Once the person approves, the identical call goes through.

class Toolkit

A set of tools for your LLM. Entries are connections (a Connection or its name: every operation, as {connection}__{operation} tools), single operations ("gmail.send_email_message"), capabilities ("search", "fetch", "code") or a Database ({database}__query, __execute and __schema; invite-only beta), a Bucket and operations with arguments bound (gmail.only("send_email_message").bind({ to }): the bound parameters leave the tool's schema and are filled on every call, so a toolkit sends its entries with each call). A Connection object from another scope, another user's or the account's, stays that connection (invite-only beta). A name resolves for the user the calls act for (user if given, else the user current at each call, asUser), so one module-level toolkit serves every user: a connection there, else an integration's operations that need no account (on NoClick's key), so "exa.search" needs no connection.

Attributes
refsToolRef[]

What was passed: names, "name.operation" strings and Connection objects.

simulatedboolean

Whether a simulated world answers every call instead of the real accounts: the definitions are the real ones, nothing is read or sent, and each answer is billed as AI at NoClick's model price.

scenariostring | null

What that world is like; its answers keep to it.

toolsstring[]

The refs as names (a Connection known only by id shows its id until used).

mcpServer

mcpServer(name: string): McpServer

These tools as a hosted MCP server called name, in the toolkit's user (McpServer.fromName with createIfMissing). Sends nothing yet.

Parameters
namestringrequired
Returns

The server, created on first use (or brought in step with this toolkit's tools); its url is what you give an MCP client.

definitions

definitions(
  options?: { format?: ToolFormat; user?: UserOption },
): Promise<JsonObject[]>

Tool definitions to pass straight to your LLM API. Cached per format.

Parameters
options.userUserOption

Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).

(defaults to the current user)
options.formatToolFormatdefault "anthropic"
Returns

The tool definitions in that API's shape, ready to pass as tools. The first call for a format fetches them; later calls reuse them.

call

call(
  name: string,
  args?: JsonObject,
  options?: { approvalId?: string; user?: UserOption },
): Promise<ToolResult>

Run one tool by its wire name (gmail__send_email_message, search). A policy refusal or a hold is an isError result, never a throw; a held call goes through once approved when it is repeated with the same arguments (approvalId names the approval explicitly).

Parameters
namestringrequired
argsJsonObject
options.approvalIdstring
options.userUserOption

Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).

(defaults to the current user)
Returns

The tool's content (text as one string) and whether it is_error. A call that couldn't run says why in content, with needs_connection or approval_required set when that's the reason.

handle

handle(
  content: unknown,
  options?: HandleOptions,
): Promise<AnthropicToolResultBlock[]>

Run every Anthropic tool_use block (from a Message, its content list, or plain objects) concurrently and return the tool_result blocks for the next user turn. onApproval receives each call held for approval, and onConnect each one whose needsConnection is set, so your app can show the user the connect link itself. Each result carries the model's callId and the arguments.

Its older name handleAnthropic still works, deprecated.

Parameters
contentunknownrequired
options.userUserOption

Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).

(defaults to the current user)
options.onApprovalOnApproval
options.onConnectOnConnect
Returns

One tool_result block per tool_use, in order: the content of the next user turn.

handleOpenAI

handleOpenAI(
  toolCalls: unknown,
  options?: HandleOptions,
): Promise<OpenAIToolOutput[]>

Run OpenAI tool calls (a ChatCompletion, its message, a tool_calls list, or Responses function_call items) and return { role: "tool" } messages (or function_call_output items). onApproval and onConnect work as in handle.

Parameters
toolCallsunknownrequired
options.userUserOption

Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).

(defaults to the current user)
options.onApprovalOnApproval
options.onConnectOnConnect
Returns

One {"role": "tool"} message per call, in order, or a function_call_output item for each Responses call. A call whose arguments aren't valid JSON isn't run; its message tells the model so.

ToolResult

interface ToolResult

The outcome of one tool call. An unconnected account is a normal result with needsConnection.

Attributes
namestring
contentunknown
isErrorboolean
needsConnectionNeedsConnectionInfo | null
rawJsonObject

The response JSON exactly as the API sent it.

approvalRequiredApprovalRequiredInfo | null
argumentsJsonObject

The arguments the call was made with, as the model gave them.

callIdstring | null

The model's id for the call when it came through handle or handleOpenAI; null from call.

connectUrlstring | null
approvalHumanRequest<boolean> | null

The approval a held call waits on, as a request: wait() resolves to true once approved. Null unless the call was held and the request is addressed to you.

approveUrlstring | null

The approval link, when the call waits for your approval; once approved, repeat the identical call.

textstring

The content as one string (what an OpenAI tool message carries).