ab987986b4
域名规划统一:MCP 服务子域名与 repo 名一致。 - git-mcp.zhengchentao.win → gitea-mcp.zhengchentao.win
162 lines
5.2 KiB
Markdown
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)
|