Skip to content

2 · The tools

What you will have done: read every tool the endpoint offers, grouped by the engine it drives, and learned the one rule each of them keeps.

The tables below are generated from a live instance by calling tools/list, so the wording is the tool’s own and cannot drift from what your harness sees. Beside each table sits the rule that tool enforces, which is the part you cannot read off a schema.

Everything here dispatches into a route. No tool reimplements what a screen does. A tool composes a request, hands it to the instance’s own router as the token’s principal, and returns the answer. That is why a rule you meet in the Revenue or Projects sections applies here word for word.

Core

Six tools that are not about one engine: the whole HTTP surface, the admin subset of it, the route catalogue, the approvals waiting on you, the decision that settles one, and a conversation with the instance’s own agent.

ToolWhat it doesRequired arguments
admin_referenceThe catalog of routes this instance exposes, with shapes — read before composing api_request or admin_request calls. With no argument it answers an index of sections and their route counts; pass a section name for that section’s lines.—
admin_requestCall this neutron instance’s admin HTTP API. Any /api/admin/* route plus GET /api/agents, /api/models, /api/settings. Returns the JSON response as text. Use admin_reference first to see the route catalog. Query parameters go in the query argument — a path carrying a ? is refused. The routes that put a letter on the wire — approving a send, sending a draft, lifting a suppression, resuming a paused domain, activating or enrolling a campaign, standing down a campaign’s human review or naming its sending pool, rotating, registering or deleting a connection’s keys, creating or re-activating a sending identity, inviting a person — need the wire scope on this token. Stopping never does.method, path
api_requestCall any of this instance’s HTTP routes — every /api/* path, not just the admin subset admin_request reaches. The call runs as the person this token is bound to, so each route’s own authorization, the wire scope and the audit trail apply exactly as they do to that person on screen: this is a door, not a bypass. Returns the JSON response as text. Use admin_reference to find the route — it answers an index of sections, then one section’s routes at a time. Query parameters go in the query argument; a path carrying a ? is refused. /api/chat is refused here because it streams — the chat tool runs a turn. The Projects board has the work_* tools and approvals have approvals_inbox and approval_decide, all easier than composing these routes by hand.method, path
approval_decideApprove or refuse one pending approval, as the person this token is bound to. The same wall the screen keeps: an agent decides nothing, a role-gated card needs a holder of that role and never the person who asked for it, and an owner’s card is not a plain admin’s to settle. An id you may not decide answers the same 404 as one that does not exist, so ids cannot be probed. Mutating.approval_id, approve
approvals_inboxThe approvals waiting on YOU: every pending request this token’s person may decide, across every conversation, with what is being asked, who asked, the role the decision needs and when it was requested. Takes no arguments. Somebody who holds no required role sees an empty list rather than an error. Read-only.—
chatRun one turn against this instance’s core agent (or a named agent) and return its final text. Gated tool calls AUTO-APPROVE on token turns (the token is the standing authorization; every decision is audited) — except the agent’s self-initiated config changes, which stay human-only. Pass the returned thread_id back to continue a conversation. Turns can take minutes.prompt
ToolThe rule it keeps
api_requestIt reaches every /api/* route, as the person the token is bound to, and each route keeps its own authorization: a door, never a bypass. Nothing a person could not do on screen becomes possible. Methods are GET, POST, PUT, PATCH and DELETE. The path is written as the router holds it and canonicalised before the gate runs, so a dot segment, a percent-encoded character or a query string in the path fails closed: query parameters go in the separate query argument. /api/chat is refused because it streams and a turn started here would be filed as a web turn; the chat tool runs one.
admin_requestThe older, narrower door: /api/admin/* and three read-only public routes, and nothing else. Same methods, same canonicalisation, same query argument. It still reaches no /api/work/* route at all.
admin_referenceRead it before composing a request. It is rendered from the instance’s own router and covers every one of its 528 routes, marked where a route needs the wire scope and carrying the body keys a route requires. Called with no argument it answers an index of its 42 sections and their route counts; called with a section name it answers that section’s lines. One page had reached 65,000 characters and was growing with the router, which is past the point anything reads to the end. A route that is not in it is a route this tool will not compose for you, and a route added without a catalogue line fails the build rather than going unlisted.
approvals_inboxWhat is waiting on you: the pending cards routed to this token’s person by role, across every conversation, with what is being asked, who asked, the role the decision needs and when it was requested. Somebody holding no required role sees an empty list rather than an error. Takes no arguments. Read-only.
approval_decideThe same wall the screen keeps. An agent decides nothing. A card needing a role goes to a holder of that role and never to the person who asked for it, and a card on somebody’s own thread is not a passing admin’s to settle. An id you may not decide answers exactly as one that does not exist, so ids cannot be probed.
chatGated tool calls auto-approve on a token turn, because the token is the standing authorization and every decision is audited. The one exception is the agent changing its own configuration, which stays human-only. A turn can take minutes.
Neither request tool is a way round the gates. Both carry the token’s principal, so every route they reach applies the checks it always applied. The sixteen call sites that put something beyond recall into the world refuse a token that was not minted with the wire scope, whether the call arrived through a named tool, through api_request, through admin_request, through the REST API directly, or from a procedure running inside the pod. The refusal is one sentence: this token cannot put letters on the wire: mint one with the wire scope in Settings → Access & Security → API.
An agent does not settle an approval. approval_decide refuses an agent turn before it reaches the route, and says why: an agent does not decide approvals — this is what an approval is for. A person settles it, on screen or with a token of their own. That is the mechanism working. A person with a token of their own decides, here or on screen.

Revenue

Ten tools covering the Revenue Engine: finding people, importing them, reading what came back, and writing answers that wait.

ToolWhat it doesRequired arguments
mail_searchSearch the Inbox: conversations across email and WhatsApp with their bodies and their readings. Filter by label (POSITIVE, MEETING, MORE_INFO, REFERRED, NOT_NOW, OOO, UNSUBSCRIBE, TO_TRIAGE), campaign, sending identity, or only the ones waiting on us. Read-only.—
mail_sendWrite to somebody on a campaign, as one of your identities. This DRAFTS the message and nothing more: it waits in the Inbox for a person to approve, edit or discard, and no agent tool sends. Cite only evidence approved for the campaign’s locale — anything else is refused. Mutating (low risk: nothing leaves the building).person_id, body_text
people_findFind the legal entity behind a company domain or name, from free national registries (Norway’s Enhetsregisteret, Denmark’s CVR, GLEIF, SEC EDGAR). Keyless and unmetered. Returns normalised company records with provenance — website, status, employee count and industry where the registry publishes them.—
people_importImport a CSV of leads into a campaign: one prospect per company, one person per row, with the source URL kept as evidence. DRY RUN IS THE DEFAULT — it reports the column mapping it guessed, the rows already in the campaign, and the rows it cannot use, and writes nothing. Read that plan, then pass dry_run: false to actually write. An imported address is never VERIFIED. The write returns a batch_id that DELETE /api/admin/crm/people/import/:batch rolls back while nothing has been sent. At most 5000 rows per file.campaign, csv
people_resolve_emailResolve a work email for a named person at a domain, cheapest rung first: MX, then pattern candidates, then a live SMTP probe — all free. The paid provider rung runs ONLY when allow_paid is set AND the campaign’s budget gate approves (NEP-0007 §8). Returns the verdict plus a per-rung account of what actually ran, so a prober that could not reach the network is never mistaken for an absent mailbox. An accepted address is PROBABLE, never VERIFIED — only a delivery earns that.first_name, last_name, domain, campaign
reply_draftDraft an answer to one inbound reply, citing only evidence approved for the campaign’s locale. The draft waits in the Inbox for a person to approve, edit or discard — this never sends anything. Name the touch id of the reply being answered, which thread_read gives you. Mutating (low risk: nothing leaves the building).touch_id
sequence_enrolPut a campaign’s people in front of whoever sequences it — neutron’s own dispatcher, or Salesforge. Enrolling is idempotent: anybody already carrying a sequencer contact id for the campaign is skipped, so calling it again picks up only the people verified since. Returns how many were enrolled and a count per reason for everyone who was not (suppressed, not_schedulable, no_address, already_enrolled). Needs the wire scope on this token.campaign
thread_readOne conversation whole: every turn across every channel with the body that was stored, who has it, the drafts waiting on it and the label corrections made on it. Thread ids are p:<person_id> for a known person and a:
otherwise, and come from mail_search. Read-only.
thread_id
touch_logRecord a touch the system did not make itself — a call you had, a meeting, a message sent from somewhere else. Every send and reply Neutron makes is already recorded; this is for the ones it cannot see, so one person’s history stays whole. Mutating (low risk).channel, direction, label
webhook_registerPoint the sequencer at this instance, so replies, bounces and unsubscribes reach it at all. The vendor subscribes a webhook to exactly one event, so this registers three and reports which took. It mints a fresh receiver token as it goes, which retires the old one — a registration that half-succeeds leaves the events it did register working and names the rest. Mutating (rotates a secret; gated like a key change) — needs the wire scope on this token.—
ToolThe rule it keeps
people_resolve_emailCheapest rung first, and the paid rung runs only when it is asked for and the campaign’s budget gate agrees. An accepted address is PROBABLE, never VERIFIED; only a delivery earns that. The answer carries a per-rung account, so a prober that could not reach the network is never read as an absent mailbox.
people_findFree national registries only, with provenance on every record. Nothing here is metered and nothing here is a guess.
people_importDry run is the default. It reports the mapping it guessed, the rows already on the campaign and the rows it cannot use, and writes nothing. Passing dry_run: false writes, and only a file whose preview was read may be written. An imported address is never VERIFIED.
touch_logOne touch ledger. This is for the touches Neutron cannot see itself, so that one person’s history stays whole. Everything Neutron does is already a row.
mail_searchRead-only.
thread_readRead-only, and it is the whole conversation across every channel, with the corrections made on it.
reply_draftIt drafts. The draft waits in the Inbox for a person to approve, edit or discard. This never sends anything.
mail_sendThe name is the trap and the description says so: it drafts and nothing more. No agent tool sends. It cites only evidence approved for the campaign’s locale, and anything else is refused.
sequence_enrolIdempotent. Anyone already carrying a sequencer contact id for the campaign is skipped, so calling it twice picks up only the people verified since. It returns a count per reason for everyone it did not enrol.
webhook_registerIt rotates a secret, so it is gated like a key change. A registration that half-succeeds leaves what it registered working and names the rest.

Projects

Twenty tools that drive the board, each one dispatching into the same /api/work/* route a screen calls. Nine work on an item, eleven on the things around it: the projects, the plans, the weeks and the code.

ToolWhat it doesRequired arguments
work_claimTake a ready item: it becomes in progress and assigned to you. Refused when somebody else already holds it.item_id, expected_revision
work_code_linkRecord where an item’s issue lives on a code host, or with remove drop the link it carries. Nothing is fetched: this is Neutron’s own note of the address, and one issue may be linked to one item. Mutating.item_id
work_commentWrite a comment on a work item, signed as you. Mutating.item_id, body
work_createOpen a new work item in a project you can reach. Mutating.project_id, title
work_getOne work item whole: its fields, its comments, its relations, its children and the open review holding it, if any. Read-only.item_id
work_linkRelate two items in the same project: blocks, relates, duplicates or precedes. Mutating.item_id, target_id, kind
work_moveMove a card to another column, optionally between two named neighbours. A move to done PARKS when the item asks for review, or whenever an agent makes it: it lands in review and waits on a person, and the answer carries the approval id. Mutating.item_id, to_status, expected_revision
work_plan_completeClose a plan whose work is finished. Refused, with the open ids, while any item it minted is still open. Mutating.plan_id
work_plan_createDraft a plan on a project. The summary is markdown under ## headings — Why, What is wrong today, Why it is worth doing, Acceptance, Sizing, Not in scope — and the phases carry the work the plan will mint when it is signed off. Mutating.project_id, title
work_plan_decideAccept a submitted plan, or send it back to its author. The project’s owner or admin decides, and the plan’s own author never may. Mutating.plan_id, accept
work_plan_getOne plan whole: its summary, its links, its phases and the gate holding it. Read-only.plan_id
work_plan_signoffOpen the signoff gate on an accepted plan. Anyone who may write on the board may ask; who may then SIGN is the project’s owners, admins and pms, minus the plan’s author, and the answer carries the approval id they decide. Mutating.plan_id
work_plan_submitSend a draft plan for its decision. Mutating.plan_id
work_plansThe plans on one project: each one’s status, the items it has minted, and whether you may decide or sign it. Read-only.project_id
work_projectsEvery project you can reach, with the key its references carry — where a project_id comes from. Read-only.—
work_readyWork you can pick up right now: ready, unassigned and waiting on nothing, in the order to do it. Read-only.—
work_reportHow a project is going, in one read: the running sprint’s burndown, how long a card takes to cross the board, how long a review waits, and what finished each week. Read-only.project_id
work_searchFind work items by project, free text, status, assignee or label. Read-only.—
work_sprintsThe sprints on one project, with their dates and whether they are closed. Read-only.project_id
work_updateChange an item’s fields. Status is NOT one of them — moving a card is work_move, which enforces the transition matrix and the review gate. Mutating.item_id, expected_revision
ToolThe rule it keeps
work_readyReady, unassigned, blocked by nothing, in the order to do it. Read-only.
work_getRead-only, and the whole item: fields, comments, relations, children.
work_searchRead-only.
work_createAn item in a project the token can reach, and no other.
work_updateStatus is not a field here. Moving a card is work_move, which is where the transition matrix and the review gate live. Acceptance criteria replace the stored list wholesale.
work_claimTwo workers cannot hold one card. The second attempt is refused and says who holds it.
work_moveA move to done parks. It parks when the item asks for review, and it parks whenever an agent makes the move, whether or not anybody ticked anything. The item lands in review and the answer carries the approval id.
work_commentSigned as the principal the token acts as.
work_linkTwo items in the same project, related as blocks, relates, duplicates or precedes.
work_projectsThe projects this token can reach, and nothing about the ones it cannot.
work_plansOne project’s plans. Read-only.
work_plan_getOne plan whole. Read-only.
work_plan_createDrafts a plan. Drafting is not deciding.
work_plan_submitPuts a draft up for a decision.
work_plan_decideAccepts a submitted plan or returns it to its author, storing the note it was decided on, and the author may not be the decider.
work_plan_signoffOpens the signoff gate on an accepted plan. Anyone who may write may ask; the answer carries the approval id, and a person decides it.
work_plan_completeCloses a plan whose work has landed.
work_sprintsOne project’s weeks. Read-only.
work_code_linkAttaches a code-host link to an item, or detaches one. The item’s status is then written onto that issue as a label.
work_reportWhat a project has done, read in one call.

Three tools take expected_revision, read from work_get: work_claim, work_update and work_move. Those are the three that contend over one card, and a stale revision is refused rather than merged, so two workers editing one card produce a refusal instead of a silent overwrite. Commenting, linking, attaching a code host link, creating an item and the five plan verbs do not take one.

Procedures

A procedure is one tool call that does the work of six, run as Lua inside the pod. Eleven ship in the image, named plainly with no prefix, and each one’s advertised description ends in the word that matters: Read-only. or Mutating. Alongside them sits run, which takes Lua of your own.

ToolWhat it doesRequired arguments
campaign_statusOne campaign whole, in one call: prospects by pipeline stage, people by verification state, held letters by reason, replies by label since a date, spend against budget, and deals by state. Read-only.campaign
campaign_verify_pressOne Verify pass on a campaign: count the people by verification state, run the verifier, and count them again, so the pass is reported by what it changed rather than by what it attempted. The route verifies at most ten people per call. Mutating.campaign
claims_listThe evidence a letter may cite, with its proof and the date it stops being citable. Asking for citable claims narrows it to the approved ones still in date, and needs a locale. Read-only.—
costs_reportWhat the revenue engine is spending: each vendor’s month to date, the totals per currency, the budgets and what each campaign has spent against its cap, and the lead-data lookups per provider. Read-only.—
deal_advanceMove one deal to its next state and read the stored deal back, so the answer is what the ledger now holds rather than what was asked for. A deal cannot move backwards or sideways. Mutating.deal, state
fleet_healthThe sending estate in one call: each fleet’s boxes and how many are warm, the domains with their state, placement, heat and daily cap, and the attention lines the fleet view raises — a paused domain, a cold box, a failing DNS record. Read-only.—
held_queueEvery letter the review queue is holding, grouped by the reason it is held, with the sentence that names each reason and the first few letters under it. A queued letter is waiting on a reviewer and carries no reason of its own. Read-only.—
inbox_digestThreads nobody has answered, grouped by the reading the inbox gave them, since a date. Each thread carries the person, the company they are filed under, and the first line of the last turn — never the letter. Read-only.—
reply_correctCorrect the reading the inbox gave one inbound turn, and report what the correction moved. The label must be one of the seven readings, never TO_TRIAGE. Mutating.touch_id, label
runRun a Lua script inside this instance, with assay.neutron already pointed at its own API as you. A script may call this instance’s API as the token, many calls in one go, and nothing else: no shell, no files, no other hosts. Use it for the reading a named procedure does not cover; a procedure is cheaper and safer when one fits. The script’s return value is the result. Needs the scripts scope on this token. Every run is audited.script
suppression_proposePut an address or a domain on the do-not-contact list and read it back. This only ever adds: lifting a suppression is a person’s decision and this procedure never calls it. Mutating.value
work_statusOne project’s board in one call: how many items sit in each column, what is waiting in review, what is ready to pick up, and every plan with the status it has reached. Read-only.project
ToolThe rule it keeps
campaign_status, claims_list, costs_report, fleet_health, held_queue, inbox_digest, work_statusRead-only, and that is enforced rather than declared: each runs under the runtime’s own read-only gate, where a write dies inside the runtime whatever the script says.
campaign_verify_pressThe route verifies at most ten people per call, so one press cannot spend a month’s budget.
reply_correctThe label must be one of the seven readings, never TO_TRIAGE. It reports what the correction moved rather than what was asked for.
deal_advanceA deal cannot move backwards or sideways.
suppression_proposeIt only ever adds. Lifting a suppression is a person’s decision, and no procedure calls it.
runNeeds the scripts scope. A script may call this instance’s API as the token and nothing else: no shell, no files, no other hosts. Every run is audited, including a refused one.

The next page is about all of them: how they run, what confines a script, and what the audit row holds.

What a token can never do

No tool on this endpoint puts a letter in a stranger’s inbox. There is no send tool. mail_send drafts. reply_draft drafts. Approving a send is a person’s act, on the Approvals screen or the Inbox, and the route behind it refuses a token minted without the wire scope.

No tool lifts a suppression. Somebody who asked to be left alone stays suppressed. Suppression is permanent and account-wide, it is not per campaign, and importing them again does not undo it.

No tool decides that an agent’s work is finished. Every move to done an agent makes parks in review and waits for a person who is not its author. An agent is never that person.

No tool moves a person backwards along the spine. The spine is forward-only. A reply read as positive asks the spine to move somebody forward; if they have already unsubscribed, the move is refused and the answer says what actually happened rather than what was asked for.

No tool writes an address as VERIFIED. Only a delivery earns that word. Everything an import or a lookup produces is PROBABLE at best.

No tool overwrites a person’s correction. A correction wins, including against a machine’s reading still in flight.

No token mints a token. The mint route refuses every one of them, whatever scopes it carries, because minting is how a scope is granted.

No tool settles an approval on an agent’s behalf. approval_decide refuses an agent turn outright, whatever the card and whoever minted the token.

Neither request tool widens any of this. api_request reaches more routes than admin_request does, and both carry the same principal and meet the same checks on every route they reach.

Regenerating this page

The tables above come from data/mcp_tools.json, written by a script in this repository:

scripts/mcp-tools.sh https://<host>

It calls tools/list with the bearer from ~/.config/neutron/<instance>-mcp-token and rewrites the file. Nothing is edited by hand, so a tool added to an instance appears here the next time the script runs and not before.

Last updated on