# gitea-mcp-oauth-bridge Gitea에는 동적 클라이언트 등록(DCR)이 없어서, claude.ai·Cursor 같은 MCP 클라이언트가 URL만으로 OAuth 연결을 못 한다. 이 브리지가 OAuth 인가 서버 역할(DCR 포함)을 대신하고, 로그인은 Gitea로 받아 사용자별 Gitea 토큰을 암호화해 둔 뒤 MCP 요청을 gitea-mcp로 넘긴다. 각 사용자는 자기 Gitea 계정 권한으로 동작한다. - 주소: `https://git-mcp.sejong.dev` (MCP 엔드포인트는 `/mcp`) - 구성: 클라이언트 → Caddy → 브리지(NAS 13332) → `gitea-mcp-oauth` 컨테이너(호스트 포트 없음, 도커 네트워크 `gitea-mcp-oauth_default`) ``` 클라이언트 --OAuth(MCP, DCR)--> 브리지 --OIDC--> Gitea (git.sejong.dev) |-- Gitea 토큰 암호화 저장 (SQLite, data/bridge.db) `-- MCP 프록시 --> http://gitea-mcp-oauth:8080/mcp ``` 브리지가 발급하지 않은 Bearer 토큰(Gitea PAT 등)은 그대로 gitea-mcp로 넘긴다(`PASSTHROUGH_UNKNOWN_TOKENS`, 기본 켜짐). 그래서 PAT를 넣어 쓰던 클라이언트도 계속 동작한다. ## 클라이언트 연결 - claude.ai: 설정 → 커넥터 → 커스텀 커넥터 추가 → URL `https://git-mcp.sejong.dev/mcp`. 고급 설정은 비워 둔다. - Claude Code: `claude mcp add --transport http gitea https://git-mcp.sejong.dev/mcp` 후 `/mcp`에서 인증. - Cursor: `"gitea": { "url": "https://git-mcp.sejong.dev/mcp" }` ## 환경 변수 `.env.example` 참고. `.env`는 NAS에만 두고(권한 600) 리포에는 올리지 않는다. | 이름 | 설명 | |---|---| | `PUBLIC_BASE_URL` | `https://git-mcp.sejong.dev` (발급자·콜백 주소의 기준) | | `UPSTREAM_MCP_URL` | `http://gitea-mcp-oauth:8080/mcp` | | `UPSTREAM_HOST_HEADER` | `git-mcp.sejong.dev`. gitea-mcp `-oauth`는 `-oauth-public-url` 호스트만 받는다 | | `OIDC_ISSUER` | `https://git.sejong.dev` | | `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` | 아래 Gitea OAuth2 앱 | | `OIDC_SCOPES` | 기본 `openid profile email write:repository write:issue write:user write:organization write:notification write:package write:misc` | | `ALLOWED_MCP_CLIENTS` | 고정 클라이언트 `client_id\|redirect_uri` 콤마 구분. 비우면 DCR만 | | `TOKEN_ENCRYPTION_KEY` | Gitea 토큰 암호화·세션 키 (`openssl rand -hex 32`). 바꾸면 모두 다시 로그인해야 한다 | | `PASSTHROUGH_UNKNOWN_TOKENS` | 기본 `true` | | `DCR_ENABLED` | 기본 `true` | ## Gitea OAuth2 앱 Gitea → 설정 → 애플리케이션 → OAuth2 애플리케이션 생성. - 이름: `gitea-mcp-oauth-bridge` - Redirect URI: `https://git-mcp.sejong.dev/oidc/callback` - **Confidential Client 체크** (브리지가 client secret으로 토큰을 받는다) ## 운영 (NAS) ``` cd /volume1/docker/gitea-mcp-oauth-bridge git pull --ff-only sudo -n /usr/local/bin/docker compose up -d --build sudo -n /usr/local/bin/docker compose logs -f bridge ``` `gitea-mcp-oauth`(`/volume1/docker/gitea-mcp-oauth`)가 먼저 떠 있어야 한다(외부 네트워크 `gitea-mcp-oauth_default`). ## 개발 ``` python -m venv .venv && . .venv/bin/activate pip install -r requirements.txt pytest ``` ## 코드 레이아웃 | 경로 | 역할 | |---|---| | `app/main.py` | FastAPI: OAuth AS(메타데이터·DCR·authorize·token), Gitea OIDC 로그인, `/mcp` 프록시 | | `app/dcr.py` | RFC 7591 등록 검증·레이트 리밋 | | `app/config.py` | 환경 변수 | | `app/db.py` | SQLite: 사용자·Gitea 토큰·OAuth 코드·액세스 토큰·등록 클라이언트 | | `app/crypto.py` | 토큰 Fernet 암호화 | | `tests/` | pytest (Gitea·gitea-mcp는 모킹) |