Repository navigation
Workspace approval policies are not enforced on toolkit-scoped MCP endpoints (/mcp/toolkits/<slug>) — gated tools dispatch without approval #1752
Description
Executor version
Executor Cloud (hosted, executor.sh), tested 2026-08-26. Same toolkit routing code path as the /mcp/toolkits/<slug> endpoints.
Summary
Workspace tool policies (require_approval) are enforced on the base /mcp endpoint but are silently skipped on toolkit-scoped endpoints (/mcp/toolkits/<slug>). A tool that is gated behind an approval policy at the workspace level runs immediately, with no pause and no approval prompt, when the same call is made through a toolkit endpoint. The approval mode is irrelevant — URL approval, native elicitation, and model-side approval all bypass equally on toolkit endpoints.
Because toolkits are the mechanism for handing a curated tool set to a team, this means policy governance is absent on exactly the surface where least-privilege delegation is expected to apply.
Reproduction
- Create a workspace (
org-owned) policy:require_approvalon a read tool, e.g.<integration>.contacts.getById(also tested with an embedded-wildcard pattern<integration>.*.*.contacts.getById). Confirm it appears under Active policies, scoped to Workspace. - Via the
executemeta-tool on the base/mcpendpoint, call that tool. - Via the
executemeta-tool on a toolkit endpoint/mcp/toolkits/<slug>bound to the same workspace/connection, call the identical tool with the identical arguments.
Expected
Both endpoints evaluate the workspace policy and pause the execution for approval (waiting_for_interaction + executionId), regardless of endpoint scope.
Actual
| Endpoint | Approval mode | Result |
|---|---|---|
base /mcp |
URL approval | ✅ Pauses → approval URL → decline propagates and blocks the call |
base /mcp |
native elicitation | elicitation capability (separate issue, noted below) |
/mcp/toolkits/<slug> |
native approval | ❌ Runs immediately, returns full record, no pause |
/mcp/toolkits/<slug> |
URL approval | ❌ Runs immediately, returns full record, no pause |
/mcp/toolkits/<slug> |
model approval | ❌ Runs immediately, returns full record, no pause |
On the base endpoint the policy fired correctly and a user decline propagated back as a blocked tool call. On every toolkit endpoint the same gated call returned the underlying record (which in our case contained third-party PII) with no policy evaluation at all. Reproduced repeatedly across all three toolkit approval modes.
Analysis / likely cause
The policy check appears to be wired into the executor constructed for the default /mcp resource but not into the toolkit-scoped executor built in createConfigForResource for resource.kind !== "default". The toolkit executor resolves the same connections and dispatches tools, but the workspace-policy guard that gates dispatch on the base path is not applied on the toolkit path — so require_approval (and, by extension, very likely block) is not evaluated for toolkit-scoped invocations.
This is the same class of defect as #1384 (an authorization gate — there, granted OAuth scope — that exists in configuration but is never evaluated at dispatch), and it fits the pattern in #1520 where toolkit MCP endpoints diverge from the base endpoint's behaviour in another subsystem. It is distinct from #1618 / #1406, which are local-daemon 500s on toolkit routes (there the toolkit route fails closed; here it fails open).
Impact
- Governance bypass: any workspace
require_approvalpolicy can be circumvented by routing the call through a toolkit endpoint. Since agents call tools throughexecuteby default, this is the normal path, not an edge case. - Likely affects
blocktoo: if the guard isn't consulted on toolkit dispatch, "blocked" tools may also be reachable via toolkit endpoints (not yet tested — flagging for the maintainer). - Least-privilege inversion: toolkits are the intended delegation surface for teams, so the one place a workspace owner most expects policy to hold is the one place it doesn't.
Suggested fix
Apply the same workspace/policy guard used for the default resource when constructing the toolkit-scoped executor in createConfigForResource, and add a regression test that (a) sets a require_approval policy and (b) asserts a toolkit-endpoint invocation of the gated tool pauses rather than dispatching. Worth also asserting block on a toolkit endpoint.
Secondary observation (separate, minor)
On the base /mcp endpoint, the native elicitation approval mode errors the execution when the connected MCP client does not advertise the elicitation capability, rather than falling back to a URL/redirect approval or returning a clear "client cannot approve" result. URL approval is unaffected and is the safe default for clients without elicitation support. Happy to split this into its own issue if useful.
Created via ASI MCP
Requested by: lvickery@asi.co.nz
Session: dec48a1d807caa26f9b5c959033ec9dc3f5a97f7706fb0767998f69d8164ad7b
Activity
Adityakk9031 commentedon Aug 29, 2026
Opened PR #1846 to fix this issue by combining workspace policies ( ool_policy table) with active toolkit policy providers under least-privilege resolution.
fix(sdk): enforce workspace approval and block policies on toolkit en…
RhysSullivan commentedon Oct 8, 2026
We're clearing the backlog ahead of the v2 launch, so we're closing this. If it still applies to v2, please open a new issue or PR against v2.
Sent from my Claude