From 8c535e4a32ab03adad7a92435dac2878566369fb Mon Sep 17 00:00:00 2001 From: Kyle Bernhardy Date: Wed, 8 Jul 2026 08:56:12 -0600 Subject: [PATCH] Correct custom mcpTools auth wording: invocable anonymously, no login gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #566. The "is the user logged in only" claim was wrong — custom tools register with visibleTo: () => true and the MCP route imposes no auth requirement, so anonymous sessions can list and call them. Now states that plainly and contrasts with the RBAC-filtered verb tools. Co-Authored-By: Claude Fable 5 --- reference/mcp/tools-and-resources.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reference/mcp/tools-and-resources.md b/reference/mcp/tools-and-resources.md index 4b050447..749f3032 100644 --- a/reference/mcp/tools-and-resources.md +++ b/reference/mcp/tools-and-resources.md @@ -106,7 +106,9 @@ class Orders extends Tables.orders { } ``` -The corresponding instance method runs through Harper's normal `transactional()` envelope, so per-record `allow*` predicates and audit logging behave the same way as regular verb dispatch. Authentication is "is the user logged in" only — finer-grained gating is the method's responsibility. +The corresponding instance method runs through Harper's normal `transactional()` envelope, so per-record `allow*` predicates and audit logging behave the same way as regular verb dispatch. + +**Custom tools are exposed to any MCP session — including anonymous, unauthenticated ones.** Unlike the auto-generated verb tools (which are RBAC-filtered per user at `tools/list` time and enforce table permissions on call), the MCP layer performs no authentication or ACL check for a custom tool: it is listed to every session and its method executes even when no user is logged in (`context.user` may be empty). Access control is entirely the method's responsibility — to restrict a tool to authenticated users or specific roles, check `context.user` (or rely on the per-record `allow*` predicates its data access triggers) inside the method and throw when the caller doesn't qualify. ### `exportTypes` gating