OpenClaw Tool Executor
General-purpose tool executor for OpenClaw agents. Uses Scalekit Connect to discover and run tools for any connected service — OAuth (Notion, Slack, Gmail, GitHub, etc.) or non-OAuth (API Key, Bearer, Basic auth).
Environment Variables
Required in .env:
CODEBLOCK0
INLINECODE1 is used as the default --identifier for all operations. If not set, the script will prompt the user at runtime and display a warning advising them to set it in .env.
Execution Flow
When the user asks to perform an action on a connected service, follow these steps in order:
Step 1 — Discover the Connection
Dynamically resolve the connection_name by listing all configured connections for the provider. The API paginates automatically through all pages:
CODEBLOCK1
- - Only consider connections with
"status": "COMPLETED" — ignore any with DRAFT, PENDING, or other non-completed statuses. - Use the
key_id from the first COMPLETED result as <CONNECTION_NAME> for all subsequent steps. - If no connection found → inform the user that no
<PROVIDER> connection is configured in Scalekit and stop. - If connections exist but none are COMPLETED → inform the user of the connection
key_id(s) found and tell them the connection configuration is not completed. Ask them to complete setup in the Scalekit Dashboard and stop. - If multiple COMPLETED connections found → the first one is selected automatically (a warning is shown).
Step 2 — Check & Authorize
Run --generate-link for the connection. The tool automatically detects the connection type (OAuth vs non-OAuth) and applies the correct auth flow:
CODEBLOCK2
OAuth connections:
- - If already ACTIVE → proceed to Step 3.
- If not active → a magic link is generated. Present it to the user, wait for them to complete the flow, then proceed to Step 3.
Non-OAuth connections (BEARER, BASIC, API Key, etc.):
- - If account not found → stop. Tell the user: "Please create and configure the
<CONNECTION_NAME> connection in the Scalekit Dashboard." - If account exists but not active → stop. Tell the user: "Please activate the
<CONNECTION_NAME> connection in the Scalekit Dashboard." - If ACTIVE → proceed to Step 3.
Never use --get-authorization in the execution flow — that is only for inspecting raw OAuth tokens and does not work for non-OAuth connections.
Step 3 — Discover Available Tools
Fetch the list of tools available for the provider:
CODEBLOCK3
- - Look for a tool that matches the user's intent (e.g.
notion_page_get for reading a page). - If a matching tool exists → go to Step 3b.
- If no matching tool exists → go to Step 5 (proxy fallback).
Step 3b — Fetch Tool Schema (mandatory before executing)
Always fetch the schema of the matched tool before constructing the input. This tells you the exact parameter names, types, required vs optional fields, and valid enum values:
CODEBLOCK4
- - Read the
input_schema.properties from the response — use only the parameter names defined there. - Note which fields are in
required — these must always be included in --tool-input. - Use
description and display_properties to understand what each field expects. - Never guess parameter names — always derive them from the schema.
Step 4 — Execute the Tool
Construct the tool input using only parameters from the schema fetched in Step 3b, then run:
CODEBLOCK5
Return the result to the user.
Step 5 — Proxy Fallback (only if no tool exists)
If no Scalekit tool covers the required action, attempt a proxied HTTP request directly to the provider's API:
CODEBLOCK6
Note: Proxy may be disabled on some environments. If it returns TOOL_PROXY_DISABLED, inform the user that this action isn't supported by the current Scalekit tool catalog and suggest they request a new tool from Scalekit.
Example: Search LinkedIn (via HarvestAPI)
CODEBLOCK7
- 1.
--list-connections --provider HARVESTAPI → key_id: harvestapi-xxxx, INLINECODE25 - INLINECODE26 → detects API_KEY, checks account → ACTIVE
- INLINECODE27 → finds INLINECODE28
3b.
--get-tool --tool-name harvestapi_search_people → schema shows valid params:
first_names,
last_names,
search,
locations,
current_job_titles, etc.
- 4. INLINECODE35
→ returns matching LinkedIn profiles
Any LinkedIn-related request (profiles, jobs, companies, posts, people search, ads, groups) → use provider HARVESTAPI.
Example: Search the web with Exa (API Key connection)
CODEBLOCK8
- 1.
--list-connections --provider EXA → key_id: exa, INLINECODE39 - INLINECODE40 → detects API_KEY, checks account → ACTIVE
- INLINECODE41 → finds INLINECODE42
3b.
--get-tool --tool-name exa_search → schema shows
query (required),
num_results,
type, etc.
- 4. INLINECODE47
→ returns search results
Example: Read a Notion Page (OAuth connection)
CODEBLOCK9
- 1.
--list-connections --provider NOTION → key_id: notion-ijIQedmJ, INLINECODE50 - INLINECODE51 → detects OAuth, already ACTIVE
- INLINECODE52 → finds INLINECODE53
3b.
--get-tool --tool-name notion_page_get → schema shows
page_id (required)
- 4. INLINECODE56
→ returns page metadata
Example: Action Not Yet in Scalekit
CODEBLOCK10
- 1.
--list-connections --provider NOTION → INLINECODE58 - INLINECODE59 → ACTIVE
- INLINECODE60 → no
notion_blocks_fetch tool found - INLINECODE62 → fallback attempt
- If proxy disabled → inform user the action isn't available yet
File Uploads & Downloads
Some providers do not have Scalekit tools for file operations. Use --proxy-request with --input-file (upload) or direct S3/CDN URL download (download). Provider-specific flows are documented below.
⚠️ Proxy token expiry: --proxy-request passes the stored OAuth access token directly to the provider. If the token has expired, the provider will return 401 Unauthorized. Unlike --execute-tool which auto-refreshes tokens, the proxy does not. If you get a 401, the token needs to be refreshed — re-run --generate-link to check status; if the connection is ACTIVE but proxy still returns 401, the user must re-authorize via a new magic link to obtain a fresh token.
Notion
Upload a File to a Notion Page
Notion file uploads are a 3-step process via proxy:
Step 1 — Create an upload object
CODEBLOCK11
Returns a file_upload object with an id and upload_url. The upload is valid for 1 hour.
Step 2 — Send the file
CODEBLOCK12
- - The file is sent as
multipart/form-data. On success, status becomes uploaded. - ⚠️ Notion rejects
application/octet-stream. If the file extension is not recognized (e.g. .md), copy it to a .txt extension first so the MIME type resolves to text/plain.
Step 3 — Attach the file block to a page
CODEBLOCK13
Do not use notion_page_content_append for file blocks — it does not support the file_upload block type and will return an INTERNAL_ERROR. Always use the proxy for file attachment.
Download a File from a Notion Page
Notion files are stored on S3 with pre-signed URLs that expire in 1 hour. The download is a 2-step process:
Step 1 — Get a fresh pre-signed URL
List the page blocks to find the file block and its current URL:
CODEBLOCK14
Find the block with "type": "file" — the URL is at file.file.url. Always fetch a fresh URL; never reuse a URL from a previous response as it may be expired.
Step 2 — Download directly from S3
The S3 URL is public (pre-signed) — no Scalekit proxy needed. Download it directly:
CODEBLOCK15
Or use --output-file if going through the proxy:
CODEBLOCK16
Note: --output-file saves the raw API response (JSON block object), not the file itself. Use direct S3 download for the actual file content.
Google Drive
Coming soon
OneDrive / SharePoint
Coming soon
Supported Providers
Any provider configured in Scalekit (Notion, Slack, Gmail, Google Sheets, GitHub, Salesforce, HubSpot, Linear, and 50+ more). Use the provider name in uppercase for --provider (e.g. NOTION, SLACK, GOOGLE).
OpenClaw 工具执行器
用于OpenClaw智能体的通用工具执行器。使用Scalekit Connect来发现并运行任何已连接服务的工具——包括OAuth(Notion、Slack、Gmail、GitHub等)和非OAuth(API密钥、Bearer令牌、基本认证)服务。
环境变量
需要在.env中配置:
TOOLCLIENTID=clientid>
TOOLCLIENTSECRET=clientsecret>
TOOLENVURL=environmenturl>
TOOLIDENTIFIER=identifier> # 可选但建议配置
TOOL_IDENTIFIER用作所有操作的默认--identifier。如果未设置,脚本会在运行时提示用户,并显示警告建议在.env中配置。
执行流程
当用户要求在已连接服务上执行操作时,请按顺序执行以下步骤:
步骤1 — 发现连接
通过列出提供商的所有已配置连接来动态解析connection_name。API会自动分页遍历所有页面:
bash
uv run tool_exec.py --list-connections --provider
- - 仅考虑status: COMPLETED的连接——忽略任何DRAFT、PENDING或其他未完成状态的连接。
- 使用第一个COMPLETED结果的keyid作为所有后续步骤的NAME>。
- 如果未找到连接 → 告知用户在Scalekit中未配置连接并停止。
- 如果存在连接但均未COMPLETED → 告知用户找到的连接key_id,并说明连接配置未完成。要求用户在Scalekit Dashboard中完成设置并停止。
- 如果找到多个COMPLETED连接 → 自动选择第一个(会显示警告)。
步骤2 — 检查与授权
为连接运行--generate-link。工具会自动检测连接类型(OAuth与非OAuth)并应用正确的认证流程:
bash
uv run tool_exec.py --generate-link \
--connection-name
OAuth连接:
- - 如果已ACTIVE → 进入步骤3。
- 如果未激活 → 生成魔法链接。呈现给用户,等待他们完成流程,然后进入步骤3。
非OAuth连接(BEARER、BASIC、API密钥等):
- - 如果未找到账户 → 停止。告知用户:请在Scalekit Dashboard中创建并配置NAME>连接。
- 如果账户存在但未激活 → 停止。告知用户:请在Scalekit Dashboard中激活NAME>连接。
- 如果ACTIVE → 进入步骤3。
切勿在执行流程中使用--get-authorization——该命令仅用于检查原始OAuth令牌,不适用于非OAuth连接。
步骤3 — 发现可用工具
获取提供商可用的工具列表:
bash
uv run tool_exec.py --get-tool --provider
- - 查找与用户意图匹配的工具(例如读取页面的notionpageget)。
- 如果存在匹配工具 → 进入步骤3b。
- 如果不存在匹配工具 → 进入步骤5(代理回退)。
步骤3b — 获取工具模式(执行前必须执行)
在构建输入之前始终获取匹配工具的模式。这将告知您确切的参数名称、类型、必填与可选字段以及有效的枚举值:
bash
uv run toolexec.py --get-tool --tool-name NAME>
- - 读取响应中的inputschema.properties——仅使用其中定义的参数名称。
- 注意required中的字段——这些字段必须始终包含在--tool-input中。
- 使用description和displayproperties来理解每个字段的预期内容。
- 切勿猜测参数名称——始终从模式中获取。
步骤4 — 执行工具
仅使用步骤3b中获取的模式中的参数构建工具输入,然后运行:
bash
uv run tool_exec.py --execute-tool \
--tool-name \
--connection-name \
--tool-input
将结果返回给用户。
步骤5 — 代理回退(仅当没有工具时)
如果没有Scalekit工具覆盖所需操作,尝试直接向提供商API发送代理HTTP请求:
bash
uv run tool_exec.py --proxy-request \
--connection-name \
--path \
--method \
--query-params \ # 可选
--body # 可选
注意:某些环境可能禁用代理。如果返回TOOLPROXYDISABLED,告知用户当前Scalekit工具目录不支持此操作,并建议向Scalekit请求新工具。
示例:在LinkedIn上搜索(通过HarvestAPI)
用户:在LinkedIn上查找旧金山的软件工程师
- 1. --list-connections --provider HARVESTAPI → keyid: harvestapi-xxxx,type: APIKEY
- --generate-link --connection-name harvestapi-xxxx → 检测到APIKEY,检查账户 → ACTIVE
- --get-tool --provider HARVESTAPI → 找到harvestapisearch_people
3b. --get-tool --tool-name harvestapi
searchpeople → 模式显示有效参数:first
names、lastnames、search、locations、current
jobtitles等
- 4. --execute-tool --tool-name harvestapisearchpeople --connection-name harvestapi-xxxx --tool-input {firstnames: John, locations: San Francisco, currentjob_titles: Software Engineer}
→ 返回匹配的LinkedIn个人资料
任何与LinkedIn相关的请求(个人资料、职位、公司、帖子、人员搜索、广告、群组)→ 使用提供商HARVESTAPI。
示例:使用Exa搜索网络(API密钥连接)
用户:使用Exa搜索最新的AI新闻
- 1. --list-connections --provider EXA → keyid: exa,type: APIKEY
- --generate-link --connection-name exa → 检测到APIKEY,检查账户 → ACTIVE
- --get-tool --provider EXA → 找到exasearch
3b. --get-tool --tool-name exa
search → 模式显示query(必填)、numresults、type等
- 4. --execute-tool --tool-name exa_search --connection-name exa --tool-input {query: latest AI news}
→ 返回搜索结果
示例:读取Notion页面(OAuth连接)
用户:读取我的Notion页面 https://notion.so/...
- 1. --list-connections --provider NOTION → keyid: notion-ijIQedmJ,type: OAUTH
- --generate-link --connection-name notion-ijIQedmJ → 检测到OAuth,已ACTIVE
- --get-tool --provider NOTION → 找到notionpage_get
3b. --get-tool --tool-name notion
pageget → 模式显示page_id(必填)
- 4. --execute-tool --tool-name notionpageget --connection-name notion-ijIQedmJ --tool-input {page_id: ...}
→ 返回页面元数据
示例:Scalekit中尚不支持的操作
用户:获取Notion页面的块
- 1. --list-connections --provider NOTION → keyid: notion-ijIQedmJ
- --generate-link --connection-name notion-ijIQedmJ → ACTIVE
- --get-tool --provider NOTION → 未找到notionblocksfetch工具
- --proxy-request --path /blocks/id>/children → 回退尝试
- 如果代理禁用 → 告知用户该操作尚不可用
文件上传与下载
某些提供商没有用于文件操作的Scalekit工具。使用--proxy-request配合--input-file(上传)或直接S3/CDN URL下载(下载)。提供商特定流程如下所述。
⚠️ 代理令牌过期: --proxy-request直接将存储的OAuth访问令牌传递给提供商。如果令牌已过期,提供商将返回401 Unauthorized。与自动刷新令牌的--execute-tool不同,代理不会自动刷新。如果收到401,需要刷新令牌——重新运行--generate-link检查状态;如果连接为ACTIVE但代理