# Troubleshooting ## "Internal server error (-32603)" from ChatGPT **Symptom:** ChatGPT shows `Internal server error` with JSON-RPC error code `-32603` when trying to use Gitea tools. **Cause:** The OAuth token stored by ChatGPT was issued without Gitea API scopes (e.g. `read:repository`). This happens when the initial authorization request didn't include the correct `scope` parameter. The token passes OIDC validation (openid/profile/email) but gets **403 Forbidden** from Gitea's REST API. **Fix:** 1. In Gitea: Go to **Settings > Applications > Authorized OAuth2 Applications** and revoke the MCP application. 2. In ChatGPT: Go to **Settings > Connected apps** and disconnect the Gitea integration. 3. Re-authorize: Use the ChatGPT integration again. It will trigger a fresh OAuth flow with the correct scopes (`read:repository`). **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 ``` ## "Gitea rejected the API call" (403) **Symptom:** Tool calls return 403 with a message about re-authorizing. **Cause:** Same root cause as above — the OAuth token doesn't have the required Gitea API scopes. The middleware's API scope probe detected this and returned a clear error instead of letting it fail deep in the tool handler. **Fix:** Same as above — revoke and re-authorize. ## ChatGPT caches stale tokens **Symptom:** After fixing the OAuth configuration, ChatGPT still sends the old token. **Cause:** ChatGPT caches access tokens and doesn't automatically re-authenticate when the server configuration changes. **Fix:** 1. In ChatGPT: **Settings > Connected apps** > disconnect the integration. 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 will validate via the userinfo endpoint but will be rejected by Gitea's REST API with 403. The MCP server's `openapi-gpt.yaml` file controls which scopes ChatGPT 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