Commit graph

3 commits

Author SHA1 Message Date
5eeac663d8 feat(broker): wire OAuth + MCP session glue into main; e2e test (forgejo-mcp-broker-q6n)
cmd/broker/main.go now composes every phase-2-5 component into a live
binary:

  /healthz      → internal/httpserver
  /oauth/*      → internal/oauth.Server.Handler()
  /.well-known  → internal/oauth.Server.Handler()
  /mcp          → oauth.Authenticator.RequireBearer
                   over session.Registry.Handler()

The SpawnFunc passed to the registry composes supervisor + bridge: each
new MCP session forks `forgejo-mcp --transport stdio` with the user's
upstream token in env, wraps stdio with a bridge, and returns the
bridge's HandleSSE as the per-session http.Handler. The reaper is wired
with a refresh callback that calls forgejo.Client.Refresh and persists
rotated tokens back to access_tokens before the rotator swaps the
session's child.

cmd/broker/e2e_test.go is the gating local validation: builds the
binary, builds forgejo-mcp from the sibling repo (skipped if absent),
stands up a fake Forgejo, runs the broker, and walks
register → authorize → callback → token → /mcp initialize → tools/list.
This catches:

  - any component left unwired
  - the subprocess-context bug fixed in this commit (using a request
    context in supervisor.Start kills the child when the request that
    minted it returns; the fix is a long-lived childCtx)
  - the happy-path Mcp-Session-Id mint+reuse cycle that unit tests
    can't exercise without a real subprocess

docs/phase7-findings.md documents both the local automated validation
(this test) and the manual Claude.ai-side checklist (OAuth completes,
tool discovery, tool invocation, session reuse, idle reap, mid-session
token refresh, revocation). The Claude.ai half is fundamentally manual
and stays that way; the automated test catches the broker bugs that
would otherwise hide behind operator setup mistakes.

Closes forgejo-mcp-broker-q6n. Phase 7 — and the project's primary
implementation track — complete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 17:55:18 +02:00
09fcdc5af4 feat(cmd/broker): wire config → log → store → httpserver (forgejo-mcp-broker-t37)
Final phase-1 step: the broker now starts. run() parses config, opens
the store, builds the httpserver, and blocks on signal.NotifyContext
until SIGTERM/SIGINT fires, at which point it drains through
httpserver.Run's graceful-shutdown path and closes the store.

--version is handled before config.Load so operators can inspect a
binary without providing the rest of the config. flag.ErrHelp is passed
through so -h exits 0. Config failure exits 2; runtime failure exits 1.

Integration tests build the binary once in TestMain and exercise three
acceptance scenarios against it:
- --version: prints build info, exits 0
- no config: exits nonzero with stderr listing every missing field
- full startup: /healthz returns 200 with correct JSON; SIGTERM triggers
  clean exit within 2s

Closes forgejo-mcp-broker-t37. Phase 1 complete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 17:29:37 +02:00
de5ce2de94 feat: bootstrap Go project layout (forgejo-mcp-broker-n84)
- Initialize go.mod with module path kode.naiv.no/olemd/forgejo-mcp-broker
- Create directory layout: cmd/broker + internal/{buildinfo,config,log,store,httpserver}
- Add Makefile with build/test/lint/tidy/clean targets and ldflags-injected build info
- Stub cmd/broker/main.go with --version support; real wiring follows in -t37
- Stub doc.go for each internal/* package, pointing to the issue that fills it in

Closes forgejo-mcp-broker-n84.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 16:54:27 +02:00