Authorization & Approval
How Daintree authorizes MCP sessions: how each session gets its tier, agent panes and their approval line, handing a terminal to an orchestrator, widening a session, host confirmation and what can stand in for it, and the security boundaries that exist only over MCP.
This page is the authorization half of MCP Server: how a session gets its tier, what an agent pane can reach, how a session widens, when Daintree asks before acting, and the boundaries that exist only over MCP. The three tiers themselves are summarized on the hub, and the exact tool lists are on Tool surface and budgets.
How a session gets its tier
Every session resolves to exactly one of three tiers: the in-app tool sets core and full, or external for API-key clients.
- API-key bearer. The
Authorizationheader matches the configured key on a timing-safe comparison, so the session isexternal. - Empty-auth fallback. No key configured and an empty
Authorizationheader also resolves toexternal. This dies the moment a key is set, and it is only safe because non-loopbackHostandOriginvalues are already refused. - Per-pane token. An agent pane's own token maps to
coreorfullfrom its project's Agent integrations setting. Neverexternal. See Agent panes below for what it can reach. - Help-session token. The assistant's own sessions. Pinned to the window that minted the token and to the action context captured at provision time, so calls dispatch against the worktree you had focused when you launched the assistant.
Anything else falls to the core baseline. If getTier finds no live transport at all the call fails closed with SESSION_GONE rather than defaulting to a tier: a revoked bearer must not quietly widen onto the in-app baseline.
The assistant's Tool set lives in Settings > Daintree Assistant > Security, defaults to Core, and applies from the next assistant session. See Daintree Assistant for what each set means in that context.
There is no off tier for the assistant. Turning its Daintree control off is a separate switch from choosing its tool set. A project's Agent integrations setting does have Off, its default, which simply gives that project's agents no Daintree MCP server.
Both tool sets can delete worktrees. At Core the assistant can delete any eligible worktree in the project, and an agent pane only one it created; Full adds tearing down a worktree's resources. Deletes and teardowns run project-defined teardown commands. Tier membership and confirmation are separate gates: read the settings preview before widening access, and see Host confirmation for when a delete still asks.
Agent panes
A project's Agent integrations setting (Settings > Project > General) decides whether the agents Daintree launches in that project's worktrees get the server: Off (the default for new projects), Core or Full. Daintree hands each newly launched agent a token of its own, through the mechanism that agent's CLI uses to merge extra MCP servers (a --mcp-config file for Claude Code, -c overrides for Codex, and equivalents for the other built-in CLIs), so nothing in your own agent config or the repository is changed. The token is revoked and any file deleted when the terminal exits. The setting only takes effect while the MCP server is on, and agents launched before a change keep the token they were given.
An agent pane's tier is an approval line rather than a ceiling. A pane set to Core sees the Full tool set in its listing, and a call to a Full tool asks you in Daintree's confirmation dialog instead of failing. The dialog offers Allow for the rest of this session, which lets that agent's later calls to the same tool run without asking, with any arguments, for up to 30 minutes. Approval never reaches past Full, and never reaches the assistant-only tools below.
An agent pane's input and cleanup are scoped to what it owns. Where the assistant has terminal.sendCommand, terminal.inject, terminal.sendKeys, terminal.close and worktree.delete, a pane gets the *Owned form of each, which acts only on terminals and worktrees that pane created (and, for input, terminals handed to it). Killing, restarting and bulk-closing terminals, injecting CopyTree context and opening the diagnostics review are reserved for the assistant. A pane keeps ownership of what it launched across MCP reconnects, idle reaps and server restarts, until the pane exits or is relaunched.
To let an orchestrating agent drive a terminal it did not create, right-click that terminal, open Hand to orchestrator and pick the agent pane. The submenu appears only while at least one agent pane holds a Daintree token. The confirmation names both and what the orchestrator gains: typing into the terminal and submitting, interrupting it, bringing it on screen and reading its last message, as if it had launched it. Daintree doesn't filter what it sends, so answering a prompt with 1 can approve a push. It cannot close the terminal. While handed over the terminal is marked Driven by the orchestrator, and Take back from the orchestrator on the same menu ends it.
Listing and dispatch authorization
Tier checks govern both tools/list and tools/call. Restricted or hidden actions remain unavailable. Discovery through actions.list, actions.search and actions.getSchema is filtered to the caller's effective surface, including eligible live grants and, for an agent pane, the tools it may ask for. Workspace-bound external sessions have the additional confirmation ceiling described under Background workspace limits. Discovery is not a way around these checks.
The assistant's own sessions also learn which tools exist above their tool set: discovery reports such a tool as unavailable and names the tool set that would permit it, so the assistant can tell you what to change instead of guessing. That is a name, never a permission. External clients never receive these entries.
Widening a session, and its limits
When the assistant calls a tool outside its tool set, the call is denied and a Tool not permitted banner names the tool and the tool set it needs. Two ways to widen, both time-bounded:
- Allow this tool mints a per-tool grant keyed on
(sessionId, toolId)with a 15-minute sliding TTL, refreshed on each successful dispatch, under a hard 30-minute wall-clock ceiling that the sliding window cannot extend. - Set project default saves the required tool set as the project's default for agent panes, and elevates this help session, returning it to its original tier after 30 minutes of awake time. Sleep and wake do not extend it.
Both TTLs sit at or under the 30-minute idle session timeout, so neither can outlive the session that holds it. Grant lifecycle events (grant.issued, grant.expired, grant.revoked) interleave with tool-call records in the audit log.
If the same (sessionId, toolId) pair is denied twice in a row the banner is suppressed for the rest of the session, but every denial still writes an audit record carrying bannerSuppressed: true. The counter resets when a grant is issued or the session ends.
Agent panes widen differently, by asking per call (see Agent panes). External API-key sessions do not widen at all.
Host confirmation and automation grants
Tools annotated danger: "confirm" are exposed and dispatchable when the tier permits, and normally dispatch unconfirmed so a human approves them in Daintree's own native confirmation dialog. The dialog shows the action title and description, who is asking (the client's user agent and key suffix, an agent pane, or the Daintree Assistant), why the action is gated, a preview of what it would touch where one exists (such as a worktree's uncommitted changes), a checklist when the action has several targets, and a redacted argument summary: long strings collapse to <string: N chars> and nested objects to <object>, to reduce accidental disclosure. Redaction is not a guarantee that every possible secret is recognized.
A client's self-declared elicitation.form capability is never treated as authorization. A headless client could answer its own elicitation and self-approve a destructive call, so authorization must come from Daintree. With no Daintree window open, a confirm-gated call is refused up front with CONFIRMATION_REQUIRED and confirmationChannel: "unavailable" rather than running unattended.
A few things can stand in for the dialog, each one a choice you made in Daintree, and each recorded on the audit record as the call's authorization:
- The assistant's Daintree confirmations. Settings > Daintree Assistant > Security > Daintree confirmations is Follow global setting (the default, which follows Settings > Agents > Skip permission prompts), Always ask, or Never ask. The confirmation dialog shows the same control when the assistant is asking, and a change applies from its next call. It covers the assistant's own sessions only.
- A project's Skip confirmations. At Full, a project's Agent integrations can turn on Skip confirmations, so that project's agent panes run everything Full allows without asking, deletes and teardowns included. It does not cover calls above the pane's tier.
- Allow for the rest of this session, given to an agent pane from the dialog (see Agent panes).
- A native automation grant, issued from the assistant's live session in Settings > Daintree Assistant: an explicit list of up to 20 tools, for a bounded number of uses and at most 30 minutes. The ordinary per-tool tier grant does not itself bypass confirmation.
The project setting, the session approval and native grants never cover a call whose dialog is where you choose which targets it touches (closing or killing several terminals at once, for example). A force delete that would discard uncommitted changes always asks you to type the worktree's name, whatever else is set.
The renderer cancels a pending confirmation after 28 seconds, two seconds inside the 30-second main-process dispatch deadline, so the audit log records a clean timeout rather than a torn-down dispatch. Concurrent confirm calls queue behind the visible dialog. While it is open the audit record sits at confirmation-pending and then resolves to approved, rejected or timeout; a rejection reaches the caller as USER_REJECTED.
Security posture over MCP
The MCP surface is the one place where a non-human caller reaches into a running habitat, so several boundaries exist only here.
- Project settings are not readable over MCP.
project.getSettingsis on neither tool set nor the external surface, so run commands (which may have a credential inlined by whoever wrote them) and secure environment variables do not cross the server. Every action result that does is parsed against the action's declared schema before it is returned, as a second boundary. - Introspection is scoped to the calling session's tier.
actions.list,actions.searchandactions.getSchemadescribe the caller's own surface, not the registry. - Confirm-gated calls require host approval, or a choice you made in Daintree, and never trust client elicitation. See above.
- Only Daintree's own assistant reaches terminals it did not open. Agent panes and API-key clients type into and interrupt only terminals they created or were handed, and close and delete only what they created. An agent running in a read-only sandbox therefore cannot type into your own shell through Daintree.
- Routing is bound or observable, never silent. A workspace-scoped session fails closed rather than falling through to another window; an unscoped one follows focus and can retarget mid-session. Either way every dispatch reports the workspace it resolved to: kind, id and path.
- Terminal dispatch requires an explicit terminal id. An agent or MCP caller sending input to "the terminal" is not resolved implicitly.
- There is no
fullToolSurfaceopt-in. External API keys remain on the curated external allowlist. - The
github.*action aliases were removed in v0.18.github.listIssues,github.listPullRequests,github.getIssueByNumber,github.checkCli,github.getRepoStatsandgithub.openPRdo not exist at any tier. Everything forge-shaped isforge.*and routes through the provider abstraction described in Code Forge.
For the process-level picture (sandboxing, IPC hardening, secret scrubbing, git hardening), see Security & Privacy.