Add gated tool live invocation and snippets - #79
Merged
Conversation
Signed-off-by: Pratik Gandhi <gandhipratik203@gmail.com>
gcgoncalves
requested changes
Aug 26, 2026
Signed-off-by: Pratik Gandhi <gandhipratik203@gmail.com>
gcgoncalves
approved these changes
Aug 26, 2026
vishu-bh
requested changes
Aug 26, 2026
vishu-bh
left a comment
Contributor
There was a problem hiding this comment.
Approach is good, few things to check before merging
Signed-off-by: Pratik Gandhi <gandhipratik203@gmail.com>
vishu-bh
approved these changes
Aug 26, 2026
vishu-bh
left a comment
Contributor
There was a problem hiding this comment.
Thanks for addressing the comments!!
LGTM 🐎
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
In simple terms: PR #53 added the Try-it shell, and PR #55 made preview results readable. This PR adds the guarded path for calling a real tool from that same surface, plus copyable MCP
tools/callsnippets.It adds UI support for:
/rpcroutetools.executeandservers.useRBAC gating before any annotation-based live invoke decisionreadOnlyHint: truetoolsdestructiveHint: truetools, withdestructiveHinttaking priority over conflictingreadOnlyHintnotifications/cancelledBefore / After
Context
Notes
api.post("/rpc", ...); the API client resolves that to same-origin/api/rpc, and the BFF proxies upstream.tools/callwithparams.name = tool.nameandparams.arguments = args.server_id; backend name resolution usesDbTool.namefor this route shape.errorbodies are treated as failures even when HTTP status is 200, including permission errors like-32003.MCPGATEWAY_URL/rpcwithAuthorization: Bearer $MCPGATEWAY_BEARER_TOKEN, not the browser-only/api/rpcURL.2025-11-25, which is supported by the backend. No unsupported2026-07-28variant is emitted./rpcnotifications/cancelledmessage for the active JSON-RPC id before aborting the browser request. The REST/v1/cancellation/cancelendpoint is admin-scoped today, so this stays frontend-only and uses the backend's existing owner-authorized MCP path.tools.executeandservers.use; each missing permission has a distinct disabled state.VITE_ENABLE_TOOL_PREVIEWTry-it feature flag.Authorization,Cookie,Forwarded,X-Forwarded-*, andX-Real-IPare not forwarded from this surface.Tests
npm run lintnpm run format:checknpm run generate./node_modules/.bin/tsc -bnpm run testnpm run buildHEADLESS=1 node tool-live-invoke-manual.mjsPLAYWRIGHT_SKIP_WEBSERVER=1 PLAYWRIGHT_BASE_URL=http://127.0.0.1:5173 npm run e2e -- e2e/tools.spec.ts -g "live invokes|confirms destructive|tools.execute|servers.use|federated|cancellation"git diff --checkManual verification
Manual test steps
Setup
Save the mock script from the next collapsible at the repo root as
tool-live-invoke-manual.mjs.Two terminals:
Terminal B opens a Chrome for Testing window with
/auth/session,/api/rbac/my/permissions,/api/tools,/api/gateways, and/api/rpcmocked. Ctrl-C in terminal B to close. Do everything in that window, in the tab it opens.Optional RBAC-denied modes:
Steps
1. Open More options for live-lab -> View details.
Expect: the details drawer opens with Try it selected.
2. Confirm all tool chips are visible:
live_readonly_search,live_jsonrpc_error,live_slow_tool,local_destructive_cleanup,federated_destructive_blocked, andlocal_untagged_blocked.3. Select
live_readonly_search. Fillquerywithcloudflareandlimitwith5. Add headerX-Tenant-Idwith valueteam-a, then click Live invoke.Expect: Live invoke 200 and Live result for live_readonly_search. Terminal B should show
/api/rpcwithmethod: "tools/call",params.name: "live_readonly_search", noserver_id, andx-tenant-id: team-a.4. Inspect the snippet tabs.
Expect:
curl,JSON-RPC,Python, andTypeScripttabs render with an MCP 2025-11-25 badge. Snippets targetMCPGATEWAY_URL/rpc, not browser-only/api/rpc.5. Select
live_jsonrpc_errorand click Live invoke.Expect: Live invoke failed -32003 and Mock JSON-RPC permission denied from body, even though the mocked HTTP status is 200.
6. Select
local_destructive_cleanupand click Live invoke.Expect: an Invoke destructive tool confirmation. Clicking Cancel sends no
/api/rpcrequest; clicking Invoke tool sends exactly one request and renders Destructive invoke confirmed and completed.7. Select
federated_destructive_blocked.Expect: Live invoke is not offered for federated tools without readOnlyHint. and the live invoke button is disabled.
8. Select
local_untagged_blocked.Expect: Live invoke is not offered until the tool declares readOnlyHint or destructiveHint. and the live invoke button is disabled.
9. Select
live_slow_tooland click Live invoke.Expect: Invoking... plus Cancel request. Click Cancel request; terminal B should show a second
/api/rpcrequest withmethod: "notifications/cancelled"andparams.requestIdmatching the originaltools/callid.10. Stop Terminal B and rerun with
PERMISSIONS=NO_EXECUTE node tool-live-invoke-manual.mjs. Open the drawer again and select a read-only tool.Expect: Live invoke requires tools.execute. and the live invoke button is disabled.
11. Stop Terminal B and rerun with
PERMISSIONS=NO_SERVERS_USE node tool-live-invoke-manual.mjs. Open the drawer again and select a read-only tool.Expect: Live invoke requires servers.use. and the live invoke button is disabled.
Teardown
Ctrl-C both terminals. If :5173 is stuck:
Mock script (tool-live-invoke-manual.mjs)
Save at the repo root. Requires
@playwright/test, already a dev dependency; runnpx playwright install chromiumif the browser is missing.Manual test results
Latest verification was run against this PR head. Browser launch required running Playwright outside the sandbox in this local environment for the manual smoke check.
node --check tool-live-invoke-manual.mjsexits cleanlyHEADLESS=1 node tool-live-invoke-manual.mjslogstools card: okandpermissions mode: full accessMCPGATEWAY_URL/rpcwith MCP 2025-11-25live_jsonrpc_errorrenders Live invoke failed -32003 even though the mock returns HTTP 200/api/rpcrequest withmethod: "notifications/cancelled", reason"user", andparams.requestIdmatching the originaltools/callidtools.executedenial,servers.usedenial, and federated gate passnpm run testcompletesnpm run buildcompletesgit diff --checkcompleteFocused command used for live-invoke browser coverage:
PLAYWRIGHT_SKIP_WEBSERVER=1 PLAYWRIGHT_BASE_URL=http://127.0.0.1:5173 npm run e2e -- e2e/tools.spec.ts -g "live invokes|confirms destructive|tools.execute|servers.use|federated|cancellation"Scope of this verification: the manual script is mock-backed. It covers frontend behavior for MCP JSON-RPC payload construction, passthrough headers, snippets, JSON-RPC error bodies, destructive confirmation, annotation gates, RBAC gating, and MCP cancellation request emission. It does not verify execution against a real upstream tool.