- Go 88.9%
- Shell 3.8%
- HTML 2.8%
- Python 2.7%
- Just 0.9%
- Other 0.9%
| .agents/skills | ||
| .beads | ||
| .castra | ||
| .claude | ||
| .devcontainer | ||
| .husky | ||
| .pi/skills | ||
| .social-media | ||
| .tekton | ||
| cmd | ||
| demos | ||
| docs | ||
| extension | ||
| hack | ||
| image/release-tools | ||
| manifests | ||
| openspec | ||
| operation | ||
| pkg | ||
| scripts | ||
| test | ||
| .containerignore | ||
| .editorconfig | ||
| .env.sample | ||
| .gitattributes | ||
| .gitignore | ||
| .gitleaks.toml | ||
| .golangci.yml | ||
| .goreleaser.yml | ||
| .mcp.json | ||
| .pre-commit-config.yaml | ||
| .releaserc | ||
| .renovaterc | ||
| .sops.yaml | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| codemcp.toml | ||
| Containerfile | ||
| DEVELOPER.md | ||
| go.mod | ||
| go.sum | ||
| justfile | ||
| LICENSE | ||
| main.go | ||
| Makefile | ||
| OWNERS | ||
| PRD-issue-dependencies.md | ||
| README.md | ||
| SECURITY.md | ||
| skills-lock.json | ||
Forgejo MCP Server
📦 This project has moved. Development, issues, releases, and container images now live at https://git.b4mad.industries/agentic-forges/forgejo-mcp. The Codeberg repository at
codeberg.org/goern/forgejo-mcpremains only as a read-only mirror, and its container registry no longer publishes images — pull fromgit.b4mad.industries/agentic-forges/forgejo-mcpinstead. Issue numbers are preserved across the move. Contributions from humans and AI agents are welcome at the new location.git clone https://git.b4mad.industries/agentic-forges/forgejo-mcp.gitIf you have a remote or a bookmark pointing at
forgejo.b4mad.net, that is the same forge under its previous name — renamed 2026-07-29, not moved again. The old name still resolves and serves port 2222 with the same host key, so existing clones keep working; repoint them at your leisure:git remote set-url origin \ ssh://git@git.b4mad.industries:2222/agentic-forges/forgejo-mcp.git ssh-keyscan -p 2222 git.b4mad.industries >> ~/.ssh/known_hosts
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 agentic-forges/forgejo-mcp"
Quick Start
1. Install
Option A: Using Go (Recommended)
git clone https://git.b4mad.industries/agentic-forges/forgejo-mcp.git
cd forgejo-mcp
go install .
Ensure $GOPATH/bin (typically ~/go/bin) is in your PATH.
Note: you can also install straight from the module path, without cloning:
go install git.b4mad.industries/agentic-forges/forgejo-mcp/v3@latest
Option B: Download Binary
Download the latest release from the releases page.
For Arch Linux, use your favorite AUR helper:
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:
nix-shell -p forgejo-mcp
Or using Flakes:
nix run nixpkgs#forgejo-mcp
Note:
forgejo-mcpis currently only available in theunstablechannel 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
git.b4mad.industries/agentic-forges/forgejo-mcp. Run the server without building from source:
# Latest release
podman run --rm -i \
-e FORGEJO_ACCESS_TOKEN="<your personal access token>" \
git.b4mad.industries/agentic-forges/forgejo-mcp:latest \
--transport stdio --url https://your-forgejo-instance.org
# Or pin a specific version
podman run --rm -i git.b4mad.industries/agentic-forges/forgejo-mcp:v3.1.0 --help
| Tag | Meaning |
|---|---|
vMAJOR.MINOR.PATCH |
Immutable — the exact release (e.g. v3.1.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
to check the signature and provenance before running.
2. Get Your Access Token
- Log into your Forgejo instance
- Go to Settings → Applications → Access Tokens
- 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):
{
"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):
{
"mcpServers": {
"forgejo": {
"url": "http://localhost:8080/mcp"
}
}
}
When using streamable HTTP mode, start the server first:
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.
- Start the server (optionally without any global token):
forgejo-mcp --transport http --url https://your-forgejo-instance.org - Clients include their specific token in each request:
Authorization: token <token>(Forgejo style)Authorization: Bearer <token>(OAuth2/MCP style)- Note: The scheme (
tokenorBearer) is case-insensitive.
See demos/multi-tenant-http.md for a copy-pasteable walkthrough.
Exposing the server to a network
By default the sse and http transports listen on loopback only, so nothing outside
this machine can reach them. This follows the Model Context Protocol's guidance for
locally-run servers, and it is a change in behaviour: earlier versions listened on
every network interface. The default, localhost, binds both loopback families, so a
client that resolves localhost to either 127.0.0.1 or ::1 connects. If the port is
already taken on either family the server refuses to start, rather than serve on the
other family while some clients reach whatever holds the port. A family the machine
cannot use at all — IPv6 disabled, say — is skipped, and the startup log says so.
Pass an address rather than a name — --host 127.0.0.1 or --host ::1 — to bind that
family alone. Use it when the other family is unusable on this machine in a way the
server cannot recognise as "absent", so that it would otherwise refuse to start.
If you run the server in a container, or serve remote clients, you must now say so explicitly. The default will not accept connections from outside the machine — or, in a container, from outside the container:
- set
--hostto an address the network can reach (0.0.0.0for all interfaces, which is the usual choice inside a container); - and set
--allowed-hoststo the host names your clients use. This is required, not optional: the server refuses to start on a network-reachable address without it, rather than starting and rejecting every request.
Requests are refused with 403 Forbidden when their Host header is not one you
declared. Loopback names are always accepted on a loopback listener, so declaring a
proxy's hostname does not stop you connecting directly from the same machine.
Browser clients. A request carrying an Origin header is refused unless that
origin is listed in --allowed-origins, which is empty by default. Origins are
compared in full — scheme, host and port — because an Origin's port belongs to the
page making the request, not to this server. Requests with no Origin header at all
are unaffected, which is the normal case: an MCP client is not a browser.
Authentication on sse and http
On these transports every request must carry its own Authorization header. A request
without one is refused with 401 Unauthorized, rather than being served using the
server's own configured token. This is what the multi-tenant setup above expects
anyway, and it is why that setup is safe to expose.
On stdio the configured token still stands in for an absent header exactly as
before. Nothing about stdio changes.
If you run a single-user deployment over sse or http and want the old behaviour,
--allow-operator-token-fallback restores it. Understand what it means before you use
it: any client that can reach the port acts as the identity behind your token, without
presenting a credential. The startup log says so, loudly, whenever it is on.
For SSE mode (legacy HTTP-based):
{
"mcpServers": {
"forgejo": {
"url": "http://localhost:8080/sse"
}
}
}
When using SSE mode, start the server first:
forgejo-mcp --transport sse --url https://your-forgejo-instance.org --token <your-token>
Remote operation as an OAuth resource server
With --auth-mode resource-server, the http transport becomes an OAuth 2.0
resource server as the MCP authorization specification defines it. Clients no
longer send a Forgejo token. They log in at an OpenID Connect provider you choose
and send its JWT access token. The server validates that token, signs a JWT that
lives five minutes for the caller, and presents it to Forgejo through a Forgejo 16
Authorized Integration. No forge token is configured anywhere, and the caller's
access token never reaches Forgejo.
The mode needs:
- Forgejo 16.0 or newer;
- an OpenID Connect provider that issues JWT access tokens and can add a per-user
claim (default
forgejo_aud) holding the audience of that user's Authorized Integration; - a public HTTPS origin for the server, because Forgejo fetches the server's issuer documents from it;
- a signing key file: EC P-256 or P-384, Ed25519, or RSA of at least 2048 bits.
forgejo-mcp --transport http --url https://forgejo.example.org \
--host 0.0.0.0 --allowed-hosts mcp.example.org \
--auth-mode resource-server \
--authorization-server https://id.example.org \
--resource https://mcp.example.org/mcp \
--forgejo-jwt-issuer https://mcp.example.org/issuer \
--forgejo-jwt-signing-key-file /run/credentials/forgejo-mcp.service/signing-key
The mode is opt-in: without --auth-mode, everything above behaves as before. In
this mode the server answers only /mcp, the protected resource metadata, and the
discovery document and key set under the issuer path. It refuses to start on a
configuration it cannot serve safely, and the refusal names the setting to fix.
The signing key acts for every user whose integration trusts the issuer, so guard
it like the forge token it replaces.
- Operator guide: identity provider requirements, deployment order, proxy rules, key rotation, and a worked Zitadel example.
- User guide: creating the Authorized
Integration, the mandatory
subclaim rule, and configuring an MCP client.
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 |
get_repo |
Get a single repository by owner and name |
create_repo |
Create a new repository |
fork_repo |
Fork a repository |
edit_repo |
Edit repository settings. Only fields you pass change; omitted fields are left unchanged. Providing no fields is an error. |
search_repos |
Search for repositories |
| Topics | |
list_repo_topics |
List a repository's topics. Bounded by page (default 1) + limit (default 100); returns {topics, page, limit, count}. |
set_repo_topics |
Replace all topics. topics is a required comma-separated string; an empty string clears. Invalid names are rejected before the request. |
add_repo_topic |
Add one topic |
delete_repo_topic |
Delete one topic |
| 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 |
| Webhooks | |
list_repo_hooks |
List repository webhooks. Bounded by page (default 1) + limit (default 30, no server-imposed ceiling); returns total_count when Forgejo reports X-Total-Count. |
get_repo_hook |
Get a single repository webhook by ID |
create_repo_hook |
Create a repository webhook. The secret is accepted but never echoed in the response. |
edit_repo_hook |
Edit a repository webhook. Only fields you pass change; omitted fields are left unchanged. |
delete_repo_hook |
Delete a repository webhook by ID |
test_repo_hook |
Trigger a test delivery for a repository webhook — WARNING: triggers a live HTTP delivery |
| 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). |
list_repo_contents |
List files and directories at a path. path="" lists the repository root. Returns one level; for a full tree use get_repo_tree with recursive=true. |
get_repo_tree |
Get the Git tree. recursive=true returns the complete file tree in one response (subject to the server's tree-endpoint size cap); recursive=false (default) returns one level. |
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 |
get_commit_statuses |
List per-context commit statuses for a full 40-character SHA. Bounded by page (default 1) + limit (default 30, maximum 50); returns {sha, statuses, page, limit, count, total_count} — total_count is present only when Forgejo reports X-Total-Count. Combined aggregate stays on the commit status resource. Not Actions runs (list_workflow_runs). |
| Issues | |
list_repo_issues |
List issues in a repository (page/limit). Optional sort orders server-side: relevance, latest, oldest, recentupdate, leastupdate, mostcomment, leastcomment, nearduedate, farduedate (the last two are the due-date directions). |
search_issues |
Search issues across every repository of one owner (page/limit); returns {issues,page,limit,count,has_next,total_count} — total_count is present only when Forgejo reports X-Total-Count |
get_issue_by_index |
Get a specific issue |
create_issue |
Create a new issue. Optional labels (comma-separated names or IDs), assignees (comma-separated usernames) and milestone (numeric ID) are applied by the same request that creates the issue. |
add_issue_labels |
Add labels to an issue. labels takes comma-separated label names or numeric IDs; an unrecognised name is an error and nothing is applied. |
remove_issue_labels |
Remove labels from an issue. labels takes comma-separated label names or numeric IDs. |
update_issue |
Update an existing issue (requires numeric milestone ID). due_date sets the deadline (RFC3339); clear_due_date=true removes it. The two are mutually exclusive — setting both is an error, and omitting both leaves the deadline unchanged. set_labels replaces the issue's entire label set (names or IDs); an empty string clears every label. |
issue_state_change |
Open or close an issue |
list_issue_dependencies |
List issues the given issue depends on. Bounded by page (1-based) + limit (page size); the response echoes page/limit so callers can fetch the next page. |
list_issue_dependents |
List issues that depend on the given issue. Bounded by page (1-based) + limit (page size); the response echoes page/limit so callers can fetch the next page. |
add_issue_dependency |
Make one issue depend on another. The dependency may live in a different repository: optional depends_on_owner/depends_on_repo default to owner/repo. |
remove_issue_dependency |
Remove a dependency from an issue. For a cross-repo dependency, optional dependency_owner/dependency_repo default to owner/repo. |
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. The assignment tools accept label names directly, so this is for discovery and for the rare name that exists in both the repo and the org scope. |
create_repo_label |
Create a repository label (name, color as 6-digit hex, optional description). Returns the numeric id; add_issue_labels also takes the name. |
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. |
submit_pull_review |
Submit a pending pull request review |
dismiss_pull_review |
Dismiss a pull request review |
delete_pull_review |
Delete a pending pull request review |
create_review_requests |
Request reviews from specific users or teams |
delete_review_requests |
Cancel pending review requests |
| Packages | |
list_packages |
List package versions of a user or org (one row per version). Optional type and q. Server-paged via page/limit (default 30, max 50). Envelope {packages, page, limit, count, has_next, total_count?}. A missing owner is an error, not an empty list |
get_package |
Get one package version. Does not embed owner/creator users |
delete_package |
Delete one package version (not every version of the name). No preflight. 4xx/5xx stay errors |
list_package_files |
List files of one package version. Client-paged via page/limit (default 30, max 50); envelope {files, page, limit, count, has_next, total_count} (total_count is the fetched list length) |
| 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 |
list_action_run_jobs |
List jobs for a Forgejo v16+ workflow run with client-side page and limit bounds |
get_action_job_logs |
Read a Forgejo v16+ job log with resumable offset and max_bytes bounds; defaults to the tail |
cancel_workflow_run |
Cancel a pending or running workflow run. Already-finished runs also return success (HTTP 204); the run is left unchanged |
delete_workflow_run |
Delete a completed workflow run. A live run is an API error. Removes the run and its job logs; Forgejo marks that run's artifacts deleted |
list_action_run_artifacts |
List artifacts of a workflow run. Server-paged via page/limit (default 30, max 50); optional name filter. Envelope {artifacts, page, limit, count, total_count?} |
get_action_artifact |
Get metadata for one Actions artifact. Does not download the zip |
| Organizations | |
list_my_orgs |
List my organizations |
list_user_orgs |
List a user's organizations |
get_org |
Get organization details |
create_org |
Create an organization |
edit_org |
Edit organization settings |
delete_org |
Delete an organization — destructive and irreversible: all repos, teams and data are permanently removed |
list_org_members |
List members of an organization |
check_org_membership |
Check if a user is a member of an organization |
remove_org_member |
Remove a member from an organization |
list_org_teams |
List teams in an organization |
search_org_teams |
Search for teams in an organization |
create_org_team |
Create a team in an organization |
add_team_member |
Add a user to a team |
remove_team_member |
Remove a user from a team |
add_team_repo |
Add a repository to a team |
remove_team_repo |
Remove a repository from a team |
| 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 or a file path on the MCP host) |
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 or a file path on the MCP host) |
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 or a file path on the MCP host) |
edit_release_attachment |
Rename a release attachment |
delete_release_attachment |
Delete a release attachment — destructive |
| Wiki | |
list_wiki_pages |
List pages using page/limit; returns has_next and, when Forgejo reports X-Total-Count, total_count. total_count counts upstream's raw wiki tree entries, so it can exceed the number of pages listed on a wiki with subdirectories — an upper bound, not an exact total. |
get_wiki_page |
Read decoded Markdown; optional start_line/end_line, always returns total_lines. |
get_wiki_revisions |
List revision history using page/limit; returns has_next and total_count, the page's total revision count as reported in the response body. |
create_wiki_page |
Create a page and return its server-normalized page_name; slash-separated titles are a flat subpage naming convention (no hierarchy and no automatic parent page), and an existing title is overwritten. |
update_wiki_page |
Update content/title by normalized page_name; last writer wins. |
delete_wiki_page |
Delete a page by normalized page_name. |
| 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}/issues{?state,labels,page,limit} |
application/json | Bounded list of issues as rows — index, title, state, author, labels, assignees, milestone, comment count, timestamps, due date — and no bodies. state ∈ {open, closed, all} (default open); labels comma-separated; cap 30, sentinel names list_repo_issues. Read the single-issue resource for a body. |
forgejo://repo/{owner}/{repo}/{kind}/{index}/comment/{id} |
application/json (+ text/markdown sidecar) | Single comment by id; kind ∈ {issue, pr}. |
forgejo://repo/{owner}/{repo}/{kind}/{index}/comments{?page,limit} |
application/json | Bounded comment thread with full bodies (the single-issue resource excerpts them at 200 chars); kind ∈ {issue, pr}; cap 30, sentinel names list_issue_comments. |
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}/branch_protections |
application/json | Bounded list of branch protection rules. |
forgejo://repo/{owner}/{repo}/branch_protection/{rule} |
application/json | Single branch protection rule. Rule names are branch patterns, so encode a literal / as %2F and spaces as %20 (release%2Fv1); a raw / does not resolve. |
forgejo://repo/{owner}/{repo}/hooks |
application/json | Bounded list of repository webhooks (cap 30, sentinel names list_repo_hooks). The secret is never returned. |
forgejo://repo/{owner}/{repo}/hook/{id} |
application/json | Single repository webhook by id. The secret is never returned. |
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). |
forgejo://repo/{owner}/{repo}/wiki/{pageName} |
application/json (+ text/markdown sidecar) | Wiki page with bounded revisions and Markdown capped at 1 MiB. Use the returned normalized page_name; encode a literal / as %2F and spaces as %20 in the URI (do not double-encode an already normalized name). |
Slash-separated titles such as Guides/Setup are useful as a subpage naming convention,
but Forgejo stores the pages in a flat list: it neither creates Guides automatically nor
records a parent-child relationship. Create the parent separately when readers need it, and
always address subsequent calls with the normalized page_name returned by create or list.
The wiki REST behavior documented here was live-tested against Forgejo
15.0.4+gitea-1.22.0; the complete MCP demo was replayed successfully against
16.0.0+gitea-1.22.0. This is the tested range, not a guarantee for every intermediate
or differently proxied deployment.
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.
# 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
# List jobs and inspect the tail of a failed job (Forgejo v16+)
forgejo-mcp --cli list_action_run_jobs \
--args '{"owner":"goern","repo":"forgejo-mcp","run_id":123}' \
--output=text
forgejo-mcp --cli get_action_job_logs \
--args '{"owner":"goern","repo":"forgejo-mcp","job_id":456,"max_bytes":32768}' \
--output=text
# Forgejo's run-wide ZIP log endpoint has no Range support. Enumerate jobs and
# fetch their bounded plaintext logs instead.
# List artifacts of a run, then read one artifact's metadata (no zip download)
forgejo-mcp --cli list_action_run_artifacts \
--args '{"owner":"goern","repo":"forgejo-mcp","run_id":123,"limit":30}' \
--output=text
forgejo-mcp --cli get_action_artifact \
--args '{"owner":"goern","repo":"forgejo-mcp","artifact_id":789}' \
--output=text
# List package versions for an owner, then inspect one version's files
forgejo-mcp --cli list_packages \
--args '{"owner":"OWNER","type":"container","limit":30}' \
--output=text
forgejo-mcp --cli get_package \
--args '{"owner":"OWNER","type":"container","name":"app","version":"1.0.0"}' \
--output=text
forgejo-mcp --cli list_package_files \
--args '{"owner":"OWNER","type":"container","name":"app","version":"1.0.0"}' \
--output=text
# delete_package removes one version. Do not invoke it against a registry you do not own.
# cancel_workflow_run is 204 even when the run already finished.
# delete_workflow_run only succeeds for a completed run; a live run is an error.
# 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) |
--host |
FORGEJO_MCP_HOST |
Address the sse and http transports bind to (default: localhost, reachable from this machine only, binding both 127.0.0.1 and ::1; pass one of those addresses to bind that family alone) |
--allowed-hosts |
FORGEJO_MCP_ALLOWED_HOSTS |
Comma-separated Host names this server answers to; required when --host is not loopback |
--allowed-origins |
FORGEJO_MCP_ALLOWED_ORIGINS |
Comma-separated web origins allowed to send an Origin header, as full origins (https://console.example.org). Empty by default |
--allow-operator-token-fallback |
FORGEJO_MCP_ALLOW_OPERATOR_TOKEN_FALLBACK |
On sse/http, serve requests with no Authorization header using this server's own token. Off by default |
--auth-mode |
FORGEJO_MCP_AUTH_MODE |
passthrough (default) or resource-server; see Remote operation as an OAuth resource server |
--authorization-server |
FORGEJO_MCP_AUTHORIZATION_SERVER |
resource-server mode: issuer URL of the OpenID Connect provider, compared byte for byte |
--resource |
FORGEJO_MCP_RESOURCE |
resource-server mode: canonical URI of the MCP endpoint, for example https://mcp.example.org/mcp; its path must be /mcp |
--resource-audience |
FORGEJO_MCP_RESOURCE_AUDIENCE |
resource-server mode: value an access token's aud must contain (default: the value of --resource) |
--scopes-supported |
FORGEJO_MCP_SCOPES_SUPPORTED |
resource-server mode: space-separated scopes published in the metadata and the 401 challenge (default: none published) |
--forgejo-audience-claim |
FORGEJO_MCP_FORGEJO_AUDIENCE_CLAIM |
resource-server mode: access-token claim holding the audience of the caller's Forgejo Authorized Integration (default: forgejo_aud) |
--forgejo-jwt-issuer |
FORGEJO_MCP_FORGEJO_JWT_ISSUER |
resource-server mode: issuer URL under which the server signs JWTs for Forgejo, for example https://mcp.example.org/issuer; https, without a trailing slash |
--forgejo-jwt-signing-key-file |
FORGEJO_MCP_FORGEJO_JWT_SIGNING_KEY_FILE |
resource-server mode: PEM private key that signs the JWTs for Forgejo (EC P-256 or P-384, Ed25519, or RSA of at least 2048 bits) |
--forgejo-jwt-published-key-files |
FORGEJO_MCP_FORGEJO_JWT_PUBLISHED_KEY_FILES |
resource-server mode: comma-separated PEM keys published next to the signing key, for key rotation |
--cli |
- | Enter CLI mode for direct tool invocation |
--user-agent |
FORGEJO_USER_AGENT |
HTTP User-Agent header (default: forgejo-mcp/<version>) |
| - | FORGEJO_MCP_ALLOW_FILE_PATH_UPLOAD |
Allow file_path attachment uploads to read the host filesystem (1/true/yes/on; off by default) |
| - | FORGEJO_MCP_UPLOAD_ROOT |
Confine file_path uploads to this directory (default: anywhere the process can read) |
Command-line arguments take priority over environment variables.
The resource-server settings are refused in passthrough mode, so a configuration that sets them but forgets --auth-mode resource-server does not start.
Uploading attachments from the host filesystem
create_issue_attachment, create_comment_attachment, and
create_release_attachment accept either base64 content or a file_path on
the machine running forgejo-mcp. The path form avoids base64-expanding a large
release artifact through the MCP transport.
It is off by default, because it hands whatever drives the MCP client the
ability to read any file the server process can read — a prompt-injected agent
could upload ~/.ssh/id_ed25519 as a public release asset. Turn it on
deliberately, and prefer confining it:
export FORGEJO_MCP_ALLOW_FILE_PATH_UPLOAD=1
export FORGEJO_MCP_UPLOAD_ROOT=/home/you/build/dist # optional but recommended
With FORGEJO_MCP_UPLOAD_ROOT set, a path that resolves outside that directory
— by being absolute, by .., or through a symlink — is rejected before anything
is read. Base64 content uploads are unaffected by either variable.
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
.sigfile — verification applies fromv2.23.xonward only, and only when theCOSIGN_PRIVATE_KEYsecret was configured at release time.
1. Install cosign
Follow the upstream cosign installation guide for your platform. Quick paths:
# 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:
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):
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):
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. v3.1.0) and grab the checksum file,
its signature, and the binary archive:
TAG=v3.1.0
VERSION="${TAG#v}"
BASE="https://git.b4mad.industries/agentic-forges/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.
# 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. 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):
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:
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-attestationpayload.
6. Verify the container image
The git.b4mad.industries/agentic-forges/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:
IMAGE_TAG=v3.1.0 # substitute the release you are pulling
cosign verify \
--key cosign-images.pub \
"git.b4mad.industries/agentic-forges/forgejo-mcp:${IMAGE_TAG}" \
| jq .
Verify the SLSA provenance attestation:
cosign verify-attestation \
--type slsaprovenance \
--key cosign-images.pub \
"git.b4mad.industries/agentic-forges/forgejo-mcp:${IMAGE_TAG}" \
| jq .
Verify and download the signed CycloneDX SBOM attestation:
cosign verify-attestation \
--type cyclonedx \
--key cosign-images.pub \
"git.b4mad.industries/agentic-forges/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 unsignedattach sbomartifact.cosign download sbomno 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.sigfile is from a different release, orcosign.pubis 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.puband 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 frombranch/main.
Troubleshooting
Enable debug mode to see detailed logs:
forgejo-mcp --transport sse --url <url> --token <token> --debug
Or set the environment variable:
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:
# 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 — bugs, questions, feature requests
- Found a security problem? Do not use the issue tracker. See SECURITY.md for how to report it privately.
- View source code
- Chat on Matrix —
#forgejo-mcp:b4mad.net
This repository is also mirrored on Radicle — a peer-to-peer code collaboration network. Clone via:
rad clone rad:z4PdPpsH9iJQcWfqTbxpFcWaZ9zPL
For Developers
See DEVELOPER.md for build instructions, architecture overview, and contribution guidelines.
Known Issues
-
Installing from the old Codeberg module path —
go install codeberg.org/goern/forgejo-mcp/v2@lateststill resolves, against the read-only mirror, but that mirror lags behind the current release. Usegit.b4mad.industries/agentic-forges/forgejo-mcp/v3@latestinstead.This entry used to say that the new path was not installable until a release carried the renamed
go.mod. That release has happened —v3.0.0onwards declaremodule git.b4mad.industries/agentic-forges/forgejo-mcp/v3— so the new path installs normally. The earlierreplace-directive blocker (#67) is also gone;go.modno longer contains one.
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); network transport hardening — loopback-by-default bind, Host/Origin checks, per-request credential (PR #545, landed as #573; #586, #585, #589); OAuth resource-server mode — inbound JWT validation and outbound Forgejo 16 Authorized Integration signing, with operator and user guides and 40 anchored demo scenarios (PR #584, researched in #582); dev-env FORGEJO_MCP_EXEC (PR #580); 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, #123); issue due_date + server-side sort (PR #483); bounded issue-list and comment-thread resources (PR #487); total_count on paginated envelopes from X-Total-Count (PR #507); create_*_attachment timeout hardening (PR #534, #536); cross-repo issue dependencies (PR #535) |
| 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! 🎉 |
| nesvet (Eugene Nesvetaev) | get_repo/edit_repo (PR #527); repository topic tools (PR #528); Actions run cancel/delete and run artifacts (PR #533); get_commit_statuses (PR #542); package list/get/delete/files tools (PR #543); label names accepted on issue create, assignment and replace (PR #591) |
| pisco (Marco Pisco) | file_path uploads for issue, comment, and release attachments, with streaming multipart so large release assets no longer round-trip through base64 (PR #481) |
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 |
| decarvalhoaa (Antonio De Carvalho) | Filed #593 (server-side response size cap) from a real context-window overflow behind Open WebUI, with the measurement that prompted the list_repo_pull_requests payload work in #596 |
| chris420 (Chris Oloff) | Filed #452 (org-wide issue search — since implemented as search_issues); design review on PR #458 that replaced the next-page probe with instance-ceiling enforcement, and caught the response envelope misreporting its own limit |
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-agent | 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.