@amonstack/gitea-mcp 0.2.1 → 0.3.0

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.
package/README.md CHANGED
@@ -52,13 +52,50 @@ node dist/cli.js
52
52
 
53
53
  ## Configuration
54
54
 
55
+ All variables are optional — `gitea-mcp` auto-discovers the Gitea instance, repository,
56
+ and token from the project's local git config so a single global install can serve many
57
+ projects. Set them only to override the discovery.
58
+
55
59
  | Variable | Required | Description |
56
60
  |----------|:--------:|-------------|
57
- | `GITEA_BASE_URL` | Yes | Gitea instance URL (e.g. `https://gitea.example.com`) |
58
- | `GITEA_TOKEN` | Yes | Gitea API access token |
61
+ | `GITEA_BASE_URL` | No | Gitea instance URL (e.g. `https://gitea.example.com`). Auto-detected from the project's git remote when omitted. |
62
+ | `GITEA_TOKEN` | No | Gitea API access token. Resolved from `.git/config`, the git credential store, then this variable (see [Token discovery](#token-discovery)). |
59
63
  | `GITEA_DEFAULT_OWNER` | No | Default repository owner — skip passing `owner` on every call |
60
64
  | `GITEA_DEFAULT_REPO` | No | Default repository name — skip passing `repo` on every call |
61
65
 
66
+ ### How auto-discovery works
67
+
68
+ On start, `gitea-mcp` reads `<cwd>/.git/config` and derives:
69
+
70
+ - **Instance URL** — from the selected remote's host. SSH remotes (`git@host:owner/repo`)
71
+ resolve to `https://host`. Override with `GITEA_BASE_URL`.
72
+ - **owner / repo** — from the selected remote's URL. Override with `GITEA_DEFAULT_OWNER` /
73
+ `GITEA_DEFAULT_REPO`, or detect ad hoc with the `resolve_repo` tool.
74
+ - **Remote selection** — the `upstream` remote is preferred, falling back to `origin`, then
75
+ any other remote. Both are reported by `resolve_repo` when they differ.
76
+
77
+ If the current directory has no git remote and `GITEA_BASE_URL` is not set, the server does
78
+ **not** start — it prints a skip reason and exits 0. Run it from inside a cloned Gitea
79
+ repository, or set `GITEA_BASE_URL` / `GITEA_TOKEN` explicitly.
80
+
81
+ ### Token discovery
82
+
83
+ The token is resolved in this order (first match wins):
84
+
85
+ 1. A `[gitea "<baseUrl>"]` section in `.git/config`:
86
+ ```ini
87
+ [gitea "https://gitea.example.com"]
88
+ token = <your-token>
89
+ ```
90
+ A bare `[gitea]` section with `token = ...` is a host-wide fallback.
91
+ 2. The git credential store (`~/.git-credentials`, or `$XDG_CONFIG_HOME/git/credentials`) —
92
+ a line whose host matches the instance, e.g. `https://oauth2:<token>@gitea.example.com`.
93
+ 3. The `GITEA_TOKEN` environment variable.
94
+
95
+ If none resolves, the server still starts without a token (anonymous). Public repositories
96
+ may be read; private repos and write operations return `401` — use the `gitea-configure`
97
+ skill to guide setup, or set `GITEA_TOKEN`.
98
+
62
99
  When `GITEA_DEFAULT_OWNER` and `GITEA_DEFAULT_REPO` are set, you can omit the
63
100
  `owner` and `repo` parameters in tool calls. The `resolve_repo` tool can also
64
101
  auto-detect them from a local git repository.
@@ -107,22 +144,38 @@ Add to your opencode MCP configuration:
107
144
 
108
145
  If you built from source, use `node /path/to/gitea-mcp/dist/cli.js` instead.
109
146
 
110
- opencode also loads native **skills** — one per action (find, create, update,
111
- label, summarize, plan milestones, resolve repo) — that teach the assistant the
112
- safest workflow for that action, including pre-use checks and pitfalls. Install
113
- them once:
147
+ opencode and other AI tools can load native **skills** — one per action (find,
148
+ create, update, label, comment, summarize, plan milestones, resolve repo) — that
149
+ teach the assistant the safest workflow for that action, including pre-use checks
150
+ and pitfalls. Install them once with the `init` command, targeting your tool
151
+ (`--tool`, default `opencode`):
114
152
 
115
153
  ```bash
116
- gitea-mcp skills install # global (~/.config/opencode/skills/)
117
- gitea-mcp skills install --project # this project (./.opencode/skills/)
154
+ gitea-mcp init # opencode (global ~/.config/opencode/skills/)
155
+ gitea-mcp init --tool claude # Claude Code (~/.claude/skills/)
156
+ gitea-mcp init --tool cursor # Cursor (~/.cursor/skills/)
157
+ gitea-mcp init --project # this project (./.<tool>/skills/)
158
+ gitea-mcp init --dir /exact/path # custom location
118
159
  ```
119
160
 
120
- Then restart opencode. See [AI Guidance & Skills](#ai-guidance--skills) below.
161
+ Supported `--tool` values: `amazon-q`, `antigravity`, `auggie`, `claude`,
162
+ `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`,
163
+ `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `opencode`, `qoder`,
164
+ `qwen`, `roocode`, `windsurf`. Paths follow each tool's conventional skills
165
+ directory; use `--dir` for an exact location. Then restart your tool. See
166
+ [AI Guidance & Skills](#ai-guidance--skills) below.
121
167
 
122
168
  ### Other MCP Clients
123
169
 
124
170
  Any client that supports stdio-based MCP servers can use `gitea-mcp`. After
125
- installation, set the required environment variables and run:
171
+ installation, run it from inside a cloned Gitea repository (config is auto-discovered):
172
+
173
+ ```bash
174
+ cd /path/to/your/gitea-repo
175
+ gitea-mcp
176
+ ```
177
+
178
+ Or set the variables explicitly if you prefer:
126
179
 
127
180
  ```bash
128
181
  export GITEA_BASE_URL="https://gitea.example.com"
@@ -180,7 +233,7 @@ gitea-mcp
180
233
  | Tool | Description |
181
234
  |------|-------------|
182
235
  | `list_my_repos` | List repositories accessible to the authenticated user |
183
- | `resolve_repo` | Auto-detect `owner` and `repo` from a local git remote URL |
236
+ | `resolve_repo` | Detect `baseUrl`, `owner`, and `repo` from the project's git remotes (`upstream` preferred, then `origin`) |
184
237
 
185
238
  ## AI Guidance & Skills
186
239
 
@@ -195,12 +248,12 @@ through three channels:
195
248
  `summarize_issue`, `audit_labels`, `milestone_report`) and on-demand reference
196
249
  docs (field reference, label guide, tool cookbook) for clients that surface them.
197
250
 
198
- ### opencode skills
251
+ ### Action skills
199
252
 
200
- For opencode, the server ships a set of **action-scoped skills** — one per
201
- workflow, so the assistant loads only the guidance it needs (and never, say,
202
- delete instructions while creating). Install them with the
203
- `gitea-mcp skills install` command shown in the opencode section above.
253
+ For opencode and other tools, the server ships a set of **action-scoped skills**
254
+ — one per workflow, so the assistant loads only the guidance it needs (and never,
255
+ say, delete instructions while creating). Install them with the
256
+ `gitea-mcp init --tool <name>` command shown above.
204
257
 
205
258
  | Skill | Invoke when |
206
259
  |-------|-------------|
@@ -209,14 +262,18 @@ delete instructions while creating). Install them with the
209
262
  | `gitea-update-issue` | editing fields, closing, clearing assignee/milestone |
210
263
  | `gitea-label-issue` | adding / replacing / removing / clearing labels on an issue |
211
264
  | `gitea-manage-labels` | creating or editing label definitions |
265
+ | `gitea-comment-issue` | posting a comment that advances an issue's discussion |
212
266
  | `gitea-summarize-issue` | reading and summarizing an issue's discussion |
213
267
  | `gitea-plan-milestones` | creating / editing / closing milestones |
214
268
  | `gitea-resolve-repo` | resolving owner/repo or listing repositories |
269
+ | `gitea-configure` | fixing the connection — instance URL, token, or 401/403 errors |
215
270
 
216
271
  Each skill is a short, AI-facing action flow (purpose, when to use, when not to,
217
- rules, and what to check first). Destructive single-tool actions (delete issue /
218
- comment / label / milestone) are intentionally left to the tool descriptions so
219
- they never contaminate a creative workflow.
272
+ rules, and what to check first). The create, comment, and milestone skills also
273
+ embed **body templates** (bug / feature / performance issue, comment, milestone)
274
+ that standardize the format of what the assistant writes. Destructive
275
+ single-tool actions (delete issue / comment / label / milestone) are intentionally
276
+ left to the tool descriptions so they never contaminate a creative workflow.
220
277
 
221
278
  ## Development
222
279
 
package/README.zh-CN.md CHANGED
@@ -50,13 +50,47 @@ node dist/cli.js
50
50
 
51
51
  ## 配置
52
52
 
53
+ 所有变量都是可选的——`gitea-mcp` 会从项目本地 git 配置自动发现 Gitea 实例、仓库和令牌,
54
+ 因此一次全局安装即可服务多个项目。仅在需要覆盖自动发现结果时才设置它们。
55
+
53
56
  | 变量 | 必填 | 说明 |
54
57
  |------|:----:|------|
55
- | `GITEA_BASE_URL` | | Gitea 实例地址(如 `https://gitea.example.com`) |
56
- | `GITEA_TOKEN` | | Gitea API 访问令牌 |
58
+ | `GITEA_BASE_URL` | | Gitea 实例地址(如 `https://gitea.example.com`)。未设置时从项目 git 远程地址自动推导。 |
59
+ | `GITEA_TOKEN` | | Gitea API 访问令牌。依次从 `.git/config`、git 凭据存储、本变量解析(见[令牌发现](#令牌发现))。 |
57
60
  | `GITEA_DEFAULT_OWNER` | 否 | 默认仓库所有者,免去每次传入 `owner` 参数 |
58
61
  | `GITEA_DEFAULT_REPO` | 否 | 默认仓库名称,免去每次传入 `repo` 参数 |
59
62
 
63
+ ### 自动发现的工作方式
64
+
65
+ 启动时,`gitea-mcp` 读取 `<cwd>/.git/config` 并推导:
66
+
67
+ - **实例地址** —— 取自选中远程地址的 host。SSH 远程(`git@host:owner/repo`)会被推导为
68
+ `https://host`。可用 `GITEA_BASE_URL` 覆盖。
69
+ - **owner / repo** —— 取自选中远程地址。可用 `GITEA_DEFAULT_OWNER` / `GITEA_DEFAULT_REPO`
70
+ 覆盖,或随时用 `resolve_repo` 工具检测。
71
+ - **远程选择** —— 优先 `upstream`,回退 `origin`,再回退其它远程。两者不同时 `resolve_repo`
72
+ 会同时返回。
73
+
74
+ 若当前目录没有 git 远程、且未设置 `GITEA_BASE_URL`,服务器**不会启动**——它会打印跳过原因并
75
+ 以 exit 0 退出。请在克隆的 Gitea 仓库内运行,或显式设置 `GITEA_BASE_URL` / `GITEA_TOKEN`。
76
+
77
+ ### 令牌发现
78
+
79
+ 令牌按以下顺序解析(先匹配者胜出):
80
+
81
+ 1. `.git/config` 中的 `[gitea "<baseUrl>"]` 段:
82
+ ```ini
83
+ [gitea "https://gitea.example.com"]
84
+ token = <your-token>
85
+ ```
86
+ 不带地址的 `[gitea]` 段中的 `token = ...` 作为全局兜底。
87
+ 2. git 凭据存储(`~/.git-credentials`,或 `$XDG_CONFIG_HOME/git/credentials`)——host 匹配实例
88
+ 的那一行,如 `https://oauth2:<token>@gitea.example.com`。
89
+ 3. `GITEA_TOKEN` 环境变量。
90
+
91
+ 若都未解析到,服务器仍会以匿名方式启动。公开仓库可读;私有仓库和写操作返回 `401`——此时使用
92
+ `gitea-configure` 技能引导配置,或设置 `GITEA_TOKEN`。
93
+
60
94
  设置 `GITEA_DEFAULT_OWNER` 和 `GITEA_DEFAULT_REPO` 后,调用工具时可以省略
61
95
  `owner` 和 `repo` 参数。也可以使用 `resolve_repo` 工具自动从本地 git 仓库
62
96
  检测这两个值。
@@ -105,21 +139,36 @@ node dist/cli.js
105
139
 
106
140
  如果从源码构建,将 `command` 改为 `node /path/to/gitea-mcp/dist/cli.js`。
107
141
 
108
- opencode 还会加载原生**技能(skills)**——按动作拆分(查找、创建、更新、打
109
- 标签、总结、规划里程碑、解析仓库等),教会助手针对该动作的最安全工作流,含
110
- 使用前检查与各类陷阱。一次性安装:
142
+ opencode 及其它 AI 工具可加载原生**技能(skills)**——按动作拆分(查找、创建、
143
+ 更新、打标签、评论、总结、规划里程碑、解析仓库等),教会助手针对该动作的最安全
144
+ 工作流,含使用前检查与各类陷阱。用 `init` 命令一次性安装,并通过 `--tool` 指定
145
+ 目标工具(默认 `opencode`):
111
146
 
112
147
  ```bash
113
- gitea-mcp skills install # 全局(~/.config/opencode/skills/)
114
- gitea-mcp skills install --project # 仅当前项目(./.opencode/skills/)
148
+ gitea-mcp init # opencode(全局 ~/.config/opencode/skills/)
149
+ gitea-mcp init --tool claude # Claude Code(~/.claude/skills/)
150
+ gitea-mcp init --tool cursor # Cursor(~/.cursor/skills/)
151
+ gitea-mcp init --project # 仅当前项目(./.<tool>/skills/)
152
+ gitea-mcp init --dir /exact/path # 自定义路径
115
153
  ```
116
154
 
117
- 然后重启 opencode。详见下方 [AI 引导与技能](#ai-引导与技能)。
155
+ 支持的 `--tool` 取值:`amazon-q`、`antigravity`、`auggie`、`claude`、`cline`、
156
+ `codex`、`codebuddy`、`continue`、`costrict`、`crush`、`cursor`、`factory`、
157
+ `gemini`、`github-copilot`、`iflow`、`kilocode`、`opencode`、`qoder`、`qwen`、
158
+ `roocode`、`windsurf`。路径遵循各工具约定的 skills 目录;如需精确位置请用 `--dir`。
159
+ 随后重启对应工具。详见下方 [AI 引导与技能](#ai-引导与技能)。
118
160
 
119
161
  ### 其他 MCP 客户端
120
162
 
121
- 任何支持 stdio 方式运行 MCP 服务端的客户端都可以使用。安装完成后设置环境
122
- 变量并启动:
163
+ 任何支持 stdio 方式运行 MCP 服务端的客户端都可以使用。安装完成后,在克隆的 Gitea 仓库内
164
+ 吏动即可(配置会自动发现):
165
+
166
+ ```bash
167
+ cd /path/to/your/gitea-repo
168
+ gitea-mcp
169
+ ```
170
+
171
+ 也可显式设置环境变量:
123
172
 
124
173
  ```bash
125
174
  export GITEA_BASE_URL="https://gitea.example.com"
@@ -177,7 +226,7 @@ gitea-mcp
177
226
  | 工具 | 说明 |
178
227
  |------|------|
179
228
  | `list_my_repos` | 列出当前用户可访问的仓库 |
180
- | `resolve_repo` | 从本地 git 仓库的远程地址自动检测 `owner` `repo` |
229
+ | `resolve_repo` | 从项目 git 远程地址检测 `baseUrl`、`owner`、`repo`(优先 `upstream`,回退 `origin`) |
181
230
 
182
231
  ## AI 引导与技能
183
232
 
@@ -191,11 +240,11 @@ gitea-mcp
191
240
  `audit_labels`、`milestone_report`)与按需参考文档(字段参考、标签指南、工具
192
241
  食谱),供支持的客户端使用。
193
242
 
194
- ### opencode 技能
243
+ ### 动作技能
195
244
 
196
- 对 opencode,服务端内置了一组**按动作划分的技能**——每个工作流一个,助手只
197
- 加载所需指引(避免例如创建时把删除说明一并带入造成幻觉)。用上面 opencode
198
- 小节展示的 `gitea-mcp skills install` 命令安装。
245
+ 对 opencode 及其它工具,服务端内置了一组**按动作划分的技能**——每个工作流一
246
+ 个,助手只加载所需指引(避免例如创建时把删除说明一并带入造成幻觉)。用上方展示的
247
+ `gitea-mcp init --tool <name>` 命令安装。
199
248
 
200
249
  | 技能 | 何时触发 |
201
250
  |------|----------|
@@ -204,13 +253,16 @@ gitea-mcp
204
253
  | `gitea-update-issue` | 编辑字段、关闭、清空负责人/里程碑 |
205
254
  | `gitea-label-issue` | 为 issue 增加 / 替换 / 移除 / 清空标签 |
206
255
  | `gitea-manage-labels` | 创建或编辑标签定义 |
256
+ | `gitea-comment-issue` | 在 issue 下发表推动讨论的评论 |
207
257
  | `gitea-summarize-issue` | 读取并总结某 issue 的讨论 |
208
258
  | `gitea-plan-milestones` | 创建 / 编辑 / 关闭里程碑 |
209
259
  | `gitea-resolve-repo` | 解析 owner/repo 或列出仓库 |
260
+ | `gitea-configure` | 修复连接——实例地址、令牌或 401/403 报错 |
210
261
 
211
262
  每个技能都是面向 AI 的简短动作流程(目的、何时用、何时不用、规则、先检查什么)。
212
- 破坏性的单工具操作(删除 issue / 评论 / 标签 / 里程碑)有意仅保留在工具描述里,
213
- 不会污染创建类工作流。
263
+ 创建、评论、里程碑三类技能还内嵌**正文模板**(bug / 新功能 / 性能 issue、评论、
264
+ 里程碑),用以规范助手所写内容的格式。破坏性的单工具操作(删除 issue / 评论 /
265
+ 标签 / 里程碑)有意仅保留在工具描述里,不会污染创建类工作流。
214
266
 
215
267
  ## 二次开发
216
268
 
@@ -4,18 +4,29 @@ You manage Gitea issues, comments, labels, and milestones through this MCP serve
4
4
  Every tool returns Gitea's JSON verbatim as text. Follow these rules to use them
5
5
  correctly.
6
6
 
7
+ ## Config is auto-discovered from git (env vars optional)
8
+
9
+ On start the server reads `<cwd>/.git/config` and derives `baseUrl`, `owner`, `repo`,
10
+ and `token` so one global install can serve many projects. The `GITEA_BASE_URL` /
11
+ `GITEA_TOKEN` / `GITEA_DEFAULT_OWNER` / `GITEA_DEFAULT_REPO` env vars are OPTIONAL
12
+ overrides; when set they take precedence over git discovery. The remote is chosen
13
+ `upstream` first, then `origin`. If the cwd has no git remote and `GITEA_BASE_URL` is
14
+ unset, the server does not start (it prints a skip reason and exits 0). If you hit a
15
+ 401/403 or the connection looks unset, use the **gitea-configure** skill.
16
+
7
17
  ## Resolve owner/repo FIRST (most common failure)
8
18
 
9
19
  Most tools target one repository and need both `owner` and `repo`. They resolve in
10
20
  this order:
11
21
 
12
22
  1. The `owner` / `repo` arguments you pass to the call.
13
- 2. `GITEA_DEFAULT_OWNER` / `GITEA_DEFAULT_REPO` env vars (set at server start).
14
- 3. The `resolve_repo` tool (detects owner/repo from a local git remote).
23
+ 2. `GITEA_DEFAULT_OWNER` / `GITEA_DEFAULT_REPO` env vars (or the git-discovered defaults
24
+ captured at server start).
25
+ 3. The `resolve_repo` tool (re-reads `.git/config` and returns `baseUrl`, `owner`, `repo`,
26
+ the selected `remote`, and every parsed remote under `remotes`).
15
27
 
16
- If neither argument nor env var is set, the call errors. Before a batch of work on a
17
- repo you have not used this session, call `resolve_repo` (or confirm the env defaults)
18
- once and reuse the result — do not guess.
28
+ If none resolve, the call errors. Before a batch of work on a repo you have not used this
29
+ session, call `resolve_repo` once and reuse the result — do not guess.
19
30
 
20
31
  ## Labels: IDs vs names (critical gotcha)
21
32
 
@@ -59,5 +70,6 @@ Confirm the target id/index and scope with the user before calling. For labels,
59
70
  ## Error format
60
71
 
61
72
  Failed calls throw `Gitea API error (<status>): <body>`. Read the status: 401/403 →
62
- token scope/expiry; 404 wrong owner/repo or no permission; 409 conflict;
63
- 422validation. Do not retry blindly on 4xx.
73
+ token missing, wrong, or lacks scope run the **gitea-configure** skill to fix the
74
+ connection; 404 wrong owner/repo or no permission; 409 → conflict; 422 → validation.
75
+ Do not retry blindly on 4xx.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: gitea-comment-issue
3
+ description: Invoke to POST a new comment on a Gitea issue or pull request. The flow confirms the issue exists first, then posts. Do NOT invoke to edit or delete a comment (author/admin only, partly destructive — no skill), read or summarize the thread (gitea-summarize-issue), or create/edit the issue itself (gitea-create-issue / gitea-update-issue).
4
+ ---
5
+
6
+ # gitea-comment-issue
7
+
8
+ Post one new comment that advances an issue's discussion. Tools: `get_issue`, `create_comment`.
9
+
10
+ ## Prerequisites
11
+ - Resolve `owner`+`repo`: pass explicitly, else `GITEA_DEFAULT_OWNER`/`GITEA_DEFAULT_REPO`, else `resolve_repo` (gitea-resolve-repo). Never guess — wrong values post to the wrong place.
12
+ - `index` = the issue `number` (URL #N → N), never the internal `id`.
13
+
14
+ ## Flow
15
+ 1. CONFIRM TARGET: `get_issue({ index })` — verify the issue exists and is the one you mean. Do NOT post blind.
16
+ 2. POST: `create_comment({ index, body })`.
17
+
18
+ ## create_comment
19
+ - RULES: `body` required, Markdown. The comment APPENDS to the thread — it never edits or replaces prior content. The response carries the comment `id`; retain it only if a follow-up `update_comment` / `delete_comment` is planned.
20
+ - CHECK FIRST: re-read the latest thread (gitea-summarize-issue) so your comment is not redundant or contradicting a newer message.
21
+ - CHECK AFTER: the comment appears with the returned `id`.
22
+
23
+ ## Body template — standardize what you write into `body`
24
+ A useful comment is contextual, evidence-backed, and proposes a next step. Structure `body` with this template; drop sections that add nothing.
25
+
26
+ ```markdown
27
+ **Context:** <the point you are responding to>
28
+
29
+ **Finding / proposal:** <what you discovered or suggest>
30
+
31
+ **Evidence:** <log excerpt, link, reproduction, or metric>
32
+
33
+ **Suggested next step:** <the concrete action you propose>
34
+ ```
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: gitea-configure
3
+ description: Invoke to CONFIGURE / SET UP / FIX the Gitea connection — instance URL, token, or owner/repo discovery. Use when a tool fails with 401/403 (bad or missing token), when the user asks how to wire up gitea-mcp, or when baseUrl/owner/repo could not be auto-detected. Do NOT invoke for normal issue/label/milestone work once the connection works.
4
+ ---
5
+
6
+ # gitea-configure
7
+
8
+ Diagnose and fix the Gitea connection. The server auto-discovers its config from the
9
+ project's git remotes; this skill is the fallback when that fails or the token is wrong.
10
+
11
+ ## How gitea-mcp discovers config (no env vars required)
12
+
13
+ On start, the server reads `<cwd>/.git/config` and resolves in this order:
14
+
15
+ 1. **baseUrl** — `GITEA_BASE_URL` env var, else derived from the selected remote's host.
16
+ SSH remotes (`git@host:owner/repo`) resolve to `https://host`.
17
+ 2. **owner / repo** — `GITEA_DEFAULT_OWNER` / `GITEA_DEFAULT_REPO` env vars, else from the
18
+ selected remote's URL.
19
+ 3. **Remote selection** — `upstream` remote first, falling back to `origin`, then any
20
+ other remote. Both are surfaced in `resolve_repo` output.
21
+
22
+ If the working directory has NO git remote and `GITEA_BASE_URL` is unset, the server does
23
+ NOT start (it prints a skip reason and exits 0). That is intentional, not a crash.
24
+
25
+ ## Token discovery chain (tried in order)
26
+
27
+ 1. `.git/config` — a `[gitea "<baseUrl>"]` section, e.g.
28
+ ```ini
29
+ [gitea "https://gitea.example.com"]
30
+ token = <your-token>
31
+ ```
32
+ A bare `[gitea]` section with `token = ...` is a host-wide fallback.
33
+ 2. The git credential store (`~/.git-credentials`, or `$XDG_CONFIG_HOME/git/credentials`)
34
+ — a line whose host matches the instance, e.g.
35
+ `https://oauth2:<token>@gitea.example.com`.
36
+ 3. `GITEA_TOKEN` env var.
37
+ 4. If none of the above yield a token, the server starts WITHOUT a token (anonymous). Public
38
+ repos may be read; writes and private repos return 401 — that is the signal to help the
39
+ user add a token via one of the sources above.
40
+
41
+ ## Fix flow — when a tool returns 401 / 403
42
+
43
+ 1. Confirm the instance: run `resolve_repo` (no args) and read its `baseUrl` and `remote`.
44
+ If it throws, the cwd has no usable git remote — tell the user to run gitea-mcp from a
45
+ cloned repo, or set `GITEA_BASE_URL` + `GITEA_TOKEN`.
46
+ 2. Ask the user to create a token at `<baseUrl>/user/settings/applications` (Gitea → Settings
47
+ → Applications → Access Tokens). Capture the scopes they need: `issue`, `comment`,
48
+ `label`, `milestone` (read+write). NEVER have the user paste a token into chat unless they
49
+ explicitly choose to — prefer having them run a git command themselves.
50
+ 3. Have the user store it so discovery finds it. Recommend, in priority order:
51
+ - `git config --file=.git/config gitea."<baseUrl>".token "<token>"` (project-scoped), or
52
+ - add to the credential store, or
53
+ - export `GITEA_TOKEN` (and `GITEA_BASE_URL`) in their MCP client config.
54
+ `<baseUrl>` is the EXACT value `resolve_repo` reported (scheme + host, with port if any).
55
+ 4. The server must be restarted for new config to take effect — discovery runs once at start.
56
+
57
+ ## Never log the token
58
+
59
+ Tokens are secret. Do not echo, paste into notes, or include in issue/comment bodies. Pass
60
+ configuration values to the user as commands to run themselves; never print a token back.
@@ -11,7 +11,7 @@ Open one new issue after ruling out a duplicate. Tools: `search_issues`, `create
11
11
  - Resolve `owner`+`repo`: pass explicitly, else `GITEA_DEFAULT_OWNER`/`GITEA_DEFAULT_REPO`, else `resolve_repo` (gitea-resolve-repo). Never guess — wrong values create the issue in the wrong repo.
12
12
 
13
13
  ## Flow
14
- 1. DUPLICATE CHECK (always first): `search_issues({ query: "<title keywords>", type: "issues" })`. If a match exists, comment on it (gitea-summarize-issue, then `create_comment`) instead of creating a duplicate. Do NOT skip this — creation does not de-duplicate.
14
+ 1. DUPLICATE CHECK (always first): `search_issues({ query: "<title keywords>", type: "issues" })`. If a match exists, comment on it (gitea-comment-issue) instead of creating a duplicate. Do NOT skip this — creation does not de-duplicate.
15
15
  2. CREATE: `create_issue({ title, body?, assignees? })`.
16
16
 
17
17
  ## create_issue
@@ -19,3 +19,46 @@ Open one new issue after ruling out a duplicate. Tools: `search_issues`, `create
19
19
  - Do NOT pass `labels` or `milestone` here: `labels` expect IDs (error-prone) and milestone needs an id. Create WITHOUT them, then attach labels by name via `add_issue_labels` (gitea-label-issue) and set the milestone via `update_issue` (gitea-update-issue).
20
20
  - CHECK FIRST: confirm no duplicate (step 1) and that `owner`/`repo` are correct before writing.
21
21
  - CHECK AFTER: the returned object's `number` is the new issue index.
22
+
23
+ ## Body templates — standardize what you write into `body`
24
+ Always structure `body` with the template matching the issue type. Ask the user which type if it is not obvious. Drop a section only when it is genuinely empty; never invent data. These are GitHub-OSS conventions adapted for the Markdown body that `create_issue` accepts.
25
+
26
+ ### Bug report
27
+ ```markdown
28
+ **Summary:** <one-line description of what is wrong>
29
+
30
+ **Steps to reproduce**
31
+ 1. <step>
32
+ 2. <step>
33
+
34
+ **Expected:** <what should happen>
35
+ **Actual:** <what happens instead>
36
+
37
+ **Environment**
38
+ - gitea-mcp version:
39
+ - Gitea version:
40
+ - Node / runtime:
41
+ - OS:
42
+ ```
43
+
44
+ ### Feature request
45
+ ```markdown
46
+ **Motivation:** <the problem or need this addresses>
47
+
48
+ **Proposal:** <what to add or change>
49
+
50
+ **Alternatives considered:** <other approaches and why they fall short>
51
+ ```
52
+
53
+ ### Performance issue
54
+ ```markdown
55
+ **Symptom:** <what is slow, or which metric regressed>
56
+
57
+ **How to reproduce:** <scenario + data size / load>
58
+
59
+ **Measurements**
60
+ - Before: <baseline metric>
61
+ - After / target: <current or goal metric>
62
+
63
+ **Suspected bottleneck:** <where the cost seems to come from>
64
+ ```
@@ -22,3 +22,20 @@ Create / edit / close milestones. Tools: `list_milestones`, `get_milestone`, `cr
22
22
 
23
23
  ## get_milestone
24
24
  - Read one milestone by `id`: includes `open_issues` / `closed_issues` counts for progress (progress = closed / (open + closed)).
25
+
26
+ ## Description template — standardize what you write into `description`
27
+ Milestones succeed when scope is explicit. When creating or editing, structure `description` with this template; keep it short and drop empty sections.
28
+
29
+ ```markdown
30
+ **Goal:** <the single outcome this milestone delivers>
31
+
32
+ **Scope**
33
+ - In: <what this milestone covers>
34
+ - Out: <what is explicitly deferred>
35
+
36
+ **Acceptance criteria**
37
+ - <observable, checkable condition>
38
+ - <observable, checkable condition>
39
+
40
+ **Owners:** <who is accountable>
41
+ ```
@@ -1,18 +1,29 @@
1
1
  ---
2
2
  name: gitea-resolve-repo
3
- description: Invoke to RESOLVE which owner/repo the other gitea tools should target (auto-detect from a git remote) or to LIST repositories the token can access. Run FIRST when the target repository is unknown. Do NOT invoke for issue/comment/label/milestone work once owner/repo are known.
3
+ description: Invoke to RESOLVE which owner/repo (and baseUrl) the other gitea tools should target (auto-detect from a git remote) or to LIST repositories the token can access. Run FIRST when the target repository is unknown. Do NOT invoke for issue/comment/label/milestone work once owner/repo are known.
4
4
  ---
5
5
 
6
6
  # gitea-resolve-repo
7
7
 
8
- Discover the target repository. Tools: `resolve_repo`, `list_my_repos`.
8
+ Discover the target repository and instance. Tools: `resolve_repo`, `list_my_repos`.
9
9
 
10
10
  ## resolve_repo
11
- - Reads the `origin` remote of the git repo at `path` (default: current directory) and parses owner/repo from SSH (`git@gitea.example:owner/repo.git`) or HTTPS (`https://gitea.example/owner/repo.git`) URLs.
12
- - Throws if there is no `origin` remote or the URL is unparseable. Do NOT guess owner/repo from context — call this, or ask the user.
11
+ - Reads `.git/config` of the git repo at `path` (default: current directory) and parses
12
+ EVERY remote from SSH (`git@gitea.example:owner/repo.git`) or HTTPS
13
+ (`https://gitea.example/owner/repo.git`) URLs.
14
+ - Selects the remote to target in this priority: `upstream` → `origin` → any other.
15
+ SSH remotes resolve to `baseUrl = https://<host>` (the API is assumed HTTPS).
16
+ - Returns `{ baseUrl, owner, repo, remote, remote_url, remotes: { <name>: {baseUrl, owner, repo, url} } }`.
17
+ Read `baseUrl` to know which instance a token must be valid for; read `remotes` to see
18
+ upstream vs origin when they differ.
19
+ - Throws `No parseable git remotes found` if the cwd has no git remote or none parse. Do
20
+ NOT guess owner/repo from context — call this, or ask the user.
13
21
 
14
22
  ## list_my_repos
15
- - Lists repositories the token can access. GLOBAL. Returns large objects — paginate (`limit` ≤ 100) and read only the fields you need (name, full_name, owner.login).
23
+ - Lists repositories the token can access. GLOBAL. Returns large objects — paginate (`limit` ≤ 100) and read only the fields you need (name, full_name, owner.login). If this returns
24
+ 401/403 there is no usable token — switch to the **gitea-configure** skill.
16
25
 
17
26
  ## Resolution order (every repo-scoped tool)
18
- explicit `owner`/`repo` args → `GITEA_DEFAULT_OWNER`/`GITEA_DEFAULT_REPO` → `resolve_repo`. If none resolve, the tool throws `owner and repo are required`. Wrong values 404 or silently target the wrong repo — never guess.
27
+ explicit `owner`/`repo` args → `GITEA_DEFAULT_OWNER`/`GITEA_DEFAULT_REPO` (or git-discovered
28
+ defaults) → `resolve_repo`. If none resolve, the tool throws `owner and repo are required`.
29
+ Wrong values 404 or silently target the wrong repo — never guess.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gitea-summarize-issue
3
- description: Invoke to READ and SUMMARIZE an issue's discussion — the issue body plus its comment thread. Do NOT invoke to create/edit an issue (gitea-create-issue / gitea-update-issue), post or edit a comment (no skill — single tool), or manage labels/milestones.
3
+ description: Invoke to READ and SUMMARIZE an issue's discussion — the issue body plus its comment thread. Do NOT invoke to create/edit an issue (gitea-create-issue / gitea-update-issue), post a comment (gitea-comment-issue), or manage labels/milestones.
4
4
  ---
5
5
 
6
6
  # gitea-summarize-issue
package/dist/cli.js CHANGED
@@ -1,25 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  import { runServer } from "./server.js";
3
+ import { discoverConfig } from "./git-config.js";
3
4
  const argv = process.argv.slice(2);
4
- if (argv[0] === "skills") {
5
- // `gitea-mcp skills ...` manages the bundled opencode skill. It needs no Gitea
6
- // credentials, so it is dispatched before the env-var guard below.
7
- const { runSkillsCommand } = await import("./skills.js");
8
- runSkillsCommand(argv.slice(1)).catch((err) => {
5
+ if (argv[0] === "init") {
6
+ // `gitea-mcp init [--tool <name>]` installs the bundled skills into a target
7
+ // AI tool's skills directory. It needs no Gitea credentials, so it is
8
+ // dispatched before the config-discovery logic below.
9
+ const { runInitCommand } = await import("./skills.js");
10
+ runInitCommand(argv.slice(1)).catch((err) => {
9
11
  console.error("Fatal error:", err);
10
12
  process.exit(1);
11
13
  });
12
14
  }
13
15
  else {
14
- const baseUrl = process.env.GITEA_BASE_URL;
15
- const token = process.env.GITEA_TOKEN;
16
- const defaultOwner = process.env.GITEA_DEFAULT_OWNER;
17
- const defaultRepo = process.env.GITEA_DEFAULT_REPO;
18
- if (!baseUrl || !token) {
19
- console.error("GITEA_BASE_URL and GITEA_TOKEN environment variables are required");
16
+ // Resolve baseUrl/owner/repo/token from env first, then the local git context
17
+ // (`.git/config` remotes + credential store). When neither env nor any git
18
+ // remote provides a baseUrl, the server is intentionally skipped: a single
19
+ // global install should stay dormant outside of git projects.
20
+ const discovered = await discoverConfig().catch((err) => {
21
+ console.error("Fatal error:", err);
20
22
  process.exit(1);
23
+ });
24
+ if (!discovered) {
25
+ console.error(`gitea-mcp: no git remote found in ${process.cwd()} and GITEA_BASE_URL is not set; skipping server start.`);
26
+ process.exit(0);
21
27
  }
22
- runServer(baseUrl, token, defaultOwner, defaultRepo).catch((err) => {
28
+ runServer(discovered.baseUrl, discovered.token, discovered.defaultOwner, discovered.defaultRepo).catch((err) => {
23
29
  console.error("Fatal error:", err);
24
30
  process.exit(1);
25
31
  });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;IACzB,+EAA+E;IAC/E,mEAAmE;IACnE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACzD,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QAC5C,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IACtC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACrD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAEnD,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACnF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjE,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;IACvB,6EAA6E;IAC7E,sEAAsE;IACtE,sDAAsD;IACtD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACvD,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACnD,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,8EAA8E;IAC9E,2EAA2E;IAC3E,2EAA2E;IAC3E,8DAA8D;IAC9D,MAAM,UAAU,GAAG,MAAM,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QAC/D,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CACX,qCAAqC,OAAO,CAAC,GAAG,EAAE,wDAAwD,CAC3G,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,SAAS,CACP,UAAU,CAAC,OAAO,EAClB,UAAU,CAAC,KAAK,EAChB,UAAU,CAAC,YAAY,EACvB,UAAU,CAAC,WAAW,CACvB,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACvB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}