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

+53 -62
View File
@@ -1,76 +1,67 @@
# Troubleshooting
## "Internal server error (-32603)" from Claude
Start with the result of the failing call: errors carry `error.status`, `error.kind` and
Gitea's sanitized message, and the audit log has one event per call (see
[audit-logging.md](audit-logging.md)).
**Symptom:** Claude shows `Internal server error` with JSON-RPC error code `-32603` when trying to use Gitea tools.
## The server does not start
**Cause:** In user-token mode, the OAuth token stored by the client may have been issued without Gitea API scopes (e.g. `read:repository`). In service-PAT mode, the call may fail because the authenticated user does not have the required repository permission or the permission probe cannot be completed.
| Message or exit | Cause and fix |
|---|---|
| Exit code 2, "GITEA_TOKEN" required (stdio) | stdio needs `GITEA_TOKEN`. Put it in the client's `env` block or in `.env` in the working directory the client starts the server in. |
| Exit code 2, refuses a non-loopback bind | `MCP_HOST` is not loopback and there is no `MCP_BEARER_TOKEN` or complete OAuth setup. Set one of them, or bind `127.0.0.1` behind a reverse proxy. |
| Exit code 2, lists OAuth settings | `OAUTH_ENABLED=true` needs `GITEA_OAUTH_CLIENT_ID`, `GITEA_OAUTH_CLIENT_SECRET`, `TOKEN_ENCRYPTION_KEY` and `PUBLIC_BASE_URL`. |
| Validation error naming a setting | See the rules in [configuration.md](configuration.md): URLs must be http(s) without credentials, `PUBLIC_BASE_URL` must be https, secrets need 32 characters, `OAUTH_SCOPES` accepts only granular scopes. |
| Startup error listing tool names | `DISABLED_TOOLS` contains names that are not registered. Check [tools.md](tools.md). |
**Fix:**
1. In Gitea: Go to **Settings > Applications > Authorized OAuth2 Applications** and revoke the MCP application.
2. In Claude: disconnect the MCP server and authenticate again.
3. Re-authorize: Use the MCP connector again. It will trigger a fresh OAuth flow. For repository-targeted calls in service-PAT mode, also verify the signed-in Gitea user has read/write access to the target repository.
## stdio client shows nothing or breaks
**Verification:** Check the server logs for `oauth_auth_summary`. A working token shows:
```
oauth_auth_summary: api_probe=pass login=alice
```
A scopeless token shows:
```
oauth_token_lacks_api_scope: status=403 login=alice
```
stdout carries only JSON-RPC. If a wrapper script prints to stdout before the server starts, the
client fails to parse the stream. Logs go to stderr; look at the client's MCP server log.
`uvx` needs access to the package index that hosts `aegis-gitea-mcp`, see
[packaging.md](packaging.md).
## "Gitea rejected the API call" (403)
## Tool calls fail
**Symptom:** Tool calls return 403 with a message about re-authorizing.
| `kind` | Meaning |
|---|---|
| `unauthorized` (401) | Gitea rejected the token: wrong, expired or revoked. In OAuth mode the user signs in again. |
| `forbidden` (403) | The token or the user lacks the scope or permission. Admin tools return this for non-admins. Widen the token scopes (see "Token scopes" in the [README](../README.md)) or change the user's rights in Gitea. Sudo needs a site-admin token. |
| `not_found` (404) | The object does not exist, or Gitea hides it from this identity. Also returned for endpoints the Gitea version lacks. |
| `validation_failed` (422), `bad_request` (400) | Gitea rejected the values. The message says which. |
| `invalid_argument` | The arguments do not match the tool schema (missing, wrong type, extra property, bad owner or repository name). The message gives the path, not the value. |
| `timeout`, `upstream_unreachable` | Gitea did not answer within `REQUEST_TIMEOUT_SECONDS`, or the connection failed. Check `GITEA_URL` from the server's host (DNS, TLS, firewall). |
| `redirect` | Gitea answered with a redirect, which is never followed. Use the final URL (for example https) as `GITEA_URL`. |
| `payload_too_large` | The response is above `MAX_BINARY_BYTES`. Raise it or fetch a smaller object. |
| `secret_blocked` | `SECRET_DETECTION_MODE=block` withheld a result containing secret-like content. Use `mask` if that is acceptable. |
| `rate_limited` (429) | Gitea or this server's `RATE_LIMIT_PER_MINUTE` limit. |
**Cause:** The OAuth token does not have the required API scope in user-token mode, or the per-user repository permission check denied the request in service-PAT mode.
A result with a `truncated` object was cut to `MAX_TOOL_RESPONSE_ITEMS` or
`MAX_TOOL_RESPONSE_CHARS`. Use `page` and `limit` on paginated tools to walk through it.
**Fix:** Revoke and re-authorize if the token lacks API scope. If the error mentions repository permission, grant the signed-in Gitea user the required repository access or use a repository they can access.
A tool the client cannot see is probably filtered by `TOOLSETS`, `READ_ONLY` or
`DISABLED_TOOLS`. Calling a filtered or unknown tool is a protocol error.
## Claude caches stale tokens
## HTTP problems
**Symptom:** After fixing the OAuth configuration, Claude still sends the old token.
- `GET /health` returns 503 `degraded`: the server cannot reach Gitea (the probe is cached for
10 seconds). Fix connectivity from the server's host.
- 401 on `/mcp`: no or wrong bearer token, and no valid OAuth token. The response has a
`WWW-Authenticate` header that points clients to the OAuth metadata.
- Request rejected with an invalid Host: the name you used is not allowed. Add it to
`ALLOWED_HOSTS` or set `PUBLIC_BASE_URL`.
- 429: the client exceeded `RATE_LIMIT_PER_MINUTE`.
- Responses arrive in one chunk or time out behind nginx: set `proxy_buffering off;`.
**Cause:** The client caches access tokens and doesn't automatically re-authenticate when the server configuration changes.
## OAuth sign-in
**Fix:**
1. Disconnect the server in the client.
2. Start a new conversation and use the integration again - this forces a fresh OAuth flow.
## How OAuth scopes work with Gitea
Gitea's OAuth2/OIDC implementation uses **granular scopes** for API access:
| Scope | Access |
|-------|--------|
| `read:repository` | Read repositories, issues, PRs, files |
| `write:repository` | Create/edit issues, PRs, comments, files |
| `openid` | OIDC identity (login, email) |
When an OAuth application requests authorization, the `scope` parameter in the authorize URL determines what permissions the resulting token has. If only OIDC scopes are requested (e.g. `openid profile email`), the token can establish identity but may not be usable for direct Gitea REST calls. When `GITEA_TOKEN` is configured, the server uses OIDC for identity and checks the user's repository permission before using the service PAT.
The MCP server's OAuth metadata controls which scopes the client requests. Ensure it includes:
```yaml
scopes:
read:repository: "Read access to Gitea repositories"
write:repository: "Write access to Gitea repositories"
```
## Reading the `oauth_auth_summary` log
Every authenticated request emits a structured log line:
| Field | Description |
|-------|-------------|
| `token_type` | `jwt` or `opaque` |
| `scopes_observed` | Scopes extracted from the token/userinfo |
| `scopes_effective` | Final scopes after implicit grants |
| `api_probe` | `pass`, `fail:403`, `fail:401`, `skip:cached`, `skip:error` |
| `login` | Gitea username |
- `api_probe=pass` — token works for Gitea API calls
- `api_probe=fail:403` — token lacks API scopes, request rejected with re-auth guidance
- `api_probe=skip:cached` — previous probe passed, cached result used
- `api_probe=skip:error` — network error during probe, request allowed to proceed
- `repository_permission_denied` in the audit log — the user lacks required read/write permission for a service-PAT call
- The client reports that dynamic client registration is unsupported: OAuth is off. Set
`OAUTH_ENABLED=true` and the settings that go with it.
- Gitea shows a redirect URI error: the OAuth application's redirect URI must be exactly
`<PUBLIC_BASE_URL>/oauth/callback`. Re-run `setup --public-base-url ...` or fix it in Gitea.
- Signed in, but admin tools return 403: the user is not a site administrator. That is intended.
- Users are asked to sign in again after a restart: `TOKEN_ENCRYPTION_KEY` or the `DATA_DIR`
volume changed. The key must stay stable and the volume persistent.
- After fixing OAuth settings the client still fails: some clients cache tokens. Disconnect the
server in the client and connect again, which starts a fresh flow. Users can also revoke the
application under Settings, Applications, Authorized OAuth2 Applications in Gitea.