docs: rewrite README and docs for the full-access design, generate tool inventory
This commit is contained in:
1 parent
68bd8700dc
commit
7c7cfc05ff
13 files changed
+1693
-1026
No files matched your search
+51
-74
@@ -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.
|
||||
Reference in new issue
Block a user