Skip to content

Replace the MCP access level with tool permissions - #8688

Merged
andypalmi merged 8 commits into
feat/mcp-token-tool-permissions-enforcementfrom
feat/mcp-tool-permissions-ui
Oct 1, 2026
Merged

andypalmi merged 8 commits into
feat/mcp-token-tool-permissions-enforcementfrom
feat/mcp-tool-permissions-ui

Conversation

@andypalmi

@andypalmi andypalmi commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Description

Replaces the single read-only access level in the MCP consent screen with a tool-permissions grid, so a user granting access can choose read / write / destructive per tool group, and override those choices per team.

Stacked on #8687.

  • Replaces the Access Level choice (Full access / Read-only) with a read/write/destructive grid per tool group (Platform, Flow Building). The grid is now the source of truth; the legacy readOnly flag is derived on the backend (Store tool permissions on MCP tokens #8660).
  • New McpToolPermissions component: enabling write implies read, disabling read clears write and destructive.
  • Consent opens with team access preset to "All teams" and a permission preset (Platform read and write, Flow Building read, write, destructive) applied to every team unless customised per team, and sends toolPermissions: { default, teams }.
  • A tooltip on Destructive explains it covers tools that delete or overwrite data, or change what is running.

Test plan

  • npm run test:unit:frontend
  • Unit tests for the grid component (category dependencies, tooltip) and the consent screen (default and per-team payloads, team scope changes, expiry validation)
  • Grant access with default permissions and confirm the token reflects them
  • Customise one team, grant access, and confirm that team's override is applied while other teams use the default

Screenshots

Before and after the change:

Before After (default landing)
Before: single Access Level with Full access and Read-only After: per-group read/write/destructive grid, all teams on the preset

The preset (Platform read and write, Flow Building read, write and destructive) is what the user lands on. Teams start on that preset and read "Default" until edited. The note under the grid changes with team scope: all teams, selected teams, or "not used" when every selected team is customised.

Other states

Editing a team gives it its own grid, marks it "Custom", and offers Reset:

A team expanded with its own grid, marked Custom with Reset and Close

When specific teams are selected and every one is customised, the default grid is disabled and marked as not used:

The default grid greyed out with the note that it is not used

Related Issue(s)

Part of #8659.
closes #8662

Checklist

  • I have read the contribution guidelines
  • Suitable unit/system level tests have been added and they pass
  • Documentation has been updated
    • Upgrade instructions
    • Configuration details
    • Concepts
  • Changes flowforge.yml?
    • Issue/PR raised on FlowFuse/helm to update ConfigMap Template
    • Issue/PR raised on FlowFuse/CloudProject to update values for Staging/Production
  • Link to Changelog Entry PR, or note why one is not needed.

Labels

  • Includes a DB migration? -> add the area:migration label

@andypalmi
andypalmi added this pull request to stack #8690 September 29, 2026 10:35
@andypalmi
andypalmi requested a review from cstns September 29, 2026 10:43
@codecov

codecov Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.77%. Comparing base (f36de9f) to head (2ed4977).

Additional details and impacted files
@@                             Coverage Diff                              @@
##           feat/mcp-token-tool-permissions-enforcement    #8688   +/-   ##
============================================================================
  Coverage                                        77.77%   77.77%           
============================================================================
  Files                                              474      474           
  Lines                                            25530    25530           
  Branches                                          6798     6798           
============================================================================
  Hits                                             19857    19857           
  Misses                                            5673     5673           
Flag Coverage Δ
backend 77.77% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cstns cstns mentioned this pull request Sep 30, 2026
13 of 21 tasks
@andypalmi
andypalmi force-pushed the feat/mcp-tool-permissions-ui branch from cd208f1 to 5d7f9e2 Compare September 30, 2026 10:49

@cstns cstns 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.

The grid and the per-team editing work nicely, and the payload lines up with what the backend expects. Two things I'd like changed before this goes in, both about what the user lands on: Destructive starts on for Flow Building, and "All teams" is preselected again. Together they mean one click on Allow hands over every team with destructive flow tools enabled. Details are inline, along with a few smaller bits.

The two manual checks in the test plan are still open too. Might be worth running them once the defaults change.

function defaultToolPermissions () {
return {
platform: { read: true, write: true, destructive: false },
flow_building: { read: true, write: true, destructive: true }

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.

#8662 asks for Read and Write pre-selected with Destructive off, and the reason for the whole epic (#8659) is that the user has to opt in to destructive tools explicitly. With this preset, clicking Allow lets the agent remove nodes, overwrite flows and deploy without anyone choosing that. Could Flow Building start on read + write like Platform?

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.

I'd lean the other way here and would like your view. With Destructive off, the agent can't remove nodes, tabs or wires, or deploy, until the user re-authenticates and changes the permissions. Deploy Flows is destructive, so even after a team turns on AI Flow Deploy the user would have to re-authenticate again before the agent can deploy. Starting Flow Building on read + write + destructive keeps build-and-deploy working from one consent, and the user still sees the grid and has to click Allow. As this is the decision the epic is about, @Steve-Mcl @dimitrieh @ZJvandeWeg could you weigh in on the default? @cstns what do you think?

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.

Kept as is: Flow Building still starts with read, write and destructive on, and Platform with read and write. The team scope is now the deliberate choice (see the other thread), which was the main concern.

// No defaults for access level/team scope: the user must make an explicit choice before Allow enables
accessLevel: null,
teamScope: null,
teamScope: 'all',

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.

This brings back the preselected "All teams" that #8419 removed (#8417). The fastest path was blindly clicking Allow and giving the agent access to everything, so both choices were left empty and Allow stayed disabled until the user picked one. The grid needs a starting state, but team scope could stay empty like before.

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.

I think preselecting all teams is less friction. The user still has to click Allow, so it stays their decision, and most MCP consent screens start with everything selected. The blind-click risk is also limited by the permission defaults: Platform starts on read + write with Destructive off, so a click through can't run destructive platform tools. Flow Building's default is the other open question in the thread above. I do see the concern from #8419, so I'd like to hear from you and from @Steve-Mcl @dimitrieh @ZJvandeWeg on whether team scope should start empty.

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 with Serban: no team scope is selected when the screen loads, so Allow stays disabled until the user chooses All teams or Specific teams. The Platform and Flow Building defaults are unchanged. Pushed in 2ed4977.

v-if="isCustom(team.id)"
type="button"
class="text-blue-600 hover:underline"
data-action="reset-team-default"

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.

Small one: these are hand-styled <button>s. ff-button with kind="tertiary" and size="small" would match the rest of the UI.

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.

Done, both are ff-button with kind="tertiary" and size="small" now.

template: '<span v-if="readOnly" class="ff-badge ff-badge--info">Read Only</span><span v-else></span>'
props: ['readOnly', 'toolPermissions', 'teams'],
template: `
<span v-if="toolPermissions" class="ff-badge ff-badge--info" :title="tooltip" style="cursor:help">Custom permissions</span>

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.

After the backfill every MCP token has a grant, so every MCP token gets "Custom permissions", even on plain defaults, and "Read Only" never shows for them. The tooltip also shows the raw keys (platform, flow_building) and uses a native title. v-ff-tooltip, which the grid already uses, with "Platform" / "Flow Building" labels would read better. Maybe a short summary like "Read only" / "Read + write" / "Custom" based on what the grant actually allows, too?

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.

The list now shows "Read only", "Read + write" or "Custom" from what the grant allows. Custom covers destructive, different levels per group, or any team override. The tooltip uses v-ff-tooltip with "Platform" and "Flow Building" labels, plus a count of teams with custom permissions. Would it be OK to do a structured per-team view on this page, and a way to change permissions there, as a follow-up? Today editing an MCP token means revoking and re-consenting.

andypalmi added 2 commits October 1, 2026 12:37
…on the consent page

The tokens list labels a token with a grant as Read only, Read + write or Custom from what the grant allows, with a tooltip naming the Platform and Flow Building levels and any team overrides. The per-team Edit and Reset actions on the consent page use ff-button.
@andypalmi

Copy link
Copy Markdown
Contributor Author

I'll run the two manual checks once the defaults are settled.

@andypalmi
andypalmi requested a review from cstns October 1, 2026 10:50
@andypalmi
andypalmi merged commit 4184afe into main Oct 1, 2026
29 checks passed
@andypalmi
andypalmi deleted the feat/mcp-tool-permissions-ui branch October 1, 2026 15:30

This branch was successfully deployed

1 active deployment
staging — 2ed49774 Deployed Oct 1, 2026 by andypalmi via Remove application #12069
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.

Replace the MCP access level with tool permissions

2 participants