Commit Graph

85 Commits

Author SHA1 Message Date
a69d3a8b76 Merge pull request 'feat(tools): repo_tree, repo_topics_update, file_read dir fix (#14, #15, #18)' (#22) from feat/repo-ux into main
All checks were successful
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Has been skipped
v0.2.3
2026-05-15 08:24:35 +00:00
Mathias Bergqvist
5f3ad99122 feat(tools): repo_tree, repo_topics_update, file_read dir fix (#14, #15, #18)
All checks were successful
CD / Lint / Test / Vet (pull_request) Successful in 7s
CD / Build & Import (pull_request) Has been skipped
CD / Deploy via GitOps (pull_request) Has been skipped
repo_tree: GET /git/trees/{ref}?recursive=1 — full recursive file tree
repo_topics_update: PUT /repos/{owner}/{repo}/topics — replace topic list
file_read: detect array response and return descriptive error for dir paths
2026-05-15 10:23:31 +02:00
2c94de7b59 Merge pull request 'feat(tools): repo_create, repo_update, repo_mirror_push (#12, #13, #16)' (#21) from feat/repo-crud into main
All checks were successful
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Has been skipped
v0.2.2
2026-05-15 08:21:23 +00:00
Mathias Bergqvist
e2da495581 feat(tools): add repo_create, repo_update, repo_mirror_push (#12, #13, #16)
All checks were successful
CD / Lint / Test / Vet (pull_request) Successful in 7s
CD / Build & Import (pull_request) Has been skipped
CD / Deploy via GitOps (pull_request) Has been skipped
repo_create: POST /user/repos or /orgs/{org}/repos, is_org flag routes
repo_update: PATCH /repos/{owner}/{repo}, confirm required when private=false
repo_mirror_push: add/list/delete push mirrors, password never returned
2026-05-15 10:14:18 +02:00
Mathias Bergqvist
7178ae32be chore: re-sync context adapters 2026-05-15 09:53:09 +02:00
cb4f0caf0b docs: add current sprint context for gitea-mcp v0.2 tools (#11-#19)
All checks were successful
CD / Lint / Test / Vet (push) Successful in 8s
CD / Build & Import (push) Successful in 14s
CD / Deploy via GitOps (push) Successful in 3s
2026-05-14 21:27:29 +00:00
Mathias
174669b9f6 fix(mcp): drop strict session-id requirement on POST /mcp
All checks were successful
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Successful in 48s
The claude.ai connector's MCP transport proxy does not reliably
propagate the Mcp-Session-Id header issued during initialize. With the
previous strict gate (return 400 plain text "missing or invalid
Mcp-Session-Id"), every tools/list and tools/call from claude.ai
failed and the Anthropic proxy surfaced it as:

  Streamable HTTP error: {"jsonrpc":"2.0","id":N,"error":
    {"code":-32600,"message":"Anthropic Proxy: Invalid content from server"}}

— because the plain-text 400 response is not valid JSON-RPC.

All tools the gitea-mcp server exposes are stateless single-shot
calls, so there is no functional reason to gate them on a session.
brain-mcp and supervisor-mcp don't gate either, and claude.ai works
against them fine. Match that behavior: keep issuing Mcp-Session-Id
on initialize for clients that want to use it, but stop rejecting
calls that don't send one back.

Test renamed PostWithoutSessionRejected → PostWithoutSessionAccepted
and updated to assert the tools/list response shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:58:13 +02:00
Mathias Bergqvist
7a53935a9e chore(mcp): remove supervisor MCP entry
Some checks failed
CD / Lint / Test / Vet (push) Successful in 7s
CD / Build & Import (push) Successful in 13s
CD / Deploy via GitOps (push) Failing after 1m3s
2026-05-12 14:49:35 +02:00
Mathias
3795800461 fix(auth): require Bearer on /mcp regardless of DefaultToken
All checks were successful
CD / Lint / Test / Vet (push) Successful in 7s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Successful in 4s
Previously BearerMiddleware allowed requests with no Authorization
header to pass through whenever GITEA_MCP_DEFAULT_TOKEN was set. The
intent was "fall back to the service PAT for upstream Gitea calls,"
but the side effect was that anyone could hit /mcp anonymously and the
server would happily proxy requests as the service account.

Drop that path. Auth on /mcp now requires either:
  - a valid Dex-issued JWT, or
  - a Bearer matching GITEA_MCP_STATIC_TOKEN.

The Gitea service PAT (GITEA_MCP_DEFAULT_TOKEN) is no longer wired
into BearerMiddleware at all — it stays an upstream-client concern,
used by gitea.NewClient for outbound API calls only. This decouples
"can this caller invoke a tool" from "what credentials does the tool
use against Gitea".

Tests updated: drop the NoAuthHeader_WithDefault permissive case, add
NoAuthHeader_RejectsEvenWhenStaticConfigured to lock in the new
behavior.

Closes part of mathias/infra#2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:44:38 +02:00
Mathias Bergqvist
9987522f1a fix(ci): skip context sync drift check in CI environment
All checks were successful
CD / Lint / Test / Vet (push) Successful in 8s
CD / Build & Import (push) Successful in 13s
CD / Deploy via GitOps (push) Successful in 4s
Context-sync walks up the directory tree to find the root AGENT.md.
On koala's act_runner, checkout is under /var/lib/act_runner/, not
under ~/dev/, so ROOT_CONTEXT resolves to empty. Generated files
differ from committed files (which include root context), causing
the drift check to fail.

Skip context sync when CI=true; local checks still verify sync.
2026-05-12 12:09:24 +02:00
Mathias Bergqvist
0e53738d9f ci: retrigger after deps fix
Some checks failed
CD / Lint / Test / Vet (push) Failing after 2s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
2026-05-12 11:40:53 +02:00
Mathias Bergqvist
91be18c100 feat(auth): JWT-or-static middleware + /.well-known/oauth-protected-resource (issue #5)
Some checks failed
CD / Lint / Test / Vet (push) Failing after 2s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
- internal/auth/jwt.go: JWTValidator via lestrrat-go/jwx/v2, JWKS auto-refresh
- internal/auth/bearer.go: replace Gitea PAT validation with JWT->static->default chain
- internal/gitea/client.go: always use service PAT; remove TokenFromContext lookup
- internal/config/config.go: add DexIssuerURL, MCPAudience, MCPResourceURL, StaticToken
- cmd/gitea-mcp/main.go: wire validator, fix /.well-known to return real AS list
- bearer_test.go: rewrite for new API
2026-05-12 11:30:52 +02:00
Mathias Bergqvist
efbbd37882 chore: remove debug request logging
All checks were successful
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Successful in 11s
CD / Deploy via GitOps (push) Successful in 2s
Root cause confirmed (claude.ai sends no auth header); fallback token
is in place. Logging no longer needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:30:08 +02:00
Mathias Bergqvist
9d08352324 feat(auth): fall back to GITEA_MCP_DEFAULT_TOKEN when no Bearer header
All checks were successful
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Successful in 11s
CD / Deploy via GitOps (push) Successful in 3s
claude.ai connectors call the server with no Authorization header (confirmed
via request logging). Add a configurable default Gitea PAT so unauthenticated
clients (like claude.ai) can still reach the server.

Claude Code continues to pass per-request PATs; defaultToken="" preserves
the existing strict behaviour when the env var is unset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:22:04 +02:00
Mathias Bergqvist
70173875d8 debug: add request logging to diagnose claude.ai connector auth
All checks were successful
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Successful in 3s
Logs method, path, origin, has_auth, user_agent per request so we can
see exactly what claude.ai sends. Temporary; remove once root cause found.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 13:41:50 +02:00
Mathias Bergqvist
3784bcc31b fix(lint): check resp.Body.Close error in bearer_test.go
All checks were successful
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Successful in 15s
CD / Deploy via GitOps (push) Successful in 2s
Silences errcheck violations that have been breaking CI since the test
was written.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 13:25:37 +02:00
Mathias Bergqvist
f63605bdd0 fix(mcp): downgrade protocolVersion to 2025-03-26
Some checks failed
CD / Lint / Test / Vet (push) Failing after 3s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
Claude Code CLI rejects 2025-06-18 and silently drops the connection;
2025-03-26 is the highest version it supports. Fixes #4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.2.1
2026-05-09 07:53:18 +02:00
Mathias Bergqvist
c4d3735272 fix(mcp): allow GET/SSE without session ID for claude.ai compatibility
Some checks failed
CD / Lint / Test / Vet (push) Failing after 3s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
2026-05-07 23:22:21 +02:00
Mathias Bergqvist
d8db786e27 ci: add environment: staging gate to deploy job
Some checks failed
CD / Lint / Test / Vet (push) Failing after 2s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
Aligns with cobalt-dingo reference — the deploy job was missing the
Gitea Actions environment protection so staging approvals/secrets were
not enforced.
2026-05-07 21:52:40 +02:00
Mathias Bergqvist
923689afa5 feat: replace static API token with per-request Gitea PAT pass-through
Callers now supply their own Gitea PAT as a Bearer token; the server validates
it against GET /api/v1/user and threads it through context to all downstream
Gitea API calls. GITEA_API_TOKEN env var and the GiteaAPIToken config field are
removed.
2026-05-07 21:04:47 +02:00
Mathias Bergqvist
9a5d0005c5 feat: add 9 GitOps agent tools for full GitOps loop
All checks were successful
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Successful in 11s
CD / Deploy via GitOps (push) Has been skipped
Adds branch_list, branch_delete, branch_protection_get, pr_list,
pr_merge, dir_list, file_delete, tag_create, and repo_status so an
AI agent can autonomously drive feature-branch or trunk-based
development workflows against Gitea.
v0.2.0
2026-05-07 08:11:45 +02:00
Mathias Bergqvist
c0576359d7 feat: register 9 new GitOps tools in main
Wires branch_list, branch_delete, branch_protection_get, pr_list,
pr_merge, dir_list, file_delete, tag_create, and repo_status into the
MCP server registry so they are discoverable and callable by agents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 23:00:29 +02:00
Mathias Bergqvist
0c5903a196 feat(tools): repo_status 2026-05-06 22:59:51 +02:00
Mathias Bergqvist
839fc93dcd feat(tools): tag_create 2026-05-06 22:54:22 +02:00
Mathias Bergqvist
5dac4856bd feat(tools): file_delete 2026-05-06 22:51:21 +02:00
Mathias Bergqvist
0eb9ebcafd feat(tools): dir_list 2026-05-06 22:49:50 +02:00
Mathias Bergqvist
284d5e19f6 feat(tools): pr_merge 2026-05-06 22:48:02 +02:00
Mathias Bergqvist
388131c8cd feat(tools): pr_list 2026-05-06 22:46:11 +02:00
Mathias Bergqvist
ddfcc32afd feat(tools): branch_protection_get 2026-05-06 22:44:24 +02:00
Mathias Bergqvist
9e4251c1a7 feat(tools): branch_delete 2026-05-06 22:42:38 +02:00
Mathias Bergqvist
06882d185e fix(tools): branch_list schema constraints 2026-05-06 22:41:05 +02:00
Mathias Bergqvist
073d88b29a feat(tools): branch_list 2026-05-06 22:38:15 +02:00
Mathias Bergqvist
44c42fa636 feat(gitea): add DeleteJSONBody for delete-with-body requests 2026-05-06 22:36:37 +02:00
Mathias Bergqvist
e7bd954e90 docs: add GitOps agent tools implementation plan
11 tasks covering 9 new tools, client methods, tests, and registration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 22:22:41 +02:00
Mathias Bergqvist
0cd465fb68 docs: add GitOps agent tools design spec
9 new tools to enable full autonomous GitOps loop: repo_status,
branch_list/delete/protection_get, pr_list/merge, dir_list,
file_delete, tag_create.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 21:51:39 +02:00
4f0f65e26a Merge pull request 'fix: add OAuth discovery endpoints for claude.ai handshake' (#3) from fix/oauth-discovery-endpoints into main
All checks were successful
CD / Lint / Test / Vet (push) Successful in 5s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Successful in 3s
Reviewed-on: #3
2026-05-06 15:20:58 +00:00
Mathias Bergqvist
9cbb564cd9 fix: add OAuth discovery endpoints for claude.ai handshake
All checks were successful
CD / Lint / Test / Vet (pull_request) Successful in 5s
CD / Build & Import (pull_request) Has been skipped
CD / Deploy via GitOps (pull_request) Has been skipped
Implements RFC 9728 protected resource metadata and HEAD probe so
claude.ai can complete its pre-handshake discovery without hitting 404.

- GET /.well-known/oauth-protected-resource → 200 {"authorization_servers":[]}
- GET /.well-known/oauth-authorization-server → 404 (no auth server)
- HEAD /mcp → 200 + MCP-Protocol-Version: 2025-06-18 header

Closes #2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 17:19:14 +02:00
47e631da23 Merge pull request 'fix(file_write_branch): support file creation by routing POST/PUT on sha' (#1) from fix/file-write-branch-create into main
All checks were successful
CD / Lint / Test / Vet (push) Successful in 6s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Successful in 3s
Reviewed-on: #1
2026-05-06 14:44:38 +00:00
d35ff9781c test(file_write_branch): assert branch and commit_sha on PUT path for parity
All checks were successful
CD / Lint / Test / Vet (pull_request) Successful in 5s
CD / Build & Import (pull_request) Has been skipped
CD / Deploy via GitOps (pull_request) Has been skipped
2026-05-06 14:35:20 +00:00
052827320a test(file_write_branch): cover POST-on-create and PUT-on-update routing
All checks were successful
CD / Lint / Test / Vet (pull_request) Successful in 6s
CD / Build & Import (pull_request) Has been skipped
CD / Deploy via GitOps (pull_request) Has been skipped
2026-05-06 14:05:23 +00:00
c85197ea5e fix(files): route UpsertFile to POST when sha is empty so new files can be created 2026-05-06 14:04:36 +00:00
Mathias Bergqvist
c345025221 fix(lint): staticcheck S1030, QF1002 and remove unused _ctx stub
All checks were successful
CD / Lint / Test / Vet (push) Successful in 4s
CD / Build & Import (push) Successful in 12s
CD / Deploy via GitOps (push) Has been skipped
v0.1.2
2026-05-05 09:02:39 +02:00
Mathias Bergqvist
64559f0250 fix(lint): check Body.Close error return in http client
Some checks failed
CD / Lint / Test / Vet (push) Failing after 2s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
v0.1.1
2026-05-05 08:55:31 +02:00
Mathias Bergqvist
b8463d66a0 chore: drop environment: staging (no-op for solo homelab)
Some checks failed
CD / Lint / Test / Vet (push) Failing after 2s
CD / Build & Import (push) Has been skipped
CD / Deploy via GitOps (push) Has been skipped
v0.1.0
2026-05-05 08:51:17 +02:00
Mathias Bergqvist
d261a9f3fe feat: gitea actions cd.yml (cobalt-dingo pattern) 2026-05-05 07:52:45 +02:00
Mathias Bergqvist
09b3f25211 chore: add check task for CI 2026-05-05 07:52:39 +02:00
Mathias Bergqvist
a8d04242d9 feat: dockerfile 2026-05-05 07:52:29 +02:00
Mathias Bergqvist
1f9934349b chore(tools): centralize pagination cap helper 2026-05-04 23:06:38 +02:00
Mathias Bergqvist
4274b48ea5 feat(gitea): default-branch lru cache
Shared LRU avoids repeated Gitea calls for default-branch resolution;
the simple stdlib map alternative would race on concurrent access without
a mutex per entry, which is more code than the LRU.
2026-05-04 23:06:06 +02:00
Mathias Bergqvist
fb473262ba feat(gitea): read retry once on 5xx GET 2026-05-04 23:04:55 +02:00