Skip to content

HITL: "Always allow this tool" via set_tool_approval gateway meta-tool - #20

Merged
pragati-agrawal-glean merged 15 commits into
mainfrom
pragati/hitl-always-allow
Sep 18, 2026
Merged

pragati-agrawal-glean merged 15 commits into
mainfrom
pragati/hitl-always-allow

Conversation

@pragati-agrawal-glean

@pragati-agrawal-glean pragati-agrawal-glean commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Add an Always Allow flow for approval-gated Glean MCP tools.

This PR implements the feature directly in the shared Glean MCP adapter used by this repository. It is a standalone implementation, not a dependency on another plugin repository.

  • Show an initial Accept/Decline prompt for the current tool call.
  • After Accept, show a separate five-second Always Allow follow-up.
  • Persist only an explicit follow-up Accept through set_tool_approval with ALWAYS_ALLOWED.
  • Execute the already-approved call once regardless of the follow-up result.
  • Keep initial approval failures fail-closed.
  • Treat follow-up No, cancel, timeout, and errors as non-persistent while still executing the already-approved call.
  • Skip subsequent prompts through a process-local approval fast path until discovery reflects the persisted grant.

The implementation lives in the shared MCP source. It is included in the Claude and Codex local MCP targets. The Cursor target does not bundle this local MCP adapter and continues to use its separately connected MCP integration.

Validation

  • npm run test:bundle — 340 tests passed
  • npm run typecheck:bundle
  • npm test — build and validation passed for Claude, Cursor, and Codex

— sent via Glean Tau

Fall back to the existing approval flow when the remote lookup fails or returns malformed data, with regression coverage for approval, denial, cancellation, timeout, and recovery.

— sent via Glean Tau
Use downstream annotations matched by server and tool when get_tool_approval fails. Require approval for write, destructive, unknown, or conflicting metadata, and keep successful remote decisions authoritative.

— sent via Glean Tau

@eshwar-sundar-glean eshwar-sundar-glean left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving since its a port. Hope you have tested E2E

* metadata remains cached: inputSchema for argument shaping, and downstream
* annotations for the read-only fallback when the remote lookup fails.
*/
function sanitizeSkillFile(filePath: string, text: string): string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we okay doing this? would this require a network call always now?
Read tools are always allow anyway right, can we use that information to optimize network call count from the client?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that we should optimize for read tools. Fixed, now we retain read-only annotations and use them to skip approval checks entirely. Approval preferences are still excluded from the cache, so write tools use current remote settings.


let requiresApproval = true;
try {
requiresApproval = await getToolApproval(remoteClient, serverId, toolName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#blocking, please clarify
Majority of tool calls would be read only tools right? and we dont allow setting approval bits for read only tools right? is this network call always required?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks for pointing out. Read-only tools now execute directly without an approval lookup or HITL prompt. Write tools still call get_tool_approval, and an explicit “Always Allow” choice is saved through set_tool_approval.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Make sure our idea of read only tools and what the glean server treats as read only tools are the same. If you have checked that and verified it end to end, code LGTM and can merge

@eshwar-sundar-glean eshwar-sundar-glean left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to address my comments before merge on performance front

Execute known read-only tools directly. Keep live approval lookups and explicit Always Allow persistence for write tools, with regression coverage for remote revocation.

— sent via Glean Tau
Comment thread shared/glean/mcp/src/tools/run-tool.ts Outdated
}

const remoteArgs = buildRemoteArgs(serverId, toolName, resolvedArgs);
// Read-only tools need no approval lookup, host capability check, or prompt.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#nit
I feel " host capability check or prompt" and stuff is not required, just add "Does not need approval lookup because Glean does not allow changing preferences for read tools" the later is the important part

@eshwar-sundar-glean eshwar-sundar-glean left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Make sure our idea of read only tools and what the glean server treats as read only tools are the same. If you have checked that and verified it end to end, code LGTM and can merge

Explain why read-only tools skip approval lookups and document the canonical Glean predicate. Exercise all valid annotation combinations through skill caching and execution without changing runtime behavior.

— sent via Glean Tau
@pragati-agrawal-glean
pragati-agrawal-glean merged commit 8e3cf39 into main Sep 18, 2026
1 check passed
@pragati-agrawal-glean
pragati-agrawal-glean deleted the pragati/hitl-always-allow branch September 18, 2026 19:33
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.

2 participants