feat(plugins): mcp:tools permission and the mcpToolProvider hook

Modelled on the hook:* family rather than on geolocation:read. The host
dispatches INTO the child for every tool call, so it needs what
HOOK_PERMISSION buys: providersOf()'s active-and-holds-the-grant check,
the second gate in invokeHook, and the acting-user binding. That last one
is the point. The user is bound host-side from the supervisor's
invocation map, so a tool called by user A reaches A's data whatever the
model puts in args.

The permission keeps no hook: prefix because the surface it opens is MCP,
not a TREK render slot, and nothing keys off that prefix. It is the first
HOOK_PERMISSION value shaped that way; `satisfies` still holds.

One commit, because it cannot be split. requireTotalCoverage makes a
HOOK_PERMISSION key with no @PluginHook consumer a boot failure, not a
test failure, and PluginRpcRegistryService.onModuleInit runs in every
buildApp() — so a half-landed version breaks every integration test in the
repo. The generator is chained to it too: it refuses to run without both
the en admin label and the CLI hint.

15s is the longest budget of any read hook. The others back a render
someone is waiting on and fall back when they time out; this one backs a
chat turn, and the plugin is likely calling a third-party API of its own.
Still under the supervisor's unused 30s default, which is a hung client
rather than a budget.

One callTool fn for every tool, since tool names are runtime data and
hookContracts() is keyed by (hook, fn).

PluginDefinition exists in two copies with no generator between them, so
both get McpToolProvider. grantGaps and the dev mock host need no change:
both read HOOK_PERMISSION, which is generated.

PLUGHOOK-010, plus the CONTRACTS row.
This commit is contained in:
Renzo Beux
2026-08-28 13:32:19 -03:00
committed by Maurice
parent 092223c259
commit 21f4a1241b
31 changed files with 145 additions and 0 deletions
+2
View File
@@ -327,6 +327,8 @@ const admin: TranslationStrings = {
'Dołączanie wpisów czasowych do planu dnia (postoje na ładowanie, bufory czasowe)',
'admin.plugins.perm.hook:day-tint-provider':
'Oznaczanie dni w planie dnia kolorami (na przykład do którego etapu podróży należy dany dzień)',
'admin.plugins.perm.mcp:tools':
'Publikowanie narzędzi, które asystent AI może uruchomić w Twoim imieniu (działa z uprawnieniami nadanymi tutaj wtyczce, nie z własnymi)',
'admin.plugins.perm.geolocation:read':
'Odczytywanie Twojej aktualnej lokalizacji, gdy otwarty jest któryś z jego widoków (TREK odczytuje ją z uprawnieniem do lokalizacji tej witryny, a nie z własnym uprawnieniem wtyczki)',
'admin.plugins.perm.hook:pdf-section-provider': 'Dołączanie sekcji tekstowych do eksportu PDF podróży',