Tools
A tool is one markdown file describing something an agent may call. One noun
for capability: transport: says how it connects, and an agent grants it by
name in tools:.
tools/email.md flat — a definition and nothing else
tools/bounce-verify/ folder — tool.md plus the code it runs
├── tool.md
└── run.py
Nothing is callable until an agent names it. That is the whole security model:
reading one agent.md tells you its blast radius.
HTTP — an API as a tool
---
transport: http
name: google-ads
description: The Google Ads API. GET /customers/… to read; POST to mutate.
base: https://googleads.googleapis.com/v18
methods: [GET, POST]
headers:
Authorization: Bearer ${GOOGLE_ADS_TOKEN}
---
| field | |
|---|---|
base |
the URL every call is relative to |
methods |
the verb allowlist — a tool that declares none is read-only |
headers |
${SECRET} placeholders, resolved host-side at call time |
openapi |
a URL or file; turns one generic tool into typed ones, one per operation |
The model never sees a credential — the host substitutes it as the request goes out. The method allowlist protects against the agent; the key’s own scopes protect against everyone else, so pair a read-only tool with a read-only key.
Script — code as a tool
---
transport: script
name: sql
run: run.py
description: >
Run SQL over CSV and JSON files in the working directory. Use whenever the
answer is a number: totals, averages, joins, de-duplication.
args:
query: The SQL — one SELECT or WITH statement
files: Comma-separated .csv / .json paths, one table each
timeout: 120
runtime:
packages: [pandas]
---
| field | |
|---|---|
run |
the program beside this file. Omit it and a fenced code block in the body is the program (the single-file form) |
args |
each argument and what it means — this is what the model reads |
timeout |
seconds; without one the program runs until it finishes |
runtime |
interpreters and packages, merged into the step’s environment |
args descriptions are the tool’s interface. Write them for someone who has
never seen the program, and say when to use the tool in description — that
sentence is what decides whether it gets called at all.
MCP — someone else’s tools
---
transport: mcp
name: linear
url: https://mcp.linear.app/sse
headers:
Authorization: Bearer ${LINEAR_TOKEN}
---
Both transports the SDK supports: a local process (command:, with args: and
env:) or a remote endpoint (url:, with headers:). Every tool the server
exposes reaches the agent that grants it. mcpServers: in an agent’s own
frontmatter is the inline spelling of the same thing.
The library — define it once
<account>/library/
├── tools/<name>.md
├── skills/<name>/SKILL.md
├── knowledge/ · memory/ · scripts/
Resolution is nearest wins: an agent’s own beats its project’s, which beats the account library. So a shared integration is defined once for the whole account and rotating its credential is a single edit — and a workspace can still shadow it by defining the same name locally.
The Library page lists, for every shared file, which agents granted it and where a nearer copy overrides it. That list is the blast radius of changing it.
Skills — procedure, not capability
A skill is a folder with a SKILL.md, in the open
Agent Skills format:
---
name: pacing-check
description: Check whether ad spend is pacing to budget. Use when asked if spend is on track.
---
Run `scripts/pace.py --spent <amount> --budget <amount>` from this skill's
folder, then report the verdict in one sentence.
Only names and descriptions sit in context; the agent reads the full file when
a task matches. So an agent can carry many skills for a few tokens each — which
is the reason to move a procedure out of agent.md in the first place.
Skills are discovered in the agent’s own skills/, the workspace’s, the
account library, and the cross-client .agents/skills/ convention that other
tools read and write. A skill written here drops into them, and one they
install is visible here.
A tool is what an agent may call; a skill is how to do something well. The test for moving text out of an agent body: is it procedure (not role), does it apply to some runs rather than all, and does more than one agent need it?
Secrets
Names in secrets:, values in the vault. A secret may also be an OAuth2
credential — the vault stores the refresh recipe (token_url, client_id,
client_secret, refresh_token) and the host exchanges it for a live access
token immediately before every use, cached until near expiry.
Resolution is nearest-wins across the workspace and account vaults, and the run log says which store each one came from — a workspace quietly falling back to an account credential is the kind of thing you want to see rather than infer.
Testing one
The Tool Test button calls a tool with arguments you type, from where a run would call it, and shows the raw result. That is the difference between “the tool is broken” and “the agent used it wrong”, and it costs no model call.