docs: local vs server quickstart, authz model, packaging
Reframe the README around two transports and add a local stdio quickstart with uvx/pip and Claude Desktop / Claude Code wiring. New docs: local-quickstart.md and packaging.md (uv build/publish). Document resource-type-aware authorization and classified gitea_request in security.md; stdio env vars + audit-log fallback in configuration.md; local install in deployment.md; core+adapters in architecture.md. Add the missing root AGENTS.md contract, update CLAUDE.md with the core/adapter layout, fail-closed invariants, and the branching flow (HEAD -> feature -> dev -> main). Update roadmap/todo and .env.example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# Packaging & publishing
|
||||
|
||||
AegisGitea-MCP is distributed as a single Python package, `aegis-gitea-mcp`,
|
||||
built with [`uv`](https://docs.astral.sh/uv/) and published to the self-hosted
|
||||
Gitea package registry.
|
||||
|
||||
## Distribution layout
|
||||
|
||||
One package, two console scripts, one optional extra:
|
||||
|
||||
| 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 |
|
||||
|
||||
- **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.
|
||||
|
||||
## Build locally
|
||||
|
||||
```bash
|
||||
uv build
|
||||
# -> 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:
|
||||
|
||||
```bash
|
||||
GITEA_URL=https://git.hiddenden.cafe GITEA_TOKEN=<pat> \
|
||||
uvx --from ./dist/aegis_gitea_mcp-*.whl aegis-gitea-mcp
|
||||
```
|
||||
|
||||
## Install from the Gitea registry
|
||||
|
||||
```bash
|
||||
uv pip install \
|
||||
--index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple \
|
||||
aegis-gitea-mcp
|
||||
```
|
||||
|
||||
(With `pip`, use `--index-url` the same way.)
|
||||
|
||||
## Cutting a release
|
||||
|
||||
Releases are tag-driven. The publish workflow
|
||||
(`.gitea/workflows/publish.yml`) triggers on a `v*` tag, runs lint + tests
|
||||
first, builds with `uv`, and publishes to the Gitea PyPI registry.
|
||||
|
||||
1. Bump `version` in `pyproject.toml` (e.g. `0.2.0`).
|
||||
2. Open a PR into `dev`, merge `dev` into `main`.
|
||||
3. Tag the release commit and push the tag:
|
||||
|
||||
```bash
|
||||
git tag v0.2.0
|
||||
git push origin v0.2.0
|
||||
```
|
||||
|
||||
4. The workflow publishes the wheel + sdist and attaches them to the run.
|
||||
|
||||
### Required CI secrets
|
||||
|
||||
The publish job uses Gitea Actions secrets — never hardcode credentials:
|
||||
|
||||
| Secret | Purpose |
|
||||
|--------|---------|
|
||||
| `GITEA_PACKAGE_USER` | Gitea username that owns the package |
|
||||
| `GITEA_PACKAGE_TOKEN` | least-privilege PAT with `write:package` |
|
||||
|
||||
If either 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.
|
||||
Reference in New Issue
Block a user