feat(mcp): merge forgejo-mcp into fj as fj mcp serve (FJCLI-45) #59

Merged
David merged 1 commit from feat/FJCLI-45-merge-mcp-into-fj into main 2026-07-02 16:11:17 +02:00
Owner

Merges the standalone forgejo-mcp server into the fj binary as a new fj mcp serve subcommand, so the CLI and the MCP server ship from one repo through one release process. Implements FJCLI-45.

Why

forgejo-mcp was a separate repo whose every tool is a thin wrapper over a fj_core::* operation, pinned to fj-core / fj-client by a git rev that had already drifted (pinned at 8f27115 while this repo was at v0.9.0). Two repos meant two release processes: a critical fix touching the shared fj-core API had to be released twice. This is a hard fork with no upstream sync, so both repos are fully controlled here and there is no reason to keep them split.

What changed

  • New crates/fj-mcp workspace member holds the MCP server surface: the ForgejoServer rmcp tool router wrapping fj_core::*, the default-deny WritePolicy gating, and the stdio + axum Streamable-HTTP transports. It depends on fj-core / fj-client by path, replacing the git rev pin with compile-time coupling.
  • fj gains an mcp subcommand. fj mcp serve runs the stdio server; MCP_TRANSPORT=http fj mcp serve runs the bearer-gated Streamable-HTTP server. It is excluded from needs_keys() (the server loads its own credentials), and the host resolves from the global --host flag, then FORGEJO_HOST, then the built-in default.
  • The forgejo-mcp self-updater is dropped. fj version check|update (the update-check feature, train-aware and sha256-verified) supersedes it, so no FORGEJO_MCP_* build bakes or version module are carried over.
  • Both oci-build Dockerfiles COPY the new crate through their dependency-prime and real-source layers. README.md and CLAUDE.md document fj mcp serve, its env vars, and the claude mcp add -- fj mcp serve invocation.

Design decisions (confirmed with maintainer)

  • Separate crates/fj-mcp library crate, not an inline module, to isolate the rmcp/axum dependency tree.
  • MCP is always compiled into fj (no cargo feature gate).
  • Drop the MCP self-updater in favour of fj version.
  • Host resolution is a non-breaking superset (--host, then FORGEJO_HOST, then default), so existing env-driven deployments keep working.

Testing

  • just pre-commit (fmt + clippy -D warnings + build + full test suite in the rust-builder-glibc image): green, including the 9 fj-mcp tests.
  • just check-docker (builder-stage compile of oci-build/Dockerfile with the new COPY lines): green, image exported.
  • fj mcp serve --help renders the subcommand and its write-policy flags.

Follow-ups (filed and linked, both depend on this)

  • FJMCP-22: archive the forgejo-mcp repo, replace its README with a pointer to fj mcp serve, stop publishing forgejo-mcp-* packages, and migrate claude mcp add / HTTP deployments.
  • FJCLI-46: port the fully-static musl build so the combined binary has a portable fj-linux-x86_64-static artifact.

Breaking change

forgejo-mcp serve becomes fj mcp serve; the separate forgejo-mcp-* binaries are discontinued (tracked in FJMCP-22). Existing MCP client configs must switch to fj mcp serve (same env vars).

Merges the standalone `forgejo-mcp` server into the `fj` binary as a new `fj mcp serve` subcommand, so the CLI and the MCP server ship from one repo through one release process. Implements FJCLI-45. ## Why `forgejo-mcp` was a separate repo whose every tool is a thin wrapper over a `fj_core::*` operation, pinned to `fj-core` / `fj-client` by a git `rev` that had already drifted (pinned at `8f27115` while this repo was at `v0.9.0`). Two repos meant two release processes: a critical fix touching the shared `fj-core` API had to be released twice. This is a hard fork with no upstream sync, so both repos are fully controlled here and there is no reason to keep them split. ## What changed - New `crates/fj-mcp` workspace member holds the MCP server surface: the `ForgejoServer` rmcp tool router wrapping `fj_core::*`, the default-deny `WritePolicy` gating, and the stdio + axum Streamable-HTTP transports. It depends on `fj-core` / `fj-client` by path, replacing the git `rev` pin with compile-time coupling. - `fj` gains an `mcp` subcommand. `fj mcp serve` runs the stdio server; `MCP_TRANSPORT=http fj mcp serve` runs the bearer-gated Streamable-HTTP server. It is excluded from `needs_keys()` (the server loads its own credentials), and the host resolves from the global `--host` flag, then `FORGEJO_HOST`, then the built-in default. - The forgejo-mcp self-updater is dropped. `fj version check|update` (the `update-check` feature, train-aware and sha256-verified) supersedes it, so no `FORGEJO_MCP_*` build bakes or `version` module are carried over. - Both `oci-build` Dockerfiles COPY the new crate through their dependency-prime and real-source layers. README.md and CLAUDE.md document `fj mcp serve`, its env vars, and the `claude mcp add -- fj mcp serve` invocation. ## Design decisions (confirmed with maintainer) - Separate `crates/fj-mcp` library crate, not an inline module, to isolate the rmcp/axum dependency tree. - MCP is always compiled into `fj` (no cargo feature gate). - Drop the MCP self-updater in favour of `fj version`. - Host resolution is a non-breaking superset (`--host`, then `FORGEJO_HOST`, then default), so existing env-driven deployments keep working. ## Testing - `just pre-commit` (fmt + clippy `-D warnings` + build + full test suite in the rust-builder-glibc image): green, including the 9 `fj-mcp` tests. - `just check-docker` (builder-stage compile of `oci-build/Dockerfile` with the new COPY lines): green, image exported. - `fj mcp serve --help` renders the subcommand and its write-policy flags. ## Follow-ups (filed and linked, both depend on this) - FJMCP-22: archive the `forgejo-mcp` repo, replace its README with a pointer to `fj mcp serve`, stop publishing `forgejo-mcp-*` packages, and migrate `claude mcp add` / HTTP deployments. - FJCLI-46: port the fully-static musl build so the combined binary has a portable `fj-linux-x86_64-static` artifact. ## Breaking change `forgejo-mcp serve` becomes `fj mcp serve`; the separate `forgejo-mcp-*` binaries are discontinued (tracked in FJMCP-22). Existing MCP client configs must switch to `fj mcp serve` (same env vars).
feat(mcp): add fj-mcp crate and fj mcp serve subcommand
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 2m5s
Create release / Create release from merged PR (pull_request) Has been skipped
94ddaefed5
New `crates/fj-mcp` workspace member holds the MCP server surface (the `ForgejoServer` rmcp tool router wrapping `fj_core::*` operations, the default-deny `WritePolicy` gating, and the stdio + axum Streamable-HTTP transports), moved from the standalone forgejo-mcp repo and now depending on `fj-core` / `fj-client` by path instead of a git `rev`. This collapses two release processes into one: the CLI and the MCP server now ship from a single repo in a single `fj` binary.

`fj` gains an `mcp` subcommand (`fj mcp serve`) wired into the clap tree and dispatched in `Command::run`. It is excluded from `needs_keys()` because the server loads its own credentials (FORGEJO_TOKEN, else keys.json); the target host resolves from the global `--host` flag, then `FORGEJO_HOST`, then the built-in default. Write-policy flags (`--allow-edit` / `--allow-delete` / `--allow-global-write`) and their `MCP_ALLOW_*` env equivalents gate mutating tools as before.

The self-updater from forgejo-mcp is dropped; `fj version check|update` (the `update-check` feature) supersedes it, so no `FORGEJO_MCP_*` build bakes or `version` module are carried over.

Both `oci-build` Dockerfiles COPY the new crate through the dependency-prime and real-source layers; README.md and CLAUDE.md document `fj mcp serve`, its env vars, and the `claude mcp add -- fj mcp serve` invocation.

#FJCLI-45

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: David Randall <David@NiceGuyIT.biz>
David merged commit 7f8b184817 into main 2026-07-02 16:11:17 +02:00
David deleted branch feat/FJCLI-45-merge-mcp-into-fj 2026-07-02 16:11:17 +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-cli!59
No description provided.