Commit Graph

10 Commits

Author SHA1 Message Date
zhengchen.tao f5b925f242 fix(build): NuGet cache mount sharing=locked to avoid concurrent restore races
Build Docker Image / build (push) Successful in 18m11s
Build Docker Image / deploy (push) Successful in 1m22s
With capacity=2 in the runner, two builds can run in parallel and share
the same buildkit cache mount (sharing=shared is the default). dotnet
restore writes NuGet temp files (*.ar5 etc.) that the OTHER build can
race-remove mid-extraction, yielding 'Could not find file' errors like:

  error : Could not find file '/root/.nuget/packages/microsoft.identitymodel.abstractions/8.0.1/3wu4hkqc.ar5'

sharing=locked serializes cache access (one build at a time can touch
the mount). Still benefits from across-build caching, just no concurrency
on the mount itself.
2026-05-17 14:02:32 +08:00
zhengchen.tao 7b04971e86 fix(deps): drop explicit pin on Microsoft.IdentityModel.Tokens
Build Docker Image / build (push) Has been cancelled
Build Docker Image / deploy (push) Has been cancelled
Same fix as obsidian-mcp: JwtBearer 10.0.x's transitive JsonWebTokens 9.x
calls Decode(ReadOnlySpan, Span) which is only in Tokens 9.x. Explicit
pin to 8.* forces downgrade → MissingMethodException → 401 on every
JWT validation.
2026-05-17 13:47:32 +08:00
zhengchen.tao 386111280c ci: cache-to use mode=min + ignore-error to unblock deploy
Build Docker Image / build (push) Failing after 11s
Build Docker Image / deploy (push) Has been skipped
Same fix as nas-auth and obsidian-mcp.
2026-05-17 01:17:38 +08:00
zhengchen.tao 7953f768f6 build: NuGet cache mount + buildx registry cache
Build Docker Image / build (push) Failing after 15m18s
Build Docker Image / deploy (push) Has been skipped
Mirror the cache infra added to nas-auth (commit a1ecba3) and
obsidian-mcp. Same pattern: --mount=type=cache for restore+publish
in Dockerfile, registry cache mode=max in workflow.
2026-05-17 00:35:22 +08:00
zhengchen.tao 16bd328849 feat(oauth): expose RFC 9728 protected resource metadata endpoint
Build Docker Image / build (push) Failing after 12m20s
Build Docker Image / deploy (push) Has been skipped
Same fix as obsidian-mcp: Claude.ai needs PRM to know the resource
identifier and send RFC 8707 `resource` in /authorize requests.

Adds /.well-known/oauth-protected-resource. ResourceUrl is configurable
via Mcp__OAuthDiscovery__ResourceUrl, falling back to request authority
when unset.
2026-05-16 17:36:04 +08:00
zhengchen.tao 0f07300cec refactor: unify JwtOptions schema with obsidian-mcp + simplify deploy
Build Docker Image / build (push) Has been cancelled
Build Docker Image / deploy (push) Has been cancelled
- Config/JwtOptions: flatten SigningKeyCurrent/Previous into nested
  SigningKey { Current, Previous } class to match obsidian-mcp shape.
  Both services now bind the same env var pattern (Jwt__SigningKey__Current),
  removing the schema fork that caused gitea-mcp to start with empty keys
  when compose used the obsidian-mcp convention.
- Auth/JwtBearerSetup, appsettings.json, README: follow rename.
- .gitea/workflows/build-image.yml: deploy job no longer clones nas-infra
  to a temp dir (which lacks the gitignored .env.shared). Now cd directly
  into /volume1/docker/compose/gitea-mcp, exposed by gitea-runner mount.
2026-05-16 17:24:09 +08:00
zhengchen.tao 8f35bf5b15 fix(http): set CircuitBreaker.SamplingDuration to 60s
Build Docker Image / build (push) Successful in 10m45s
Build Docker Image / deploy (push) Failing after 53s
Polly StandardResilienceHandler validates SamplingDuration >= 2 * AttemptTimeout
at startup. Default SamplingDuration is 30s and our AttemptTimeout is 30s, so
the container failed to boot with OptionsValidationException.

Set SamplingDuration explicitly to 60s while keeping AttemptTimeout at 30s.
2026-05-16 16:53:18 +08:00
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
zhengchen.tao bbe1ccecd1 fix(docker): 用 useradd 替换 adduser(slim 镜像无 adduser)
Build Docker Image / build (push) Successful in 9m29s
Build Docker Image / deploy (push) Failing after 24s
Debian bookworm-slim 不带 adduser(perl wrapper 包),
导致 build 阶段 exit 127 (command not found)。
改用预装 passwd 包提供的 useradd,语义等价。
2026-05-06 23:28:37 +08:00
zhengchen.tao c7fa6aeb7f gitea-mcp: 初次落地 Gitea MCP Server (.NET 10, V1 only-read)
Build Docker Image / build (push) Failing after 5m41s
Build Docker Image / deploy (push) Has been skipped
把 Gitea (git.zhengchentao.win) 通过 MCP 暴露给 Claude.ai:列 repo、读代码、看 commits / issues / PR / orgs / packages / actions。
设计文档见 vault Coding/gitea-mcp/gitea-mcp 设计.md。
代码模板复用 obsidian-mcp(.NET 10 + ModelContextProtocol SDK + JwtBearer)。

19 个只读 Tool(全部 scope=read:gitea):

Repo / 文件:
- list_repos / read_repo
- list_tree(max_entries=500 防爆)
- read_file(max_bytes=1MB,超出 truncated=true)
- search_code(走 /repos/search-code,indexer 未启用时返回结构化错误说明)

分支 / 提交:
- list_branches / list_commits / read_commit(diff 文件数限 50)

Issue / PR:
- list_issues / read_issue(含评论)
- list_pulls / read_pull(含评论 + 改动文件列表)

Org / Package(用户额外授权 read:organization + read:package):
- list_orgs / read_org
- list_packages / read_package

Gitea Actions(运维友好):
- list_workflow_runs / read_run_log

技术栈:
- .NET 10 + ModelContextProtocol SDK 1.0
- HttpClientFactory + Microsoft.Extensions.Http.Resilience(指数 backoff,5xx/429/网络错误重试)
- JwtBearer (HS256, Current+Previous fallback, MapInboundClaims=false)
- aud=gitea, scope=read:gitea, iss=https://auth.zhengchentao.win

Gitea API client:
- Authorization: token <PAT> (admin PAT,仅 read scope)
- BaseUrl=https://git.zhengchentao.win
- 错误映射:401/403 → UnauthorizedAccessException,404 → KeyNotFoundException,5xx → InvalidOperationException
- RepoBlacklist 黑名单(owner/repo 精确匹配,默认空)

部署:
- Dockerfile multi-stage,COPY --chown,non-root user
- .gitea/workflows/build-image.yml:build + deploy 双 job,buildkit v0.13.2
- 容器内 :8080,宿主端口 9092
- 子域名 git-mcp.zhengchentao.win(区别于 Gitea 本体 git.zhengchentao.win)

测试:6/6 单测过(GiteaRepoFilter 黑名单匹配)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 01:32:42 +08:00