Files
AegisGitea-MCP/docs/configuration.md
T

8.6 KiB

Configuration

All settings are environment variables. They are read case-insensitively from the process environment and from an env file (the environment always wins). Unknown variables are ignored. A blank value (KEY= in the env file) counts as unset for the optional secrets, URLs and paths. List values accept commas or whitespace as separators.

Which env file is read

The env file is never trusted just because it sits in the working directory: MCP clients start stdio servers inside the project they work on, which can be a cloned repository carrying a planted .env that switches off secret masking or the audit log or points GITEA_URL at another host. The file is chosen in this order:

  1. --env-file PATH of serve (and setup): used as given. It must exist and be a regular file.
  2. The AEGIS_ENV_FILE environment variable: same rules.
  3. ./.env, but only when it is a regular file (not a symlink), owned by the user running the server, with no group or other permissions (mode 0600, which setup writes). Otherwise it is ignored and one warning goes to stderr that says why and how to fix it: chmod 600 .env, or pass --env-file.

Real environment variables take precedence over every file. A missing ./.env is silent. Containers pass settings as environment variables (env_file: in compose), not through the working directory.

.env.example is the annotated template. uv run aegis-gitea-mcp setup fills one in for you (see 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). A non-loopback MCP_HOST with neither PUBLIC_BASE_URL nor ALLOWED_HOSTS logs a startup warning on stderr, because remote clients then get 421.
FORWARDED_ALLOW_IPS 127.0.0.1 Comma list of IP addresses or networks (or *) whose X-Forwarded-For and X-Forwarded-Proto headers are trusted. Set it to the address of the reverse proxy when it is not on the same host, for example a Docker network. Otherwise the per-IP rate limit sees the proxy address for every client: a request that carries X-Forwarded-For from a peer outside this list is not honoured and logs one warning ("add its address to FORWARDED_ALLOW_IPS"). * trusts every peer and logs a warning: only use it when the port is reachable solely from the proxy, since clients could otherwise spoof their IP.

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:<category> 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.

| OAUTH_REDIRECT_ALLOWLIST | empty | Comma list of redirect URIs MCP clients may register: exact URIs (https://client.example/cb) or prefixes ending in / that allow a whole host (https://claude.ai/). A bare origin without a path is refused. Empty accepts any https URI (and http on localhost, 127.0.0.1, [::1]). With a list, https URIs must match it; loopback URIs stay allowed for native clients. Checked at registration and again at /authorize. |

PUBLIC_BASE_URL is also required for OAuth. The Gitea OAuth application's redirect URI is <PUBLIC_BASE_URL>/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. The server opens it for append at startup and exits with code 2 and a message on stderr when it cannot.

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 and on the unauthenticated OAuth endpoints (/register, /authorize, /token, /revoke, /oauth/consent, /oauth/callback), keyed by the client IP (an IPv6 client counts per /64) and, on the MCP endpoint, by a hash of the Authorization header. Excess requests get 429. Only the first rejected request per client and minute is written to the audit log. Tracking is in memory and bounded (idle clients are forgotten).

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:

READ_ONLY=true
TOOLSETS=repo,issue,pull,release,wiki

Everything except instance administration and credentials:

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; the server refuses to start if a name in DISABLED_TOOLS does not exist.)