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

+51 -74
View File
@@ -1,117 +1,94 @@
# Packaging & publishing
# Packaging and publishing
AegisGitea-MCP is built with [`uv`](https://docs.astral.sh/uv/) and published to
the self-hosted Gitea package registry on every merge. There are two channels:
AegisGitea MCP is built with [uv](https://docs.astral.sh/uv/) (hatchling backend) and published
to the self-hosted Gitea package registry on every merge. There are two channels:
| Channel | Package | Published on | Versioning |
|---------|---------|--------------|------------|
| **stable** | `aegis-gitea-mcp` | merge to `main` | `X.Y.Z` |
| **dev** | `aegis-gitea-mcp-dev` | merge to `dev` | `X.Y.Z.devN` (N = CI run number, always unique) |
| Channel | Package | Published on | Version |
|---|---|---|---|
| stable | `aegis-gitea-mcp` | push to `main` | `X.Y.Z` from `pyproject.toml` |
| dev | `aegis-gitea-mcp-dev` | push to `dev` | `X.Y.Z.dev<N>`, N is the CI run number |
Both channels build from the same source and install the **same import module**,
`aegis_gitea_mcp`, with the same two console scripts. They differ only in the
distribution name and the version. Install one or the other in a given
environment, not both — they would collide on the module.
Both build from the same source and install the same import module, `aegis_gitea_mcp`, and the
same console script, `aegis-gitea-mcp`. They differ only in the distribution name and version.
Install one or the other in an environment, not both, because they would collide on the module.
## Distribution layout
## What is in the package
Each channel ships one distribution with two console scripts and one optional
extra (the stable and dev packages are identical here — only the dist name and
version differ):
One distribution, one console script:
| Console script | Entry point | Requires |
|----------------|-------------|----------|
| `aegis-gitea-mcp` | `aegis_gitea_mcp.stdio_app:main` | core only |
| `aegis-gitea-mcp-server` | `aegis_gitea_mcp.server_entry:main` | `[server]` extra |
| Console script | Entry point |
|---|---|
| `aegis-gitea-mcp` | `aegis_gitea_mcp.cli:main` (subcommands `serve`, `setup`, `version`; `serve` is the default) |
- **Core** (default install): `httpx`, `pydantic`, `pydantic-settings`, `PyYAML`,
`python-dotenv`, `structlog`, `mcp`. Enough to run the local stdio server.
- **`[server]` extra**: `fastapi`, `uvicorn[standard]`, `PyJWT[crypto]`,
`python-multipart`. The public HTTP/OAuth server.
The `aegis-gitea-mcp-server` entry point degrades gracefully: invoked without
the web stack it prints `install 'aegis-gitea-mcp[server]'` instead of a
`ModuleNotFoundError` traceback.
Dependencies are the `mcp` SDK (2.3 or newer, below 3), `httpx`, `pydantic`, `pydantic-settings`,
`jsonschema`, `cryptography` and `uvicorn`. There are no extras: both transports and per-user
OAuth are in the default install. The generated tool catalog (`catalog/tools.json`) ships inside
the package.
## Build locally
```bash
uv build
# -> dist/aegis_gitea_mcp-<version>-py3-none-any.whl
# -> dist/aegis_gitea_mcp-<version>.tar.gz
# dist/aegis_gitea_mcp-<version>-py3-none-any.whl
# dist/aegis_gitea_mcp-<version>.tar.gz
```
Smoke-test the local stdio server from the built wheel:
Smoke-test the built wheel over stdio:
```bash
GITEA_URL=https://git.hiddenden.cafe GITEA_TOKEN=<pat> \
GITEA_URL=https://git.example.com GITEA_TOKEN=<your-gitea-token> \
uvx --from ./dist/aegis_gitea_mcp-*.whl aegis-gitea-mcp
```
Dependencies are pinned in `uv.lock`; `uv sync` reproduces the environment.
## Install from the Gitea registry
**Stable** (`aegis-gitea-mcp`, published from `main`):
Stable:
```bash
uv pip install \
--index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
--extra-index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
aegis-gitea-mcp
# or run it one-off without installing into the environment:
# or run it without installing into an environment:
uvx --index https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ aegis-gitea-mcp
```
**Dev** (`aegis-gitea-mcp-dev`, published from `dev` — newest pre-release build):
Dev (newest pre-release build):
```bash
uv pip install \
--index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
uv pip install --pre \
--extra-index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
aegis-gitea-mcp-dev
```
(With `pip`, use `--index-url` the same way.) Both packages expose the same
`aegis-gitea-mcp` / `aegis-gitea-mcp-server` console scripts and the same
`aegis_gitea_mcp` import module, so install one **or** the other per environment.
The registry holds only this project's packages and does not proxy PyPI, so it is added as an
extra index and the dependencies (`mcp`, `httpx`, ...) still come from PyPI. With `pip` use
`--extra-index-url` the same way.
## Publishing channels
## Publishing
Publishing is merge-driven, not tag-driven. The publish workflow
(`.gitea/workflows/publish.yml`) triggers on a push to `dev` or `main`, runs
lint + tests first, then builds with `uv` and publishes to the Gitea PyPI
registry. The package name + version are patched into `pyproject.toml` **at build
time only** (never committed):
Publishing is merge-driven, not tag-driven. `.gitea/workflows/publish.yml` triggers on a push to
`dev` or `main`, runs the lint and test gates first, builds with `uv build`, and publishes with
`uv publish`. The package name and version are patched into `pyproject.toml` at build time only
and never committed.
- **`dev` push** → `aegis-gitea-mcp-dev` at `X.Y.Z.dev<run_number>`. The CI run
number is monotonic, so every merge to `dev` yields a unique pre-release.
- **`main` push** → `aegis-gitea-mcp` at the plain `X.Y.Z` from `pyproject.toml`.
Publishing uses `uv publish --check-url`, so a `main` push that did **not** bump
the version is a clean no-op (the existing files are skipped) rather than a 409.
- A push to `dev` publishes `aegis-gitea-mcp-dev` at `X.Y.Z.dev<run number>`, unique per run.
- A push to `main` publishes `aegis-gitea-mcp` at the plain `X.Y.Z`. `uv publish --check-url`
skips files that already exist, so a push that did not bump the version is a clean no-op.
### Cutting a stable release
1. Bump `version` in `pyproject.toml` (e.g. `0.2.0` → `0.3.0`) on a branch off
`dev`.
2. Open a PR into `dev` and merge it (this publishes a fresh
`aegis-gitea-mcp-dev` build).
3. Promote `dev` → `main`. The push to `main` publishes the new stable
`aegis-gitea-mcp X.Y.Z`.
1. Bump `version` in `pyproject.toml` on a branch off `dev`.
2. Open a pull request into `dev` and merge it. That publishes a fresh dev build.
3. Promote `dev` to `main`. The push to `main` publishes the stable version.
Re-pushing `main` at an unchanged version is harmless — `--check-url` skips the
already-published files.
### CI secret
### Required CI secrets
Publishing uses the `REGISTRY_TOKEN` Actions secret, a personal access token with
`write:package`, the same one the image build uses. The token authenticates as its owner, so the
job's actor is the username and the token is the password. If the secret is missing the job
fails instead of publishing anonymously.
The publish job reuses the **existing** `REGISTRY_TOKEN` Actions secret — the same
PAT (`write:package`) that `docker.yml` uses to push images — so no new secret is
needed. The token authenticates as its owning Gitea user, so `GITHUB_ACTOR` is the
username and the token is the password.
| Secret | Purpose |
|--------|---------|
| `REGISTRY_TOKEN` | PAT with `write:package`; used for both image and package pushes |
If the secret is absent the job fails loudly rather than publishing anonymously.
> Publishing to public PyPI is intentionally **not** configured. A second,
> separately-gated `uv publish` step would be required and is left as a
> commented stub in the workflow.
Publishing to public PyPI is intentionally not configured.