Add repository file write tools (create, update, delete) #23
Labels
No labels
status/paused
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jbr870/forgejo-mcp-server#23
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Add MCP tools for creating, updating, and deleting files in a repository, completing the file CRUD surface started by #12 (which delivered the read side).
Background
Issue #12 added
get_file_contents,list_directory, andget_repo_tree— all read-only. The Forgejo API (inherited from Gitea) also exposes write endpoints on the same/repos/{owner}/{repo}/contents/{filepath}path, but the MCP server doesn't wrap them. Today, any agent that needs to modify repo files has to ask the user to do it manually, push via git, or use some other out-of-band method.Forgejo API endpoints
The upstream API provides three individual file-mutation endpoints plus a batch endpoint. All live under
/api/v1/repos/{owner}/{repo}/contents/.1. Create file —
POST /repos/{owner}/{repo}/contents/{filepath}Creates a new file. Fails if the file already exists.
Request body (
CreateFileOptions):content(string, required) — file content, base64-encodedmessage(string, optional) — commit message; Forgejo generates a default if omittedbranch(string, optional) — target branch; defaults to the repo's default branchnew_branch(string, optional) — create a new branch frombranchand commit thereauthor/committer(object withname+email, optional)dates(object, optional) — override author/committer timestampssignoff(bool, optional)Response:
FileResponse— contains the created file'scontentmetadata (path, sha, size, etc.) and thecommitobject.2. Update file —
PUT /repos/{owner}/{repo}/contents/{filepath}Updates an existing file. Requires the current blob SHA for optimistic concurrency.
Request body (
UpdateFileOptions):CreateFileOptions, plus:sha(string, required) — the blob SHA of the file being replaced (fromget_file_contents)from_path(string, optional) — if set, moves/renames the file fromfrom_pathto thefilepathin the URLResponse:
FileResponse.3. Delete file —
DELETE /repos/{owner}/{repo}/contents/{filepath}Deletes a file. Also requires the current blob SHA.
Request body (
DeleteFileOptions):sha(string, required) — blob SHA of the file to deletemessage(string, optional)branch(string, optional)new_branch(string, optional)author/committer(optional)dates(optional)signoff(optional)Response:
FileDeleteResponse— containscommitbutcontentis null.4. Batch modify files —
POST /repos/{owner}/{repo}/contents(no filepath)Applies multiple file operations in a single commit.
Request body (
ChangeFilesOptions):files(array ofChangeFileOperation, required) — each operation has:operation—"create","update", or"delete"path(string) — file pathcontent(string, base64) — for create/updatesha(string) — for update/deletefrom_path(string, optional) — for rename/movemessage,branch,new_branch,author,committer,dates,signofffieldsResponse:
FilesResponse— array of file results plus a single commit.Proposed tools
create_fileupdate_filedelete_fileDesign decisions
Plain text content, not base64
The MCP server should accept
contentas plain text and base64-encode it before sending to the Forgejo API. This mirrors the read side: issue #2 established the pattern of decoding base64 content from Forgejo before returning it to the MCP client. Agents work with text, not base64.For binary files, a separate
content_base64parameter could be added later, or the tool could accept a flag — but binary file creation via MCP is an edge case and can be deferred.SHA as explicit parameter
Both
update_fileanddelete_filerequire the blob SHA of the current file. This is by design in the Forgejo API (optimistic concurrency control). The agent gets the SHA from a priorget_file_contentscall. The tool docstrings should make this workflow explicit: "callget_file_contentsfirst to obtain the currentsha".Omit author/committer/dates/signoff
These fields are optional in the API and default to the authenticated user. For a first implementation, omitting them keeps the tools simple. They can be added as optional parameters later if a use case emerges.
Nice-to-have (separate issue if pursued)
modify_files— batch endpoint wrapper. Useful for atomic multi-file commits (e.g. updating a config file and its corresponding test). More complex parameter shape; worth deferring until the single-file tools are stable.content_base64parameter for non-text files.Why this matters
_Sidebar, etc. — though wiki pages have their own API, the same pattern applies to any file-based setup.from_pathfor file moves. The update endpoint'sfrom_pathparameter enables rename/move operations, which are otherwise impossible via the contents API.Scope
src/tools/repos.py— addcreate_file,update_file,delete_filetoolssrc/forgejo_client.py— add corresponding client methodsRelated