Today AegisGitea-MCP is read-only by design. This issue tracks adding write capability so the AI can not only inspect but also act on the Gitea environment — with the intent of giving it as complete access as possible through MCP tool calls.
Requested change
Expose write tools alongside the existing read-only ones, covering as much of the Gitea surface as practical:
Repository content: create/edit files, commits (where the API allows)
Labels & milestones: create/update
Anything else the Gitea API exposes that fits the "complete access" intent
The aim is that the AI can drive a full workflow end-to-end, not just read state.
Design notes / considerations
This deliberately reverses the original read-only posture, so it's worth being explicit about how to do it safely rather than just flipping a flag:
Keep it opt-in. A write mode toggle (env var / config) so read-only stays the default and full access is a conscious choice, not the baseline.
Bot user scoping. Access is already managed through a dedicated bot user inside Gitea — that user's permissions become the real ceiling on "complete access," so scope it intentionally.
Auditability. The project's value is that every action is an explicit, auditable MCP tool call. Write actions should log at least as clearly as reads.
Fix the known PAT bypass first. The earlier security audit flagged a PAT bypass and an open-redirect issue. Granting full write on top of an unpatched bypass is the risky combination — those should land before (or together with) write mode.
Acceptance
Write tools implemented and gated behind an explicit opt-in mode
Audit logging covers write actions
Known PAT bypass / open-redirect remediated
README documents the read-only vs full-access modes and the security trade-off
## Goal
Today AegisGitea-MCP is read-only by design. This issue tracks adding **write capability** so the AI can not only inspect but also act on the Gitea environment — with the intent of giving it as complete access as possible through MCP tool calls.
## Requested change
Expose write tools alongside the existing read-only ones, covering as much of the Gitea surface as practical:
- **Issues**: create, comment, update (title/body/state), label, assign, close/reopen
- **Pull requests**: create, comment, review, merge
- **Branches & tags**: create branches, create releases/tags
- **Repository content**: create/edit files, commits (where the API allows)
- **Labels & milestones**: create/update
- Anything else the Gitea API exposes that fits the "complete access" intent
The aim is that the AI can drive a full workflow end-to-end, not just read state.
## Design notes / considerations
This deliberately reverses the original read-only posture, so it's worth being explicit about how to do it safely rather than just flipping a flag:
- **Keep it opt-in.** A `write` mode toggle (env var / config) so read-only stays the default and full access is a conscious choice, not the baseline.
- **Bot user scoping.** Access is already managed through a dedicated bot user inside Gitea — that user's permissions become the real ceiling on "complete access," so scope it intentionally.
- **Auditability.** The project's value is that every action is an explicit, auditable MCP tool call. Write actions should log at least as clearly as reads.
- **Fix the known PAT bypass first.** The earlier security audit flagged a PAT bypass and an open-redirect issue. Granting full write on top of an unpatched bypass is the risky combination — those should land before (or together with) write mode.
## Acceptance
- [ ] Write tools implemented and gated behind an explicit opt-in mode
- [ ] Audit logging covers write actions
- [ ] Known PAT bypass / open-redirect remediated
- [ ] README documents the read-only vs full-access modes and the security trade-off
Checked the current main against all four acceptance criteria. All met:
Write tools behind explicit opt-in mode — 16 write handlers in tools/write_tools.py; WRITE_MODE=false by default; scope write:repository; policy enforced via is_write=tool_def.write_operation.
Audit logging covers write actions — every dispatch goes through audit.log_tool_invocation / log_access_denied on the hash-chained audit log.
PAT bypass / open-redirect remediated — _verify_user_repository_access runs before any service-PAT use plus the service_pat_requires_repository_target guard (server.py:1210-1237); is_redirect_uri_allowed allowlist enforced on the authorize proxy, callback and DCR registration (server.py:842/888/990). Path-traversal on ref/sha/base/head also fixed (#18).
Repository content writes (create/edit files, commits) — not implemented; tools/repository.py is read-only.
If these are wanted later they belong in a dedicated follow-up issue. Minor doc lag: docs/write-mode.md "Supported Write Tools" lists 6 while 16 are implemented.
Closing as all acceptance criteria are met.
## Verified done — closing
Checked the current `main` against all four acceptance criteria. All met:
- [x] **Write tools behind explicit opt-in mode** — 16 write handlers in `tools/write_tools.py`; `WRITE_MODE=false` by default; scope `write:repository`; policy enforced via `is_write=tool_def.write_operation`.
- [x] **Audit logging covers write actions** — every dispatch goes through `audit.log_tool_invocation` / `log_access_denied` on the hash-chained audit log.
- [x] **PAT bypass / open-redirect remediated** — `_verify_user_repository_access` runs before any service-PAT use plus the `service_pat_requires_repository_target` guard (server.py:1210-1237); `is_redirect_uri_allowed` allowlist enforced on the authorize proxy, callback and DCR registration (server.py:842/888/990). Path-traversal on ref/sha/base/head also fixed (#18).
- [x] **README documents read-only vs full-access + trade-off** — README WRITE_MODE/scopes section + `docs/write-mode.md` (Threat Model, Default Posture, Risk Tradeoffs).
Implemented write tools: create/update_issue (incl. state = close/reopen), issue/PR comments + edit, add/remove/create/update_label, assign_issue, create_pull_request, create/edit_release, create_branch, create_milestone.
### Deliberately out of scope (not gaps)
The formal acceptance checklist is fully satisfied. Two items from the broader "complete access" wishlist were intentionally not implemented:
- **PR merge & review** — `docs/write-mode.md` explicitly forbids merge / force-push / branch-deletion by design.
- **Repository content writes** (create/edit files, commits) — not implemented; `tools/repository.py` is read-only.
If these are wanted later they belong in a dedicated follow-up issue. Minor doc lag: `docs/write-mode.md` "Supported Write Tools" lists 6 while 16 are implemented.
Closing as all acceptance criteria are met.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Goal
Today AegisGitea-MCP is read-only by design. This issue tracks adding write capability so the AI can not only inspect but also act on the Gitea environment — with the intent of giving it as complete access as possible through MCP tool calls.
Requested change
Expose write tools alongside the existing read-only ones, covering as much of the Gitea surface as practical:
The aim is that the AI can drive a full workflow end-to-end, not just read state.
Design notes / considerations
This deliberately reverses the original read-only posture, so it's worth being explicit about how to do it safely rather than just flipping a flag:
writemode toggle (env var / config) so read-only stays the default and full access is a conscious choice, not the baseline.Acceptance
Verified done — closing
Checked the current
mainagainst all four acceptance criteria. All met:tools/write_tools.py;WRITE_MODE=falseby default; scopewrite:repository; policy enforced viais_write=tool_def.write_operation.audit.log_tool_invocation/log_access_deniedon the hash-chained audit log._verify_user_repository_accessruns before any service-PAT use plus theservice_pat_requires_repository_targetguard (server.py:1210-1237);is_redirect_uri_allowedallowlist enforced on the authorize proxy, callback and DCR registration (server.py:842/888/990). Path-traversal on ref/sha/base/head also fixed (#18).docs/write-mode.md(Threat Model, Default Posture, Risk Tradeoffs).Implemented write tools: create/update_issue (incl. state = close/reopen), issue/PR comments + edit, add/remove/create/update_label, assign_issue, create_pull_request, create/edit_release, create_branch, create_milestone.
Deliberately out of scope (not gaps)
The formal acceptance checklist is fully satisfied. Two items from the broader "complete access" wishlist were intentionally not implemented:
docs/write-mode.mdexplicitly forbids merge / force-push / branch-deletion by design.tools/repository.pyis read-only.If these are wanted later they belong in a dedicated follow-up issue. Minor doc lag:
docs/write-mode.md"Supported Write Tools" lists 6 while 16 are implemented.Closing as all acceptance criteria are met.