Labsco
goern logo

Forgejo MCP Server

β˜… 89

from goern

Manage Forgejo repositories and execute commands through an MCP-compatible chat interface.

πŸ”₯πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedAccount requiredNeeds API keys

Forgejo MCP Server

Connect your AI assistant to Forgejo repositories. Manage issues, pull requests, files, and more through natural language.

What It Does

Forgejo MCP Server is an integration plugin that connects Forgejo with Model Context Protocol (MCP) systems. Once configured, you can interact with your Forgejo repositories through any MCP-compatible AI assistant like Claude, Cursor, or VS Code extensions.

Example commands you can use:

  • "List all my repositories"

  • "Create an issue titled 'Bug in login page'"

  • "Show me open pull requests in my-org/my-repo"

  • "Get the contents of README.md from the main branch"

  • "Show me the latest Actions workflow runs in goern/forgejo-mcp"

Available Tools

Tool Description User get_my_user_info Get information about the authenticated user check_notifications Check and list user notifications get_notification_thread Get detailed info on a single notification thread mark_notification_read Mark a single notification thread as read mark_all_notifications_read Acknowledge all notifications list_repo_notifications Filter notifications scoped to a single repository mark_repo_notifications_read Mark all notifications in a specific repo as read search_users Search for users Repositories list_my_repos List all repositories you own create_repo Create a new repository fork_repo Fork a repository search_repos Search for repositories Branches list_branches List all branches in a repository create_branch Create a new branch delete_branch Delete a branch Branch Protection list_branch_protections List a repository's branch protection rules. Bounded by page (1-based) + limit (page size); the response echoes page/limit so callers can fetch the next page. get_branch_protection Get a single rule by rule name create_branch_protection Create a rule. Requires branch_name; status_check_contexts is a comma-separated list of required checks (e.g. "ci/build,ci/test"). edit_branch_protection Edit a rule by rule name. Only fields you pass change; omitted fields are left unchanged. delete_branch_protection Delete a rule by rule name Files get_file_content Get the content of a file. Optional start_line/end_line request a 1-indexed inclusive line range (clamps to file extent; ignored when with_metadata=true). create_file Create a new file update_file Update an existing file delete_file Delete a file Commits list_repo_commits List commits in a repository Issues list_repo_issues List issues in a repository get_issue_by_index Get a specific issue create_issue Create a new issue add_issue_labels Add labels to an issue (requires numeric label IDs) remove_issue_labels Remove labels from an issue (requires numeric label IDs) update_issue Update an existing issue (requires numeric milestone ID) issue_state_change Open or close an issue list_repo_milestones List milestones with their IDs (use with update_issue) list_repo_labels List labels with their IDs. Merges org-level labels for org-owned repos (set include_org_labels=false to opt out). Each entry carries a scope field ("repo" or "org"). list_org_labels List organization-level labels with their IDs (use with add_issue_labels, remove_issue_labels). create_repo_label Create a repository label (name, color as 6-digit hex, optional description). Returns numeric id for immediate use in add_issue_labels. edit_repo_label Edit a repository label (PATCH β€” only supplied fields change: name, color, description). delete_repo_label Delete a repository label. Refuses by default when the label is in use (reports count); set delete_mode=force to override. get_repo_label Get a single repository label by numeric id. create_org_label Create an organization-level label. Same fields as create_repo_label. edit_org_label Edit an organization-level label (PATCH semantics). delete_org_label Delete an organization-level label. In-use guard counts across visible org repos (best-effort); delete_mode=force overrides. get_org_label Get a single organization-level label by numeric id. Comments list_issue_comments List comments on an issue or PR get_issue_comment Get a specific comment create_issue_comment Add a comment to an issue or PR edit_issue_comment Edit a comment delete_issue_comment Delete a comment Pull Requests list_repo_pull_requests List pull requests in a repository get_pull_request_by_index Get a specific pull request create_pull_request Create a new pull request update_pull_request Update an existing pull request list_pull_reviews List reviews for a pull request get_pull_review Get a specific pull request review list_pull_review_comments List comments on a pull request review list_pull_request_files List changed files in a pull request (paginated). Use the returned filenames as the file_path argument to get_pull_request_diff. get_pull_request_diff Get the unified diff of a pull request. Optional file_path returns only that file's hunks (matches on either pre- or post-rename path). merge_pull_request Merge a pull request (style: merge/rebase/rebase-merge/squash; optional title/message/delete-branch/force-merge/wait-for-checks). create_pull_review Create a review on a pull request (state: APPROVED/REQUEST_CHANGES/COMMENT) with optional inline comments. Actions dispatch_workflow Trigger a workflow run via workflow_dispatch event list_workflow_runs List workflow runs with optional filtering by status, event, or SHA get_workflow_run Get details of a specific workflow run by ID Organizations search_org_teams Search for teams in an organization Time Tracking list_issue_tracked_times List tracked time entries on an issue or PR list_repo_tracked_times List tracked time entries across a repository list_my_tracked_times List your own tracked time entries add_issue_time Log time against an issue or PR (accepts seconds or duration like 15m) reset_issue_time Delete ALL tracked time entries on an issue or PR (destructive) delete_issue_time_entry Delete a single tracked time entry by ID start_issue_stopwatch Start a stopwatch on an issue or PR stop_issue_stopwatch Stop a running stopwatch and record the elapsed time cancel_issue_stopwatch Cancel a running stopwatch without recording list_my_stopwatches List currently running stopwatches Attachments list_issue_attachments List attachments on an issue or PR get_issue_attachment Get metadata for a single issue/PR attachment download_issue_attachment Download an issue/PR attachment (inline if < 1 MiB; metadata + URL otherwise) create_issue_attachment Upload a new attachment to an issue or PR (base64 content) edit_issue_attachment Rename an issue/PR attachment delete_issue_attachment Delete an issue/PR attachment list_comment_attachments List attachments on an issue/PR comment get_comment_attachment Get metadata for a single comment attachment download_comment_attachment Download a comment attachment (inline if < 1 MiB; metadata + URL otherwise) create_comment_attachment Upload a new attachment to an issue/PR comment (base64 content) edit_comment_attachment Rename a comment attachment delete_comment_attachment Delete a comment attachment Releases list_releases List releases for a repository (page/limit + client-side state filter: all/draft/prerelease/published) get_release_by_id Get a release by numeric ID get_release_by_tag Get a release by tag name get_latest_release Get the latest non-draft, non-prerelease release create_release Create a new release (pass target_commitish to also create the tag) edit_release Update fields of an existing release (only supplied fields are sent) delete_release Delete a release by numeric ID β€” destructive delete_release_by_tag Delete a release by tag name β€” destructive, verify tag list_release_attachments List attachments on a release (response fetched in full, sliced client-side) get_release_attachment Get metadata for a single release attachment download_release_attachment Download a release attachment (inline if < 1 MiB; metadata + URL otherwise) create_release_attachment Upload a new attachment to a release (base64 content) edit_release_attachment Rename a release attachment delete_release_attachment Delete a release attachment β€” destructive Server get_forgejo_mcp_server_version Get the MCP server version

Resources

MCP resource templates expose Forgejo entities as URI-addressable resources using the forgejo:// scheme. The URI scheme is instance-portable β€” the same URI form works against any Forgejo instance β€” and does not collide with Forgejo web links. Clients that support resources/templates/list and resources/read (Claude Code, Claude Desktop, Codex, Cursor) can resolve these URIs directly. Clients without resource-template support continue to use the tools above β€” no functionality is removed.

Resources do NOT replace any MCP tool β€” every existing list/get tool stays available; resources are an additive, URI-addressable read surface intended for auto-resolution from LLM context and for content-addressable caching of immutable entities like commits.

Resources that embed a list (issue, pr) cap the embedded array at 30 items. When truncated, the JSON payload includes a sentinel naming the corresponding list_* tool the caller should invoke for the full list.

When to use resources vs tools: prefer a resource when you have a specific sha or index in hand; prefer a tool when listing or searching.

URI Template Entity Notes forgejo://owner/{owner} application/json User or org profile addressed by login; resolves user first, falls back to org. forgejo://repo/{owner}/{repo} application/json Repository overview: identity + counts, no embedded lists. forgejo://repo/{owner}/{repo}/commit/{sha} Commit metadata Immutable per sha. Returns JSON + markdown sidecar. sha must be 40 hex chars. forgejo://repo/{owner}/{repo}/commit/{sha}/status application/json Combined CI status for a sha: aggregate state + bounded per-context statuses (cap 30, sentinel names list tool get_commit_statuses). forgejo://repo/{owner}/{repo}/issue/{index} application/json (+ text/markdown sidecar) Issue metadata + rendered body + bounded recent comments (cap 30, sentinel names list_issue_comments). forgejo://repo/{owner}/{repo}/{kind}/{index}/comment/{id} application/json (+ text/markdown sidecar) Single comment by id; kind ∈ {issue, pr}. forgejo://repo/{owner}/{repo}/pr/{index} application/json (+ text/markdown sidecar) PR metadata, head/base refs, mergeability, bounded recent comments (cap 30, sentinel list_issue_comments) and reviews (cap 30, sentinel list_pull_reviews). forgejo://repo/{owner}/{repo}/label/{id} application/json Single repository label by numeric id. forgejo://repo/{owner}/{repo}/labels{?page,limit} application/json Bounded list of repository labels (cap 30, sentinel names list_repo_labels). forgejo://org/{org}/labels{?page,limit} application/json Bounded list of organization-level labels (cap 30, sentinel names list_org_labels).

Client Compatibility

Client resources/templates/list resources/read Claude Code supported supported Claude Desktop supported supported Codex supported supported Cursor (current) supported supported Older / minimal clients tools only tools only

Demos

End-to-end, copy-pasteable walkthroughs of the tools above β€” grouped by topic (labels, attachments, time tracking, notifications, orgs, bounded I/O code review, transport) β€” live in demos/. Each demo pairs real ./forgejo-mcp --cli invocations with the output they produced against codeberg.org.

CLI Mode

You can invoke any tool directly from the command line without running an MCP server. This is useful for shell scripts, CI/CD pipelines, and Claude Code skills.

Copy & paste β€” that's it
# List all available tools (grouped by domain)
forgejo-mcp --cli list

# Invoke a tool with JSON arguments
forgejo-mcp --cli get_issue_by_index --args '{"owner":"goern","repo":"forgejo-mcp","index":1}'

# Pipe JSON arguments via stdin
echo '{"owner":"goern","repo":"forgejo-mcp"}' | forgejo-mcp --cli list_repo_issues

# List recent workflow runs (text output)
forgejo-mcp --cli list_workflow_runs \
 --args '{"owner":"goern","repo":"forgejo-mcp"}' \
 --output=text

# List only failed runs
forgejo-mcp --cli list_workflow_runs \
 --args '{"owner":"goern","repo":"forgejo-mcp","status":"failure"}' \
 --output=text

# Show a tool's parameters
forgejo-mcp --cli create_issue --help

# Control output format (json or text)
forgejo-mcp --cli list --output=json
forgejo-mcp --cli get_my_user_info --args '{}' --output=text

CLI mode requires the same FORGEJO_URL and FORGEJO_ACCESS_TOKEN configuration as MCP server mode. Tool results are written as JSON to stdout by default; errors go to stderr with a non-zero exit code.

Verifying Releases

Release archives are accompanied by a checksums.txt file and an optional checksums.txt.sig produced by cosign with the project's release keypair. Verifying both files lets you confirm that the binary you downloaded was built by the project's release pipeline and has not been tampered with in transit.

Heads up: cosign signing was introduced mid-2026. Tags released before signing was wired up ship without a .sig file β€” verification applies from v2.23.x onward only, and only when the COSIGN_PRIVATE_KEY secret was configured at release time.

1. Install cosign

Follow the upstream cosign installation guide for your platform. Quick paths:

Copy & paste β€” that's it
# Linux/macOS β€” pinned binary
COSIGN_VERSION=v2.4.1
curl -sSfL -o /usr/local/bin/cosign \
 "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64"
chmod +x /usr/local/bin/cosign

# macOS via Homebrew
brew install cosign

# Arch Linux
sudo pacman -S cosign

Confirm:

Copy & paste β€” that's it
cosign version

2. Fetch the public key

The normative source for the cosign public key is the op1st-emea-b4mad GitOps repo β€” same source of truth that provisions the cosign-signing-key-artifacts Secret in the op1st-pipelines namespace where the release pipeline runs. This is the artifact-signing key that signs release blobs (checksums.txt.sig); it is distinct from the image-signing key cosign-signing-key-images.pub used in Β§5–§6 below. Two ways to fetch it:

Branch-tip (live, follows future key rotations):

Copy & paste β€” that's it
curl -sSfL -o cosign.pub \
 https://codeberg.org/operate-first/op1st-emea-b4mad/raw/branch/main/manifests/applications/op1st-pipelines-tokens/cosign-signing-key-artifacts.pub

Commit-pinned (tamper-evident, recommended for CI/scripts):

Copy & paste β€” that's it
curl -sSfL -o cosign.pub \
 https://codeberg.org/operate-first/op1st-emea-b4mad/raw/commit/cd3715fa8283a2069a2e3e299744a7b55b1b0260/manifests/applications/op1st-pipelines-tokens/cosign-signing-key-artifacts.pub

The commit-pinned permalink hashes its content into the URL β€” if anyone ever rewrites the file at that commit, your download fails or mismatches. Pin to the latest commit that you trust before adopting the key in automation.

3. Download the release artifacts

Pick the tag you installed (e.g. v2.23.1) and grab the checksum file, its signature, and the binary archive:

Copy & paste β€” that's it
TAG=v2.23.1
VERSION="${TAG#v}"
BASE="https://codeberg.org/goern/forgejo-mcp/releases/download/${TAG}"

curl -sSfLO "${BASE}/forgejo-mcp_${VERSION}_checksums.txt"
curl -sSfLO "${BASE}/forgejo-mcp_${VERSION}_checksums.txt.sig"
curl -sSfLO "${BASE}/forgejo-mcp_${VERSION}_linux_amd64.tar.gz" # adjust os/arch

4. Verify the signature, then the checksum

Cosign verifies that checksums.txt was signed by the holder of the private key matching cosign.pub. Once the checksum file is trusted, a plain sha256sum -c check confirms the archive's integrity.

Copy & paste β€” that's it
# Verify checksums.txt against the signature.
cosign verify-blob \
 --key cosign.pub \
 --signature "forgejo-mcp_${VERSION}_checksums.txt.sig" \
 "forgejo-mcp_${VERSION}_checksums.txt"
# Expected: "Verified OK"

# Verify the downloaded archive against the (now-trusted) checksums.
sha256sum --ignore-missing -c "forgejo-mcp_${VERSION}_checksums.txt"
# Expected: " : OK"

The checksum chain transitively covers the SBOMs and other per-archive assets β€” verifying checksums.txt once is sufficient for everything listed inside it.

5. Verify SLSA provenance for the release-tools image

The release-tools container image (used internally by the Tekton release pipeline) carries SLSA v1.0 provenance generated by Tekton Chains. This attestation binds the image digest to the exact PipelineRun, git commit, and builder identity that produced it β€” providing supply-chain provenance beyond what the cosign signature alone can attest.

Fetch the cosign-signing-key-images public key (a separate key from the artifact-signing key above):

Copy & paste β€” that's it
curl -sSfL -o cosign-images.pub \
 https://codeberg.org/operate-first/op1st-emea-b4mad/raw/branch/main/manifests/applications/op1st-pipelines-tokens/cosign-signing-key-images.pub

Verify the attestation against a specific image tag:

Copy & paste β€” that's it
IMAGE_TAG=v1.0.0 # substitute the release-tools tag you want to verify
cosign verify-attestation \
 --type slsaprovenance \
 --key cosign-images.pub \
 "codeberg.org/operate-first/release-tools:${IMAGE_TAG}" \
 | jq .

A successful run prints the decoded in-toto statement (JSON). Check that predicate.buildDefinition.externalParameters.runSpec.params references the expected git revision, and predicate.runDetails.builder.id shows the Tekton Chains builder.

Note: SLSA provenance attestations are available from releases built after forgejo-mcp-46j (Tekton Chains support) landed. Earlier image tags carry only the cosign signature; they have no verify-attestation payload.

6. Verify the container image

The codeberg.org/goern/forgejo-mcp application image ( Option D ) is signed by the same cosign-signing-key-images key as the release-tools image, carries an attached CycloneDX SBOM, and gets SLSA v1.0 provenance from Tekton Chains. Reuse the cosign-images.pub key fetched above.

Verify the signature:

Copy & paste β€” that's it
IMAGE_TAG=v2.24.0 # substitute the release you are pulling
cosign verify \
 --key cosign-images.pub \
 "codeberg.org/goern/forgejo-mcp:${IMAGE_TAG}" \
 | jq .

Verify the SLSA provenance attestation:

Copy & paste β€” that's it
cosign verify-attestation \
 --type slsaprovenance \
 --key cosign-images.pub \
 "codeberg.org/goern/forgejo-mcp:${IMAGE_TAG}" \
 | jq .

Verify and download the signed CycloneDX SBOM attestation:

Copy & paste β€” that's it
cosign verify-attestation \
 --type cyclonedx \
 --key cosign-images.pub \
 "codeberg.org/goern/forgejo-mcp:${IMAGE_TAG}" \
 | jq -r '.payload | @base64d | fromjson | .predicate' > forgejo-mcp.cdx.json

The SBOM is now a signed in-toto attestation (cosign attest), not an unsigned attach sbom artifact. cosign download sbom no longer applies.

Because the publish pipeline pushes by digest and only promotes the vX.Y.Z / latest tags after signing and SBOM attachment succeed, any tag you can pull is guaranteed to be signed.

Troubleshooting verification

  • Error: no matching signatures β€” the .sig file is from a different release, or cosign.pub is the wrong key. Re-download both from the same tag.

  • Error: cannot read file: checksums.txt.sig β€” release predates cosign signing, or signing was skipped that run because the secret was unset. Fall back to the checksum-only check (sha256sum -c), which still detects in-transit corruption but not tampering.

  • Mismatch between cosign.pub and the signature β€” confirm you fetched the public key from a commit that includes the key in use at the time of the release. If in doubt, fetch from branch/main.

Getting Help

This repository is also mirrored on Radicle β€” a peer-to-peer code collaboration network. Clone via:

Copy & paste β€” that's it
rad clone rad:z4PdPpsH9iJQcWfqTbxpFcWaZ9zPL

For Developers

See DEVELOPER.md for build instructions, architecture overview, and contribution guidelines.

Contributors

forgejo-mcp is shaped by everyone who files issues, writes code, reviews PRs, and pushes the project forward. Thank you all. πŸ™

Code contributors

Contributor Highlights goern (Christoph GΓΆrn) Project creator and maintainer Ronmi Ren Co-creator; SSE/HTTP transport, issue blocking, CI/CD improvements, logo, Glama spec twstagg (Tristin Stagg) User agent configuration support (PR #89) mattdm (Matthew Miller) Logging improvements, FORGEJO_* migration, README, URL refactor byteflavour check_notifications + full notification management API (PR #84, #86); stateless per-request auth for HTTP/SSE transports (PR #138); NixOS installation docs (PR #146); feature requests #80, #85 jesterret Pull request reviews and comments support (PR #51) appleboy Custom SSE port support, bug fixes ignasgil remove_issue_labels tool (PR #96) dmikushin (Dmitry Mikushin) Fix string-encoded number parameter parsing from MCP clients (PR #93) jiriks74 mcp-go v0.44.0 dependency update (PR #90) th (Tomi Haapaniemi) update_pull_request tool hiifong Early bug fixes and updates Lunny Xiao Early contributions techknowlogick Early contributions yp05327 Early contributions mw75 Owner/org support for repo creation (PR #18) Dax Kelson Issue comment management (PR #34) Guruprasad Kulkarni Arch Linux AUR installation docs (PR #69) Mario Wolff Contributions Massimo Fraschetti Contributions synath (David Paul Turley) Repository-scoped token support via ServerVersion probe (PR #112); merge status-code check (PR #113); Claude Desktop Extension (.mcpb) packaging (PR #118) BrilliantKahn get_file_content plain-text default (PR #116); list_repo_contents and get_repo_tree tools (PR #117). First-ever open source contribution β€” welcome aboard! πŸŽ‰

Community contributors

Issue reporters and discussion participants who shaped the direction of the project:

Contributor Contributions byteflavour Filed #80 (milestone/label discovery), #85 (notification API proposal); active reviewer in discussions choucavalier Filed #82 (fix skill), #70 (macOS arm64 releases), #62 (binary releases & mise support) MalcolmMielle Filed #59 (PR review tools β€” since implemented) redbeard Filed #60 (Actions support β€” since implemented) c6sepl6p Filed #72 (base64 encoding), #54 (merge pull request β€” since implemented) malik Filed #73 (version flag), #47 (Nix build fix) a2800276 Filed #74 (OpenAI compatibility) simenandre Filed #49 (go install support) BasdP Filed #42 (Projects support) BoBeR182 Filed #32 (wiki support) ignasgil Filed #95 (remove_issue_labels feature request) Vokuar Filed #99 (streamable HTTP transport support) janbaer Filed #98 (reply to review comment) fraschm98 Early issue reports heathen711 Filed #106 (issue/comment attachments β€” since implemented); shaped the 1 MiB inline cap + browser_download_url fall-through design

Cyborg contributors

This project also received contributions from AI coding agents β€” submitted as regular PRs, reviewed by humans:

Agent Role Contributions brenner-axiom (b4-dev, B4arena) AI dev agent Organization management tools (PR #94); showboat demos (PR #97); list_repo_milestones, list_repo_labels tools (PR #83); race condition fix (PR #78); contributors docs (PR #87, #88); filed #76; code reviews opencode AI dev agent Pull request reviews and comments support (PR #51) claude-code AI dev agent get_file_content plain-text default and list_repo_contents/get_repo_tree tools, paired with BrilliantKahn (PR #116, #117) b4mad-release-bot Release automation Automated changelog and release tagging the #B4mad Renovate bot Dependency updates Automated dependency upgrades

Want to contribute? Open an issue or pull request β€” all are welcome.

License

This project is open source. See the repository for license details.