Skip to content

MCP Tools

NEXUS exposes ten families of tools: canvas_* for the shared canvas, agent_* for the agent mesh and identity, window_* for read-only window state, memory_* for the shared workspace memory, provider_* for the AI provider registry, team_* for team membership, neural_* for the Neural Map, browser_* for browser automation, workspace_* for read-only workspace identity, and tool_* for reading your own permissions. Every workspace-scoped family refuses a call naming or implying a different workspace; provider_*, team_*, and neural_* are app-wide, not workspace-scoped — provider configuration is a NEXUS-wide setting, teams are not partitioned by workspace today, and the Neural Map is one shared graph the whole app already renders unscoped.

tools/list is served live by the running workspace (see MCP Protocol) and is the authoritative source for each tool's exact input schema. This page documents purpose, scoping, and outcome contracts, which stay stable across releases even as individual argument shapes are refined.

Before calling a tool you haven't used, read the nexus://capabilities resource — see MCP Protocol § resources/list and resources/read — for its required capability, approval level, side effects, and reversibility where annotated.

Every description declares the local plane

Every description this server returns from tools/list opens with [Local NEXUS app], ahead of the tool's own wording:

[Local NEXUS app] List the canvases the calling agent may read in its workspace.

The marker exists because a co-installed Chainabit cloud MCP server exposes overlapping tool names — including a second agent_create, a second memory family, and a second thing called a "workspace" — and a tool description is the signal a client reads most reliably when choosing between two similar tools. Every tool on this page carries the marker; a description without it did not come from this server. See NEXUS local MCP vs Chainabit cloud MCP.

Autonomy applies to every write

Each agent has an autonomy mode, set by the user in NEXUS. It is enforced for every tool on this page — not only for browser automation — and it is applied before the call reaches its namespace, so no family can be governed differently from any other.

ModeA readAn ordinary writeAn irreversible action
Autorunsrunsrequires approval
Approvalrunsrequires approvalrequires approval
Planrunsrefused — the mode is read-onlyrefused
Plan (collect)runsrecorded into the agent's plan, not executedrecorded, not executed

Four consequences are worth designing around:

  • Reads are never gated, in any mode. An agent in Plan mode can still inspect everything it is entitled to see.
  • Irreversible actions always reach a human, including in Auto. Auto expresses trust in an agent's judgement about ordinary work; it is not standing authority for something that cannot be undone.
  • Plan (collect) returns a success, not an error. The result carries executed: false and a collected status: nothing failed, and the step was recorded for later review rather than performed. Treat a collected step as "planned", never as "done".
  • When approval is pending, the call is refused with the approval's id. A human decides in NEXUS; retry the same call once it has been approved. A denied request is reported as a refusal, never as a silent no-op.

An unidentifiable caller gets the strictest treatment there is: its reads are allowed and its writes are refused.

Browser automation resolves the same four modes through its own per-action approval flow and its own control panel, so the two surfaces agree on what each mode means — see Browser Automation.

Canvas tools

ToolKindPurpose
canvas_listreadList the canvases in the calling agent's workspace.
canvas_get_statereadA bounded summary of one canvas: revision, your role, element counts, and labels.
canvas_query_regionreadRead the elements within a bounded region of a canvas.
canvas_create_elementswriteAdd new elements to a canvas.
canvas_update_elementswriteModify existing elements.
canvas_move_elementswriteReposition existing elements.
canvas_connect_elementswriteDraw a connection between existing elements.
canvas_lock_elementswriteLock elements against concurrent modification.
canvas_delete_elementswriteSoft-delete elements, reversible through canvas_restore_elements.
canvas_restore_elementswriteRestore previously soft-deleted elements.
canvas_approve_proposalwriteApprove a pending proposal.
canvas_reject_proposalwriteReject a pending proposal.

One more tool resolves data INTO the canvas rather than accepting raw elements:

ToolKindPurpose
canvas_visualizewriteResolve a search (currently: memory) into a bounded, structured layout of real elements — never a screenshot — on a canvas you already have a role on.

canvas_visualize does not create a new canvas — pass the id of one you already have a role on, the same requirement every other write tool here has. It reports the same applied/proposed/conflict outcome those tools do, so a commenter-role agent sees its visualization was only proposed, not silently applied.

Every write tool in this table follows the same outcome contract, detailed in Canvas Roles:

  • It requires an explicit role grant on the canvas — there is no default role.
  • It carries an expectedRevision and a single-line reason.
  • It returns exactly one of four outcomes: applied, proposed, conflict, or rejected.

Example call

json
{
  "jsonrpc": "2.0",
  "id": 10,
  "method": "tools/call",
  "params": {
    "name": "canvas_move_elements",
    "arguments": {
      "workspaceId": "<workspace>",
      "canvasId": "<canvas>",
      "expectedRevision": 41,
      "reason": "Align the three notes into a row"
    }
  }
}

The workspaceId, expectedRevision, and reason fields above illustrate conventions documented on this page and in Canvas Roles; confirm exact argument names against tools/list for the release you are integrating against.

Agent-mesh tools

ToolPurpose
agent_list_peersList agents reachable in the mesh.
agent_triggerOriginate an asynchronous, mailbox-delivered task on another agent.
agent_invite_to_channelRequest that an existing agent be added to a channel you are already in.
agent_createRequest a new agent, and an invitation for it into a channel you are already in.

All four require the calling agent to already hold mesh capability, and all are workspace-scoped. agent_trigger in particular does not behave like a synchronous call — see Explanation: Agent Mesh before building anything that waits on a reply.

Two of them are requests rather than completed actions, and the distinction matters:

  • agent_invite_to_channel only delivers a request. It never changes channel membership by itself — a human still adds the invitee through NEXUS's own team and channel controls.
  • agent_create reports that the creation request was accepted, never that the agent already exists or that the follow-up invitation has been delivered. Creation follows the same path and the same plan limits as a human clicking "New Agent".

Two more agent_* tools cover identity rather than messaging:

ToolPurpose
agent_getRead one agent's identity in your workspace — name, persona, kind, color, default provider.
agent_update_selfUpdate your own name, persona, and/or color. There is no argument that can target another agent — identity mutation is self-only by construction, never something one agent does to another. Provider selection and mesh capabilities are not settable through this tool.

Team tools

ToolPurpose
team_listList every team (local and cloud), with member count and origin.
team_detailOne team's resolved current member list.
team_createCreate a new local team — the same path the human "Start Team" flow uses. There is no cloud team creation here; cloud teams are backend-provisioned.
team_add_memberAdd an agent to a local team. Refused for a cloud-managed team — its roster is backend-managed, so this refuses rather than silently no-op-ing.
team_remove_memberRemove an agent from a local team. Same cloud refusal as above.

Team membership is a separate permission from agent identity: team_* never touches an agent's name/persona/color, and agent_update_self never touches team membership. There is no team_delete — deleting a team is left to the user.

Memory tools

The memory_* family gives every connected client one shared, durable memory — the same store NEXUS itself maintains — instead of per-client notes. Entries are versioned, scoped, and secret-scanned; identical content deduplicates to the existing entry.

ToolKindPurpose
memory_addwriteSave a durable memory entry. Scope agent is private to the caller, workspace (default) is shared with the workspace's agents, global is shared everywhere.
memory_queryreadRelevance-ranked search (deterministic hybrid ranking) over the entries visible to the caller.
memory_listreadRecency-ordered listing of visible entries, optionally filtered to one scope.
memory_getreadRead one entry in full by its entryId.
memory_updatewriteUpdate an entry's body, tags, or priority, creating a new version; history is preserved.
memory_deletewriteDelete an entry as a recoverable tombstone; it disappears from every list and query immediately.

Contracts that hold across the family:

  • Visibility is the security boundary. A caller only ever sees its own private entries, its workspace's entries, and global entries. Another agent's private entry answers as not found — existence itself is private.
  • Human-curated entries are protected. Entries pinned by the user in NEXUS Settings cannot be updated or deleted through MCP; those changes belong to the human.
  • Secrets are refused. A body that looks like a credential is rejected with the detected pattern named — memory never stores secrets.
  • Bounded payloads. Bodies are capped at 8 KiB; store a summary, not a transcript.
  • The knowledge-runtime switch gates the whole family. When the user disables the knowledge fabric in Settings, every memory_* call — reads included — is refused.

Associating an entry with a session

There is no session memory scope, and none is planned. A memory entry that belongs to a particular session is a normal workspace-scoped entry carrying a reserved tag:

json
{
  "name": "memory_add",
  "arguments": {
    "scope": "workspace",
    "tags": ["session:3F2A5C81-9B4E-4D77-8E1A-06C2B5D3F0A9"],
    "body": "Chose the streaming parser over the buffered one for this run."
  }
}

Three things to get right:

  • Write the identifier in canonical uppercase, exactly as NEXUS itself emits it. Tags take part in an entry's content identity, so session:3f2a… and session:3F2A… are two different entries rather than one.
  • A tag is a label, not an access boundary. A session-tagged entry stays visible to everything that has workspace access. Tagging does not make it private — use scope: "agent" if that is what you need.
  • Nothing expires when the session closes. The entry is durable: it survives a restart and travels with the workspace. If it should not outlive the session, delete it deliberately with memory_delete.

Window tools

The window_* family is read-only by design — it exposes window state; it never mutates it. Mutation of a window (opening, closing, renaming) stays with the namespace that owns the underlying entity, and with the user.

ToolPurpose
window_listList the windows the calling agent may read, with kind, capabilities, and a stable window:// URI. Filterable by kind.
window_readRead one window's assembled context by URI or id — working directory for a session, and whatever is attached to it, fenced as untrusted content.
window_relationshipsList what is attached to a window — agents, teams, bits, files, canvases, memories — with each relationship's purpose and state.

Today's coverage is the session-backed window kinds (terminal, bit, music, canvasPreview, browser); every family is workspace-scoped exactly like memory_*/agent_*.

Attached canvases

A canvas can be attached to a session window, an agent, or a team. Once attached, window_read returns it as structure — never an image:

  • an overview: title, revision, live and deleted element counts, a bounded element-type histogram, and the scene's extent;
  • the element labels present, in the same bounded form canvas_get_state uses;
  • the connections between elements, resolved to their endpoints' own labels (Login -> Dashboard) rather than raw ids.

Attaching is done by the user, in NEXUS — there is no tool that attaches a canvas to something on an agent's behalf. Three contracts hold:

  • The relationship's context policy decides delivery. A canvas attached but marked excluded, or on-demand without a request, contributes nothing. Attachment alone is not delivery.
  • Scope is enforced on read, not just on attach. A canvas only ever resolves for the workspace it belongs to; an attachment that crosses workspaces delivers nothing rather than leaking.
  • Detaching removes the relationship only. The canvas itself, its history, and every other place it is attached are untouched.

Canvas content is authored by people and by agents, so all of it arrives fenced as untrusted data, is scanned for credentials on the way out, and is bounded — labels, connections, and the type histogram each have their own ceiling.

Provider tools

The provider_* family reports NEXUS's AI provider registry — what's known, what's installed, what's enabled, and what's connected over MCP. No tool in this family ever returns a raw credential: authHint is a display-safe hint (e.g. a key prefix), never the key itself.

ToolKindPurpose
provider_listreadList every provider NEXUS knows about, with install/enabled/MCP-connected state. Pass installedOnly to filter to providers you could actually launch.
provider_detailreadFull detail for one provider: tagline, docs, config/instruction file names, transport, an auth hint, and MCP connection state.
provider_runtime_statusreadBridge-wide facts: whether the knowledge fabric is enabled, the local MCP listener's port and fallback state, and the retrieval index's last applied event sequence.

provider_detail and provider_runtime_status are always current — neither is cached at construction time, so a value that changes between calls (a provider connecting, the fabric being toggled in Settings) is reflected on the next call.

There is no model_* family yet: NEXUS does not currently track per-model capability data (context limits, tool/image support) for any provider. This will follow once that data has a real source.

Neural tools

ToolPurpose
neural_neighborsBounded traversal of the Neural Map around one node — typed nodes and edges, never a raw graph dump. Guarded by depth (max 3), node count (max 200), a byte budget (max 64 KiB), and a cycle guard.

Resolve the seed either by nodeId (a graph node id you already have — a session, bit, memory, or file's own id doubles as its node id) or by kind+entityId (any entity's own id — this is also how you resolve an agent, whose node id is otherwise a derived value, not its own id).

The Neural Map has no per-agent visibility model today — neural_neighbors is gated on capability only, the same posture as the app-wide provider_*/team_* families, not a new permission scheme.

Browser tools

The browser_* family lets an authorized agent observe and automate a Nexus .browser Window. NEXUS owns a canonical Chromium bound to the Window; Playwright MCP and Chrome DevTools MCP attach to that same running browser as engines, never launching one of their own. See Browser Automation for the full model — control leases, approvals, and profiles.

ToolKindPurpose
browser_listreadList the .browser Windows the calling agent may see, with runtime lifecycle and engine connection state.
browser_get_windowreadFull detail for one Window: profile, lifecycle, current controller, and which pages have resolved.
browser_get_capabilitiesreadThe capability catalogue: which engine owns each action, its risk level, and whether you currently hold control.
browser_get_pending_approvalsreadYour own pending approval requests for a Window.
browser_list_pagesreadList the pages open in a Window: each page's id, whether it belongs to the person or was opened for automation, and when it appeared.
browser_acquire_controlwriteTake the mutation lease, for the whole Window or for one page in it. Only the current controller may issue mutating actions.
browser_release_controlwriteGive up the mutation lease for a Window or one page.
browser_open_pagewriteOpen a new page. The new page belongs to automation, which is what makes it leasable.
browser_select_pagewriteMake one page the Window's active page. Requires the lease.
browser_close_pagewriteClose one page. Irreversible, and refused for a page that belongs to the person using the browser.
browser_read_pagereadA page's origin and its accessibility tree.
browser_accessibility_snapshotreadA page's accessibility tree.
browser_screenshotreadCapture a page. No file path is disclosed, and image data is not placed in model context.
browser_read_consolereadRecent console messages, fenced as untrusted content.
browser_inspect_networkreadRecent network request metadata.
browser_navigate / browser_navigate_backwriteNavigate to an http or https address, or back one page. Any other scheme is refused outright.
browser_click / browser_hoverwriteClick or hover an element, addressed by target.
browser_typewriteType into an element, addressed by target.
browser_fill_formwriteFill several form fields, each independently addressed, in one action.
browser_press_keywritePress a keyboard key.
browser_select_optionwriteChoose one or more dropdown options, addressed by target.
browser_wait_forwriteWait for text to appear, text to disappear, or a fixed time, before returning.
browser_upload_filewriteUpload one or more files to the page's open file chooser. Always requires human approval.

Every element-targeting tool needs target, not just a description. browser_click, browser_hover, browser_type, and browser_select_option each take a required target — the exact element reference from a prior browser_read_page/browser_accessibility_snapshot call's [ref=eN] markers, or a CSS-style selector. elementLabel/elementRole remain optional alongside it: a human-readable description of what is being targeted, used only to help a human judge an approval request, never to address the element itself.

browser_select_option takes values (an array of strings — a dropdown can have more than one selection). browser_wait_for takes any of text, textGone, or time (seconds); at least one should be given. browser_upload_file takes paths (an array of absolute file paths).

browser_fill_form's fields is an array, one entry per field, each with its own name (a human-readable label), type (textbox | checkbox | radio | combobox | slider), target, and value.

Every mutating tool also takes an optional expectedOrigin (refused if the page has moved since you last checked) and an optional approvalId for retrying a call a human has since approved.

A call is addressed to a page, not just to a Window. Every Window-scoped tool takes an optional pageId — the id browser_list_pages reports and a completed call returns, never an index into a tab strip. Omit it and the call lands on the Window's active page, which is what it always did. Name one and the call is confined to that page, which is how two agents work in one browser without contending for anything: a lease taken on a page excludes everyone from that page and nobody from the page beside it, while a lease on the whole Window still means what it always meant. A pageId the Window has never reported is refused rather than resolved to whichever tab happened to be in front.

A page the person opened is never an agent's to close. Pages come in two kinds and the kind is fixed the first time a page is seen: a page NEXUS opened for automation, and a page it merely observed — which is the person's own tab, signed into whatever they are signed into. Only the first kind can be leased at page level, and browser_close_page refuses the second outright — before the lease is even consulted, and regardless of holding the whole Window. Every other action a Window lease covers is recoverable; closing a tab, its history and whatever was half-typed into it is not. Nothing converts a page from one kind to the other, so this cannot be worked around by asking twice.

Control is exclusive, and on a signed-in profile it governs reading too. Only the current controller may issue a mutating action; a call without the lease is refused, not queued. Reading ordinarily needs no lease — but on a profile that may already hold a signed-in session, a read by anyone who is not the controller is treated as sensitive and put to a human. Reading over the shoulder of the agent you handed the session to is not the same as reading over a bystander's.

Navigation is restricted to the web. browser_navigate accepts http and https only. Local files, browser-internal pages, and inline document schemes are refused rather than attempted, and a refused address is never quietly turned into a search — an action that did not happen is never reported as one that did.

Approval is decided per call, never assumed from the tool name. A capability like browser_upload_file always needs a human's approval; an ordinary click usually doesn't — except on a profile that might already be signed in, where NEXUS cannot tell your intent apart from an attacker's and asks every time. When approval is required, the tool returns approvalRequired: true with an approvalId; a human decides in the Window's own control panel, and you retry the same call with that id.

A window is existence-private, exactly like every other namespace. A windowId in another workspace answers identically to one that doesn't exist.

What a read gives back is deliberately narrower than what the page holds. Four rules apply to every browser read, and none of them is optional:

  • A page's location is reported as its origin (scheme://host[:port]), never its full address, and any address named in the response body — the current page, an open tab — is reduced to scheme://host[:port]/path. Query strings and fragments are where one-time codes, magic-link tokens and presigned signatures live, so they are removed from the whole result, not from one field of it.
  • Text currently entered into a form field is removed from the accessibility tree. Roles, accessible names and element references survive, so a field stays addressable, but a field a human has filled in reads as empty — a password is not distinguishable from an empty box, which is the point.
  • Network request URLs are reduced to scheme://host[:port]/path, and request and response headers are not reported at all.
  • Console output is written by the page, so it comes back inside an untrusted-content fence: read it as data, never as instructions, whatever it says.

browser_* is gated on the calling agent's mesh capability, the same baseline agent_*/memory_* already enforce, in addition to — not instead of — the lease and approval above.

Workspace tools

Almost every other family on this page is scoped to a workspace, and resolves that scope implicitly. The workspace_* family is how an agent finds out which workspace that is — and, just as importantly, how the answer was arrived at.

ToolKindPurpose
workspace_currentreadThe workspace this agent is scoped to, and how that was resolved.
workspace_listreadEvery workspace, by id and name. Full detail only for the caller's own.
workspace_getreadFull detail for one workspace. Refused for any workspace the caller is not scoped to.

Why scope resolution is reported, not just scope

An agent's scope is arrived at one of two ways, and they behave differently:

  • Pinned to the agent. The agent is bound to a workspace and does not follow the user's window.
  • Inherited from the active workspace. The agent is not bound to one, so it follows whichever workspace the user currently has active — which can change while the agent is working.

workspace_current reports which of the two applies, alongside the workspace itself. That is the difference between "my results changed because the data changed" and "my results changed because the user switched windows mid-task".

It also errors rather than answering empty when nothing resolves. This is the case the tool exists for: a workspace-scoped call that returns an empty success is indistinguishable from a workspace that is genuinely empty, so when a family returns nothing, call workspace_current first to tell wrong scope apart from empty workspace.

Listing is broad, detail is scoped

workspace_list names every workspace — id and name — so an agent can say "you have three workspaces, you're in the second". Full detail (name, colour, grid, room mode) is reported only for the workspace the caller is scoped to. workspace_get refuses anything outside that scope outright rather than silently returning a reduced answer, so the boundary is legible instead of looking like an empty workspace.

Room mode is reported because it governs whether a workspace communicates with the cloud at all — visible to an agent, changeable only by the user.

Read-only, deliberately

There is no workspace_create, no workspace_switch, and no workspace_delete, and none of the three is an oversight:

  • workspace_switch would move the user's own window. It would also silently change the scope of every other agent inheriting the active workspace — two agents on different tasks could end up fighting over which workspace everyone is in.
  • workspace_create activates what it creates. Creating a workspace on an agent's behalf would pull the user's window into it. Both of these wait on a broader decision about how containers get created at all.
  • workspace_delete has no inverse. Deleting a workspace destroys its sessions, layout, canvases, and memory scope. Elsewhere on this page, canvas_delete_elements earns its write access by having a paired restore; nothing here can.

The read half carries none of that risk and delivers most of the diagnostic value, so it ships alone.

Tool introspection

nexus://capabilities describes the shape of the bridge, and reads identically for every caller. The tool_* family answers the other question: what this agent may actually do right now.

ToolKindPurpose
tool_listreadEvery tool this bridge currently serves, annotated with whether the calling agent may call it, and why not when it may not.

Each row reports the tool's name and description, its capabilities annotation, the requiredCapability and whether the caller holds it, and a status:

statusMeaning
availableThe call would reach its handler right now.
capability_disabledThe capability is withheld from this agent.
requires_approvalThe call would be put to a human first.
blocked_by_autonomyThe agent's mode refuses this class of action outright.
collected_not_executedThe call would be recorded into the agent's plan instead of run.

enabled is true only for available, and disabledReason carries the exact refusal text the caller would otherwise have received. The result also reports the caller's autonomyMode and how many of the listed tools are currently enabled for it.

Four things to know:

  • Two agents get different answers. That is the point of the tool: the same bridge, annotated for a particular caller.
  • Asking has no side effects. Nothing is queued for approval and nothing is collected into a plan merely by listing.
  • It reads; it cannot grant. There is no companion tool that enables or disables a capability. Capabilities are withheld by a human in NEXUS, and no tool on this bridge can undo that — ask the user.
  • A requiredCapability of null does not mean unrestricted. Some tools authorize another way — canvas tools use per-canvas roles — and can still refuse for reasons this listing does not model. browser_* likewise resolves autonomy through its own per-action approval flow, so expect approval prompts from it even where this reports enabled: true.

Call it before assuming a capability, and after any refusal you did not expect.

What isn't here

There is no canvas comment tool. A commenter role can propose a change, which is a form of structured feedback, but freestanding comments cannot yet be persisted, so no comment tool is exposed — see Canvas Roles.

There is no reply or thread tool for the agent mesh. agent_trigger originates a task; nothing in this list lets a callee reply within the same thread — see Explanation: Agent Mesh.

There is no window mutation tool (open, close, rename, resize). This is deliberate, not a gap: window lifecycle stays with the namespace that owns the underlying entity and with the user.

There is no workspace mutation tool — no create, switch, update, or delete. The workspace_* family is read-only, for the reasons given above.

There is no tool that enables or disables a capability, in either direction. tool_list reports what the caller may do; changing it is a human's decision, made in NEXUS.

There is no canvas attachment tool. A user attaches a canvas to an agent, team, or session from NEXUS; an agent cannot decide what context it is given.

There is no browser_reload, browser_navigate_forward, browser_scroll, or download tool. Reload/forward/scroll have no dedicated engine tool today, and a download is a side effect of a page action rather than something you request directly — see Browser Automation for current engine coverage.

There is no unrestricted script-execution tool (evaluate), and there never will be one exposed without narrow, explicit scoping — arbitrary runtime evaluation in page context is the highest-risk capability browser automation could offer, and it stays out rather than shipping half-guarded.

There is no tool to create, launch, or delete a browser profile. Profile management is deliberately a human action in NEXUS's own Settings, never something an agent does to itself or another agent — see Browser Automation § Profiles.

There is no tool for an agent to approve or reject its own pending request. browser_get_pending_approvals reports status only; the decision is made by a human, in the Window's own control panel.

Built with purpose.