# ADR 0003: tools generated from the pinned swagger Status: accepted (2026-10-14) ## Context Coverage target: every operation in the instance swagger gets a tool. Gitea 28.1.0 has 537 operations. Hand-writing them is error-prone and drifts. ## Decision - Pin the instance swagger at `spec/gitea-swagger.v1.json` (sha256 matches the live instance at time of pinning). - `scripts/generate_catalog.py` turns it into a committed `src/aegis_gitea_mcp/catalog/tools.json`. `--check` fails when the committed file is stale. Runtime only reads the JSON. - Tool name: `gitea__`, lowercase snake_case, at most 64 characters, unique. Domain comes from the path (admin, repo, issue, pull, release, wiki, org, team, user, actions, hook, package, notification, misc), action from the operationId with redundant domain words stripped. A small override map handles collisions and awkward names. - Input schema: path and query parameters as top-level properties, the JSON body under `body`, multipart files as base64 strings. `additionalProperties: false` everywhere we control. Owner, repo and username path parameters get name patterns. - Annotations: `readOnlyHint` for GET, `destructiveHint` for DELETE and for PUT/PATCH that replace state, `idempotentHint` for GET/PUT/DELETE. A small explicit override set in `catalog/build.py` corrects POST operations: the render endpoints (`/markdown`, `/markdown/raw`, `/markup`) and the read-only `file-contents` POST are read-only and idempotent; irreversible or wide-reaching POSTs (PR merge, merge upstream, repo transfer and its accept/reject, user and org rename, cron run, mirror sync, adopt unadopted repository) are destructive. - Every tool also accepts optional `sudo` (admin acts as another user). - One extra hand-written tool, `gitea_api_request`, reaches endpoints added in newer Gitea versions than the pinned spec. - Filters: `TOOLSETS` (comma-separated domains, default all), `READ_ONLY` (default false), `DISABLED_TOOLS`. ## Consequences Upgrading Gitea means re-pinning the swagger and regenerating. Tool names are stable for a given spec. The docs inventory is generated from the same catalog and checked in CI.