docs: rewrite README and docs for the full-access design, generate tool inventory

This commit is contained in:
Latte committed 2026-10-14 16:13:11 +02:00
1 parent 68bd8700dc
commit 7c7cfc05ff
13 files changed
+1693 -1026

No files matched your search

+95 -96
View File
@@ -1,104 +1,103 @@
# Configuration
Copy `.env.example` to `.env` and set values before starting:
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:<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. |
`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](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
cp .env.example .env
READ_ONLY=true
TOOLSETS=repo,issue,pull,release,wiki
```
## Local stdio transport (`aegis-gitea-mcp`)
Everything except instance administration and credentials:
The local single-user server reads only two variables; a local `.env` file is
supported via python-dotenv.
```bash
TOOLSETS=repo,issue,pull,release,wiki,org,team,hook,actions,package,notification,misc
DISABLED_TOOLS=gitea_user_create_token
```
| Variable | Required | Default | Description |
|---|---|---|---|
| `GITEA_URL` | Yes | - | Base URL of your Gitea instance |
| `GITEA_TOKEN` | Yes | - | Your Gitea Personal Access Token (the local identity) |
| `AUDIT_LOG_PATH` | No | per-user state path | Audit log location (see below) |
The local adapter forces `OAUTH_MODE=false` and defaults `AUTH_ENABLED=false`
(no API-key requirement) — the operator is the trusted PAT owner. `WRITE_MODE`,
`WRITE_REPOSITORY_WHITELIST`, `POLICY_FILE_PATH`, `SECRET_DETECTION_MODE`,
`RAW_API_ENABLED`, and `RAW_API_ALLOW_SENSITIVE` all behave exactly as on the
server.
**Audit-log fallback.** When `AUDIT_LOG_PATH` is unset, the container default
(`/var/log/aegis-mcp/audit.log`) is replaced with a writable per-user path:
- Windows: `%LOCALAPPDATA%\aegis-gitea-mcp\audit.log`
- Linux/macOS: `$XDG_STATE_HOME/aegis-gitea-mcp/audit.log`, else
`~/.local/state/aegis-gitea-mcp/audit.log`
## Raw API dispatch (`gitea_request`)
| Variable | Required | Default | Description |
|---|---|---|---|
| `RAW_API_ENABLED` | No | `true` | Enable the generic `gitea_request` escape hatch |
| `RAW_API_ALLOW_SENSITIVE` | No | `false` | Opt in to the admin/credential surface (`/admin`, `*tokens*`, `*secrets*`, `*hooks*`, `*keys*`, `applications/oauth2`, runner registration). Admin calls additionally require a verified site administrator. |
## OAuth/OIDC Settings (Primary)
| Variable | Required | Default | Description |
|---|---|---|---|
| `GITEA_URL` | Yes | - | Base URL of your Gitea instance |
| `OAUTH_MODE` | No | `false` | Enables OAuth-oriented validation settings |
| `GITEA_OAUTH_CLIENT_ID` | Yes when `OAUTH_MODE=true` | - | OAuth client id |
| `GITEA_OAUTH_CLIENT_SECRET` | Yes when `OAUTH_MODE=true` | - | OAuth client secret |
| `OAUTH_EXPECTED_AUDIENCE` | No | empty | Additional accepted JWT audience beyond the MCP resource and Gitea client id |
| `OAUTH_CACHE_TTL_SECONDS` | No | `300` | OIDC discovery/JWKS cache TTL |
| `OAUTH_STATE_SECRET` | Yes when `OAUTH_MODE=true` | - | HMAC secret for signed OAuth state wrappers; must be at least 32 characters (e.g. `openssl rand -hex 32`) |
| `OAUTH_REDIRECT_ALLOWLIST` | No | empty | Additional allowed redirect URIs for OAuth clients |
## MCP Server Settings
| Variable | Required | Default | Description |
|---|---|---|---|
| `MCP_HOST` | No | `127.0.0.1` | Interface to bind to |
| `MCP_PORT` | No | `8080` | Port to listen on |
| `PUBLIC_BASE_URL` | No | empty | Public HTTPS base URL advertised in OAuth metadata (recommended behind reverse proxy) |
| `ALLOW_INSECURE_BIND` | No | `false` | Explicit opt-in required for `0.0.0.0` bind |
| `LOG_LEVEL` | No | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
| `STARTUP_VALIDATE_GITEA` | No | `true` | Validate OIDC discovery endpoint at startup |
| `DCR_ENABLED` | No | `true` | Enable dynamic client registration at `/register` |
| `DCR_STORAGE_PATH` | No | `/var/lib/aegis-mcp/dcr_clients.json` | Persisted OAuth client registry path. Written with owner-only (`0o600`) permissions on POSIX hosts |
## Security and Limits
| Variable | Required | Default | Description |
|---|---|---|---|
| `MAX_AUTH_FAILURES` | No | `5` | Failed auth attempts before rate limiting |
| `AUTH_FAILURE_WINDOW` | No | `300` | Window in seconds for auth failure counting |
| `RATE_LIMIT_PER_MINUTE` | No | `60` | Per-IP request limit |
| `TOKEN_RATE_LIMIT_PER_MINUTE` | No | `120` | Per-token request limit |
| `MAX_FILE_SIZE_BYTES` | No | `1048576` | Max file payload returned by read tools |
| `MAX_TOOL_RESPONSE_ITEMS` | No | `200` | Max list items in tool responses |
| `MAX_TOOL_RESPONSE_CHARS` | No | `20000` | Max chars in text fields |
| `REQUEST_TIMEOUT_SECONDS` | No | `30` | Upstream timeout for Gitea calls |
| `SECRET_DETECTION_MODE` | No | `mask` | `off`, `mask`, `block` |
| `REPO_AUTHZ_CACHE_TTL_SECONDS` | No | `60` | TTL for cached per-user repository permission checks |
## Write Mode
| Variable | Required | Default | Description |
|---|---|---|---|
| `WRITE_MODE` | No | `false` | Enables write tools |
| `WRITE_REPOSITORY_WHITELIST` | Required if write mode enabled and allow-all disabled | empty | Comma-separated `owner/repo` allow list |
| `WRITE_ALLOW_ALL_TOKEN_REPOS` | No | `false` | Allow all repos accessible by token |
## Automation
| Variable | Required | Default | Description |
|---|---|---|---|
| `AUTOMATION_ENABLED` | No | `false` | Enables automation endpoints |
| `AUTOMATION_SCHEDULER_ENABLED` | No | `false` | Enables scheduler loop |
| `AUTOMATION_STALE_DAYS` | No | `30` | Age threshold for stale issue checks |
## Legacy Compatibility Variables
These are retained for compatibility but not used for OAuth-protected MCP tool execution:
- `GITEA_TOKEN` — note: in **service-PAT** server mode and in the **local stdio**
transport this is required and is the API identity (see above).
- `MCP_API_KEYS`
- `AUTH_ENABLED`
(`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.)