This release is a pre-release and may not be stable for production use.
forgejo-projects-mcp
An MCP server that lets an AI agent manage Forgejo Projects / Kanban boards, which Forgejo does not expose over its REST API.
It works by driving the same internal web routes the browser uses, authenticated
with a session cookie. HTTP is done through Playwright's APIRequestContext, so
no browser binary is downloaded — only the playwright Python package is
needed. See forgejo-projects-automation-reference.md for the reverse-engineered
endpoints this is built on.
⚠️ This is a janky backend — do not rely on it for production
Forgejo exposes no API for Projects/Kanban, so this tool resorts to browser-style automation: it logs in with a username and password, keeps a session cookie, and calls Forgejo's undocumented, unversioned internal web routes — scraping HTML to recover ids and board state. That is a fragile approach by nature:
- These routes are not a public contract. A Forgejo upgrade (even a minor one) can change markup or routes and silently break tools here.
- State is recovered by HTML scraping and regex, not a structured API, so parsing can drift.
- It authenticates as a real user with a password, not a scoped API token, and performs writes with no transactional guarantees.
- It was verified against one instance (v15.0.7) only.
Treat it as a best-effort convenience / stop-gap for personal or experimental use. Do not put it on a critical path, run it against data you can't afford to lose, or depend on it for production workflows. If/when Forgejo ships a real Projects API, migrate to it. Use at your own risk; test against a throwaway repo first.
Prerequisites
- uv — used to install and run the tool. Install it from the official guide: https://docs.astral.sh/uv/getting-started/installation/.
Installation
All methods install a forgejo-projects-mcp executable onto your PATH (in uv's
tool bin directory). If uv warns that the directory isn't on your PATH, run
uv tool update-shell once and restart your shell. Verify with
forgejo-projects-mcp --help (or uv tool list).
No playwright install step is needed — the tool uses Playwright's HTTP layer,
not a real browser.
Latest release (PyPI)
uv tool install forgejo-projects-mcp
uv tool upgrade forgejo-projects-mcp # update later
Beta testing (latest from source)
Installs the current main branch straight from GitHub — newer than the last
release, and not guaranteed stable:
uv tool install git+https://github.com/UnwantedForeignCloudProvider/ForgejoProjectsMCP
uv tool upgrade forgejo-projects-mcp # re-pull the latest main
Local build (from a clone)
For development, or to install a specific checkout:
git clone https://github.com/UnwantedForeignCloudProvider/ForgejoProjectsMCP
cd ForgejoProjectsMCP
uv tool install .
To pick up local code changes automatically, install with
uv tool install --editable .; to update after pulling changes,
uv tool install . --force. To remove any of the above:
uv tool uninstall forgejo-projects-mcp.
Configuration
Credentials come from environment variables:
| Variable | Example |
|---|---|
FORGEJO_URL |
https://forge.example.com |
FORGEJO_USERNAME |
your-username |
FORGEJO_PASSWORD |
your-password |
A .env file in the working directory is loaded automatically (via
python-dotenv) — copy .env.example to .env and fill it in; no source/
export needed. Real environment variables already set (and an MCP client's own
env block) take precedence. See .env.example for the full list, including the
optional FORGEJO_MCP_MAX_CONCURRENCY, FORGEJO_MCP_RPS, and
FORGEJO_MCP_LOG_LEVEL.
The authenticated session is cached at
<config>/forgejo_projects_mcp/storage_state.json and refreshed automatically
when it expires. <config> is $XDG_CONFIG_HOME if set, otherwise ~/.config
— resolved in an OS-agnostic way (Linux, macOS, Windows) via Path.home().
Run
export FORGEJO_URL=... FORGEJO_USERNAME=... FORGEJO_PASSWORD=...
uv run forgejo-projects-mcp # stdio MCP server
Register with an MCP client
Once installed, reference the command directly:
{
"mcpServers": {
"forgejo-projects-mcp": {
"command": "forgejo-projects-mcp",
"env": {
"FORGEJO_URL": "https://forge.example.com",
"FORGEJO_USERNAME": "your-username",
"FORGEJO_PASSWORD": "your-password"
}
}
}
}
If your MCP client doesn't inherit your shell PATH, use the absolute path to the
executable instead (find it with which forgejo-projects-mcp, or
where forgejo-projects-mcp on Windows).
Agent installation
After uv tool install ., the forgejo-projects-mcp stdio command is on your
PATH. Register it with your agent below (replace the credential values). If the
command isn't found, use its absolute path (which forgejo-projects-mcp).
Claude Code
claude mcp add forgejo-projects-mcp \
-e FORGEJO_URL=https://forge.example.com \
-e FORGEJO_USERNAME=your-username \
-e FORGEJO_PASSWORD=your-password \
-- forgejo-projects-mcp
Codex
codex mcp add forgejo-projects-mcp \
--env FORGEJO_URL=https://forge.example.com \
--env FORGEJO_USERNAME=your-username \
--env FORGEJO_PASSWORD=your-password \
-- forgejo-projects-mcp
Qwen Code
qwen mcp add forgejo-projects-mcp \
-e FORGEJO_URL=https://forge.example.com \
-e FORGEJO_USERNAME=your-username \
-e FORGEJO_PASSWORD=your-password \
forgejo-projects-mcp
OpenClaw
openclaw mcp add forgejo-projects-mcp \
--command forgejo-projects-mcp \
--env FORGEJO_URL=https://forge.example.com \
--env FORGEJO_USERNAME=your-username \
--env FORGEJO_PASSWORD=your-password
opencode
opencode's opencode mcp add is an interactive wizard (no inline env flags), so
add it to opencode.json instead:
{
"mcp": {
"forgejo-projects-mcp": {
"type": "local",
"command": ["forgejo-projects-mcp"],
"environment": {
"FORGEJO_URL": "https://forge.example.com",
"FORGEJO_USERNAME": "your-username",
"FORGEJO_PASSWORD": "your-password"
}
}
}
}
Hermes
Hermes is config-file based — add to ~/.hermes/config.yaml:
mcp_servers:
forgejo-projects-mcp:
command: forgejo-projects-mcp
env:
FORGEJO_URL: https://forge.example.com
FORGEJO_USERNAME: your-username
FORGEJO_PASSWORD: your-password
Tools
Session & discovery
forgejo_status— check authenticationauthenticate(force=False)— log in / refresh sessionlist_repositories(query, limit, page)— repos the user can access (pick one to work in)
Projects
list_projects(owner, repo, state)create_project(owner, repo, title, description, card_type)get_project(owner, repo, project_id)— board with columns + cardsupdate_project(...),close_project(...),reopen_project(...),delete_project(...)
Columns
create_column,edit_column,delete_column,set_default_column
Cards / issues
create_issue(... project_id=)— create an issue, optionally straight onto a boardadd_issues_to_project,remove_issues_from_projectmove_card(owner, repo, project_id, column_id, issue_numbers)bulk_move_cards(owner, repo, project_id, moves)— move many cards, each to its own column, in one call (moves= list of{issue_number, column_id})delete_issue
Bulk reads (run concurrently, rate-limited)
bulk_read_issues(owner, repo, issue_numbers, state="all")— lightweight summaries (number, title, state, milestone)read_card(owner, repo, number)— one card's full content (body + comments) ⚠️read_column(owner, repo, project_id, column_id, state="all", milestone=None)⚠️read_milestone(owner, repo, milestone_id, state="all", project=None)⚠️read_project(owner, repo, project_id, state="all", milestone=None)⚠️
Optional filters on the readers use direct values (no name lookup): state
(open/closed/all), and a milestone/project id (each tool omits the
filter that is already its own subject).
The full readers take limit/offset to cap and page results, and return
total / returned / truncated / error_count so cost and completeness are
explicit. bulk_read_issues returns count (successful only) plus a separate
errors list.
⚠️ = network- and token-expensive; use only when needed. Concurrency and request
rate are tunable via FORGEJO_MCP_MAX_CONCURRENCY (default 8) and
FORGEJO_MCP_RPS (default 5).
Error signaling. Tool failures are returned as MCP errors (isError: true)
with a [CODE] message (e.g. [NOT_FOUND], [INVALID_STATE],
[MILESTONE_NOT_FOUND], [NETWORK_ERROR]) — agents can detect failure without
parsing content. Invalid state values and missing projects/columns/milestones/
issues are hard errors, not silent empty results. Individual issues that fail to
read inside a bulk call are reported inline instead (partial success).
Milestones
list_milestones,create_milestone,edit_milestone,close_milestone,reopen_milestone,delete_milestone
Issue arguments use the repo issue number (what you see as #N); the server
resolves the internal id automatically.
CLI (no MCP client needed)
For harnesses that can't speak MCP, forgejo-projects-cli exposes every tool
as a subcommand, generated from the same tool definitions and dispatched
in-process — so it stays in sync automatically. It reads the same
FORGEJO_URL / FORGEJO_USERNAME / FORGEJO_PASSWORD env vars, prints the JSON
result to stdout, logs to stderr, and exits non-zero on an error result.
forgejo-projects-cli --help # lists every tool
forgejo-projects-cli <tool> --help # options for one tool
forgejo-projects-cli list_repositories --query kanban
forgejo-projects-cli create_project --owner o --repo r --title "Q3"
forgejo-projects-cli read_project --owner o --repo r --project_id 3 --state open
forgejo-projects-cli bulk_move_cards --owner o --repo r --project_id 3 \
--moves '[{"issue_number": 5, "column_id": 12}]'
Options mirror each tool's parameters (--owner, --repo, …); list/object
parameters (--issue_numbers, --moves) take a JSON string.
Notes
- Tested against Forgejo v15.0.7. The web routes are internal and unversioned,
so a major Forgejo upgrade may require adjusting
client.py. - The Forgejo session cookie does not authorize
/api/v1, so everything runs through the web routes.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file forgejo_projects_mcp-0.1.0rc1.tar.gz.
File metadata
- Download URL: forgejo_projects_mcp-0.1.0rc1.tar.gz
- Upload date:
- Size: 22.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1916ff9e707c1fc9aab891806e56d43e17f74983e08bcc9df3717d0d1ae87145
|
|
| MD5 |
7044eeffa0355ef546b7d59896567e2d
|
|
| BLAKE2b-256 |
3f6e17f8ac6efcc9e259917c54f6a9f317c911e4ca624d5ebc039c9e047cde1b
|
Provenance
The following attestation bundles were made for forgejo_projects_mcp-0.1.0rc1.tar.gz:
Publisher:
publish.yml on UnwantedForeignCloudProvider/ForgejoProjectsMCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forgejo_projects_mcp-0.1.0rc1.tar.gz -
Subject digest:
1916ff9e707c1fc9aab891806e56d43e17f74983e08bcc9df3717d0d1ae87145 - Sigstore transparency entry: 2717199860
- Sigstore integration time:
-
Permalink:
UnwantedForeignCloudProvider/ForgejoProjectsMCP@f1c18e3c8b03744f7c6d5cad29a17a279ff55f00 -
Branch / Tag:
refs/tags/v0.1.0rc1 - Owner: https://github.com/UnwantedForeignCloudProvider
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f1c18e3c8b03744f7c6d5cad29a17a279ff55f00 -
Trigger Event:
push
-
Statement type:
File details
Details for the file forgejo_projects_mcp-0.1.0rc1-py3-none-any.whl.
File metadata
- Download URL: forgejo_projects_mcp-0.1.0rc1-py3-none-any.whl
- Upload date:
- Size: 25.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f8f8e6a2d366bd2d354def94737876a9fb4ccb76ad415d4e90709895512cd7a
|
|
| MD5 |
a8dfc62b7d071d2348aaa578c95212c3
|
|
| BLAKE2b-256 |
8cb28194535b06f5ceea70b9d222464c961ee8ee53bd38faed17e7ad980ddfaa
|
Provenance
The following attestation bundles were made for forgejo_projects_mcp-0.1.0rc1-py3-none-any.whl:
Publisher:
publish.yml on UnwantedForeignCloudProvider/ForgejoProjectsMCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forgejo_projects_mcp-0.1.0rc1-py3-none-any.whl -
Subject digest:
4f8f8e6a2d366bd2d354def94737876a9fb4ccb76ad415d4e90709895512cd7a - Sigstore transparency entry: 2717200099
- Sigstore integration time:
-
Permalink:
UnwantedForeignCloudProvider/ForgejoProjectsMCP@f1c18e3c8b03744f7c6d5cad29a17a279ff55f00 -
Branch / Tag:
refs/tags/v0.1.0rc1 - Owner: https://github.com/UnwantedForeignCloudProvider
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f1c18e3c8b03744f7c6d5cad29a17a279ff55f00 -
Trigger Event:
push
-
Statement type: