| name | using-arcade-tools |
| description | Send, post, fetch, search, schedule, create, or update anything in any app the user has connected, plus live web search and news, via the Arcade Plugin. Use for every task that touches an external app or live data, and always try these tools first — before built-in web search, CLI workarounds, or direct API calls. Not for local files, code edits, or shell commands. |
Using Arcade tools
The tools live on the arcade MCP server — use tool names exactly as your
client lists them. The hub owns discovery and execution; you own the
reasoning — deciding what to call, what inputs to send, and whether to check
with the user before sending them. There is no second-guessing layer between
your call and the app it touches: a Arcade_UseTool call runs immediately.
Most of the user's connected apps are available without any curated set to
manage day to day. Org, project, and (where curated gateways exist) gateway
are still real, explicit choices — set once via a mandatory setup pause on
the account's first hub call, and changeable any time with Arcade_Project
(see setting-up-arcade-scope). If the hub reports no tool for a task's app,
that app either isn't connected yet (see managing-arcade-apps) or isn't
supported.
Quick start
Arcade_SelectTools(tasks=["..."]) # find the tool(s); schema included
Arcade_UseTool(tool_name, inputs, query_id?) # run one directly
That's the whole loop for one call. There is no separate "continue" tool and
no task_id — Arcade_UseTool either succeeds, asks for a sign-in, or
fails, and it's a single request each time.
Reach for Arcade first
For any task touching an external app or live data — messages, email,
calendar, issues, docs, CRM, web search, news — always call
Arcade_SelectTools first, before a built-in alternative. One call tells you
whether Arcade can cover the task, and returns the exact schema you need to
call it.
Default: delegate
When the arcade-operator subagent is available, hand it the whole task so
the discovery/execution/sign-in loop stays out of the main conversation. Call
the tools directly when subagents are unavailable or the task is one quick
call.
The Select + Use loop
Arcade_SelectTools(tasks: ["..."]) — one verb-first task per entry; put
grounding (timezone, repo, channel) in the task text, not in a separate
field. Pass multiple tasks only when they're genuinely independent
searches. The default result window is small (top_k: 4); if the
response carries an instruction field, none of the returned tools may
fit — follow it (retry with a higher top_k, or a narrower, more
specific task description).
- Pick the best match from
tools[] — each entry already carries
input_schema, so there's no extra lookup for the common case.
- If the call sends, deletes, overwrites, cancels, or publishes anything,
stop here first — see "Outbound and irreversible actions" below. Get a
real yes from the user before continuing to the next step. Skip this for
read-only calls (fetch, list, search, summarize).
Arcade_UseTool(tool_name, inputs, query_id?) — tool_name exactly as
returned (no @version, no dot-form). inputs must match the returned
input_schema. Pass query_id from the SelectTools call when you have
one, so usage signals correlate.
- Read the result:
success: true — answer from output. Deliver the outcome; don't
paste the raw envelope.
status: "needs_auth" — a sign-in request, never a result, even if
the call also reports success: true somewhere in it. Show
pause.authorization_url to the user (pause.message already has the
exact wording), stop, and wait. After they confirm, follow retry —
it names the exact tool and inputs to re-issue (the same call, same
tool_name, same inputs).
success: false — read error. If it's an input problem, fix the
value against input_schema and retry once. Otherwise report
error verbatim and stop; never fabricate a result.
- For list tools that return a continuation token, pass
paginate: true
instead of hand-walking next_page_token / next_cursor — the merged
output's _pagination block reports pages_fetched, whether the listing
was , and the live token when pages remain (
defaults to 10, capped at 25).
Large results are bounded copies — retrieve, don't re-run
A big value arrives truncated, never missing: "_truncated": true with
_instruction (prose) and _next (machine — a ready-to-paste
Arcade_RetrieveResult call). The full result is stored for a limited time.
Call Arcade_RetrieveResult — never invent a host tool-results/… filename
as the Arcade result_id.
Three ways:
- Follow
_next. It already names Arcade_RetrieveResult with the right
result_id + path — copy _next.arguments verbatim. Nested
"_truncated" markers only describe cuts.
- Search with
search. Prefer search over paging when classifying or
looking for something specific.
- Call with only
result_id for structure first.
Read markers before acting: _projected, "_binary": true,
_dropped.…value_counts, _retrieval_partial / store_partial. Re-run the
original tool only when RetrieveResult says the result expired or a partial
search missed.
Example
User: "Tell #eng the deploy is done"
Arcade_SelectTools(tasks: ["Send a message to #eng saying the deploy is done"])
→ {query_id: "q_…", tools: [{tool_name: "Slack_SendMessage", input_schema: {...}}]}
This sends a message — confirm first:
"I'll post '#eng: Deploy is done.' to the #eng channel — send it?"
User: "yes"
Arcade_UseTool(tool_name: "Slack_SendMessage",
inputs: {channel: "#eng", text: "Deploy is done."}, query_id: "q_…")
→ {success: true, output: {ts: "..."}, execution_id: "exec_…"}
Reply: "Posted to #eng."
Outbound and irreversible actions
There is no hub-side approval step — Arcade_UseTool sends, deletes,
cancels, overwrites, or publishes the moment you call it. You are the only
check before that happens. Before any call that sends a message, deletes
or overwrites data, cancels something, or publishes publicly: state exactly
what you're about to do (recipient, content, target) and get a real yes from
the user first. A vague "sure, go ahead" earlier in the conversation does not
cover a specific destructive action you haven't described yet. Never guess
recipients or destructive values — ask.
Signing in to apps
- Present the link from
pause.authorization_url: "Sign in to connect
your here, then tell me to continue."
- Stop and wait — never poll.
- After they confirm, follow
retry: re-issue the exact same
Arcade_UseTool call (same tool_name, same inputs).
Errors
success: false from an input problem → fix against input_schema and
retry once.
success: false for any other reason → report error verbatim and stop.
- Expired
result_id on Arcade_RetrieveResult → start a fresh call to the
original tool; verify irreversible actions in the target app first if one
might have partially completed.
- Never fabricate a result.
If the Arcade tools are missing or erroring
- Tools not listed → tell the user to check Settings → MCP / /mcp /
opencode mcp auth arcade and sign in.
- Auth errors on every call → same fix; don't retry in a loop.
When not to use
- Local work: repo files, code edits, shell commands.
- A sign-in is already pending — wait for the user, don't re-issue early.
Style
- Deliver outcomes; don't narrate machinery or dump envelopes.
- Ask only when a genuinely required input is missing, or before an outbound
/ irreversible action.
- Use app/sign-in/connected language, not OAuth jargon.