Skip to content

feat(plugin): hide tools per request with a snapshot hook - #47680

Draft
Hona wants to merge 1 commit into
v2from
tool-snapshot-hook
Draft

feat(plugin): hide tools per request with a snapshot hook#47680
Hona wants to merge 1 commit into
v2from
tool-snapshot-hook

Conversation

@Hona

@Hona Hona commented Sep 6, 2026

Copy link
Copy Markdown
Member

Adds a tool.snapshot plugin hook so a plugin can hide tools for one model request based on the session and agent. This is the missing piece for per-session availability: registrations stay Location-wide, but what a request sees can now vary.

  • Fires once per model request in Tool.Service.snapshot(permissions, request), after permission filtering.
  • Receives the permitted effective tool names; removing a name hides the tool from both the native list and the Code Mode catalog, so the rendered catalog and the execute runtime stay consistent.
  • Hooks can only remove names. Added names are ignored, so a plugin cannot reveal a tool that permissions denied.
  • Visibility only. A hidden tool still enforces its own permission if it is ever executed.
  • Works through the existing PluginHooks path, so the Promise API gets it with a type addition only.
// Hide browser tools unless a desktop browser is attached to this session
await ctx.tool.hook("snapshot", (event) => {
  if (!browsers.has(event.sessionID)) event.tools = event.tools.filter((name) => !name.startsWith("browser_"))
})
flowchart LR
  A[Registered tools<br/>Location-wide] --> B[Permission filter<br/>agent ruleset]
  B --> C[tool.snapshot hook<br/>sessionID, agent, tools]
  C --> D[Native definitions]
  C --> E[Code Mode inventory<br/>catalog + execute runtime]
Loading
interface ToolHooks {
  snapshot: {
    readonly sessionID: Session.ID
    readonly agent: Agent.ID
    /** Effective tool names advertised to this request. Remove names to hide tools; added names are ignored. */
    tools: string[]
  }
  "execute.before": ...
  "execute.after": ...
}

Why a hook rather than a per-tool predicate: it needs no change to Tool.Info, one registration covers a whole namespace, and it reuses the per-request hook infrastructure already used by execute.before. MCP catalogs keep updating live through reload(); that remains the right tool for location-wide changes.

Follow-up: the browser plugin will use this to hide its 44 Code Mode tools in sessions without an attached desktop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant