feat(mcp): make write policy per-account with a server ceiling #75

Merged
Claude-Run merged 1 commit from feat/FJ-56-per-account-write-policy into main 2026-07-18 17:51:06 +02:00
Member

The Forgejo MCP write policy moves from one process-wide value to a per-account choice bounded by a server-level ceiling, so a user chooses the risk on their own Forgejo account while an operator can still bound what the deployment permits at all. The effective policy for a call is the intersection of the ceiling and the account's own opt-ins, resolved per request, and defaults to deny.

Each account stores allow_edit / allow_delete / allow_global_write on its instance row (migration 1001, all defaulting to 0), so a fresh account can perform no mutating tool call until it opts in and replacing the instance token preserves the policy. Over HTTP the FORGEJO_MCP_ALLOW_* env vars (and the serve flags) change meaning from the effective policy to the ceiling: the most any account may enable, not a permission every account then has. An operator upgrading with them set is granting a maximum, not turning writes on for everyone.

require(Tier) still gates on a single resolved WritePolicy: on stdio that is the identity's effective policy (unchanged), and over HTTP it is the ceiling intersected with the account's stored opt-ins. A denied call now distinguishes "your account has not enabled this tier" (tick the box on the instance page) from "this deployment forbids this tier" (ask the operator), because those need different actions. stdio keeps reading FORGEJO_MCP_ALLOW_* as its effective policy exactly as before: it has one identity and no accounts, so the ceiling concept does not apply.

The instance page gains three write-policy toggles reflecting the account's stored choice; a tier the ceiling forbids renders disabled and explained rather than hidden, and a save preserves a ceiling-forbidden stored opt-in rather than clearing it. The README, the CLI help, and CLAUDE.md document the env vars' change of meaning.

#FJ-56

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

The Forgejo MCP write policy moves from one process-wide value to a per-account choice bounded by a server-level ceiling, so a user chooses the risk on their own Forgejo account while an operator can still bound what the deployment permits at all. The effective policy for a call is the intersection of the ceiling and the account's own opt-ins, resolved per request, and defaults to deny. Each account stores allow_edit / allow_delete / allow_global_write on its instance row (migration 1001, all defaulting to 0), so a fresh account can perform no mutating tool call until it opts in and replacing the instance token preserves the policy. Over HTTP the FORGEJO_MCP_ALLOW_* env vars (and the serve flags) change meaning from the effective policy to the ceiling: the most any account may enable, not a permission every account then has. An operator upgrading with them set is granting a maximum, not turning writes on for everyone. require(Tier) still gates on a single resolved WritePolicy: on stdio that is the identity's effective policy (unchanged), and over HTTP it is the ceiling intersected with the account's stored opt-ins. A denied call now distinguishes "your account has not enabled this tier" (tick the box on the instance page) from "this deployment forbids this tier" (ask the operator), because those need different actions. stdio keeps reading FORGEJO_MCP_ALLOW_* as its effective policy exactly as before: it has one identity and no accounts, so the ceiling concept does not apply. The instance page gains three write-policy toggles reflecting the account's stored choice; a tier the ceiling forbids renders disabled and explained rather than hidden, and a save preserves a ceiling-forbidden stored opt-in rather than clearing it. The README, the CLI help, and CLAUDE.md document the env vars' change of meaning. #FJ-56 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(mcp): make write policy per-account with a server ceiling
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 29s
Create release / Create release from merged PR (pull_request) Has been skipped
528f03c7f7
The Forgejo MCP write policy moves from one process-wide value to a per-account choice bounded by a server-level ceiling, so a user chooses the risk on their own Forgejo account while an operator can still bound what the deployment permits at all. The effective policy for a call is the intersection of the ceiling and the account's own opt-ins, resolved per request, and defaults to deny.

Each account stores allow_edit / allow_delete / allow_global_write on its instance row (migration 1001, all defaulting to 0), so a fresh account can perform no mutating tool call until it opts in and replacing the instance token preserves the policy. Over HTTP the FORGEJO_MCP_ALLOW_* env vars (and the serve flags) change meaning from the effective policy to the ceiling: the most any account may enable, not a permission every account then has. An operator upgrading with them set is granting a maximum, not turning writes on for everyone.

require(Tier) still gates on a single resolved WritePolicy: on stdio that is the identity's effective policy (unchanged), and over HTTP it is the ceiling intersected with the account's stored opt-ins. A denied call now distinguishes "your account has not enabled this tier" (tick the box on the instance page) from "this deployment forbids this tier" (ask the operator), because those need different actions. stdio keeps reading FORGEJO_MCP_ALLOW_* as its effective policy exactly as before: it has one identity and no accounts, so the ceiling concept does not apply.

The instance page gains three write-policy toggles reflecting the account's stored choice; a tier the ceiling forbids renders disabled and explained rather than hidden, and a save preserves a ceiling-forbidden stored opt-in rather than clearing it. The README, the CLI help, and CLAUDE.md document the env vars' change of meaning.

#FJ-56

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Run deleted branch feat/FJ-56-per-account-write-policy 2026-07-18 17:51:06 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pandoras-box/forgejo-cli!75
No description provided.