# Configuration All settings are environment variables. They are read case-insensitively from the process environment and from a `.env` file in the working directory (the environment wins). Unknown variables are ignored. A blank value (`KEY=` in `.env`) counts as unset for the optional secrets, URLs and paths. List values accept commas or whitespace as separators. `.env.example` is the annotated template. `uv run aegis-gitea-mcp setup` fills one in for you (see [getting-started.md](getting-started.md)). Secret settings never appear in logs, errors or `repr` output. Requirements that depend on how the server is started are checked at start, not on import: `GITEA_TOKEN` for stdio, authentication for a non-loopback HTTP bind, complete OAuth settings when OAuth is on. ## Gitea | Variable | Default | Rules | |---|---|---| | `GITEA_URL` | required | `http` or `https`, must have a host, no credentials, query or fragment. A trailing `/api/v1` is removed. | | `GITEA_TOKEN` | unset | Token for stdio and for admin-token mode on HTTP. Its scopes bound what the server can do. Required for stdio (exit code 2 without it). | ## Transport | Variable | Default | Rules | |---|---|---| | `MCP_TRANSPORT` | `stdio` | `stdio` or `http`. `serve --transport` overrides it. | | `MCP_HOST` | `127.0.0.1` | Bind address for HTTP. A non-loopback value refuses to start unless HTTP auth is configured. | | `MCP_PORT` | `8080` | 1 to 65535. | | `MCP_PATH` | `/mcp` | Starts with a single `/`, no query, spaces or trailing slash, not just `/`. | | `MCP_BEARER_TOKEN` | unset | Static bearer token for HTTP (admin identity). At least 32 characters. Generate with `openssl rand -hex 32`. | | `PUBLIC_BASE_URL` | unset | Public URL behind a reverse proxy. Same URL rules as `GITEA_URL`, and `https` unless the host is loopback. Required for OAuth. | | `ALLOWED_HOSTS` | empty | Extra `Host` header values accepted behind a proxy. The loopback names with the port and the host of `PUBLIC_BASE_URL` are always allowed. Other `Host` values are rejected (DNS-rebinding protection). | ## Per-user OAuth (HTTP only) | Variable | Default | Rules | |---|---|---| | `OAUTH_ENABLED` | `false` | When true, the four settings below are required, or the server refuses to start (exit code 2, with the list of what is missing). | | `GITEA_OAUTH_CLIENT_ID` | unset | Client id of the Gitea OAuth application (created by `setup`). | | `GITEA_OAUTH_CLIENT_SECRET` | unset | Its client secret. | | `TOKEN_ENCRYPTION_KEY` | unset | At least 32 characters. Encrypts stored user tokens. Losing it invalidates every stored login. | | `OAUTH_SCOPES` | all `write:` scopes | Granular Gitea scopes only (`read:` or `write:` plus activitypub, admin, issue, misc, notification, organization, package, repository, user). Anything else is rejected, because Gitea grants full access for unknown scope strings. Must not be empty. | `PUBLIC_BASE_URL` is also required for OAuth. The Gitea OAuth application's redirect URI is `/oauth/callback`. ## State | Variable | Default | Rules | |---|---|---| | `DATA_DIR` | `~/.local/state/aegis-gitea-mcp` (`/var/lib/aegis-mcp` in the image) | `~` is expanded. Holds the token store (`oauth-tokens.json`, mode 0600) and the audit log. | | `AUDIT_LOG_PATH` | `DATA_DIR/audit.log` | Path of the hash-chained audit log. See [audit-logging.md](audit-logging.md). | ## Tool exposure Everything is enabled by default. These settings only narrow it. A filtered tool is neither listed nor callable. | Variable | Default | Rules | |---|---|---| | `READ_ONLY` | `false` | Expose only read-only (GET) operations. `gitea_api_request` stays listed but accepts only GET. | | `TOOLSETS` | `all` | Comma separated domains: `admin`, `repo`, `issue`, `pull`, `release`, `wiki`, `org`, `team`, `user`, `actions`, `hook`, `package`, `notification`, `misc`, or `all`. Unknown domains are rejected. `gitea_api_request` belongs to `misc`. | | `DISABLED_TOOLS` | empty | Exact tool names to hide, lowercased on load. An unknown name is a startup error that lists the bad names. | ## Limits and safety | Variable | Default | Rules | |---|---|---| | `REQUEST_TIMEOUT_SECONDS` | `30` | 1 to 600. Timeout of each Gitea request. | | `MAX_TOOL_RESPONSE_ITEMS` | `200` | At least 1. Longer lists are cut and reported in `truncated`. | | `MAX_TOOL_RESPONSE_CHARS` | `60000` | At least 1. Upper bound of one serialized result. | | `MAX_BINARY_BYTES` | `5242880` | At least 1. Larger binary bodies fail with `payload_too_large`. | | `SECRET_DETECTION_MODE` | `mask` | `off`, `mask` or `block`. See below. | | `LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` or `CRITICAL`. Logs go to stderr. | | `EXPOSE_ERROR_DETAILS` | `false` | When true, the exception class name is added to internal and transport errors. Never a stack trace. Do not enable in production. | | `RATE_LIMIT_PER_MINUTE` | `120` | At least 1. Per client on the HTTP MCP endpoint, keyed by a hash of the Authorization header, else the client IP. Excess requests get 429. | Secret detection: `mask` replaces secret-like strings in results with a placeholder, `block` withholds a whole result that contains one (`secret_blocked`), `off` disables pattern matching. The server's own tokens (Gitea token, bearer token, OAuth client secret, the calling user's token) and secret values you submit in a request body are always redacted by exact match. The tools that exist to return a new credential (create token, runner registration token, OAuth application, deploy token) are exempt from pattern masking so the credential stays usable. ## Profiles Read-only assistant for issues and code: ```bash READ_ONLY=true TOOLSETS=repo,issue,pull,release,wiki ``` Everything except instance administration and credentials: ```bash TOOLSETS=repo,issue,pull,release,wiki,org,team,hook,actions,package,notification,misc DISABLED_TOOLS=gitea_user_create_token ``` (`gitea_user_create_token` must be a registered name, see [tools.md](tools.md); the server refuses to start if a name in `DISABLED_TOOLS` does not exist.)