Custom scoped tools
Developer
Custom tools are purpose-named invocable actions scoped to one domain. The generic actions cover everything; a scoped tool covers one thing, so a planner can route by intent — a tool called Sales Desk Context with a purpose statement tells it which records matter.
Generate the classes
Deploy → Custom
| Setting | What it does |
|---|---|
| Domain | Which domain’s roster the tools route through |
| Level | Pin a level, or expose it as a caller input |
| Format | Pin markdown, JSON, or both (the JSON payload with the markdown rendering inside it) — or expose it as an input |
You get six classes, each with a Copy button:
| Class | Role |
|---|---|
<Domain>GetCatalogAction | Discovery — what this domain serves right now |
<Domain>FindRecordsAction | Filtered sets from the domain |
<Domain>GetRecordsAction | One record in depth, entity chosen by the domain |
<Domain>GetBriefsAction | The standing frame the domain serves — injected briefs first, in order |
<Domain>GetSkillAction | A procedure the domain carries, fetched by name |
<Domain>UpdateRecordsAction | Updates the domain permits, with its confirmation posture |
The write tool is where pinning the domain matters most: the domain decides whether writes are allowed at all, which fields are writable, and whether a human confirms first. An agent handed the pinned class cannot reach past any of it. → Write access
Pin level or format when the tool has one job — fewer inputs is less for a planner to get wrong. Expose them when the same tool serves several depths; the generated class adds the input with an agent-readable description.
Deploy the classes
The classes live in your org and namespace. Deploy them as you deploy any Apex. They call only the package’s public API — Entity, EntityRequest, EntityFindRequest — so package upgrades and roster changes don’t break them.
Register them
Setup → Agent Actions → New → Apex, once per class, or add them as MCP tools on a server. Name each action exactly as the class — the same rule as the built-in actions. Step 3A on the Deploy page shows the agent action table; 3B covers MCP.
To add them to an existing agent, put the domain’s actions in a topic of their own, then add a transition from your agent’s router. One topic per domain keeps the planner’s choices clear. Starting fresh? The Agentforce page generates a whole agent — swap its apex:// targets for your class names.
Leave the update tool out of the topic if that agent should not write. The domain still gates it, but not offering the tool is the clearer statement.
How it works
@InvocableMethod(label='Sales Desk Context' category='ContextWorks'
description='Everything a seller needs about an account and its open business. Pass any covered record Id; uncovered objects return the current coverage list.')
public static List<Response> execute(List<Request> requests) {
// ...
ctxl.EntityRequest req = new ctxl.EntityRequest();
req.domainApiName = 'sales_desk';
req.toolName = 'SalesDeskGetRecordsAction';
req.recordId = request.recordId;
req.level = 'detailed';
req.format = 'markdown';
response.result = ctxl.Entity.load(req);
// ...
}
domainApiName, not an entity list. The class reads the domain record at call time — change what the domain carries and the class covers the new objects untouched.toolNamestamps telemetry, so Usage attributes loads to this tool.- Descriptions are purpose-phrased, so they don’t go stale when the roster changes.
The code is yours — edit freely. Sharpen the @InvocableMethod description, add inputs, post-process the payload. Keep toolName (or you lose attribution) and domainApiName (or you lose data-driven routing).
Error handling
A record whose object the domain doesn’t serve returns a structured answer naming the current coverage instead of throwing, so an agent can re-plan. The catalog tool gives the same answer proactively — agents should call it first.
Custom source or custom tool?
| You want | Build |
|---|---|
| A new kind of context — computed, external, scored | An enrichment |
| A new way to address existing context | A scoped tool |