forgejo-projects-mcp 0.1.0rc1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- forgejo_projects_mcp-0.1.0rc1/.gitignore +20 -0
- forgejo_projects_mcp-0.1.0rc1/LICENSE +24 -0
- forgejo_projects_mcp-0.1.0rc1/PKG-INFO +331 -0
- forgejo_projects_mcp-0.1.0rc1/README.md +319 -0
- forgejo_projects_mcp-0.1.0rc1/pyproject.toml +64 -0
- forgejo_projects_mcp-0.1.0rc1/src/forgejo_projects_mcp/__init__.py +18 -0
- forgejo_projects_mcp-0.1.0rc1/src/forgejo_projects_mcp/_env.py +17 -0
- forgejo_projects_mcp-0.1.0rc1/src/forgejo_projects_mcp/cli.py +107 -0
- forgejo_projects_mcp-0.1.0rc1/src/forgejo_projects_mcp/client.py +1307 -0
- forgejo_projects_mcp-0.1.0rc1/src/forgejo_projects_mcp/server.py +502 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Tooling caches
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
.ruff_cache/
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv
|
|
15
|
+
|
|
16
|
+
# Credentials
|
|
17
|
+
.env
|
|
18
|
+
|
|
19
|
+
# MkDocs build output
|
|
20
|
+
site/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org>
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: forgejo-projects-mcp
|
|
3
|
+
Version: 0.1.0rc1
|
|
4
|
+
Summary: MCP server for managing Forgejo Projects/Kanban boards
|
|
5
|
+
Author-email: UnwantedForeignCloudProvider <donot@m3ss4ge.me>
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.14
|
|
8
|
+
Requires-Dist: mcp[cli]>=2.1.1
|
|
9
|
+
Requires-Dist: playwright>=1.62.0
|
|
10
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# forgejo-projects-mcp
|
|
14
|
+
|
|
15
|
+
An MCP server that lets an AI agent manage **Forgejo Projects / Kanban boards**,
|
|
16
|
+
which Forgejo does **not** expose over its REST API.
|
|
17
|
+
|
|
18
|
+
It works by driving the same internal web routes the browser uses, authenticated
|
|
19
|
+
with a session cookie. HTTP is done through Playwright's `APIRequestContext`, so
|
|
20
|
+
**no browser binary is downloaded** — only the `playwright` Python package is
|
|
21
|
+
needed. See `forgejo-projects-automation-reference.md` for the reverse-engineered
|
|
22
|
+
endpoints this is built on.
|
|
23
|
+
|
|
24
|
+
## ⚠️ This is a janky backend — do not rely on it for production
|
|
25
|
+
|
|
26
|
+
Forgejo exposes **no API** for Projects/Kanban, so this tool resorts to
|
|
27
|
+
**browser-style automation**: it logs in with a username and password, keeps a
|
|
28
|
+
session cookie, and calls Forgejo's **undocumented, unversioned internal web
|
|
29
|
+
routes** — scraping HTML to recover ids and board state. That is a fragile
|
|
30
|
+
approach by nature:
|
|
31
|
+
|
|
32
|
+
- These routes are **not a public contract**. A Forgejo upgrade (even a minor one)
|
|
33
|
+
can change markup or routes and silently break tools here.
|
|
34
|
+
- State is recovered by **HTML scraping and regex**, not a structured API, so
|
|
35
|
+
parsing can drift.
|
|
36
|
+
- It authenticates as a **real user with a password**, not a scoped API token,
|
|
37
|
+
and performs writes with no transactional guarantees.
|
|
38
|
+
- It was verified against **one instance (v15.0.7)** only.
|
|
39
|
+
|
|
40
|
+
Treat it as a **best-effort convenience / stop-gap for personal or experimental
|
|
41
|
+
use**. Do **not** put it on a critical path, run it against data you can't afford
|
|
42
|
+
to lose, or depend on it for production workflows. If/when Forgejo ships a real
|
|
43
|
+
Projects API, migrate to it. Use at your own risk; test against a throwaway repo
|
|
44
|
+
first.
|
|
45
|
+
|
|
46
|
+
## Prerequisites
|
|
47
|
+
|
|
48
|
+
- **[uv](https://docs.astral.sh/uv/)** — used to install and run the tool.
|
|
49
|
+
Install it from the official guide:
|
|
50
|
+
<https://docs.astral.sh/uv/getting-started/installation/>.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
All methods install a `forgejo-projects-mcp` executable onto your PATH (in uv's
|
|
55
|
+
tool bin directory). If uv warns that the directory isn't on your PATH, run
|
|
56
|
+
`uv tool update-shell` once and restart your shell. Verify with
|
|
57
|
+
`forgejo-projects-mcp --help` (or `uv tool list`).
|
|
58
|
+
|
|
59
|
+
No `playwright install` step is needed — the tool uses Playwright's HTTP layer,
|
|
60
|
+
not a real browser.
|
|
61
|
+
|
|
62
|
+
### Latest release (PyPI)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv tool install forgejo-projects-mcp
|
|
66
|
+
uv tool upgrade forgejo-projects-mcp # update later
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Beta testing (latest from source)
|
|
70
|
+
|
|
71
|
+
Installs the current `main` branch straight from GitHub — newer than the last
|
|
72
|
+
release, and not guaranteed stable:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uv tool install git+https://github.com/UnwantedForeignCloudProvider/ForgejoProjectsMCP
|
|
76
|
+
uv tool upgrade forgejo-projects-mcp # re-pull the latest main
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Local build (from a clone)
|
|
80
|
+
|
|
81
|
+
For development, or to install a specific checkout:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/UnwantedForeignCloudProvider/ForgejoProjectsMCP
|
|
85
|
+
cd ForgejoProjectsMCP
|
|
86
|
+
uv tool install .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
To pick up local code changes automatically, install with
|
|
90
|
+
`uv tool install --editable .`; to update after pulling changes,
|
|
91
|
+
`uv tool install . --force`. To remove any of the above:
|
|
92
|
+
`uv tool uninstall forgejo-projects-mcp`.
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
Credentials come from environment variables:
|
|
97
|
+
|
|
98
|
+
| Variable | Example |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `FORGEJO_URL` | `https://forge.example.com` |
|
|
101
|
+
| `FORGEJO_USERNAME` | `your-username` |
|
|
102
|
+
| `FORGEJO_PASSWORD` | `your-password` |
|
|
103
|
+
|
|
104
|
+
A `.env` file in the working directory is **loaded automatically** (via
|
|
105
|
+
python-dotenv) — copy `.env.example` to `.env` and fill it in; no `source`/
|
|
106
|
+
`export` needed. Real environment variables already set (and an MCP client's own
|
|
107
|
+
`env` block) take precedence. See `.env.example` for the full list, including the
|
|
108
|
+
optional `FORGEJO_MCP_MAX_CONCURRENCY`, `FORGEJO_MCP_RPS`, and
|
|
109
|
+
`FORGEJO_MCP_LOG_LEVEL`.
|
|
110
|
+
|
|
111
|
+
The authenticated session is cached at
|
|
112
|
+
`<config>/forgejo_projects_mcp/storage_state.json` and refreshed automatically
|
|
113
|
+
when it expires. `<config>` is `$XDG_CONFIG_HOME` if set, otherwise `~/.config`
|
|
114
|
+
— resolved in an OS-agnostic way (Linux, macOS, Windows) via `Path.home()`.
|
|
115
|
+
|
|
116
|
+
## Run
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
export FORGEJO_URL=... FORGEJO_USERNAME=... FORGEJO_PASSWORD=...
|
|
120
|
+
uv run forgejo-projects-mcp # stdio MCP server
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Register with an MCP client
|
|
124
|
+
|
|
125
|
+
Once installed, reference the command directly:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"mcpServers": {
|
|
130
|
+
"forgejo-projects-mcp": {
|
|
131
|
+
"command": "forgejo-projects-mcp",
|
|
132
|
+
"env": {
|
|
133
|
+
"FORGEJO_URL": "https://forge.example.com",
|
|
134
|
+
"FORGEJO_USERNAME": "your-username",
|
|
135
|
+
"FORGEJO_PASSWORD": "your-password"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
If your MCP client doesn't inherit your shell PATH, use the absolute path to the
|
|
143
|
+
executable instead (find it with `which forgejo-projects-mcp`, or
|
|
144
|
+
`where forgejo-projects-mcp` on Windows).
|
|
145
|
+
|
|
146
|
+
## Agent installation
|
|
147
|
+
|
|
148
|
+
After `uv tool install .`, the `forgejo-projects-mcp` stdio command is on your
|
|
149
|
+
PATH. Register it with your agent below (replace the credential values). If the
|
|
150
|
+
command isn't found, use its absolute path (`which forgejo-projects-mcp`).
|
|
151
|
+
|
|
152
|
+
<details>
|
|
153
|
+
<summary><b>Claude Code</b></summary>
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
claude mcp add forgejo-projects-mcp \
|
|
157
|
+
-e FORGEJO_URL=https://forge.example.com \
|
|
158
|
+
-e FORGEJO_USERNAME=your-username \
|
|
159
|
+
-e FORGEJO_PASSWORD=your-password \
|
|
160
|
+
-- forgejo-projects-mcp
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
<details>
|
|
166
|
+
<summary><b>Codex</b></summary>
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
codex mcp add forgejo-projects-mcp \
|
|
170
|
+
--env FORGEJO_URL=https://forge.example.com \
|
|
171
|
+
--env FORGEJO_USERNAME=your-username \
|
|
172
|
+
--env FORGEJO_PASSWORD=your-password \
|
|
173
|
+
-- forgejo-projects-mcp
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
</details>
|
|
177
|
+
|
|
178
|
+
<details>
|
|
179
|
+
<summary><b>Qwen Code</b></summary>
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
qwen mcp add forgejo-projects-mcp \
|
|
183
|
+
-e FORGEJO_URL=https://forge.example.com \
|
|
184
|
+
-e FORGEJO_USERNAME=your-username \
|
|
185
|
+
-e FORGEJO_PASSWORD=your-password \
|
|
186
|
+
forgejo-projects-mcp
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
</details>
|
|
190
|
+
|
|
191
|
+
<details>
|
|
192
|
+
<summary><b>OpenClaw</b></summary>
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
openclaw mcp add forgejo-projects-mcp \
|
|
196
|
+
--command forgejo-projects-mcp \
|
|
197
|
+
--env FORGEJO_URL=https://forge.example.com \
|
|
198
|
+
--env FORGEJO_USERNAME=your-username \
|
|
199
|
+
--env FORGEJO_PASSWORD=your-password
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
</details>
|
|
203
|
+
|
|
204
|
+
<details>
|
|
205
|
+
<summary><b>opencode</b></summary>
|
|
206
|
+
|
|
207
|
+
opencode's `opencode mcp add` is an interactive wizard (no inline env flags), so
|
|
208
|
+
add it to `opencode.json` instead:
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"mcp": {
|
|
213
|
+
"forgejo-projects-mcp": {
|
|
214
|
+
"type": "local",
|
|
215
|
+
"command": ["forgejo-projects-mcp"],
|
|
216
|
+
"environment": {
|
|
217
|
+
"FORGEJO_URL": "https://forge.example.com",
|
|
218
|
+
"FORGEJO_USERNAME": "your-username",
|
|
219
|
+
"FORGEJO_PASSWORD": "your-password"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
</details>
|
|
227
|
+
|
|
228
|
+
<details>
|
|
229
|
+
<summary><b>Hermes</b></summary>
|
|
230
|
+
|
|
231
|
+
Hermes is config-file based — add to `~/.hermes/config.yaml`:
|
|
232
|
+
|
|
233
|
+
```yaml
|
|
234
|
+
mcp_servers:
|
|
235
|
+
forgejo-projects-mcp:
|
|
236
|
+
command: forgejo-projects-mcp
|
|
237
|
+
env:
|
|
238
|
+
FORGEJO_URL: https://forge.example.com
|
|
239
|
+
FORGEJO_USERNAME: your-username
|
|
240
|
+
FORGEJO_PASSWORD: your-password
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
</details>
|
|
244
|
+
|
|
245
|
+
## Tools
|
|
246
|
+
|
|
247
|
+
**Session & discovery**
|
|
248
|
+
- `forgejo_status` — check authentication
|
|
249
|
+
- `authenticate(force=False)` — log in / refresh session
|
|
250
|
+
- `list_repositories(query, limit, page)` — repos the user can access (pick one to work in)
|
|
251
|
+
|
|
252
|
+
**Projects**
|
|
253
|
+
- `list_projects(owner, repo, state)`
|
|
254
|
+
- `create_project(owner, repo, title, description, card_type)`
|
|
255
|
+
- `get_project(owner, repo, project_id)` — board with columns + cards
|
|
256
|
+
- `update_project(...)`, `close_project(...)`, `reopen_project(...)`, `delete_project(...)`
|
|
257
|
+
|
|
258
|
+
**Columns**
|
|
259
|
+
- `create_column`, `edit_column`, `delete_column`, `set_default_column`
|
|
260
|
+
|
|
261
|
+
**Cards / issues**
|
|
262
|
+
- `create_issue(... project_id=)` — create an issue, optionally straight onto a board
|
|
263
|
+
- `add_issues_to_project`, `remove_issues_from_project`
|
|
264
|
+
- `move_card(owner, repo, project_id, column_id, issue_numbers)`
|
|
265
|
+
- `bulk_move_cards(owner, repo, project_id, moves)` — move many cards, each to its
|
|
266
|
+
own column, in one call (`moves` = list of `{issue_number, column_id}`)
|
|
267
|
+
- `delete_issue`
|
|
268
|
+
|
|
269
|
+
**Bulk reads** (run concurrently, rate-limited)
|
|
270
|
+
- `bulk_read_issues(owner, repo, issue_numbers, state="all")` — lightweight
|
|
271
|
+
summaries (number, title, state, milestone)
|
|
272
|
+
- `read_card(owner, repo, number)` — one card's full content (body + comments) ⚠️
|
|
273
|
+
- `read_column(owner, repo, project_id, column_id, state="all", milestone=None)` ⚠️
|
|
274
|
+
- `read_milestone(owner, repo, milestone_id, state="all", project=None)` ⚠️
|
|
275
|
+
- `read_project(owner, repo, project_id, state="all", milestone=None)` ⚠️
|
|
276
|
+
|
|
277
|
+
Optional filters on the readers use direct values (no name lookup): `state`
|
|
278
|
+
(`open`/`closed`/`all`), and a `milestone`/`project` **id** (each tool omits the
|
|
279
|
+
filter that is already its own subject).
|
|
280
|
+
|
|
281
|
+
The full readers take `limit`/`offset` to cap and page results, and return
|
|
282
|
+
`total` / `returned` / `truncated` / `error_count` so cost and completeness are
|
|
283
|
+
explicit. `bulk_read_issues` returns `count` (successful only) plus a separate
|
|
284
|
+
`errors` list.
|
|
285
|
+
|
|
286
|
+
⚠️ = network- and token-expensive; use only when needed. Concurrency and request
|
|
287
|
+
rate are tunable via `FORGEJO_MCP_MAX_CONCURRENCY` (default 8) and
|
|
288
|
+
`FORGEJO_MCP_RPS` (default 5).
|
|
289
|
+
|
|
290
|
+
**Error signaling.** Tool failures are returned as MCP errors (`isError: true`)
|
|
291
|
+
with a `[CODE] message` (e.g. `[NOT_FOUND]`, `[INVALID_STATE]`,
|
|
292
|
+
`[MILESTONE_NOT_FOUND]`, `[NETWORK_ERROR]`) — agents can detect failure without
|
|
293
|
+
parsing content. Invalid `state` values and missing projects/columns/milestones/
|
|
294
|
+
issues are hard errors, not silent empty results. Individual issues that fail to
|
|
295
|
+
read inside a bulk call are reported inline instead (partial success).
|
|
296
|
+
|
|
297
|
+
**Milestones**
|
|
298
|
+
- `list_milestones`, `create_milestone`, `edit_milestone`,
|
|
299
|
+
`close_milestone`, `reopen_milestone`, `delete_milestone`
|
|
300
|
+
|
|
301
|
+
Issue arguments use the **repo issue number** (what you see as `#N`); the server
|
|
302
|
+
resolves the internal id automatically.
|
|
303
|
+
|
|
304
|
+
## CLI (no MCP client needed)
|
|
305
|
+
|
|
306
|
+
For harnesses that can't speak MCP, `forgejo-projects-cli` exposes **every tool
|
|
307
|
+
as a subcommand**, generated from the same tool definitions and dispatched
|
|
308
|
+
in-process — so it stays in sync automatically. It reads the same
|
|
309
|
+
`FORGEJO_URL` / `FORGEJO_USERNAME` / `FORGEJO_PASSWORD` env vars, prints the JSON
|
|
310
|
+
result to stdout, logs to stderr, and exits non-zero on an error result.
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
forgejo-projects-cli --help # lists every tool
|
|
314
|
+
forgejo-projects-cli <tool> --help # options for one tool
|
|
315
|
+
|
|
316
|
+
forgejo-projects-cli list_repositories --query kanban
|
|
317
|
+
forgejo-projects-cli create_project --owner o --repo r --title "Q3"
|
|
318
|
+
forgejo-projects-cli read_project --owner o --repo r --project_id 3 --state open
|
|
319
|
+
forgejo-projects-cli bulk_move_cards --owner o --repo r --project_id 3 \
|
|
320
|
+
--moves '[{"issue_number": 5, "column_id": 12}]'
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Options mirror each tool's parameters (`--owner`, `--repo`, …); list/object
|
|
324
|
+
parameters (`--issue_numbers`, `--moves`) take a JSON string.
|
|
325
|
+
|
|
326
|
+
## Notes
|
|
327
|
+
|
|
328
|
+
- Tested against Forgejo **v15.0.7**. The web routes are internal and unversioned,
|
|
329
|
+
so a major Forgejo upgrade may require adjusting `client.py`.
|
|
330
|
+
- The Forgejo session cookie does **not** authorize `/api/v1`, so everything runs
|
|
331
|
+
through the web routes.
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# forgejo-projects-mcp
|
|
2
|
+
|
|
3
|
+
An MCP server that lets an AI agent manage **Forgejo Projects / Kanban boards**,
|
|
4
|
+
which Forgejo does **not** expose over its REST API.
|
|
5
|
+
|
|
6
|
+
It works by driving the same internal web routes the browser uses, authenticated
|
|
7
|
+
with a session cookie. HTTP is done through Playwright's `APIRequestContext`, so
|
|
8
|
+
**no browser binary is downloaded** — only the `playwright` Python package is
|
|
9
|
+
needed. See `forgejo-projects-automation-reference.md` for the reverse-engineered
|
|
10
|
+
endpoints this is built on.
|
|
11
|
+
|
|
12
|
+
## ⚠️ This is a janky backend — do not rely on it for production
|
|
13
|
+
|
|
14
|
+
Forgejo exposes **no API** for Projects/Kanban, so this tool resorts to
|
|
15
|
+
**browser-style automation**: it logs in with a username and password, keeps a
|
|
16
|
+
session cookie, and calls Forgejo's **undocumented, unversioned internal web
|
|
17
|
+
routes** — scraping HTML to recover ids and board state. That is a fragile
|
|
18
|
+
approach by nature:
|
|
19
|
+
|
|
20
|
+
- These routes are **not a public contract**. A Forgejo upgrade (even a minor one)
|
|
21
|
+
can change markup or routes and silently break tools here.
|
|
22
|
+
- State is recovered by **HTML scraping and regex**, not a structured API, so
|
|
23
|
+
parsing can drift.
|
|
24
|
+
- It authenticates as a **real user with a password**, not a scoped API token,
|
|
25
|
+
and performs writes with no transactional guarantees.
|
|
26
|
+
- It was verified against **one instance (v15.0.7)** only.
|
|
27
|
+
|
|
28
|
+
Treat it as a **best-effort convenience / stop-gap for personal or experimental
|
|
29
|
+
use**. Do **not** put it on a critical path, run it against data you can't afford
|
|
30
|
+
to lose, or depend on it for production workflows. If/when Forgejo ships a real
|
|
31
|
+
Projects API, migrate to it. Use at your own risk; test against a throwaway repo
|
|
32
|
+
first.
|
|
33
|
+
|
|
34
|
+
## Prerequisites
|
|
35
|
+
|
|
36
|
+
- **[uv](https://docs.astral.sh/uv/)** — used to install and run the tool.
|
|
37
|
+
Install it from the official guide:
|
|
38
|
+
<https://docs.astral.sh/uv/getting-started/installation/>.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
All methods install a `forgejo-projects-mcp` executable onto your PATH (in uv's
|
|
43
|
+
tool bin directory). If uv warns that the directory isn't on your PATH, run
|
|
44
|
+
`uv tool update-shell` once and restart your shell. Verify with
|
|
45
|
+
`forgejo-projects-mcp --help` (or `uv tool list`).
|
|
46
|
+
|
|
47
|
+
No `playwright install` step is needed — the tool uses Playwright's HTTP layer,
|
|
48
|
+
not a real browser.
|
|
49
|
+
|
|
50
|
+
### Latest release (PyPI)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv tool install forgejo-projects-mcp
|
|
54
|
+
uv tool upgrade forgejo-projects-mcp # update later
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Beta testing (latest from source)
|
|
58
|
+
|
|
59
|
+
Installs the current `main` branch straight from GitHub — newer than the last
|
|
60
|
+
release, and not guaranteed stable:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv tool install git+https://github.com/UnwantedForeignCloudProvider/ForgejoProjectsMCP
|
|
64
|
+
uv tool upgrade forgejo-projects-mcp # re-pull the latest main
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Local build (from a clone)
|
|
68
|
+
|
|
69
|
+
For development, or to install a specific checkout:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/UnwantedForeignCloudProvider/ForgejoProjectsMCP
|
|
73
|
+
cd ForgejoProjectsMCP
|
|
74
|
+
uv tool install .
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
To pick up local code changes automatically, install with
|
|
78
|
+
`uv tool install --editable .`; to update after pulling changes,
|
|
79
|
+
`uv tool install . --force`. To remove any of the above:
|
|
80
|
+
`uv tool uninstall forgejo-projects-mcp`.
|
|
81
|
+
|
|
82
|
+
## Configuration
|
|
83
|
+
|
|
84
|
+
Credentials come from environment variables:
|
|
85
|
+
|
|
86
|
+
| Variable | Example |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `FORGEJO_URL` | `https://forge.example.com` |
|
|
89
|
+
| `FORGEJO_USERNAME` | `your-username` |
|
|
90
|
+
| `FORGEJO_PASSWORD` | `your-password` |
|
|
91
|
+
|
|
92
|
+
A `.env` file in the working directory is **loaded automatically** (via
|
|
93
|
+
python-dotenv) — copy `.env.example` to `.env` and fill it in; no `source`/
|
|
94
|
+
`export` needed. Real environment variables already set (and an MCP client's own
|
|
95
|
+
`env` block) take precedence. See `.env.example` for the full list, including the
|
|
96
|
+
optional `FORGEJO_MCP_MAX_CONCURRENCY`, `FORGEJO_MCP_RPS`, and
|
|
97
|
+
`FORGEJO_MCP_LOG_LEVEL`.
|
|
98
|
+
|
|
99
|
+
The authenticated session is cached at
|
|
100
|
+
`<config>/forgejo_projects_mcp/storage_state.json` and refreshed automatically
|
|
101
|
+
when it expires. `<config>` is `$XDG_CONFIG_HOME` if set, otherwise `~/.config`
|
|
102
|
+
— resolved in an OS-agnostic way (Linux, macOS, Windows) via `Path.home()`.
|
|
103
|
+
|
|
104
|
+
## Run
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
export FORGEJO_URL=... FORGEJO_USERNAME=... FORGEJO_PASSWORD=...
|
|
108
|
+
uv run forgejo-projects-mcp # stdio MCP server
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Register with an MCP client
|
|
112
|
+
|
|
113
|
+
Once installed, reference the command directly:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"mcpServers": {
|
|
118
|
+
"forgejo-projects-mcp": {
|
|
119
|
+
"command": "forgejo-projects-mcp",
|
|
120
|
+
"env": {
|
|
121
|
+
"FORGEJO_URL": "https://forge.example.com",
|
|
122
|
+
"FORGEJO_USERNAME": "your-username",
|
|
123
|
+
"FORGEJO_PASSWORD": "your-password"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If your MCP client doesn't inherit your shell PATH, use the absolute path to the
|
|
131
|
+
executable instead (find it with `which forgejo-projects-mcp`, or
|
|
132
|
+
`where forgejo-projects-mcp` on Windows).
|
|
133
|
+
|
|
134
|
+
## Agent installation
|
|
135
|
+
|
|
136
|
+
After `uv tool install .`, the `forgejo-projects-mcp` stdio command is on your
|
|
137
|
+
PATH. Register it with your agent below (replace the credential values). If the
|
|
138
|
+
command isn't found, use its absolute path (`which forgejo-projects-mcp`).
|
|
139
|
+
|
|
140
|
+
<details>
|
|
141
|
+
<summary><b>Claude Code</b></summary>
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
claude mcp add forgejo-projects-mcp \
|
|
145
|
+
-e FORGEJO_URL=https://forge.example.com \
|
|
146
|
+
-e FORGEJO_USERNAME=your-username \
|
|
147
|
+
-e FORGEJO_PASSWORD=your-password \
|
|
148
|
+
-- forgejo-projects-mcp
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
<details>
|
|
154
|
+
<summary><b>Codex</b></summary>
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
codex mcp add forgejo-projects-mcp \
|
|
158
|
+
--env FORGEJO_URL=https://forge.example.com \
|
|
159
|
+
--env FORGEJO_USERNAME=your-username \
|
|
160
|
+
--env FORGEJO_PASSWORD=your-password \
|
|
161
|
+
-- forgejo-projects-mcp
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
</details>
|
|
165
|
+
|
|
166
|
+
<details>
|
|
167
|
+
<summary><b>Qwen Code</b></summary>
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
qwen mcp add forgejo-projects-mcp \
|
|
171
|
+
-e FORGEJO_URL=https://forge.example.com \
|
|
172
|
+
-e FORGEJO_USERNAME=your-username \
|
|
173
|
+
-e FORGEJO_PASSWORD=your-password \
|
|
174
|
+
forgejo-projects-mcp
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
</details>
|
|
178
|
+
|
|
179
|
+
<details>
|
|
180
|
+
<summary><b>OpenClaw</b></summary>
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
openclaw mcp add forgejo-projects-mcp \
|
|
184
|
+
--command forgejo-projects-mcp \
|
|
185
|
+
--env FORGEJO_URL=https://forge.example.com \
|
|
186
|
+
--env FORGEJO_USERNAME=your-username \
|
|
187
|
+
--env FORGEJO_PASSWORD=your-password
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
</details>
|
|
191
|
+
|
|
192
|
+
<details>
|
|
193
|
+
<summary><b>opencode</b></summary>
|
|
194
|
+
|
|
195
|
+
opencode's `opencode mcp add` is an interactive wizard (no inline env flags), so
|
|
196
|
+
add it to `opencode.json` instead:
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"mcp": {
|
|
201
|
+
"forgejo-projects-mcp": {
|
|
202
|
+
"type": "local",
|
|
203
|
+
"command": ["forgejo-projects-mcp"],
|
|
204
|
+
"environment": {
|
|
205
|
+
"FORGEJO_URL": "https://forge.example.com",
|
|
206
|
+
"FORGEJO_USERNAME": "your-username",
|
|
207
|
+
"FORGEJO_PASSWORD": "your-password"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
</details>
|
|
215
|
+
|
|
216
|
+
<details>
|
|
217
|
+
<summary><b>Hermes</b></summary>
|
|
218
|
+
|
|
219
|
+
Hermes is config-file based — add to `~/.hermes/config.yaml`:
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
mcp_servers:
|
|
223
|
+
forgejo-projects-mcp:
|
|
224
|
+
command: forgejo-projects-mcp
|
|
225
|
+
env:
|
|
226
|
+
FORGEJO_URL: https://forge.example.com
|
|
227
|
+
FORGEJO_USERNAME: your-username
|
|
228
|
+
FORGEJO_PASSWORD: your-password
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
</details>
|
|
232
|
+
|
|
233
|
+
## Tools
|
|
234
|
+
|
|
235
|
+
**Session & discovery**
|
|
236
|
+
- `forgejo_status` — check authentication
|
|
237
|
+
- `authenticate(force=False)` — log in / refresh session
|
|
238
|
+
- `list_repositories(query, limit, page)` — repos the user can access (pick one to work in)
|
|
239
|
+
|
|
240
|
+
**Projects**
|
|
241
|
+
- `list_projects(owner, repo, state)`
|
|
242
|
+
- `create_project(owner, repo, title, description, card_type)`
|
|
243
|
+
- `get_project(owner, repo, project_id)` — board with columns + cards
|
|
244
|
+
- `update_project(...)`, `close_project(...)`, `reopen_project(...)`, `delete_project(...)`
|
|
245
|
+
|
|
246
|
+
**Columns**
|
|
247
|
+
- `create_column`, `edit_column`, `delete_column`, `set_default_column`
|
|
248
|
+
|
|
249
|
+
**Cards / issues**
|
|
250
|
+
- `create_issue(... project_id=)` — create an issue, optionally straight onto a board
|
|
251
|
+
- `add_issues_to_project`, `remove_issues_from_project`
|
|
252
|
+
- `move_card(owner, repo, project_id, column_id, issue_numbers)`
|
|
253
|
+
- `bulk_move_cards(owner, repo, project_id, moves)` — move many cards, each to its
|
|
254
|
+
own column, in one call (`moves` = list of `{issue_number, column_id}`)
|
|
255
|
+
- `delete_issue`
|
|
256
|
+
|
|
257
|
+
**Bulk reads** (run concurrently, rate-limited)
|
|
258
|
+
- `bulk_read_issues(owner, repo, issue_numbers, state="all")` — lightweight
|
|
259
|
+
summaries (number, title, state, milestone)
|
|
260
|
+
- `read_card(owner, repo, number)` — one card's full content (body + comments) ⚠️
|
|
261
|
+
- `read_column(owner, repo, project_id, column_id, state="all", milestone=None)` ⚠️
|
|
262
|
+
- `read_milestone(owner, repo, milestone_id, state="all", project=None)` ⚠️
|
|
263
|
+
- `read_project(owner, repo, project_id, state="all", milestone=None)` ⚠️
|
|
264
|
+
|
|
265
|
+
Optional filters on the readers use direct values (no name lookup): `state`
|
|
266
|
+
(`open`/`closed`/`all`), and a `milestone`/`project` **id** (each tool omits the
|
|
267
|
+
filter that is already its own subject).
|
|
268
|
+
|
|
269
|
+
The full readers take `limit`/`offset` to cap and page results, and return
|
|
270
|
+
`total` / `returned` / `truncated` / `error_count` so cost and completeness are
|
|
271
|
+
explicit. `bulk_read_issues` returns `count` (successful only) plus a separate
|
|
272
|
+
`errors` list.
|
|
273
|
+
|
|
274
|
+
⚠️ = network- and token-expensive; use only when needed. Concurrency and request
|
|
275
|
+
rate are tunable via `FORGEJO_MCP_MAX_CONCURRENCY` (default 8) and
|
|
276
|
+
`FORGEJO_MCP_RPS` (default 5).
|
|
277
|
+
|
|
278
|
+
**Error signaling.** Tool failures are returned as MCP errors (`isError: true`)
|
|
279
|
+
with a `[CODE] message` (e.g. `[NOT_FOUND]`, `[INVALID_STATE]`,
|
|
280
|
+
`[MILESTONE_NOT_FOUND]`, `[NETWORK_ERROR]`) — agents can detect failure without
|
|
281
|
+
parsing content. Invalid `state` values and missing projects/columns/milestones/
|
|
282
|
+
issues are hard errors, not silent empty results. Individual issues that fail to
|
|
283
|
+
read inside a bulk call are reported inline instead (partial success).
|
|
284
|
+
|
|
285
|
+
**Milestones**
|
|
286
|
+
- `list_milestones`, `create_milestone`, `edit_milestone`,
|
|
287
|
+
`close_milestone`, `reopen_milestone`, `delete_milestone`
|
|
288
|
+
|
|
289
|
+
Issue arguments use the **repo issue number** (what you see as `#N`); the server
|
|
290
|
+
resolves the internal id automatically.
|
|
291
|
+
|
|
292
|
+
## CLI (no MCP client needed)
|
|
293
|
+
|
|
294
|
+
For harnesses that can't speak MCP, `forgejo-projects-cli` exposes **every tool
|
|
295
|
+
as a subcommand**, generated from the same tool definitions and dispatched
|
|
296
|
+
in-process — so it stays in sync automatically. It reads the same
|
|
297
|
+
`FORGEJO_URL` / `FORGEJO_USERNAME` / `FORGEJO_PASSWORD` env vars, prints the JSON
|
|
298
|
+
result to stdout, logs to stderr, and exits non-zero on an error result.
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
forgejo-projects-cli --help # lists every tool
|
|
302
|
+
forgejo-projects-cli <tool> --help # options for one tool
|
|
303
|
+
|
|
304
|
+
forgejo-projects-cli list_repositories --query kanban
|
|
305
|
+
forgejo-projects-cli create_project --owner o --repo r --title "Q3"
|
|
306
|
+
forgejo-projects-cli read_project --owner o --repo r --project_id 3 --state open
|
|
307
|
+
forgejo-projects-cli bulk_move_cards --owner o --repo r --project_id 3 \
|
|
308
|
+
--moves '[{"issue_number": 5, "column_id": 12}]'
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Options mirror each tool's parameters (`--owner`, `--repo`, …); list/object
|
|
312
|
+
parameters (`--issue_numbers`, `--moves`) take a JSON string.
|
|
313
|
+
|
|
314
|
+
## Notes
|
|
315
|
+
|
|
316
|
+
- Tested against Forgejo **v15.0.7**. The web routes are internal and unversioned,
|
|
317
|
+
so a major Forgejo upgrade may require adjusting `client.py`.
|
|
318
|
+
- The Forgejo session cookie does **not** authorize `/api/v1`, so everything runs
|
|
319
|
+
through the web routes.
|