feat: add clap CLI with serve and version self-updater (FJMCP-3) #3

Merged
David merged 1 commit from feat/cli-serve-version-fjmcp-3 into main 2026-05-28 11:04:00 +02:00
Owner

Summary

Resolves FJMCP-3. forgejo-mcp gains a real clap CLI: --help and --version work, the MCP stdio server moves behind an explicit serve subcommand, and a new version show|check|update self-updater mirrors the youtrack-cli pattern (registry download, SHA-256 sidecar verification, self_replace, post-swap --version smoke test).

Changes

  • src/main.rs parses a clap Parser and dispatches: serve runs the previous stdio-server body (logs on stderr, JSON-RPC on stdout); version { show | check | update } is the self-updater. A bare forgejo-mcp no longer starts the server (prints usage, exits 2).
  • New build.rs bakes FORGEJO_MCP_GIT_HASH, FORGEJO_MCP_BUILD_DATE (RFC 3339 UTC), and FORGEJO_MCP_UPDATE_URL; --version prints forgejo-mcp <semver> (<git-hash>, built <build-date>). A tarball build with no .git falls back to unknown and the default URL.
  • version check HEADs the registry /latest artifact and reports newer / up-to-date / indeterminate against the baked date. version update probes the target dir for writability first (sudo / Administrator hint on permission denied), downloads the platform artifact, verifies a .sha256 sidecar when present (hard-fail on mismatch, skip when absent), self-replaces, and smoke-tests the swap via --version; --dry-run / --force / --url behave as in youtrack-cli. Logic ported to eyre (the crate's existing error type) rather than adding anyhow.
  • Callers and docs pass serve: the Dockerfile ENTRYPOINT, README usage and the claude mcp add example, and the just run recipe comment.
  • Both Dockerfiles COPY build.rs and accept FORGEJO_MCP_GIT_HASH / FORGEJO_MCP_BUILD_DATE build-args. The Linux and Windows CI workflows inject the git hash and build date and publish a .sha256 sidecar per artifact (get-tags.nu always emits the latest tag the updater queries).
  • CLAUDE.md drops the old "no build.rs / no version baking" note and documents the baked vars and the serve launch.

Note on the commit trailer

Per the repo's VCS-integration policy in CLAUDE.md, the commit carries a bare #FJMCP-3 reference (link only), not a State Done trailer. Forgejo applies commit commands at push time, not on merge, so a State Done trailer would resolve the issue while this PR is still open. The issue moves to Done after a human merges.

Test plan

  • cargo fmt --check and cargo clippy --all-targets -- -D warnings clean
  • cargo test: 33 tests pass (ported version + wiremock tests)
  • forgejo-mcp --help / --version / version / version show verified; bare invocation prints usage and exits 2
  • forgejo-mcp serve logs startup on stderr, behavior identical to the prior bare invocation
  • forgejo-mcp version check against the live registry reports the indeterminate case gracefully
  • just check-docker (builder-stage compile) succeeds with build.rs present
## Summary Resolves FJMCP-3. `forgejo-mcp` gains a real clap CLI: `--help` and `--version` work, the MCP stdio server moves behind an explicit `serve` subcommand, and a new `version show|check|update` self-updater mirrors the `youtrack-cli` pattern (registry download, SHA-256 sidecar verification, `self_replace`, post-swap `--version` smoke test). ## Changes - `src/main.rs` parses a clap `Parser` and dispatches: `serve` runs the previous stdio-server body (logs on stderr, JSON-RPC on stdout); `version { show | check | update }` is the self-updater. A bare `forgejo-mcp` no longer starts the server (prints usage, exits 2). - New `build.rs` bakes `FORGEJO_MCP_GIT_HASH`, `FORGEJO_MCP_BUILD_DATE` (RFC 3339 UTC), and `FORGEJO_MCP_UPDATE_URL`; `--version` prints `forgejo-mcp <semver> (<git-hash>, built <build-date>)`. A tarball build with no `.git` falls back to `unknown` and the default URL. - `version check` HEADs the registry `/latest` artifact and reports newer / up-to-date / indeterminate against the baked date. `version update` probes the target dir for writability first (sudo / Administrator hint on permission denied), downloads the platform artifact, verifies a `.sha256` sidecar when present (hard-fail on mismatch, skip when absent), self-replaces, and smoke-tests the swap via `--version`; `--dry-run` / `--force` / `--url` behave as in `youtrack-cli`. Logic ported to `eyre` (the crate's existing error type) rather than adding `anyhow`. - Callers and docs pass `serve`: the Dockerfile ENTRYPOINT, README usage and the `claude mcp add` example, and the `just run` recipe comment. - Both Dockerfiles `COPY build.rs` and accept `FORGEJO_MCP_GIT_HASH` / `FORGEJO_MCP_BUILD_DATE` build-args. The Linux and Windows CI workflows inject the git hash and build date and publish a `.sha256` sidecar per artifact (`get-tags.nu` always emits the `latest` tag the updater queries). - `CLAUDE.md` drops the old "no build.rs / no version baking" note and documents the baked vars and the `serve` launch. ## Note on the commit trailer Per the repo's VCS-integration policy in `CLAUDE.md`, the commit carries a bare `#FJMCP-3` reference (link only), not a `State Done` trailer. Forgejo applies commit commands at push time, not on merge, so a `State Done` trailer would resolve the issue while this PR is still open. The issue moves to Done after a human merges. ## Test plan - [x] `cargo fmt --check` and `cargo clippy --all-targets -- -D warnings` clean - [x] `cargo test`: 33 tests pass (ported version + wiremock tests) - [x] `forgejo-mcp --help` / `--version` / `version` / `version show` verified; bare invocation prints usage and exits 2 - [x] `forgejo-mcp serve` logs startup on stderr, behavior identical to the prior bare invocation - [x] `forgejo-mcp version check` against the live registry reports the indeterminate case gracefully - [x] `just check-docker` (builder-stage compile) succeeds with `build.rs` present
feat: add clap CLI with serve and version self-updater (FJMCP-3)
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 30s
Create release / Create release from merged PR (pull_request) Has been skipped
8750eff62f
main.rs previously did no argument parsing, so --help and --version were silently ignored and the process blocked on stdin. It now parses a clap CLI and dispatches: serve runs the previous stdio-server body (logs on stderr, JSON-RPC on stdout) and version { show | check | update } is a self-updater mirroring youtrack-cli. A bare forgejo-mcp no longer starts the server (prints usage, exits 2); callers pass serve.

A new build.rs bakes FORGEJO_MCP_GIT_HASH, FORGEJO_MCP_BUILD_DATE (RFC 3339 UTC), and FORGEJO_MCP_UPDATE_URL, so --version prints "forgejo-mcp <semver> (<git-hash>, built <build-date>)"; a tarball build with no .git falls back to unknown and the default URL. version check HEADs the registry /latest artifact and reports newer / up-to-date / indeterminate against the baked date; version update probes the target dir for writability (sudo / Administrator hint on permission denied), downloads the platform artifact, verifies a .sha256 sidecar when present (hard-fail on mismatch, skip when absent), self-replaces, and smoke-tests the swap via --version, with --dry-run / --force / --url. The logic is ported to eyre (the crate's existing error type) rather than adding anyhow.

Callers and docs pass serve: the Dockerfile ENTRYPOINT, README usage and the claude mcp add example, and the just run recipe. Both Dockerfiles COPY build.rs and accept FORGEJO_MCP_GIT_HASH / FORGEJO_MCP_BUILD_DATE build-args; the Linux and Windows CI workflows inject the git hash and build date and publish a .sha256 sidecar per artifact. CLAUDE.md drops the old "no build.rs / no version baking" note and documents the baked vars and the serve launch.

#FJMCP-3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
David merged commit 780040fd5d into main 2026-05-28 11:04:00 +02:00
David deleted branch feat/cli-serve-version-fjmcp-3 2026-05-28 11:04:00 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pandoras-box/forgejo-mcp!3
No description provided.