`-O` / `--tools` can already narrow the exposed tool set, but it needs every tool spelled out by name. `-S` / `--scope` (`GITEA_SCOPES`) complements it by selecting whole scopes, using the same names the `Scope` column of the tool tables documents.
```bash
gitea-mcp -S issue,pull_request # only those scopes
gitea-mcp --scope repository,branch --tools get_me # those scopes plus one extra tool
```
## What changed
- Each scope is one `tool.Tool` registry carrying a canonical name, so `operation/repo` is split into the six scopes its files already imply: `repository` (`repo.go` + `tree.go`), `file`, `branch`, `tag`, `commit`, `release`. The other twelve packages map 1:1, giving 18 scopes.
- The two allowlists combine as a **union**: with neither set every tool loads; with only `--tools` set behaviour is unchanged; with both set, the selected scopes' tools plus the individually named tools load. `-r` / `GITEA_READONLY` still hides write tools on top.
- Scope names are normalized on input (case, spaces, hyphens), so `Pull Request`, `pull-request` and `PULL_REQUEST` all resolve to `pull_request`. Unknown names only warn and list the valid scopes, mirroring how `--tools` treats unknown tool names.
- The `Scope` column of all three READMEs now uses the canonical names verbatim, so it doubles as the reference for `--scope`, and `TestReadmeToolTables` compares that column against the registry in both directions — no translation table needed.
- Flag parsing moves from `cmd.init()` into `Execute()`. `main()` only ever calls `Execute()`, so this is behaviourally equivalent, and it makes the `cmd` package testable at all: previously the `init()` parse of `os.Args` hit `flag.CommandLine`'s `ExitOnError` on `go test`'s own `-test.*` flags.
## Verification
`make fmt`, `make lint-go` (0 issues) and `go test ./...` all pass. New tests cover the filter matrix (no filters / scope-only / tools-only regression / union / read-only interaction / unknown scope), scope-name uniqueness across `domainTools`, and the flag+env parsing and normalization.
Smoke-tested `tools/list` over stdio against the built binary:
| flags | tools exposed |
| :-- | :-- |
| _none_ | 54 (identical to `main`) |
| `-S branch` | `create_branch`, `delete_branch`, `list_branches` |
| `--scope 'Pull Request,TAG'` | the 4 `pull_request` + 4 `tag` tools |
| `-O get_me` | `get_me` (unchanged) |
| `-S commit -O get_me` | `get_commit`, `list_commits`, `get_me` |
| `-S file -r` | `get_dir_contents`, `get_file_contents` |
| `-S bogus,issue` | the 4 `issue` tools, plus a warning naming the valid scopes |
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/219
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: yp05327 <576951401@qq.com>
- Add a read-only `attachment_read` tool for issue and issue comment attachments.
- Use the existing Gitea SDK attachment metadata APIs for `list` and `get`.
- Add authenticated `/attachments/{uuid}` downloads in the MCP server for `download`, with small image inline results and streamed file downloads for larger content.
- Add `-max-inline-attachment-bytes` / `GITEA_MAX_INLINE_ATTACHMENT_BYTES` to configure inline image limits.
- Update the tool tables in all README variants.
Refs: #209
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/218
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: yp05327 <576951401@qq.com>
Adds `-O`/`-tools` CLI flag and `GITEA_TOOLS` environment variable
accepting a comma-separated list of tool names. When set, only the
listed tools are exposed to MCP clients, which lets AI agents trim
their tool context. Composes with `--read-only`. Unknown names are
logged at startup so typos surface instead of failing silently.
Co-Authored-By: silverwind <me@silverwind.io>
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
I don't like secrets just being added via environment variables. Add support for the `_FILE` environment variable convention used by Docker secrets.
When `GITEA_ACCESS_TOKEN_FILE` is set, the token is read from the file at that path (e.g. `/run/secrets/gitea_token`). Trailing newlines are stripped to handle the typical Docker secrets file format on both Linux and Windows.
Token resolution precedence (highest to lowest):
1. `--token` / `-T` CLI flag
2. `GITEA_ACCESS_TOKEN` env var
3. `GITEA_ACCESS_TOKEN_FILE` env var
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/186
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Dennis Gaida <gitea@mail.gaida.biz>
Co-committed-by: Dennis Gaida <gitea@mail.gaida.biz>
## Summary
- Replace default `flag.Usage` with custom 2-column layout using `text/tabwriter`
- Add short and long aliases for all CLI flags
- Add environment variables section with sorted entries
- Handle `-version` flag in `Execute()`
## Sample output
```
Usage: gitea-mcp [options]
Options:
-t, -transport <type> Transport type: stdio or http (default: stdio)
-H, -host <url> Gitea host URL (default: https://gitea.com)
-p, -port <number> HTTP server port (default: 8080)
-T, -token <token> Personal access token
-r, -read-only Expose only read-only tools
-d, -debug Enable debug mode
-k, -insecure Ignore TLS certificate errors
-v, -version Print version and exit
Environment variables:
GITEA_ACCESS_TOKEN Provide access token
GITEA_DEBUG Set to 'true' for debug mode
GITEA_HOST Override Gitea host URL
GITEA_INSECURE Set to 'true' to ignore TLS errors
GITEA_READONLY Set to 'true' for read-only mode
MCP_MODE Override transport mode
```
*Created by Claude on behalf of @silverwind*
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/139
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-committed-by: silverwind <me@silverwind.io>
## Summary
- Add `.golangci.yml` with linter configuration matching the main gitea repo
- Add `lint`, `lint-fix`, `lint-go`, `lint-go-fix`, and `security-check` Makefile targets
- Add `tidy` Makefile target (extracts min Go version from `go.mod` for `-compat` flag)
- Bump minimum Go version to 1.26
- Update golangci-lint to v2.10.1
- Replace `golang/govulncheck-action` with `make security-check` in CI
- Add `make lint` step to CI
- Fix all lint issues across the codebase (formatting, `errors.New` vs `fmt.Errorf`, `any` vs `interface{}`, unused returns, stuttering names, Go 1.26 `new(expr)`, etc.)
- Remove unused `pkg/ptr` package (inlined by Go 1.26 `new(expr)`)
- Remove dead linter exclusions (staticcheck, gocritic, testifylint, dupl)
## Test plan
- [x] `make lint` passes
- [x] `go test ./...` passes
- [x] `make build` succeeds
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/133
Reviewed-by: techknowlogick <techknowlogick@noreply.gitea.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-committed-by: silverwind <me@silverwind.io>
- Update download instructions for clarity and consistency in all README files
- Add example configuration for HTTP mode to all README files
- Expand transport type support to include "http" in command-line flags and documentation
- Implement HTTP server mode in the application entrypoint
- Update log output behavior to include "http" mode alongside "sse" for stdout logging
- Refine Chinese README translations for greater accuracy and localization
Signed-off-by: appleboy <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/45
Co-authored-by: appleboy <appleboy.tw@gmail.com>
Co-committed-by: appleboy <appleboy.tw@gmail.com>
## Why
With the following configuration:
```bash
docker run -i --rm -e GITEA_HOST=<gitea_host> -e GITEA_ACCESS_TOKEN=<gitea_access_token_for_host> docker.gitea.com/gitea-mcp-server:latest
```
after mcp-client calling a tool, the gitea client will encounter the following fatal error:
```
FATAL gitea/gitea.go:47 create gitea client err: user does not exist [uid: 0, name: ]
gitea.com/gitea/gitea-mcp/pkg/gitea.Client.func1
/app/pkg/gitea/gitea.go:47
sync.(*Once).doSlow
/usr/local/go/src/sync/once.go:78
sync.(*Once).Do
/usr/local/go/src/sync/once.go:69
gitea.com/gitea/gitea-mcp/pkg/gitea.Client
/app/pkg/gitea/gitea.go:21
gitea.com/gitea/gitea-mcp/operation/search.SearchReposFn
/app/operation/search/search.go:161
github.com/mark3labs/mcp-go/server.(*MCPServer).handleToolCall
/go/pkg/mod/github.com/mark3labs/mcp-go@v0.18.0/server/server.go:717
github.com/mark3labs/mcp-go/server.(*MCPServer).HandleMessage
/go/pkg/mod/github.com/mark3labs/mcp-go@v0.18.0/server/request_handler.go:264
github.com/mark3labs/mcp-go/server.(*StdioServer).processMessage
/go/pkg/mod/github.com/mark3labs/mcp-go@v0.18.0/server/stdio.go:228
github.com/mark3labs/mcp-go/server.(*StdioServer).processInputStream
/go/pkg/mod/github.com/mark3labs/mcp-go@v0.18.0/server/stdio.go:143
github.com/mark3labs/mcp-go/server.(*StdioServer).Listen
/go/pkg/mod/github.com/mark3labs/mcp-go@v0.18.0/server/stdio.go:209
github.com/mark3labs/mcp-go/server.ServeStdio
/go/pkg/mod/github.com/mark3labs/mcp-go@v0.18.0/server/stdio.go:282
gitea.com/gitea/gitea-mcp/operation.Run
/app/operation/operation.go:48
gitea.com/gitea/gitea-mcp/cmd.Execute
/app/cmd/cmd.go:119
main.main
/app/main.go:12
runtime.main
/usr/local/go/src/runtime/proc.go:283
```
Turns out the root cause was because the `GITEA_HOST` environment variable wasn't overriding the default flag value, resulting in mismatch of host and access token.
The if statement won't be entered
https://gitea.com/gitea/gitea-mcp/src/commit/7cfa1fa218654e14c0ed0f9bac70ef75039f6178/cmd/cmd.go#L74-L77
Due to `host` could never be evaluated as an empty string from the default value `"http://gitea.com"`
https://gitea.com/gitea/gitea-mcp/src/commit/7cfa1fa218654e14c0ed0f9bac70ef75039f6178/cmd/cmd.go#L35-L40
Unless user specify `gitea-mcp ... --host <empty_string> ...` with environment `GITEA_HOST=<non_empty_string>` at the same time, which is very unlikely IMHO.
## How
- Set `host` flag default value from `GITEA_HOST` environment variable value
- Remove possible dead code if-statement
Co-authored-by: hiifong <i@hiif.ong>
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/23
Reviewed-by: hiifong <i@hiif.ong>
Co-authored-by: Flynn Hou <flynnhou7@gmail.com>
Co-committed-by: Flynn Hou <flynnhou7@gmail.com>
- Add `GITEA_INTERACTIVE` configuration example in README files
- Add `insecure` flag to ignore TLS certificate errors in `cmd.go`
- Set insecure mode based on `GITEA_INSECURE` environment variable in `cmd.go`
- Add `Insecure` boolean variable in `pkg/flag/flag.go`
- Import `crypto/tls` and `net/http` in `pkg/gitea/gitea.go`
- Modify Gitea client creation to support insecure HTTP client in `pkg/gitea/gitea.go`
Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/20
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
- Import the `context` package
- Add context cancellation handling with log message and return in `Execute` function
Signed-off-by: appleboy <appleboy.tw@gmail.com>
- Add command to install `air` for hot reloading in `Makefile`
- Add `dev` command to run the application with hot reload in `Makefile`
- Add `vendor` command to tidy and verify module dependencies in `Makefile`
- Update log synchronization method to use `log.Default().Sync()` in `cmd/cmd.go`
- Change variadic parameter type from `interface{}` to `any` in logging functions
- Remove `Sync` function from `pkg/log/log.go`
ref: https://github.com/uber-go/zap/issues/880
Signed-off-by: appleboy <appleboy.tw@gmail.com>