Files
zhengchen.tao ab987986b4 docs(readme): 子域名改名为 gitea-mcp.zhengchentao.win
域名规划统一:MCP 服务子域名与 repo 名一致。
- git-mcp.zhengchentao.win → gitea-mcp.zhengchentao.win
2026-05-06 23:41:16 +08:00

162 lines
5.2 KiB
Markdown

# gitea-mcp
Read access to all Gitea repos (public + private, personal + org) via MCP.
OAuth via nas-auth (DCR + PKCE + JWT HS256), admin PAT held internally — Claude never touches the PAT.
## Architecture
```
Claude.ai (MCP client)
│ ① GET /.well-known/oauth-authorization-server
gitea-mcp.zhengchentao.win ←── this service
│ ② DCR + PKCE auth flow redirect
auth.zhengchentao.win ←── nas-auth
│ ③ JWT (aud=gitea, scope=read:gitea)
Claude.ai → Bearer JWT
│ ④ POST /mcp (MCP Streamable HTTP)
gitea-mcp.zhengchentao.win
│ Bearer <GITEA_ADMIN_PAT>
git.zhengchentao.win ←── Gitea
```
See [gitea-mcp 设计.md](../Coding/gitea-mcp/gitea-mcp%20设计.md) for full design rationale.
## Tools
| Tool | Description |
|------|-------------|
| `list_repos` | List all repos (personal + org, public + private) |
| `read_repo` | Repo metadata: topics, stars, default branch, mirror flag |
| `list_tree` | File tree at a ref (recursive optional, max 500 entries) |
| `read_file` | Raw file content (UTF-8, truncated at 1MB) |
| `search_code` | Code search via Gitea indexer (requires indexer enabled) |
| `list_branches` | Branch list + last commit per branch |
| `list_commits` | Recent commits with author + message |
| `read_commit` | Full commit details + per-file diff (max 50 files) |
| `list_issues` | Issues filtered by state (open/closed/all) |
| `read_issue` | Issue body + all comments |
| `list_pulls` | Pull requests filtered by state |
| `read_pull` | PR body + review comments + changed files |
| `list_orgs` | All organizations visible to admin token |
| `read_org` | Org metadata |
| `list_packages` | Packages in registry by owner (container/generic/npm/...) |
| `read_package` | Package version metadata |
| `list_workflow_runs` | Gitea Actions workflow run history |
| `read_run_log` | Run details + job list + log (truncated at 1MB) |
All tools require a valid JWT with `scope=read:gitea` issued by nas-auth.
## Configuration (env vars)
| Variable | Default | Description |
|----------|---------|-------------|
| `Gitea__BaseUrl` | `https://git.zhengchentao.win` | Gitea backend URL |
| `Gitea__AdminPat` | *(required)* | Gitea read-only PAT — see PAT Setup below |
| `Gitea__RepoBlacklist` | *(empty)* | Comma-separated `owner/repo` pairs to hide from Claude |
| `Gitea__DefaultLimit` | `50` | Default page size for list operations |
| `Gitea__MaxFileBytes` | `1048576` | Max file read size in bytes (1MB) |
| `Jwt__Issuer` | `https://auth.zhengchentao.win` | Expected JWT issuer |
| `Jwt__Audience` | `gitea` | Expected JWT audience |
| `Jwt__SigningKeyCurrent` | *(required)* | HS256 signing key (shared with nas-auth) |
| `Jwt__SigningKeyPrevious` | *(empty)* | Previous key for rotation window |
| `ASPNETCORE_ENVIRONMENT` | `Production` | Use `Development` locally |
All secrets come from `/volume1/docker/compose/.env.shared` on NAS — never hardcode them.
## Local Development
### 1. Restore and run
```bash
dotnet restore
dotnet run
# Listens on http://localhost:5000
```
### 2. Generate a dev JWT
Use `dotnet user-jwts` to sign a token without running nas-auth:
```bash
dotnet user-jwts create \
--issuer https://auth.zhengchentao.win \
--audience gitea \
--name tao \
--claim sub=tao \
--claim scope=read:gitea
```
Or use [jwt.io](https://jwt.io) with alg=HS256 and the key from `Jwt:SigningKeyCurrent`.
### 3. Test with MCP Inspector
```bash
npx @modelcontextprotocol/inspector
# Transport: Streamable HTTP
# URL: http://localhost:5000/mcp
# Bearer Token: <token from step 2>
```
### 4. Run unit tests
```bash
dotnet test gitea-mcp.Tests/
```
## PAT Setup (Gitea → Settings → Applications)
Generate a token with **only these scopes** (principle of least privilege):
- `read:repository`
- `read:organization`
- `read:package`
- `read:issue`
- `read:user`
Do NOT grant `write:*` or `admin:*` scopes.
Store the generated token in `.env.shared` as `GITEA_MCP_PAT=<token>`.
If the PAT is compromised: revoke in Gitea → generate new → update `.env.shared``docker compose up -d gitea-mcp`.
## Docker Compose (NAS deployment)
```yaml
# /volume1/docker/compose/gitea-mcp/docker-compose.yml
services:
gitea-mcp:
image: git.zhengchentao.win/zhengchen.tao/gitea-mcp:latest
container_name: gitea-mcp
restart: unless-stopped
ports:
- "9092:8080"
volumes:
- /volume1/docker/gitea-mcp/logs:/app/logs
environment:
- ASPNETCORE_ENVIRONMENT=Production
- Gitea__BaseUrl=https://git.zhengchentao.win
- Gitea__AdminPat=${GITEA_MCP_PAT}
- Gitea__RepoBlacklist=
- Jwt__Issuer=https://auth.zhengchentao.win
- Jwt__Audience=gitea
- Jwt__SigningKeyCurrent=${JWT_SIGNING_KEY_CURRENT}
- TZ=Asia/Shanghai
env_file:
- ../.env.shared
```
## Related Documents
- [gitea-mcp 设计](../Obsidian%20Vault/Coding/gitea-mcp/gitea-mcp%20设计.md)
- [MCP 实现指南](../Obsidian%20Vault/Coding/obsidian-mcp/MCP%20实现指南.md)
- [nas-auth 设计](../Obsidian%20Vault/Coding/nas-auth/nas-auth%20设计.md)
- [Gitea Actions Build-Deploy 模板](../Obsidian%20Vault/Coding/Gitea%20Actions%20Build-Deploy%20模板.md)