Wire the existing release-tools image tasks into the app release pipeline
so that pushing a vX.Y.Z tag also builds, signs, and publishes the
forgejo-mcp container image — closing forgejo-mcp-dn0.
- Build the root Containerfile, push by digest to
codeberg.org/goern/forgejo-mcp, then promote vX.Y.Z + latest only after
cosign sign + SBOM attach succeed (TOCTOU-safe).
- Reuse release-tools-{build-image,push-image-by-digest,
cosign-sign-image-by-digest,cosign-attach-sbom,promote-image-tag};
image build runs in parallel with goreleaser.
- Add an optional BUILD_ARGS param to release-tools-build-image (default
empty, no-op for the release-tools run) and pass VERSION=<tag> so the
in-image binary reports the real release instead of "dev".
- Export IMAGE_URL/IMAGE_DIGEST + enable Tekton Chains for SLSA provenance.
- Exclude .buildah/ in .containerignore so CONTEXT=. does not tar buildah's
own store into the build context.
- Document the published image (registry, tags, cosign verify, SBOM) in
README, install Option D.
Operator precondition: codeberg-pusher PAT needs write:package on
goern/forgejo-mcp (separate from its operate-first grant).
669 lines
30 KiB
Markdown
669 lines
30 KiB
Markdown
# 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)](https://modelcontextprotocol.io/) 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"
|
|
|
|
## Quick Start
|
|
|
|
### 1. Install
|
|
|
|
**Option A: Using Go (Recommended)**
|
|
|
|
```bash
|
|
git clone https://codeberg.org/goern/forgejo-mcp.git
|
|
cd forgejo-mcp
|
|
go install .
|
|
```
|
|
|
|
Ensure `$GOPATH/bin` (typically `~/go/bin`) is in your PATH.
|
|
|
|
> **Note:** `go install codeberg.org/goern/forgejo-mcp/v2@latest` does not work currently. See [Known Issues](#known-issues).
|
|
|
|
**Option B: Download Binary**
|
|
|
|
Download the latest release from the [releases page](https://codeberg.org/goern/forgejo-mcp/releases).
|
|
|
|
For Arch Linux, use your favorite AUR helper:
|
|
|
|
```bash
|
|
yay -S forgejo-mcp # builds from source
|
|
yay -S forgejo-mcp-bin # uses pre-built binary
|
|
```
|
|
|
|
**Option C: Nix / NixOS**
|
|
|
|
You can run the server directly using the Nix package manager:
|
|
```bash
|
|
nix-shell -p forgejo-mcp
|
|
```
|
|
Or using Flakes:
|
|
```bash
|
|
nix run nixpkgs#forgejo-mcp
|
|
```
|
|
|
|
> **Note:** `forgejo-mcp` is currently only available in the `unstable` channel and is not yet part of the 25.11 stable release.
|
|
|
|
**Option D: Container image**
|
|
|
|
A signed multi-stage OCI image is published on every release to
|
|
`codeberg.org/goern/forgejo-mcp`. Run the server without building from source:
|
|
|
|
```bash
|
|
# Latest release
|
|
podman run --rm -i \
|
|
-e FORGEJO_ACCESS_TOKEN="<your personal access token>" \
|
|
codeberg.org/goern/forgejo-mcp:latest \
|
|
--transport stdio --url https://your-forgejo-instance.org
|
|
|
|
# Or pin a specific version
|
|
podman run --rm -i codeberg.org/goern/forgejo-mcp:v2.24.0 --help
|
|
```
|
|
|
|
| Tag | Meaning |
|
|
|-----------------|----------------------------------------------------------------|
|
|
| `vMAJOR.MINOR.PATCH` | Immutable — the exact release (e.g. `v2.24.0`). Use in production. |
|
|
| `latest` | Moving — tracks the most recent release. Convenience only. |
|
|
|
|
The image is single-arch (`linux/amd64`), signed with cosign, and carries an
|
|
attached CycloneDX SBOM. See [Verify the container image](#6-verify-the-container-image)
|
|
to check the signature and provenance before running.
|
|
|
|
### 2. Get Your Access Token
|
|
|
|
1. Log into your Forgejo instance
|
|
2. Go to **Settings** → **Applications** → **Access Tokens**
|
|
3. Create a new token with the permissions you need (repo, issue, etc.)
|
|
|
|
### 3. Configure Your AI Assistant
|
|
|
|
Add this to your MCP configuration file:
|
|
|
|
**For stdio mode** (most common):
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"forgejo": {
|
|
"command": "forgejo-mcp",
|
|
"args": [
|
|
"--transport", "stdio",
|
|
"--url", "https://your-forgejo-instance.org"
|
|
],
|
|
"env": {
|
|
"FORGEJO_ACCESS_TOKEN": "<your personal access token>",
|
|
"FORGEJO_USER_AGENT": "forgejo-mcp/1.0.0"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**For streamable HTTP mode** (recommended for remote/Claude.ai):
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"forgejo": {
|
|
"url": "http://localhost:8080/mcp"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
When using streamable HTTP mode, start the server first:
|
|
|
|
```bash
|
|
forgejo-mcp --transport http --url https://your-forgejo-instance.org --token <your-token>
|
|
```
|
|
|
|
**Multi-tenant HTTP mode** (optional):
|
|
|
|
You can run a single centralized `forgejo-mcp` instance and let each client provide its own token via the standard HTTP `Authorization` header. This enables serving multiple users or agents from one server.
|
|
|
|
1. Start the server (optionally without any global token):
|
|
```bash
|
|
forgejo-mcp --transport http --url https://your-forgejo-instance.org
|
|
```
|
|
2. Clients include their specific token in each request:
|
|
- `Authorization: token <token>` (Forgejo style)
|
|
- `Authorization: Bearer <token>` (OAuth2/MCP style)
|
|
- Note: The scheme (`token` or `Bearer`) is case-insensitive.
|
|
|
|
See [demos/multi-tenant-http.md](demos/multi-tenant-http.md) for a copy-pasteable walkthrough.
|
|
|
|
**For SSE mode** (legacy HTTP-based):
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"forgejo": {
|
|
"url": "http://localhost:8080/sse"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
When using SSE mode, start the server first:
|
|
|
|
```bash
|
|
forgejo-mcp --transport sse --url https://your-forgejo-instance.org --token <your-token>
|
|
```
|
|
|
|
### 4. Start Using It
|
|
|
|
Open your MCP-compatible AI assistant and try:
|
|
|
|
```
|
|
List all my repositories
|
|
```
|
|
|
|
## 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 |
|
|
| **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`). |
|
|
| **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`). |
|
|
|
|
### 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/](demos/README.md). 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.
|
|
|
|
```bash
|
|
# 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.
|
|
|
|
## Configuration Options
|
|
|
|
You can configure the server using command-line arguments or environment variables:
|
|
|
|
| CLI Argument | Environment Variable | Description |
|
|
|--------------|---------------------|-------------|
|
|
| `--url` | `FORGEJO_URL` | Your Forgejo instance URL |
|
|
| `--token` | `FORGEJO_ACCESS_TOKEN` | Your personal access token |
|
|
| `--debug` | `FORGEJO_DEBUG` | Enable debug mode |
|
|
| `--transport` | - | Transport mode: `stdio`, `sse`, or `http` |
|
|
| `--sse-port` | - | Port for SSE mode (default: 8080) |
|
|
| `--http-port` | - | Port for streamable HTTP mode (default: 8080) |
|
|
| `--cli` | - | Enter CLI mode for direct tool invocation |
|
|
| `--user-agent` | `FORGEJO_USER_AGENT` | HTTP User-Agent header (default: `forgejo-mcp/<version>`) |
|
|
|
|
Command-line arguments take priority over environment variables.
|
|
|
|
## Verifying Releases
|
|
|
|
Release archives are accompanied by a `checksums.txt` file and an optional
|
|
`checksums.txt.sig` produced by [cosign](https://github.com/sigstore/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](https://docs.sigstore.dev/cosign/system_config/installation/)
|
|
for your platform. Quick paths:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
cosign version
|
|
```
|
|
|
|
### 2. Fetch the public key
|
|
|
|
The normative source for the cosign public key is the
|
|
[`op1st-emea-b4mad`](https://codeberg.org/operate-first/op1st-emea-b4mad)
|
|
GitOps repo — same source of truth that provisions the `cosign-signing-key`
|
|
Secret in the `op1st-pipelines` namespace where the release pipeline runs.
|
|
Two ways to fetch it:
|
|
|
|
**Branch-tip (live, follows future key rotations):**
|
|
|
|
```bash
|
|
curl -sSfL -o cosign.pub \
|
|
https://codeberg.org/operate-first/op1st-emea-b4mad/raw/branch/main/manifests/applications/op1st-pipelines-tokens/cosign-signing-key.pub
|
|
```
|
|
|
|
**Commit-pinned (tamper-evident, recommended for CI/scripts):**
|
|
|
|
```bash
|
|
curl -sSfL -o cosign.pub \
|
|
https://codeberg.org/operate-first/op1st-emea-b4mad/raw/commit/8a3c55e5b8c892754fd61f9141dc4817a6915f45/manifests/applications/op1st-pipelines-tokens/cosign-signing-key.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:
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
# 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: "<archive>: 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](https://tekton.dev/docs/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):
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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](#1-install))
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
cosign verify-attestation \
|
|
--type slsaprovenance \
|
|
--key cosign-images.pub \
|
|
"codeberg.org/goern/forgejo-mcp:${IMAGE_TAG}" \
|
|
| jq .
|
|
```
|
|
|
|
Download the attached SBOM:
|
|
|
|
```bash
|
|
cosign download sbom "codeberg.org/goern/forgejo-mcp:${IMAGE_TAG}" > forgejo-mcp.cdx.json
|
|
```
|
|
|
|
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`.
|
|
|
|
## Troubleshooting
|
|
|
|
**Enable debug mode** to see detailed logs:
|
|
|
|
```bash
|
|
forgejo-mcp --transport sse --url <url> --token <token> --debug
|
|
```
|
|
|
|
Or set the environment variable:
|
|
|
|
```bash
|
|
export FORGEJO_DEBUG=true
|
|
```
|
|
|
|
**Custom User-Agent**: If your Forgejo instance or proxy blocks the default `go-http-client` user agent, set a custom one:
|
|
|
|
```bash
|
|
# Via environment variable
|
|
export FORGEJO_USER_AGENT="forgejo-mcp/1.0.0"
|
|
|
|
# Or via CLI flag
|
|
forgejo-mcp --user-agent "forgejo-mcp/1.0.0" --transport sse --url <url> --token <token>
|
|
```
|
|
|
|
## Getting Help
|
|
|
|
- [Report issues](https://codeberg.org/goern/forgejo-mcp/issues)
|
|
- [View source code](https://codeberg.org/goern/forgejo-mcp)
|
|
|
|
This repository is also mirrored on [Radicle](https://radicle.xyz/) — a peer-to-peer code collaboration network. Clone via:
|
|
|
|
```bash
|
|
rad clone rad:z4PdPpsH9iJQcWfqTbxpFcWaZ9zPL
|
|
```
|
|
|
|
## For Developers
|
|
|
|
See [DEVELOPER.md](DEVELOPER.md) for build instructions, architecture overview, and contribution guidelines.
|
|
|
|
## Known Issues
|
|
|
|
- **`go install ...@latest` fails** — The `go.mod` contains a `replace` directive (for a forked Forgejo SDK), which prevents remote `go install`. Use the clone-and-build workflow shown in [Quick Start](#quick-start) instead. Tracked in [#67](https://codeberg.org/goern/forgejo-mcp/issues/67).
|
|
|
|
## 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](https://codeberg.org/goern) (Christoph Görn) | Project creator and maintainer |
|
|
| Ronmi Ren | Co-creator; SSE/HTTP transport, issue blocking, CI/CD improvements, logo, Glama spec |
|
|
| [twstagg](https://codeberg.org/twstagg) (Tristin Stagg) | User agent configuration support (PR #89) |
|
|
| [mattdm](https://codeberg.org/mattdm) (Matthew Miller) | Logging improvements, FORGEJO_* migration, README, URL refactor |
|
|
| [byteflavour](https://codeberg.org/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](https://codeberg.org/jesterret) | Pull request reviews and comments support (PR #51) |
|
|
| [appleboy](https://codeberg.org/appleboy) | Custom SSE port support, bug fixes |
|
|
| [ignasgil](https://codeberg.org/ignasgil) | `remove_issue_labels` tool (PR #96) |
|
|
| [dmikushin](https://codeberg.org/dmikushin) (Dmitry Mikushin) | Fix string-encoded number parameter parsing from MCP clients (PR #93) |
|
|
| [jiriks74](https://codeberg.org/jiriks74) | mcp-go v0.44.0 dependency update (PR #90) |
|
|
| [th](https://codeberg.org/th) (Tomi Haapaniemi) | `update_pull_request` tool |
|
|
| [hiifong](https://codeberg.org/hiifong) | Early bug fixes and updates |
|
|
| [Lunny Xiao](https://codeberg.org/lunny) | Early contributions |
|
|
| [techknowlogick](https://codeberg.org/techknowlogick) | Early contributions |
|
|
| [yp05327](https://codeberg.org/yp05327) | Early contributions |
|
|
| [mw75](https://codeberg.org/mw75) | Owner/org support for repo creation (PR #18) |
|
|
| [Dax Kelson](https://codeberg.org/dkelson) | Issue comment management (PR #34) |
|
|
| [Guruprasad Kulkarni](https://codeberg.org/comdotlinux) | Arch Linux AUR installation docs (PR #69) |
|
|
| [Mario Wolff](https://codeberg.org/mariowolff) | Contributions |
|
|
| [Massimo Fraschetti](https://codeberg.org/fraschetti) | Contributions |
|
|
| [synath](https://codeberg.org/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](https://codeberg.org/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](https://codeberg.org/byteflavour) | Filed #80 (milestone/label discovery), #85 (notification API proposal); active reviewer in discussions |
|
|
| [choucavalier](https://codeberg.org/choucavalier) | Filed #82 (fix skill), #70 (macOS arm64 releases), #62 (binary releases & mise support) |
|
|
| [MalcolmMielle](https://codeberg.org/MalcolmMielle) | Filed #59 (PR review tools — since implemented) |
|
|
| [redbeard](https://codeberg.org/redbeard) | Filed #60 (Actions support — since implemented) |
|
|
| [c6sepl6p](https://codeberg.org/c6sepl6p) | Filed #72 (base64 encoding), #54 (merge pull request — since implemented) |
|
|
| [malik](https://codeberg.org/malik) | Filed #73 (version flag), #47 (Nix build fix) |
|
|
| [a2800276](https://codeberg.org/a2800276) | Filed #74 (OpenAI compatibility) |
|
|
| [simenandre](https://codeberg.org/simenandre) | Filed #49 (go install support) |
|
|
| [BasdP](https://codeberg.org/BasdP) | Filed #42 (Projects support) |
|
|
| [BoBeR182](https://codeberg.org/BoBeR182) | Filed #32 (wiki support) |
|
|
| [ignasgil](https://codeberg.org/ignasgil) | Filed #95 (`remove_issue_labels` feature request) |
|
|
| [Vokuar](https://codeberg.org/Vokuar) | Filed #99 (streamable HTTP transport support) |
|
|
| [janbaer](https://codeberg.org/janbaer) | Filed #98 (reply to review comment) |
|
|
| [fraschm98](https://codeberg.org/fraschm98) | Early issue reports |
|
|
| [heathen711](https://codeberg.org/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](https://codeberg.org/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](https://codeberg.org/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.
|